keycloak-memoizeit

saml broker role mapper

4/20/2015 12:54:39 PM

Details

diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/mappers/RoleMapper.java b/broker/saml/src/main/java/org/keycloak/broker/saml/mappers/RoleMapper.java
new file mode 100755
index 0000000..3c6d655
--- /dev/null
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/mappers/RoleMapper.java
@@ -0,0 +1,167 @@
+package org.keycloak.broker.saml.mappers;
+
+import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
+import org.keycloak.broker.provider.BrokeredIdentityContext;
+import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.broker.saml.SAMLEndpoint;
+import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
+import org.keycloak.dom.saml.v2.assertion.AssertionType;
+import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
+import org.keycloak.dom.saml.v2.assertion.AttributeType;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderMapperModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.JsonWebToken;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RoleMapper extends AbstractIdentityProviderMapper {
+
+    public static final String[] COMPATIBLE_PROVIDERS = {SAMLIdentityProviderFactory.PROVIDER_ID};
+
+    private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+
+    public static final String ROLE = "role";
+    public static final String ATTRIBUTE_NAME = "attribute.name";
+    public static final String ATTRIBUTE_FRIENDLY_NAME = "attribute.friendly.name";
+    public static final String ATTRIBUTE_VALUE = "attribute.value";
+
+    static {
+        ProviderConfigProperty property;
+        property = new ProviderConfigProperty();
+        property.setName(ATTRIBUTE_NAME);
+        property.setLabel("Attribute Name");
+        property.setHelpText("Name of attribute to search for in assertion.  You can leave this blank and specify a friendly name instead.");
+        property.setType(ProviderConfigProperty.STRING_TYPE);
+        configProperties.add(property);
+        property = new ProviderConfigProperty();
+        property.setName(ATTRIBUTE_FRIENDLY_NAME);
+        property.setLabel("Attribute Name");
+        property.setHelpText("Friendly name of attribute to search for in assertion.  You can leave this blank and specify a name instead.");
+        property.setType(ProviderConfigProperty.STRING_TYPE);
+        configProperties.add(property);
+        property = new ProviderConfigProperty();
+        property.setName(ATTRIBUTE_VALUE);
+        property.setLabel("Attribute Value");
+        property.setHelpText("Value the attribute must have.  If the attribute is a list, then the value must be contained in the list.");
+        property.setType(ProviderConfigProperty.STRING_TYPE);
+        configProperties.add(property);
+        property = new ProviderConfigProperty();
+        property.setName(ROLE);
+        property.setLabel("Role");
+        property.setHelpText("Role to grant to user.  To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
+        property.setType(ProviderConfigProperty.STRING_TYPE);
+        configProperties.add(property);
+    }
+
+    public static final String PROVIDER_ID = "saml-role-idp-mapper";
+
+    public static String[] parseRole(String role) {
+        int scopeIndex = role.indexOf('.');
+        if (scopeIndex > -1) {
+            String appName = role.substring(0, scopeIndex);
+            role = role.substring(scopeIndex + 1);
+            String[] rtn = {appName, role};
+            return rtn;
+        } else {
+            String[] rtn = {null, role};
+            return rtn;
+
+        }
+    }
+
+    @Override
+    public List<ProviderConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String[] getCompatibleProviders() {
+        return COMPATIBLE_PROVIDERS;
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return "Role Mapper";
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Role Mapper";
+    }
+
+    @Override
+    public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+        String roleName = mapperModel.getConfig().get(ROLE);
+        if (isAttributePresent(mapperModel, context)) {
+            RoleModel role = getRoleFromString(realm, roleName);
+            if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
+            user.grantRole(role);
+        }
+    }
+
+    protected RoleModel getRoleFromString(RealmModel realm, String roleName) {
+        String[] parsedRole = parseRole(roleName);
+        RoleModel role = null;
+        if (parsedRole[0] == null) {
+            role = realm.getRole(parsedRole[1]);
+        } else {
+            ClientModel client = realm.getClientByClientId(parsedRole[0]);
+            role = client.getRole(parsedRole[1]);
+        }
+        return role;
+    }
+
+    protected boolean isAttributePresent(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+        String name = mapperModel.getConfig().get(ATTRIBUTE_NAME);
+        if (name != null && name.trim().equals("")) name = null;
+        String friendly = mapperModel.getConfig().get(ATTRIBUTE_FRIENDLY_NAME);
+        if (friendly != null && friendly.trim().equals("")) friendly = null;
+        String desiredValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
+        AssertionType assertion = (AssertionType)context.getContextData().get(SAMLEndpoint.SAML_ASSERTION);
+        for (AttributeStatementType statement : assertion.getAttributeStatements()) {
+            for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
+                AttributeType attr = choice.getAttribute();
+                if (name != null && !name.equals(attr.getName())) continue;
+                if (friendly != null && !name.equals(attr.getFriendlyName())) continue;
+                for (Object val : attr.getAttributeValue()) {
+                    if (val.equals(desiredValue)) return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    @Override
+    public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+        String roleName = mapperModel.getConfig().get(ROLE);
+        if (!isAttributePresent(mapperModel, context)) {
+            RoleModel role = getRoleFromString(realm, roleName);
+            if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
+            user.deleteRoleMapping(role);
+        }
+
+    }
+
+    @Override
+    public String getHelpText() {
+        return "If a claim exists, grant the user the specified realm or application role.";
+    }
+
+}
diff --git a/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
new file mode 100755
index 0000000..af14a9c
--- /dev/null
+++ b/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
@@ -0,0 +1 @@
+org.keycloak.broker.saml.mappers.RoleMapper
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 3e151fd..ef62c07 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -163,6 +163,7 @@
                 </fieldset>
 
                 <div class="pull-right form-actions">
+                    <a data-ng-show="!newIdentityProvider" class="btn btn-lg btn-primary" href="#/realms/{{realm.realm}}/identity-provider-mappers/{{identityProvider.alias}}/mappers">Mappers</a>
                     <a class="btn btn-lg btn-primary" href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}/export" data-ng-show="!importFile && !newIdentityProvider">Export</a>
                     <button kc-save data-ng-show="changed">Save</button>
                     <button type="submit" data-ng-click="cancel()" data-ng-show="changed" class="btn btn-lg btn-default">Cancel</button>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 1d99e1f..af202b3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -157,7 +157,7 @@ public class AccountTest {
         });
     }
 
-    //@Test
+    @Test
     public void ideTesting() throws Exception {
         Thread.sleep(100000000);
     }