Merge pull request #1707 from stianst/client-reg
Refactored client registration service
This commit is contained in:
commit
4f7979d9fc
12 changed files with 231 additions and 40 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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> {
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 <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 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.services.clientregistration.DefaultClientRegistrationProviderFactory
|
Loading…
Reference in a new issue