keycloak-aplcache

hardcoded saml mappers

3/9/2015 8:55:20 AM

Details

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 b5850a5..06b299a 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
@@ -73,14 +73,14 @@ public class AttributeStatementHelper {
 
     }
     public static ProtocolMapperModel createAttributeMapper(String name, String userAttribute, String samlAttributeName, String nameFormat,  String friendlyName, boolean consentRequired, String consentText, String mapperId) {
-        ProtocolMapperModel mapper = mapper = new ProtocolMapperModel();
+        ProtocolMapperModel mapper = new ProtocolMapperModel();
         mapper.setName(name);
         mapper.setProtocolMapper(mapperId);
         mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
         mapper.setConsentRequired(consentRequired);
         mapper.setConsentText(consentText);
         Map<String, String> config = new HashMap<String, String>();
-        config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
+        if (userAttribute != null) config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
         config.put(SAML_ATTRIBUTE_NAME, samlAttributeName);
         if (friendlyName != null) {
             config.put(FRIENDLY_NAME, friendlyName);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
new file mode 100755
index 0000000..221bcfd
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
@@ -0,0 +1,85 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mappings UserModel property (the property name of a getter method) to an AttributeStatement.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper {
+    public static final String PROVIDER_ID = "saml-hardcode-attribute-mapper";
+    public static final String ATTRIBUTE_VALUE = "attribute.value";
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+        ConfigProperty property;
+        property = new ConfigProperty();
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
+        property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
+        configProperties.add(property);
+        AttributeStatementHelper.setConfigProperties(configProperties);
+        property = new ConfigProperty();
+        property.setName(ATTRIBUTE_VALUE);
+        property.setLabel("Attribute value");
+        property.setType(ConfigProperty.STRING_TYPE);
+        property.setHelpText("Value of the attribute you want to hard code.");
+        configProperties.add(property);
+
+    }
+
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Hardcoded attribute";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Hardcode an attribute into the SAML Assertion.";
+    }
+
+    @Override
+    public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+        String attributeValue = mappingModel.getConfig().get(ATTRIBUTE_VALUE);
+        AttributeStatementHelper.addAttribute(attributeStatement, mappingModel, attributeValue);
+
+    }
+
+    public static ProtocolMapperModel create(String name,
+                                             String samlAttributeName, String nameFormat, String friendlyName, String value,
+                                             boolean consentRequired, String consentText) {
+        String mapperId = PROVIDER_ID;
+        ProtocolMapperModel model = AttributeStatementHelper.createAttributeMapper(name, null, samlAttributeName, nameFormat, friendlyName,
+                consentRequired, consentText, mapperId);
+        model.getConfig().put(ATTRIBUTE_VALUE, value);
+        return model;
+
+    }
+
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java
new file mode 100755
index 0000000..862a0ca
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java
@@ -0,0 +1,76 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Mappings UserModel property (the property name of a getter method) to an AttributeStatement.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HardcodedRole extends AbstractSAMLProtocolMapper {
+    public static final String PROVIDER_ID = "saml-hardcode-role-mapper";
+    public static final String ATTRIBUTE_VALUE = "attribute.value";
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+        ConfigProperty property;
+        property = new ConfigProperty();
+        property.setName("role");
+        property.setLabel("Role");
+        property.setHelpText("Role name you want to hardcode.");
+        property.setType(ConfigProperty.STRING_TYPE);
+        configProperties.add(property);
+    }
+
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Hardcoded role";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Hardcode role into SAML Assertion.";
+    }
+
+    public static ProtocolMapperModel create(String name,
+                                             String role) {
+        String mapperId = PROVIDER_ID;
+        ProtocolMapperModel mapper = new ProtocolMapperModel();
+        mapper.setName(name);
+        mapper.setProtocolMapper(mapperId);
+        mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+       Map<String, String> config = new HashMap<String, String>();
+        config.put("role", role);
+        mapper.setConfig(config);
+        return mapper;
+
+    }
+
+}
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
index 9895944..7f47195 100755
--- 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
@@ -14,6 +14,7 @@ import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -92,17 +93,33 @@ public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implemen
         String single = mappingModel.getConfig().get(SINGLE_ROLE_ATTRIBUTE);
         boolean singleAttribute = Boolean.parseBoolean(single);
 
-        Map<ProtocolMapperModel, SAMLRoleNameMapper> roleNameMappers = new HashMap<>();
+        List<SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper>> roleNameMappers = new LinkedList<>();
         KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
+        AttributeType singleAttributeType = null;
         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);
+            if (mapper == null) continue;
+            if (mapper instanceof SAMLRoleNameMapper) {
+                roleNameMappers.add(new SamlProtocol.ProtocolMapperProcessor<>((SAMLRoleNameMapper) mapper,mapping));
+            }
+            if (mapper instanceof HardcodedRole) {
+                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));
+                }
+                attributeType.addAttributeValue(mapping.getConfig().get("role"));
+            }
         }
 
-        AttributeType singleAttributeType = null;
         for (String roleId : clientSession.getRoles()) {
             // todo need a role mapping
             RoleModel roleModel = clientSession.getRealm().getRoleById(roleId);
@@ -118,8 +135,8 @@ public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implemen
                 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);
+            for (SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper> entry : roleNameMappers) {
+                String newName = entry.mapper.mapName(entry.model, roleModel);
                 if (newName != null) {
                     roleName = newName;
                     break;
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
index b56cf1f..52222ef 100755
--- 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
@@ -5,9 +5,12 @@ import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
+import org.keycloak.protocol.saml.SamlProtocol;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Map an assigned role to a different position and name in the token
@@ -88,4 +91,21 @@ public class SAMLBasicRoleNameMapper extends AbstractOIDCProtocolMapper implemen
         if (roleModel.getName().equals(role)) return newName;
         return null;
    }
+
+    public static ProtocolMapperModel create(String name,
+                                             String role,
+                                             String newName) {
+        String mapperId = PROVIDER_ID;
+        ProtocolMapperModel mapper = new ProtocolMapperModel();
+        mapper.setName(name);
+        mapper.setProtocolMapper(mapperId);
+        mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+        Map<String, String> config = new HashMap<String, String>();
+        config.put(ROLE_CONFIG, role);
+        config.put(NEW_ROLE_NAME, newName);
+        mapper.setConfig(config);
+        return mapper;
+
+    }
+
 }
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 62f8079..52f5d7c 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,5 +1,7 @@
 org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper
 org.keycloak.protocol.saml.mappers.SAMLBasicRoleNameMapper
+org.keycloak.protocol.saml.mappers.HardcodedRole
+org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper
 org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper
 org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddClaimMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddClaimMapper.java
index fad7bd6..76fe47d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddClaimMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddClaimMapper.java
@@ -76,7 +76,7 @@ public class OIDCAddClaimMapper extends AbstractOIDCProtocolMapper implements OI
 
     @Override
     public String getDisplayType() {
-        return "Hard coded claim";
+        return "Hardcoded claim";
     }
 
     @Override
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
index b6adb01..c81dbef 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
@@ -16,7 +16,10 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
+import org.keycloak.protocol.saml.mappers.HardcodedRole;
 import org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper;
+import org.keycloak.protocol.saml.mappers.SAMLBasicRoleNameMapper;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.admin.AdminRoot;
@@ -265,6 +268,9 @@ public class SamlBindingTest {
                         app.addProtocolMapper(mapper);
                     }
                 }
+                app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
+                app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
+                app.addProtocolMapper(SAMLBasicRoleNameMapper.create("renamed-role","manager", "el-jefe"));
             }
         }, "demo");
 
@@ -287,6 +293,8 @@ public class SamlBindingTest {
             boolean userRole = false;
             boolean managerRole = false;
             boolean single = false;
+            boolean hardcodedRole = false;
+            boolean hardcodedAttribute = false;
             for (AttributeStatementType statement : assertion.getAttributeStatements()) {
                 for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
                     AttributeType attr = choice.getAttribute();
@@ -294,14 +302,21 @@ public class SamlBindingTest {
                         if (single) Assert.fail("too many role attributes");
                         single = true;
                         for (Object value : attr.getAttributeValue()) {
-                            if (value.equals("manager")) managerRole = true;
+                            if (value.equals("el-jefe")) managerRole = true;
                             if (value.equals("user")) userRole = true;
+                            if (value.equals("hardcoded-role")) hardcodedRole = true;
                         }
+                    } else if (attr.getName().equals("hardcoded-attribute")) {
+                        hardcodedAttribute = true;
+                        Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
                     }
                 }
 
             }
 
+            Assert.assertTrue(single);
+            Assert.assertTrue(hardcodedAttribute);
+            Assert.assertTrue(hardcodedRole);
             Assert.assertTrue(userRole);
             Assert.assertTrue(managerRole);
         }