keycloak-aplcache
Changes
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AbstractSAMLProtocolMapper.java 1(+0 -1)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java 10(+7 -3)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java 1(+0 -1)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleListMapper.java 153(+153 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleNameMapper.java 91(+91 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java 1(+0 -1)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleNameMapper.java 12(+12 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java 21(+0 -21)
Details
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AbstractSAMLProtocolMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AbstractSAMLProtocolMapper.java
index 3d42ef7..303aff3 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AbstractSAMLProtocolMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AbstractSAMLProtocolMapper.java
@@ -4,7 +4,6 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.protocol.ProtocolMapper;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.saml.SamlProtocol;
/**
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java
index 378a0f6..b5850a5 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java
@@ -1,7 +1,6 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.models.ProtocolMapperModel;
-import org.keycloak.models.RealmModel;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.protocol.saml.SamlProtocol;
@@ -31,6 +30,12 @@ public class AttributeStatementHelper {
public static void addAttribute(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel,
String attributeValue) {
+ AttributeType attribute = createAttributeType(mappingModel);
+ attribute.addAttributeValue(attributeValue);
+ attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
+ }
+
+ public static AttributeType createAttributeType(ProtocolMapperModel mappingModel) {
String attributeName = mappingModel.getConfig().get(SAML_ATTRIBUTE_NAME);
AttributeType attribute = new AttributeType(attributeName);
String attributeType = mappingModel.getConfig().get(SAML_ATTRIBUTE_NAMEFORMAT);
@@ -40,8 +45,7 @@ public class AttributeStatementHelper {
attribute.setNameFormat(attributeNameFormat);
String friendlyName = mappingModel.getConfig().get(FRIENDLY_NAME);
if (friendlyName != null && !friendlyName.trim().equals("")) attribute.setFriendlyName(friendlyName);
- attribute.addAttributeValue(attributeValue);
- attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
+ return attribute;
}
public static void setConfigProperties(List<ProtocolMapper.ConfigProperty> configProperties) {
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
index 8abe681..5b1a3da 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
@@ -5,7 +5,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
-import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleListMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleListMapper.java
new file mode 100755
index 0000000..9895944
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleListMapper.java
@@ -0,0 +1,153 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapper;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRoleListMapper {
+ public static final String PROVIDER_ID = "saml-role-list-mapper";
+ public static final String SINGLE_ROLE_ATTRIBUTE = "single";
+
+ private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+ static {
+ ConfigProperty property;
+ property = new ConfigProperty();
+ property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAME);
+ property.setLabel("Role attribute name");
+ property.setDefaultValue("Role");
+ property.setHelpText("Name of the SAML attribute you want to put your roles into. i.e. 'Role', 'memberOf'.");
+ configProperties.add(property);
+ property = new ProtocolMapper.ConfigProperty();
+ property.setName(AttributeStatementHelper.FRIENDLY_NAME);
+ property.setLabel(AttributeStatementHelper.FRIENDLY_NAME_LABEL);
+ property.setHelpText(AttributeStatementHelper.FRIENDLY_NAME_HELP_TEXT);
+ configProperties.add(property);
+ property = new ProtocolMapper.ConfigProperty();
+ property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT);
+ property.setLabel("SAML Attribute NameFormat");
+ property.setHelpText("SAML Attribute NameFormat. Can be basic, URI reference, or unspecified.");
+ List<String> types = new ArrayList(3);
+ types.add(AttributeStatementHelper.BASIC);
+ types.add(AttributeStatementHelper.URI_REFERENCE);
+ types.add(AttributeStatementHelper.UNSPECIFIED);
+ property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE);
+ property.setDefaultValue(types);
+ configProperties.add(property);
+ property = new ConfigProperty();
+ property.setName(SINGLE_ROLE_ATTRIBUTE);
+ property.setLabel("Single Role Attribute");
+ property.setType(ConfigProperty.BOOLEAN_TYPE);
+ property.setDefaultValue("true");
+ property.setHelpText("If true, all roles will be stored under one attribute with multiple attribute values.");
+ configProperties.add(property);
+
+ }
+
+
+ @Override
+ public String getDisplayCategory() {
+ return "Role Mapper";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Role list";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Role names are stored in an attribute value. There is either one attribute with multiple attribute values, or an attribute per role name depending on how you configure it. You can also specify the attribute name i.e. 'Role' or 'memberOf' being examples.";
+ }
+
+ @Override
+ public List<ConfigProperty> getConfigProperties() {
+ return configProperties;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public void mapRoles(AttributeStatementType roleAttributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+ String single = mappingModel.getConfig().get(SINGLE_ROLE_ATTRIBUTE);
+ boolean singleAttribute = Boolean.parseBoolean(single);
+
+ Map<ProtocolMapperModel, SAMLRoleNameMapper> roleNameMappers = new HashMap<>();
+ KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
+ for (ProtocolMapperModel mapping : clientSession.getClient().getProtocolMappers()) {
+ if (!mapping.getProtocol().equals(SamlProtocol.LOGIN_PROTOCOL)) continue;
+
+ ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
+ if (mapper == null || !(mapper instanceof SAMLRoleNameMapper)) continue;
+ roleNameMappers.put(mapping, (SAMLRoleNameMapper)mapper);
+ }
+
+ AttributeType singleAttributeType = null;
+ for (String roleId : clientSession.getRoles()) {
+ // todo need a role mapping
+ RoleModel roleModel = clientSession.getRealm().getRoleById(roleId);
+ AttributeType attributeType = null;
+ if (singleAttribute) {
+ if (singleAttributeType == null) {
+ singleAttributeType = AttributeStatementHelper.createAttributeType(mappingModel);
+ roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType));
+ }
+ attributeType = singleAttributeType;
+ } else {
+ attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
+ roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
+ }
+ String roleName = roleModel.getName();
+ for (Map.Entry<ProtocolMapperModel, SAMLRoleNameMapper> entry : roleNameMappers.entrySet()) {
+ String newName = entry.getValue().mapName(entry.getKey(), roleModel);
+ if (newName != null) {
+ roleName = newName;
+ break;
+ }
+ }
+ attributeType.addAttributeValue(roleName);
+ }
+
+ }
+
+ public static ProtocolMapperModel create(String name, String samlAttributeName, String nameFormat, String friendlyName, boolean singleAttribute) {
+ ProtocolMapperModel mapper = new ProtocolMapperModel();
+ mapper.setName(name);
+ mapper.setProtocolMapper(PROVIDER_ID);
+ mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+ mapper.setConsentRequired(false);
+ Map<String, String> config = new HashMap<String, String>();
+ config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, samlAttributeName);
+ if (friendlyName != null) {
+ config.put(AttributeStatementHelper.FRIENDLY_NAME, friendlyName);
+ }
+ if (nameFormat != null) {
+ config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, nameFormat);
+ }
+ config.put(SINGLE_ROLE_ATTRIBUTE, Boolean.toString(singleAttribute));
+ mapper.setConfig(config);
+
+ return mapper;
+ }
+
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleNameMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleNameMapper.java
new file mode 100755
index 0000000..b56cf1f
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLBasicRoleNameMapper.java
@@ -0,0 +1,91 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Map an assigned role to a different position and name in the token
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SAMLBasicRoleNameMapper extends AbstractOIDCProtocolMapper implements SAMLRoleNameMapper {
+
+ private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+ public static final String ROLE_CONFIG = "role";
+ public static String NEW_ROLE_NAME = "new.role.name";
+
+ static {
+ ConfigProperty property;
+ property = new ConfigProperty();
+ property.setName(ROLE_CONFIG);
+ property.setLabel("Role");
+ property.setHelpText("Role name you want changed. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
+ property.setType(ConfigProperty.STRING_TYPE);
+ configProperties.add(property);
+ property = new ConfigProperty();
+ property.setName(NEW_ROLE_NAME);
+ property.setLabel("New Role Name");
+ property.setHelpText("The new role name.");
+ property.setType(ConfigProperty.STRING_TYPE);
+ configProperties.add(property);
+ }
+
+ public static final String PROVIDER_ID = "saml-role-name-mapper";
+
+
+ public List<ConfigProperty> getConfigProperties() {
+ return configProperties;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Role Name Mapper";
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Role Mapper";
+
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Map an assigned role to a new name";
+ }
+
+ @Override
+ public String mapName(ProtocolMapperModel model, RoleModel roleModel) {
+ RoleContainerModel container = roleModel.getContainer();
+ ApplicationModel app = null;
+ if (container instanceof ApplicationModel) {
+ app = ((ApplicationModel) container);
+ }
+ String role = model.getConfig().get(ROLE_CONFIG);
+ String newName = model.getConfig().get(NEW_ROLE_NAME);
+ String appName = null;
+ int scopeIndex = role.indexOf('.');
+ if (scopeIndex > -1) {
+ if (app == null) return null;
+ appName = role.substring(0, scopeIndex);
+ if (!app.getName().equals(appName)) return null;
+ role = role.substring(scopeIndex + 1);
+ } else {
+ if (app != null) return null;
+ }
+ if (roleModel.getName().equals(role)) return newName;
+ return null;
+ }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
index 306877b..d9725e8 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
@@ -4,7 +4,6 @@ import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
-import org.keycloak.representations.AccessToken;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
/**
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleNameMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleNameMapper.java
new file mode 100755
index 0000000..caf2e4d
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleNameMapper.java
@@ -0,0 +1,12 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RoleModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface SAMLRoleNameMapper {
+ public String mapName(ProtocolMapperModel model, RoleModel role);
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
index d86bb31..e5d12e8 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
@@ -19,10 +19,8 @@ import org.picketlink.identity.federation.saml.v2.assertion.AuthnStatementType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import org.w3c.dom.Document;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import static org.picketlink.common.util.StringUtil.isNotNull;
@@ -36,7 +34,6 @@ import static org.picketlink.common.util.StringUtil.isNotNull;
public class SALM2LoginResponseBuilder {
protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
- protected List<String> roles = new LinkedList<String>();
protected String destination;
protected String issuer;
protected String nameId;
@@ -68,18 +65,6 @@ public class SALM2LoginResponseBuilder {
return this;
}
- public SALM2LoginResponseBuilder roles(List<String> roles) {
- this.roles = roles;
- return this;
- }
-
- public SALM2LoginResponseBuilder roles(String... roles) {
- for (String role : roles) {
- this.roles.add(role);
- }
- return this;
- }
-
public SALM2LoginResponseBuilder authMethod(String authMethod) {
this.authMethod = authMethod;
return this;
@@ -155,12 +140,6 @@ public class SALM2LoginResponseBuilder {
assertion.addStatement(authnStatement);
}
-
- if (roles != null && !roles.isEmpty()) {
- AttributeStatementType attrStatement = StatementUtil.createAttributeStatementForRoles(roles, multiValuedRoles);
- assertion.addStatement(attrStatement);
- }
-
return responseType;
}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index f57117e..183ebd5 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -19,6 +19,7 @@ import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.saml.mappers.SAMLAttributeStatementMapper;
import org.keycloak.protocol.saml.mappers.SAMLLoginResponseMapper;
+import org.keycloak.protocol.saml.mappers.SAMLRoleListMapper;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.resources.RealmsResource;
@@ -29,7 +30,6 @@ import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.common.exceptions.ConfigurationException;
import org.picketlink.common.exceptions.ParsingException;
import org.picketlink.common.exceptions.ProcessingException;
-import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants;
import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
@@ -41,6 +41,8 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.security.PublicKey;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -258,26 +260,38 @@ public class SamlProtocol implements LoginProtocol {
.requestIssuer(clientSession.getClient().getClientId())
.nameIdentifier(nameIdFormat, nameId)
.authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());
- initClaims(builder, clientSession.getClient(), userSession.getUser());
- if (clientSession.getRoles() != null) {
- if (multivaluedRoles(client)) {
- builder.multiValuedRoles(true);
- }
- for (String roleId : clientSession.getRoles()) {
- // todo need a role mapping
- RoleModel roleModel = clientSession.getRealm().getRoleById(roleId);
- builder.roles(roleModel.getName());
- }
- }
if (!includeAuthnStatement(client)) {
builder.disableAuthnStatement(true);
}
+ List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>();
+ List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>();
+ ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper = null;
+
+ Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
+ for (ProtocolMapperModel mapping : mappings) {
+ if (!mapping.getProtocol().equals(SamlProtocol.LOGIN_PROTOCOL)) continue;
+
+ ProtocolMapper mapper = (ProtocolMapper)session.getKeycloakSessionFactory().getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
+ if (mapper == null) continue;
+ if (mapper instanceof SAMLAttributeStatementMapper) {
+ attributeStatementMappers.add(new ProtocolMapperProcessor<SAMLAttributeStatementMapper>((SAMLAttributeStatementMapper)mapper, mapping));
+ }
+ if (mapper instanceof SAMLLoginResponseMapper) {
+ loginResponseMappers.add(new ProtocolMapperProcessor<SAMLLoginResponseMapper>((SAMLLoginResponseMapper)mapper, mapping));
+ }
+ if (mapper instanceof SAMLRoleListMapper) {
+ roleListMapper = new ProtocolMapperProcessor<SAMLRoleListMapper>((SAMLRoleListMapper)mapper, mapping);
+ }
+ }
+
+
Document samlDocument = null;
try {
ResponseType samlModel = builder.buildModel();
- transformAttributeStatement(session, samlModel, client, userSession, clientSession);
- samlModel = transformLoginResponse(session, samlModel, client, userSession, clientSession);
+ transformAttributeStatement(attributeStatementMappers, samlModel, session, userSession, clientSession);
+ populateRoles(roleListMapper, samlModel, session, userSession, clientSession);
+ samlModel = transformLoginResponse(loginResponseMappers, samlModel, session, userSession, clientSession);
samlDocument = builder.buildDocument(samlModel);
} catch (Exception e) {
logger.error("failed", e);
@@ -348,54 +362,50 @@ public class SamlProtocol implements LoginProtocol {
return "true".equals(client.getAttribute(SAML_ENCRYPT));
}
- public void initClaims(SALM2LoginResponseBuilder builder, ClientModel model, UserModel user) {
- if (ClaimMask.hasEmail(model.getAllowedClaimsMask())) {
- //builder.attribute(X500SAMLProfileConstants.EMAIL_ADDRESS.getFriendlyName(), user.getEmail());
- }
- if (ClaimMask.hasName(model.getAllowedClaimsMask())) {
- //builder.attribute(X500SAMLProfileConstants.GIVEN_NAME.getFriendlyName(), user.getFirstName());
- //builder.attribute(X500SAMLProfileConstants.SURNAME.getFriendlyName(), user.getLastName());
- }
- if (ClaimMask.hasUsername(model.getAllowedClaimsMask())) {
- //builder.attribute(X500SAMLProfileConstants.USERID.getFriendlyName(), user.getUsername());
+ public static class ProtocolMapperProcessor<T> {
+ final public T mapper;
+ final public ProtocolMapperModel model;
+
+ public ProtocolMapperProcessor(T mapper, ProtocolMapperModel model) {
+ this.mapper = mapper;
+ this.model = model;
}
}
- public ResponseType transformLoginResponse(KeycloakSession session, ResponseType response, ClientModel client,
- UserSessionModel userSession, ClientSessionModel clientSession) {
- Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
- KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
- for (ProtocolMapperModel mapping : mappings) {
- if (!mapping.getProtocol().equals(SamlProtocol.LOGIN_PROTOCOL)) continue;
-
- ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
- if (mapper == null || !(mapper instanceof SAMLLoginResponseMapper)) continue;
- response = ((SAMLLoginResponseMapper)mapper).transformLoginResponse(response, mapping, session, userSession, clientSession);
-
-
+ public void transformAttributeStatement(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers,
+ ResponseType response,
+ KeycloakSession session,
+ UserSessionModel userSession, ClientSessionModel clientSession) {
+ AssertionType assertion = response.getAssertions().get(0).getAssertion();
+ AttributeStatementType attributeStatement = new AttributeStatementType();
+ assertion.addStatement(attributeStatement);
+ for (ProtocolMapperProcessor<SAMLAttributeStatementMapper> processor : attributeStatementMappers) {
+ processor.mapper.transformAttributeStatement(attributeStatement, processor.model, session, userSession, clientSession);
+ }
+ }
+ public ResponseType transformLoginResponse(List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> mappers,
+ ResponseType response,
+ KeycloakSession session,
+ UserSessionModel userSession, ClientSessionModel clientSession) {
+ for (ProtocolMapperProcessor<SAMLLoginResponseMapper> processor : mappers) {
+ response = processor.mapper.transformLoginResponse(response, processor.model, session, userSession, clientSession);
}
return response;
}
- public void transformAttributeStatement(KeycloakSession session, ResponseType response, ClientModel client,
- UserSessionModel userSession, ClientSessionModel clientSession) {
- AttributeStatementType attributeStatement = new AttributeStatementType();
+
+ public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper,
+ ResponseType response,
+ KeycloakSession session,
+ UserSessionModel userSession, ClientSessionModel clientSession) {
+ if (roleListMapper == null) return;
AssertionType assertion = response.getAssertions().get(0).getAssertion();
+ AttributeStatementType attributeStatement = new AttributeStatementType();
assertion.addStatement(attributeStatement);
- Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
- KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
- for (ProtocolMapperModel mapping : mappings) {
- if (!mapping.getProtocol().equals(SamlProtocol.LOGIN_PROTOCOL)) continue;
-
- ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
- if (mapper == null || !(mapper instanceof SAMLAttributeStatementMapper)) continue;
- ((SAMLAttributeStatementMapper)mapper).transformAttributeStatement(attributeStatement, mapping, session, userSession, clientSession);
- }
+ roleListMapper.mapper.mapRoles(attributeStatement, roleListMapper.model, session, userSession, clientSession);
}
-
-
@Override
public Response consentDenied(ClientSessionModel clientSession) {
return getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
index 5f673fb..83b4b1a 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocolFactory.java
@@ -8,6 +8,8 @@ import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.AbstractLoginProtocolFactory;
import org.keycloak.protocol.LoginProtocol;
+import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper;
import org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper;
import org.keycloak.services.managers.AuthenticationManager;
import org.picketlink.common.constants.JBossSAMLURIConstants;
@@ -75,6 +77,9 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
X500SAMLProfileConstants.SURNAME.getFriendlyName(),
true, "family name");
builtins.add(model);
+ model = SAMLBasicRoleListMapper.create("role list", "Role", AttributeStatementHelper.BASIC, null, false);
+ builtins.add(model);
+ defaultBuiltins.add(model);
}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
index 177ae9c..6e9f47e 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SignatureAlgorithm.java
@@ -1,6 +1,5 @@
package org.keycloak.protocol.saml;
-import java.security.NoSuchAlgorithmException;
import java.security.Signature;
/**
diff --git a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
index 7d75839..62f8079 100755
--- a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
+++ b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
@@ -1,3 +1,5 @@
+org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper
+org.keycloak.protocol.saml.mappers.SAMLBasicRoleNameMapper
org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper
org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
index a009323..727d74d 100755
--- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
@@ -1,8 +1,11 @@
package org.keycloak.protocol;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel;
import java.lang.reflect.Method;
+import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json
index 0baffb5..3cd3342 100755
--- a/testsuite/integration/src/test/resources/saml/testsaml.json
+++ b/testsuite/integration/src/test/resources/saml/testsaml.json
@@ -256,6 +256,17 @@
"attribute.name": "phone",
"attribute.nameformat": "Basic"
}
+ },
+ {
+ "name": "role-list",
+ "protocol": "saml",
+ "protocolMapper": "saml-role-list-mapper",
+ "consentRequired": false,
+ "config": {
+ "attribute.name": "Role",
+ "attribute.nameformat": "Basic",
+ "single": "false"
+ }
}
]
},