From 8c5b1e489245b026aa51303e24e875b1d44c1d7a Mon Sep 17 00:00:00 2001 From: mposolda Date: Mon, 5 Sep 2016 23:12:14 +0200 Subject: [PATCH] KEYCLOAK-3525 Validation callback when creating/updating protocolMapper --- .../org/keycloak/protocol/ProtocolMapper.java | 16 +++++++ .../ProtocolMapperConfigException.java | 48 +++++++++++++++++++ .../oidc/mappers/UserAttributeMapper.java | 2 + .../resources/admin/ClientResource.java | 2 +- .../admin/ClientTemplateResource.java | 2 +- .../admin/ProtocolMappersResource.java | 34 ++++++++++++- 6 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 server-spi/src/main/java/org/keycloak/protocol/ProtocolMapperConfigException.java diff --git a/server-spi/src/main/java/org/keycloak/protocol/ProtocolMapper.java b/server-spi/src/main/java/org/keycloak/protocol/ProtocolMapper.java index 1942422269..8055fae82d 100755 --- a/server-spi/src/main/java/org/keycloak/protocol/ProtocolMapper.java +++ b/server-spi/src/main/java/org/keycloak/protocol/ProtocolMapper.java @@ -17,6 +17,10 @@ package org.keycloak.protocol; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ProtocolMapperContainerModel; +import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.models.RealmModel; import org.keycloak.provider.ConfiguredProvider; import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; @@ -30,4 +34,16 @@ public interface ProtocolMapper extends Provider, ProviderFactoryMarek Posolda + */ +public class ProtocolMapperConfigException extends Exception { + + private Object[] parameters; + + public ProtocolMapperConfigException(String message) { + super(message); + } + + public ProtocolMapperConfigException(String message, Throwable cause) { + super(message, cause); + } + + public ProtocolMapperConfigException(String message, Object ... parameters) { + super(message); + this.parameters = parameters; + } + + public Object[] getParameters() { + return parameters; + } + + public void setParameters(Object[] parameters) { + this.parameters = parameters; + } + +} diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java index 56e7a48d2e..f7475a95cf 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java @@ -19,10 +19,12 @@ package org.keycloak.protocol.oidc.mappers; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ProtocolMapperContainerModel; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.protocol.ProtocolMapperConfigException; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java index dd17b07a8e..9b6593f548 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java @@ -107,7 +107,7 @@ public class ClientResource { @Path("protocol-mappers") public ProtocolMappersResource getProtocolMappers() { - ProtocolMappersResource mappers = new ProtocolMappersResource(client, auth, adminEvent); + ProtocolMappersResource mappers = new ProtocolMappersResource(realm, client, auth, adminEvent); ResteasyProviderFactory.getInstance().injectProperties(mappers); return mappers; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java index baf9bb65f3..761e307f9c 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java @@ -81,7 +81,7 @@ public class ClientTemplateResource { @Path("protocol-mappers") public ProtocolMappersResource getProtocolMappers() { - ProtocolMappersResource mappers = new ProtocolMappersResource(template, auth, adminEvent); + ProtocolMappersResource mappers = new ProtocolMappersResource(realm, template, auth, adminEvent); ResteasyProviderFactory.getInstance().injectProperties(mappers); return mappers; } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java index b9da2bf107..86dcefcfe5 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java @@ -20,14 +20,22 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; +import org.keycloak.mappers.FederationConfigValidationException; +import org.keycloak.mappers.UserFederationMapper; +import org.keycloak.mappers.UserFederationMapperFactory; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ProtocolMapperContainerModel; import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.RepresentationToModel; +import org.keycloak.protocol.ProtocolMapper; +import org.keycloak.protocol.ProtocolMapperConfigException; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.services.ErrorResponse; +import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ServicesLogger; import org.keycloak.services.resources.admin.RealmAuth.Resource; @@ -44,8 +52,10 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; +import java.util.Properties; /** * Base resource for managing users @@ -56,6 +66,8 @@ import java.util.List; public class ProtocolMappersResource { protected static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER; + protected RealmModel realm; + protected ProtocolMapperContainerModel client; protected RealmAuth auth; @@ -68,7 +80,8 @@ public class ProtocolMappersResource { @Context protected KeycloakSession session; - public ProtocolMappersResource(ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) { + public ProtocolMappersResource(RealmModel realm, ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) { + this.realm = realm; this.auth = auth; this.client = client; this.adminEvent = adminEvent.resource(ResourceType.PROTOCOL_MAPPER); @@ -119,6 +132,7 @@ public class ProtocolMappersResource { ProtocolMapperModel model = null; try { model = RepresentationToModel.toModel(rep); + validateModel(model); model = client.addProtocolMapper(model); adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(rep).success(); @@ -146,6 +160,7 @@ public class ProtocolMappersResource { ProtocolMapperModel model = null; for (ProtocolMapperRepresentation rep : reps) { model = RepresentationToModel.toModel(rep); + validateModel(model); model = client.addProtocolMapper(model); } adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(reps).success(); @@ -216,6 +231,9 @@ public class ProtocolMappersResource { ProtocolMapperModel model = client.getProtocolMapperById(id); if (model == null) throw new NotFoundException("Model not found"); model = RepresentationToModel.toModel(rep); + + validateModel(model); + client.updateProtocolMapper(model); adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success(); } @@ -242,4 +260,18 @@ public class ProtocolMappersResource { } + private void validateModel(ProtocolMapperModel model) { + try { + ProtocolMapper mapper = (ProtocolMapper)session.getKeycloakSessionFactory().getProviderFactory(ProtocolMapper.class, model.getProtocolMapper()); + if (mapper != null) { + mapper.validateConfig(session, realm, client, model); + } + } catch (ProtocolMapperConfigException ex) { + logger.error(ex.getMessage()); + Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale()); + throw new ErrorResponseException(ex.getMessage(), MessageFormat.format(messages.getProperty(ex.getMessage(), ex.getMessage()), ex.getParameters()), + Response.Status.BAD_REQUEST); + } + } + }