diff --git a/client-api/src/main/java/org/keycloak/client/registration/ClientRegistration.java b/client-api/src/main/java/org/keycloak/client/registration/ClientRegistration.java
index dae44a4157..24422c5667 100644
--- a/client-api/src/main/java/org/keycloak/client/registration/ClientRegistration.java
+++ b/client-api/src/main/java/org/keycloak/client/registration/ClientRegistration.java
@@ -231,7 +231,7 @@ public class ClientRegistration {
public ClientRegistration build() {
ClientRegistration clientRegistration = new ClientRegistration();
- clientRegistration.clientRegistrationUrl = authServerUrl + "/realms/" + realm + "/client-registration";
+ clientRegistration.clientRegistrationUrl = authServerUrl + "/realms/" + realm + "/client-registration/default";
clientRegistration.httpClient = httpClient != null ? httpClient : HttpClients.createDefault();
clientRegistration.auth = auth;
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProvider.java
new file mode 100644
index 0000000000..d1d664868a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProvider.java
@@ -0,0 +1,16 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author Stian Thorgersen
+ */
+public interface ClientRegistrationProvider extends Provider {
+
+ void setRealm(RealmModel realm);
+
+ void setEvent(EventBuilder event);
+
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProviderFactory.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProviderFactory.java
new file mode 100644
index 0000000000..d9be24047f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationProviderFactory.java
@@ -0,0 +1,9 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author Stian Thorgersen
+ */
+public interface ClientRegistrationProviderFactory extends ProviderFactory {
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java
new file mode 100644
index 0000000000..8b215face8
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationService.java
@@ -0,0 +1,37 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.AppAuthManager;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Context;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class ClientRegistrationService {
+
+ private RealmModel realm;
+
+ private EventBuilder event;
+
+ @Context
+ private KeycloakSession session;
+
+ public ClientRegistrationService(RealmModel realm, EventBuilder event) {
+ this.realm = realm;
+ this.event = event;
+ }
+
+ @Path("{provider}")
+ public Object getProvider(@PathParam("provider") String providerId) {
+ ClientRegistrationProvider provider = session.getProvider(ClientRegistrationProvider.class, providerId);
+ provider.setRealm(realm);
+ provider.setEvent(event);
+ return provider;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationSpi.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationSpi.java
new file mode 100644
index 0000000000..3672f7fd72
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationSpi.java
@@ -0,0 +1,30 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class ClientRegistrationSpi implements Spi {
+ @Override
+ public boolean isInternal() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return "client-registration";
+ }
+
+ @Override
+ public Class extends Provider> getProviderClass() {
+ return ClientRegistrationProvider.class;
+ }
+
+ @Override
+ public Class extends ProviderFactory> getProviderFactoryClass() {
+ return ClientRegistrationProviderFactory.class;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/ClientRegistrationService.java b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
similarity index 70%
rename from services/src/main/java/org/keycloak/services/resources/ClientRegistrationService.java
rename to services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
index dac9daa93c..04cb46a69c 100644
--- a/services/src/main/java/org/keycloak/services/resources/ClientRegistrationService.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProvider.java
@@ -1,14 +1,9 @@
-package org.keycloak.services.resources;
+package org.keycloak.services.clientregistration;
import org.jboss.logging.Logger;
-import org.jboss.resteasy.spi.BadRequestException;
-import org.jboss.resteasy.spi.NotFoundException;
-import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
-import org.keycloak.exportimport.ClientDescriptionConverter;
-import org.keycloak.exportimport.KeycloakClientDescriptionConverter;
import org.keycloak.models.*;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel;
@@ -16,13 +11,11 @@ import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.ErrorResponse;
-import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import javax.ws.rs.*;
-import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -31,52 +24,37 @@ import java.net.URI;
/**
* @author Stian Thorgersen
*/
-public class ClientRegistrationService {
+public class DefaultClientRegistrationProvider implements ClientRegistrationProvider {
- protected static final Logger logger = Logger.getLogger(ClientRegistrationService.class);
+ private static final Logger logger = Logger.getLogger(DefaultClientRegistrationProvider.class);
+ private KeycloakSession session;
+ private EventBuilder event;
private RealmModel realm;
- private EventBuilder event;
-
- @Context
- private KeycloakSession session;
-
- private AppAuthManager authManager = new AppAuthManager();
-
- public ClientRegistrationService(RealmModel realm, EventBuilder event) {
- this.realm = realm;
- this.event = event;
+ public DefaultClientRegistrationProvider(KeycloakSession session) {
+ this.session = session;
}
+
@POST
- @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
- public Response create(String description, @QueryParam("format") String format) {
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response create(ClientRepresentation client) {
event.event(EventType.CLIENT_REGISTER);
authenticate(true, null);
- if (format == null) {
- format = KeycloakClientDescriptionConverter.ID;
- }
-
- ClientDescriptionConverter converter = session.getProvider(ClientDescriptionConverter.class, format);
- if (converter == null) {
- throw new BadRequestException("Invalid format");
- }
- ClientRepresentation rep = converter.convertToInternal(description);
-
try {
- ClientModel clientModel = RepresentationToModel.createClient(session, realm, rep, true);
- rep = ModelToRepresentation.toRepresentation(clientModel);
+ ClientModel clientModel = RepresentationToModel.createClient(session, realm, client, true);
+ client = ModelToRepresentation.toRepresentation(clientModel);
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build();
- logger.infov("Created client {0}", rep.getClientId());
+ logger.infov("Created client {0}", client.getClientId());
- event.client(rep.getClientId()).success();
- return Response.created(uri).entity(rep).build();
+ event.client(client.getClientId()).success();
+ return Response.created(uri).entity(client).build();
} catch (ModelDuplicateException e) {
- return ErrorResponse.exists("Client " + rep.getClientId() + " already exists");
+ return ErrorResponse.exists("Client " + client.getClientId() + " already exists");
}
}
@@ -122,13 +100,19 @@ public class ClientRegistrationService {
}
}
+ @Override
+ public void close() {
+
+ }
+
+
private ClientModel authenticate(boolean create, String clientId) {
String authorizationHeader = session.getContext().getRequestHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
boolean bearer = authorizationHeader != null && authorizationHeader.split(" ")[0].equalsIgnoreCase("Bearer");
if (bearer) {
- AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(session, realm);
+ AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(session, realm);
AccessToken.Access realmAccess = authResult.getToken().getResourceAccess(Constants.REALM_MANAGEMENT_CLIENT_ID);
if (realmAccess != null) {
if (realmAccess.isUserInRole(AdminRoles.MANAGE_CLIENTS)) {
@@ -158,4 +142,14 @@ public class ClientRegistrationService {
throw new ForbiddenException();
}
+ @Override
+ public void setRealm(RealmModel realm) {
+this.realm = realm;
+ }
+
+ @Override
+ public void setEvent(EventBuilder event) {
+ this.event = event;
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProviderFactory.java b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProviderFactory.java
new file mode 100644
index 0000000000..ec996528c4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/DefaultClientRegistrationProviderFactory.java
@@ -0,0 +1,34 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class DefaultClientRegistrationProviderFactory implements ClientRegistrationProviderFactory {
+
+ @Override
+ public ClientRegistrationProvider create(KeycloakSession session) {
+ return new DefaultClientRegistrationProvider(session);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return "default";
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProvider.java
new file mode 100644
index 0000000000..baf9df1a7e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProvider.java
@@ -0,0 +1,34 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.events.EventBuilder;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class OIDCClientRegistrationProvider implements ClientRegistrationProvider {
+
+ private KeycloakSession session;
+ private RealmModel realm;
+ private EventBuilder event;
+
+ public OIDCClientRegistrationProvider(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void setRealm(RealmModel realm) {
+ this.realm = realm;
+ }
+
+ @Override
+ public void setEvent(EventBuilder event) {
+ this.event = event;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProviderFactory.java b/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProviderFactory.java
new file mode 100644
index 0000000000..a3ba0005d4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/OIDCClientRegistrationProviderFactory.java
@@ -0,0 +1,34 @@
+package org.keycloak.services.clientregistration;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author Stian Thorgersen
+ */
+public class OIDCClientRegistrationProviderFactory implements ClientRegistrationProviderFactory {
+
+ @Override
+ public ClientRegistrationProvider create(KeycloakSession session) {
+ return new OIDCClientRegistrationProvider(session);
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public String getId() {
+ return "openid-connect";
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index dda825fdf3..73aaca64f7 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -13,6 +13,7 @@ import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocolFactory;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.services.clientregistration.ClientRegistrationService;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.managers.RealmManager;
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 6d88f97303..511954861f 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -8,3 +8,4 @@ org.keycloak.authentication.ClientAuthenticatorSpi
org.keycloak.authentication.RequiredActionSpi
org.keycloak.authentication.FormAuthenticatorSpi
org.keycloak.authentication.FormActionSpi
+org.keycloak.services.clientregistration.ClientRegistrationSpi
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.services.clientregistration.ClientRegistrationProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.services.clientregistration.ClientRegistrationProviderFactory
new file mode 100644
index 0000000000..3e8773a31a
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.services.clientregistration.ClientRegistrationProviderFactory
@@ -0,0 +1 @@
+org.keycloak.services.clientregistration.DefaultClientRegistrationProviderFactory
\ No newline at end of file