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 getProviderClass() { + return ClientRegistrationProvider.class; + } + + @Override + public Class 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