keycloak-aplcache

Merge pull request #1008 from patriot1burke/master saml

2/28/2015 1:33:16 PM

Changes

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
new file mode 100755
index 0000000..cf9981f
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java
@@ -0,0 +1,72 @@
+package org.keycloak.protocol.saml.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.protocol.ProtocolMapper;
+import org.picketlink.common.constants.JBossSAMLURIConstants;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AttributeStatementHelper {
+    public static final String ATTRIBUTE_STATEMENT_CATEGORY = "AttributeStatement Mapper";
+    public static final String URI_REFERENCE = "URI Reference";
+    public static final String URI_REFERENCE_HELP_TEXT = "Attribute name for the SAML URI Reference attribute name format";
+    public static final String BASIC = "Basic name";
+    public static final String BASIC_HELP_TEXT = "Attribute name for the SAML Basic attribute name format";
+    public static final String FRIENDLY_NAME = "Friendly Name";
+    public static final String FRIENDLY_NAME_HELP_TEXT = "Standard SAML attribute setting.  An optional, more human-readable form of the attribute's name that can be provided if the actual attribute name is cryptic.";
+
+    public static void addUriReferenceAttribute(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, String attributeValue) {
+        String attributeName = mappingModel.getConfig().get(URI_REFERENCE);
+        AttributeType attribute = new AttributeType(attributeName);
+        attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get());
+        String friendlyName = mappingModel.getConfig().get(FRIENDLY_NAME);
+        if (friendlyName != null && friendlyName.trim().equals("")) friendlyName = null;
+        if (friendlyName != null) attribute.setFriendlyName(friendlyName);
+        attribute.addAttributeValue(attributeValue);
+        attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
+    }
+
+    public static void addBasicAttribute(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, String attributeValue) {
+        String attributeName = mappingModel.getConfig().get(BASIC);
+        AttributeType attribute = new AttributeType(attributeName);
+        attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get());
+        String friendlyName = mappingModel.getConfig().get(FRIENDLY_NAME);
+        if (friendlyName != null && friendlyName.trim().equals("")) friendlyName = null;
+        if (friendlyName != null) attribute.setFriendlyName(friendlyName);
+        attribute.addAttributeValue(attributeValue);
+        attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
+    }
+
+    protected static void addUriReferenceProperties(List<ProtocolMapper.ConfigProperty> configProperties) {
+        ProtocolMapper.ConfigProperty property;
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(FRIENDLY_NAME);
+        property.setLabel(FRIENDLY_NAME);
+        property.setHelpText(FRIENDLY_NAME_HELP_TEXT);
+        configProperties.add(property);
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(URI_REFERENCE);
+        property.setLabel(URI_REFERENCE);
+        property.setHelpText(URI_REFERENCE_HELP_TEXT);
+        configProperties.add(property);
+    }
+    protected static void addBasicProperties(List<ProtocolMapper.ConfigProperty> configProperties) {
+        ProtocolMapper.ConfigProperty property;
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(FRIENDLY_NAME);
+        property.setLabel(FRIENDLY_NAME);
+        property.setHelpText(FRIENDLY_NAME_HELP_TEXT);
+        configProperties.add(property);
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(BASIC);
+        property.setLabel(BASIC);
+        property.setHelpText(BASIC_HELP_TEXT);
+        configProperties.add(property);
+    }
+}
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
new file mode 100755
index 0000000..8abe681
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
@@ -0,0 +1,18 @@
+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.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>
+ * @version $Revision: 1 $
+ */
+public interface SAMLAttributeStatementMapper {
+
+    void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session,
+                                        UserSessionModel userSession, ClientSessionModel clientSession);
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelBasicAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelBasicAttributeStatementMapper.java
new file mode 100755
index 0000000..a6f8c6f
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelBasicAttributeStatementMapper.java
@@ -0,0 +1,69 @@
+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 UserModelBasicAttributeStatementMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper {
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+        ConfigProperty property;
+        property = new ConfigProperty();
+        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
+        configProperties.add(property);
+        AttributeStatementHelper.addBasicProperties(configProperties);
+
+    }
+
+    public static final String PROVIDER_ID = "saml-user-property-base-mapper";
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "User Property Basic";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Map a built in user property to a SAML Basic attribute type.";
+    }
+
+    @Override
+    public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+        UserModel user = userSession.getUser();
+        String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
+        AttributeStatementHelper.addBasicAttribute(attributeStatement, mappingModel, propertyValue);
+
+    }
+
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelUriReferenceAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelUriReferenceAttributeStatementMapper.java
new file mode 100755
index 0000000..c0a2d12
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserModelUriReferenceAttributeStatementMapper.java
@@ -0,0 +1,69 @@
+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 UserModelUriReferenceAttributeStatementMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper {
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+        ConfigProperty property;
+        property = new ConfigProperty();
+        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
+        configProperties.add(property);
+        AttributeStatementHelper.addUriReferenceProperties(configProperties);
+
+    }
+
+    public static final String PROVIDER_ID = "saml-user-property-uri-mapper";
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "User Property URI";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Map a built in user property to a SAML URI reference attribute type.";
+    }
+
+    @Override
+    public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+        UserModel user = userSession.getUser();
+        String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
+        AttributeStatementHelper.addUriReferenceAttribute(attributeStatement, mappingModel, propertyValue);
+
+    }
+
+}
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 782adbc..d86bb31 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
@@ -46,14 +46,8 @@ public class SALM2LoginResponseBuilder {
     protected String requestID;
     protected String authMethod;
     protected String requestIssuer;
-    protected Map<String, Object> attributes = new HashMap<String, Object>();
 
 
-    public SALM2LoginResponseBuilder attributes(Map<String, Object> attributes) {
-        this.attributes = attributes;
-        return this;
-    }
-
     public SALM2LoginResponseBuilder destination(String destination) {
         this.destination = destination;
         return this;
@@ -64,15 +58,6 @@ public class SALM2LoginResponseBuilder {
         return this;
     }
 
-    public SALM2LoginResponseBuilder attribute(String name, Object value) {
-        if (value == null) {
-            attributes.remove(name);
-        } else {
-            this.attributes.put(name, value);
-        }
-        return this;
-    }
-
     public SALM2LoginResponseBuilder requestID(String requestID) {
         this.requestID =requestID;
         return this;
@@ -176,11 +161,6 @@ public class SALM2LoginResponseBuilder {
             assertion.addStatement(attrStatement);
         }
 
-        // Add in the attributes information
-        if (attributes != null && attributes.size() > 0) {
-            AttributeStatementType attStatement = StatementUtil.createAttributeStatement(attributes);
-            assertion.addStatement(attStatement);
-        }
         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 dad3733..f57117e 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
@@ -17,6 +17,7 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 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.services.managers.ClientSessionCode;
 import org.keycloak.services.managers.ResourceAdminManager;
@@ -29,6 +30,8 @@ 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;
 import org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler;
 import org.w3c.dom.Document;
@@ -273,6 +276,7 @@ public class SamlProtocol implements LoginProtocol {
         Document samlDocument = null;
         try {
             ResponseType samlModel = builder.buildModel();
+            transformAttributeStatement(session, samlModel, client, userSession, clientSession);
             samlModel = transformLoginResponse(session, samlModel, client, userSession, clientSession);
             samlDocument = builder.buildDocument(samlModel);
         } catch (Exception e) {
@@ -346,14 +350,14 @@ public class SamlProtocol implements LoginProtocol {
 
     public void initClaims(SALM2LoginResponseBuilder builder, ClientModel model, UserModel user) {
         if (ClaimMask.hasEmail(model.getAllowedClaimsMask())) {
-            builder.attribute(X500SAMLProfileConstants.EMAIL_ADDRESS.getFriendlyName(), user.getEmail());
+            //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());
+            //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());
+            //builder.attribute(X500SAMLProfileConstants.USERID.getFriendlyName(), user.getUsername());
         }
     }
 
@@ -373,6 +377,21 @@ public class SamlProtocol implements LoginProtocol {
         }
         return response;
     }
+    public void transformAttributeStatement(KeycloakSession session, ResponseType response, ClientModel client,
+                                               UserSessionModel userSession, ClientSessionModel clientSession) {
+        AttributeStatementType attributeStatement = new AttributeStatementType();
+        AssertionType assertion = response.getAssertions().get(0).getAssertion();
+        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);
+        }
+    }
 
 
 
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
new file mode 100755
index 0000000..719ddff
--- /dev/null
+++ b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
@@ -0,0 +1,6 @@
+org.keycloak.protocol.saml.mappers.UserAttributeBasicAttributeStatementMapper
+org.keycloak.protocol.saml.mappers.UserModelBasicAttributeStatementMapper
+org.keycloak.protocol.saml.mappers.UserAttributeUriReferenceAttributeStatementMapper
+org.keycloak.protocol.saml.mappers.UserModelUriReferenceAttributeStatementMapper
+
+
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserAttributeMapper.java
index ffc742d..7aadbf3 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserAttributeMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserAttributeMapper.java
@@ -5,6 +5,7 @@ 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.keycloak.representations.AccessToken;
 
 import java.util.ArrayList;
@@ -21,18 +22,17 @@ import java.util.List;
 public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
 
     private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
-    public static final String USER_MODEL_ATTRIBUTE_NAME = "UserModel Attribute Name";
 
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(USER_MODEL_ATTRIBUTE_NAME);
-        property.setLabel(USER_MODEL_ATTRIBUTE_NAME);
-        property.setHelpText("Name of stored user attribute which is the name of an attribute within the UserModel.attribute map.");
+        property.setName(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
         configProperties.add(property);
         property = new ConfigProperty();
-        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
-        property.setLabel(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
         property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
         configProperties.add(property);
 
@@ -69,10 +69,10 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
     public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
                                       UserSessionModel userSession, ClientSessionModel clientSession) {
         UserModel user = userSession.getUser();
-        String attributeName = mappingModel.getConfig().get(USER_MODEL_ATTRIBUTE_NAME);
+        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
         String attributeValue = user.getAttribute(attributeName);
         if (attributeValue == null) return token;
-        AttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
+        OIDCAttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
         return token;
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserModelMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserModelMapper.java
index d5da0fb..693311f 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserModelMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserModelMapper.java
@@ -5,9 +5,9 @@ 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.keycloak.representations.AccessToken;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -21,18 +21,17 @@ import java.util.List;
  */
 public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
     private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
-    public static final String USER_MODEL_PROPERTY = "User Property";
 
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(USER_MODEL_PROPERTY);
-        property.setLabel(USER_MODEL_PROPERTY);
-        property.setHelpText("Name of the property method in the UserModel interface.  For example, a value of 'email' would reference the UserModel.getEmail() method.");
+        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
         configProperties.add(property);
         property = new ConfigProperty();
-        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
-        property.setLabel(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
         property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
         configProperties.add(property);
 
@@ -68,31 +67,11 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
     public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
                                       UserSessionModel userSession, ClientSessionModel clientSession) {
         UserModel user = userSession.getUser();
-        String propertyName = mappingModel.getConfig().get(USER_MODEL_PROPERTY);
-        String propertyValue = getUserModelValue(user,propertyName);
-        AttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
+        String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
+        OIDCAttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
 
         return token;
     }
 
-    protected String getUserModelValue(UserModel user, String propertyName) {
-
-        String methodName = "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
-        try {
-            Method method = UserModel.class.getMethod(methodName);
-            Object val = method.invoke(user);
-            if (val != null) return val.toString();
-        } catch (Exception ignore) {
-
-        }
-        methodName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
-        try {
-            Method method = UserModel.class.getMethod(methodName);
-            Object val = method.invoke(user);
-            if (val != null) return val.toString();
-        } catch (Exception ignore) {
-
-        }
-        return null;
-    }
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
index 4b60b6a..0a9c7c0 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -8,7 +8,8 @@ import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocolFactory;
-import org.keycloak.protocol.oidc.mappers.AttributeMapperHelper;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
 import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper;
@@ -65,27 +66,27 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
         int counter = 0;
         // the ids must never change!!!!  So if you add more default mappers, then add to end with higher counter.
         addClaimMapper(realm, "username", OIDCUserModelMapper.PROVIDER_ID,
-                OIDCUserModelMapper.USER_MODEL_PROPERTY, "username",
+                ProtocolMapperUtils.USER_MODEL_PROPERTY, "username",
                 "preferred_username", "String",
                 true, "username",
                 true);
         addClaimMapper(realm, "email", OIDCUserModelMapper.PROVIDER_ID,
-                OIDCUserModelMapper.USER_MODEL_PROPERTY, "email",
+                ProtocolMapperUtils.USER_MODEL_PROPERTY, "email",
                 "email", "String",
                 true, "email",
                 true);
         addClaimMapper(realm, "given name", OIDCUserModelMapper.PROVIDER_ID,
-                OIDCUserModelMapper.USER_MODEL_PROPERTY, "firstName",
+                ProtocolMapperUtils.USER_MODEL_PROPERTY, "firstName",
                 "given_name", "String",
                 true, "given name",
                 true);
         addClaimMapper(realm, "family name", OIDCUserModelMapper.PROVIDER_ID,
-                OIDCUserModelMapper.USER_MODEL_PROPERTY, "lastName",
+                ProtocolMapperUtils.USER_MODEL_PROPERTY, "lastName",
                 "family_name", "String",
                 true, "family name",
                 true);
         addClaimMapper(realm, "email verified", OIDCUserModelMapper.PROVIDER_ID,
-                OIDCUserModelMapper.USER_MODEL_PROPERTY, "emailVerified",
+                ProtocolMapperUtils.USER_MODEL_PROPERTY, "emailVerified",
                 "email_verified", "boolean",
                 false, null,
                 false);
@@ -131,8 +132,8 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
         mapper.setAppliedByDefault(appliedByDefault);
         Map<String, String> config = new HashMap<String, String>();
         config.put(propertyName, propertyNameValue);
-        config.put(AttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
-        config.put(AttributeMapperHelper.JSON_TYPE, claimType);
+        config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
+        config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
         mapper.setConfig(config);
         realm.addProtocolMapper(mapper);
     }
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
new file mode 100755
index 0000000..8f7c2e9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
@@ -0,0 +1,37 @@
+package org.keycloak.protocol;
+
+import org.keycloak.models.UserModel;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProtocolMapperUtils {
+    public static final String USER_MODEL_PROPERTY = "User Property";
+    public static final String USER_MODEL_PROPERTY_HELP_TEXT = "Name of the property method in the UserModel interface.  For example, a value of 'email' would reference the UserModel.getEmail() method.";
+    public static final String USER_MODEL_ATTRIBUTE_NAME = "User Attribute";
+    public static final String USER_MODEL_ATTRIBUTE_HELP_TEXT = "Name of stored user attribute which is the name of an attribute within the UserModel.attribute map.";
+
+    public static String getUserModelValue(UserModel user, String propertyName) {
+
+        String methodName = "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
+        try {
+            Method method = UserModel.class.getMethod(methodName);
+            Object val = method.invoke(user);
+            if (val != null) return val.toString();
+        } catch (Exception ignore) {
+
+        }
+        methodName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
+        try {
+            Method method = UserModel.class.getMethod(methodName);
+            Object val = method.invoke(user);
+            if (val != null) return val.toString();
+        } catch (Exception ignore) {
+
+        }
+        return null;
+    }
+}
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
index 1815b88..1615ecc 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
+++ b/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
@@ -1,8 +1,6 @@
 org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper
-org.keycloak.protocol.oidc.mappers.OIDCClientSessionNoteMapper
 org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper
 org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper
-org.keycloak.protocol.oidc.mappers.OIDCUserSessionNoteMapper
 org.keycloak.protocol.oidc.mappers.OIDCAddressMapper
 
 
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 a69389d..efe3fd4 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,8 +157,7 @@ public class AccountTest {
         });
     }
 
-    @Test
-    @Ignore
+    //@Test @Ignore
     public void runit() throws Exception {
         Thread.sleep(10000000);
     }