Refactored client registration service

This commit is contained in:
Stian Thorgersen 2015-10-09 14:36:30 +02:00
parent 960cd8c822
commit 2faf0eccdb
12 changed files with 231 additions and 40 deletions

View file

@ -231,7 +231,7 @@ public class ClientRegistration {
public ClientRegistration build() { public ClientRegistration build() {
ClientRegistration clientRegistration = new ClientRegistration(); 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.httpClient = httpClient != null ? httpClient : HttpClients.createDefault();
clientRegistration.auth = auth; clientRegistration.auth = auth;

View file

@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface ClientRegistrationProvider extends Provider {
void setRealm(RealmModel realm);
void setEvent(EventBuilder event);
}

View file

@ -0,0 +1,9 @@
package org.keycloak.services.clientregistration;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public interface ClientRegistrationProviderFactory extends ProviderFactory<ClientRegistrationProvider> {
}

View file

@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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;
}
}

View file

@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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;
}
}

View file

@ -1,14 +1,9 @@
package org.keycloak.services.resources; package org.keycloak.services.clientregistration;
import org.jboss.logging.Logger; 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.Errors;
import org.keycloak.events.EventBuilder; import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
import org.keycloak.exportimport.ClientDescriptionConverter;
import org.keycloak.exportimport.KeycloakClientDescriptionConverter;
import org.keycloak.models.*; import org.keycloak.models.*;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.RepresentationToModel; 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.AccessToken;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.ForbiddenException; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import javax.ws.rs.*; import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -31,52 +24,37 @@ import java.net.URI;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
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 RealmModel realm;
private EventBuilder event; public DefaultClientRegistrationProvider(KeycloakSession session) {
this.session = session;
@Context
private KeycloakSession session;
private AppAuthManager authManager = new AppAuthManager();
public ClientRegistrationService(RealmModel realm, EventBuilder event) {
this.realm = realm;
this.event = event;
} }
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN }) @Consumes(MediaType.APPLICATION_JSON)
public Response create(String description, @QueryParam("format") String format) { public Response create(ClientRepresentation client) {
event.event(EventType.CLIENT_REGISTER); event.event(EventType.CLIENT_REGISTER);
authenticate(true, null); 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 { try {
ClientModel clientModel = RepresentationToModel.createClient(session, realm, rep, true); ClientModel clientModel = RepresentationToModel.createClient(session, realm, client, true);
rep = ModelToRepresentation.toRepresentation(clientModel); client = ModelToRepresentation.toRepresentation(clientModel);
URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(clientModel.getId()).build(); 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(); event.client(client.getClientId()).success();
return Response.created(uri).entity(rep).build(); return Response.created(uri).entity(client).build();
} catch (ModelDuplicateException e) { } 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) { private ClientModel authenticate(boolean create, String clientId) {
String authorizationHeader = session.getContext().getRequestHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION); String authorizationHeader = session.getContext().getRequestHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
boolean bearer = authorizationHeader != null && authorizationHeader.split(" ")[0].equalsIgnoreCase("Bearer"); boolean bearer = authorizationHeader != null && authorizationHeader.split(" ")[0].equalsIgnoreCase("Bearer");
if (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); AccessToken.Access realmAccess = authResult.getToken().getResourceAccess(Constants.REALM_MANAGEMENT_CLIENT_ID);
if (realmAccess != null) { if (realmAccess != null) {
if (realmAccess.isUserInRole(AdminRoles.MANAGE_CLIENTS)) { if (realmAccess.isUserInRole(AdminRoles.MANAGE_CLIENTS)) {
@ -158,4 +142,14 @@ public class ClientRegistrationService {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@Override
public void setRealm(RealmModel realm) {
this.realm = realm;
}
@Override
public void setEvent(EventBuilder event) {
this.event = event;
}
} }

View file

@ -0,0 +1,34 @@
package org.keycloak.services.clientregistration;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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";
}
}

View file

@ -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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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;
}
}

View file

@ -0,0 +1,34 @@
package org.keycloak.services.clientregistration;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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";
}
}

View file

@ -13,6 +13,7 @@ import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.LoginProtocolFactory;
import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.services.clientregistration.ClientRegistrationService;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector; import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;

View file

@ -8,3 +8,4 @@ org.keycloak.authentication.ClientAuthenticatorSpi
org.keycloak.authentication.RequiredActionSpi org.keycloak.authentication.RequiredActionSpi
org.keycloak.authentication.FormAuthenticatorSpi org.keycloak.authentication.FormAuthenticatorSpi
org.keycloak.authentication.FormActionSpi org.keycloak.authentication.FormActionSpi
org.keycloak.services.clientregistration.ClientRegistrationSpi

View file

@ -0,0 +1 @@
org.keycloak.services.clientregistration.DefaultClientRegistrationProviderFactory