keycloak-aplcache

mapper refactoring

2/28/2015 9:48:50 PM

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 cf9981f..fd32561 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,46 +1,50 @@
 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;
 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.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class AttributeStatementHelper {
+    public static final String SAML_ATTRIBUTE_NAME = "SAML Attribute Name";
     public static final String ATTRIBUTE_STATEMENT_CATEGORY = "AttributeStatement Mapper";
-    public static final String URI_REFERENCE = "URI Reference";
+    public static final String URI_REFERENCE_LABEL = "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_LABEL = "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);
+    public static void addAttribute(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel,
+                                    String attributeNameFormat, String attributeValue) {
+        String attributeName = mappingModel.getConfig().get(SAML_ATTRIBUTE_NAME);
         AttributeType attribute = new AttributeType(attributeName);
-        attribute.setNameFormat(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get());
+        attribute.setNameFormat(attributeNameFormat);
         String friendlyName = mappingModel.getConfig().get(FRIENDLY_NAME);
-        if (friendlyName != null && friendlyName.trim().equals("")) friendlyName = null;
-        if (friendlyName != null) attribute.setFriendlyName(friendlyName);
+        if (friendlyName != null && !friendlyName.trim().equals("")) attribute.setFriendlyName(friendlyName);
         attribute.addAttributeValue(attributeValue);
         attributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attribute));
     }
 
+    public static void addUriReferenceAttribute(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, String attributeValue) {
+        String attributeNameFormat = JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get();
+        addAttribute(attributeStatement, mappingModel, attributeNameFormat, attributeValue);
+    }
+
     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));
+        addAttribute(attributeStatement, mappingModel, JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attributeValue);
     }
 
     protected static void addUriReferenceProperties(List<ProtocolMapper.ConfigProperty> configProperties) {
@@ -51,8 +55,8 @@ public class AttributeStatementHelper {
         property.setHelpText(FRIENDLY_NAME_HELP_TEXT);
         configProperties.add(property);
         property = new ProtocolMapper.ConfigProperty();
-        property.setName(URI_REFERENCE);
-        property.setLabel(URI_REFERENCE);
+        property.setName(SAML_ATTRIBUTE_NAME);
+        property.setLabel(URI_REFERENCE_LABEL);
         property.setHelpText(URI_REFERENCE_HELP_TEXT);
         configProperties.add(property);
     }
@@ -64,9 +68,29 @@ public class AttributeStatementHelper {
         property.setHelpText(FRIENDLY_NAME_HELP_TEXT);
         configProperties.add(property);
         property = new ProtocolMapper.ConfigProperty();
-        property.setName(BASIC);
-        property.setLabel(BASIC);
+        property.setName(SAML_ATTRIBUTE_NAME);
+        property.setLabel(BASIC_LABEL);
         property.setHelpText(BASIC_HELP_TEXT);
         configProperties.add(property);
     }
+
+    public static void addAttributeMapper(RealmModel realm, String name, String userAttribute, String samlAttributeName, String friendlyName, boolean consentRequired, String consentText, boolean appliedByDefault, String mapperId) {
+        ProtocolMapperModel mapper = realm.getProtocolMapperByName(SamlProtocol.LOGIN_PROTOCOL, name);
+        if (mapper != null) return;
+        mapper = new ProtocolMapperModel();
+        mapper.setName(name);
+        mapper.setProtocolMapper(mapperId);
+        mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+        mapper.setConsentRequired(consentRequired);
+        mapper.setConsentText(consentText);
+        mapper.setAppliedByDefault(appliedByDefault);
+        Map<String, String> config = new HashMap<String, String>();
+        config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
+        config.put(SAML_ATTRIBUTE_NAME, samlAttributeName);
+        if (friendlyName != null) {
+            config.put(FRIENDLY_NAME, friendlyName);
+        }
+        mapper.setConfig(config);
+        realm.addProtocolMapper(mapper);
+    }
 }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeBasicAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeBasicAttributeStatementMapper.java
index 86cefe1..3fc5603 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeBasicAttributeStatementMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeBasicAttributeStatementMapper.java
@@ -3,6 +3,7 @@ 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.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -23,8 +24,8 @@ public class UserAttributeBasicAttributeStatementMapper extends AbstractSAMLProt
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
         configProperties.add(property);
         AttributeStatementHelper.addBasicProperties(configProperties);
@@ -60,10 +61,21 @@ public class UserAttributeBasicAttributeStatementMapper extends AbstractSAMLProt
     @Override
     public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
         UserModel user = userSession.getUser();
-        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
         String attributeValue = user.getAttribute(attributeName);
         AttributeStatementHelper.addBasicAttribute(attributeStatement, mappingModel, attributeValue);
 
     }
 
+    public static void addAttributeMapper(RealmModel realm, String name,
+                                         String userAttribute,
+                                         String samlAttributeName,
+                                         String friendlyName,
+                                         boolean consentRequired, String consentText,
+                                         boolean appliedByDefault) {
+        String mapperId = PROVIDER_ID;
+        AttributeStatementHelper.addAttributeMapper(realm, name, userAttribute, samlAttributeName, friendlyName, consentRequired, consentText, appliedByDefault, mapperId);
+
+    }
+
 }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeUriReferenceAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeUriReferenceAttributeStatementMapper.java
index 28ce5c1..a690870 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeUriReferenceAttributeStatementMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeUriReferenceAttributeStatementMapper.java
@@ -3,6 +3,7 @@ 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.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -23,8 +24,8 @@ public class UserAttributeUriReferenceAttributeStatementMapper extends AbstractS
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
         configProperties.add(property);
         AttributeStatementHelper.addUriReferenceProperties(configProperties);
@@ -60,10 +61,20 @@ public class UserAttributeUriReferenceAttributeStatementMapper extends AbstractS
     @Override
     public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
         UserModel user = userSession.getUser();
-        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
         String attributeValue = user.getAttribute(attributeName);
         AttributeStatementHelper.addUriReferenceAttribute(attributeStatement, mappingModel, attributeValue);
 
     }
+    public static void addAttributeMapper(RealmModel realm, String name,
+                                          String userAttribute,
+                                          String samlAttributeName,
+                                          String friendlyName,
+                                          boolean consentRequired, String consentText,
+                                          boolean appliedByDefault) {
+        String mapperId = PROVIDER_ID;
+        AttributeStatementHelper.addAttributeMapper(realm, name, userAttribute, samlAttributeName, friendlyName, consentRequired, consentText, appliedByDefault, mapperId);
+
+    }
 
 }
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
index a6f8c6f..7d41322 100755
--- 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
@@ -3,6 +3,7 @@ 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.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -23,8 +24,8 @@ public class UserModelBasicAttributeStatementMapper extends AbstractSAMLProtocol
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
         configProperties.add(property);
         AttributeStatementHelper.addBasicProperties(configProperties);
@@ -60,10 +61,20 @@ public class UserModelBasicAttributeStatementMapper extends AbstractSAMLProtocol
     @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 propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
         String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
         AttributeStatementHelper.addBasicAttribute(attributeStatement, mappingModel, propertyValue);
 
     }
 
+    public static void addAttributeMapper(RealmModel realm, String name,
+                                          String userAttribute,
+                                          String samlAttributeName,
+                                          String friendlyName,
+                                          boolean consentRequired, String consentText,
+                                          boolean appliedByDefault) {
+        String mapperId = PROVIDER_ID;
+        AttributeStatementHelper.addAttributeMapper(realm, name, userAttribute, samlAttributeName, friendlyName, consentRequired, consentText, appliedByDefault, mapperId);
+
+    }
 }
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
index c0a2d12..1cefe3c 100755
--- 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
@@ -3,6 +3,7 @@ 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.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -23,8 +24,8 @@ public class UserModelUriReferenceAttributeStatementMapper extends AbstractSAMLP
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
         configProperties.add(property);
         AttributeStatementHelper.addUriReferenceProperties(configProperties);
@@ -60,10 +61,20 @@ public class UserModelUriReferenceAttributeStatementMapper extends AbstractSAMLP
     @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 propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
         String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
         AttributeStatementHelper.addUriReferenceAttribute(attributeStatement, mappingModel, propertyValue);
 
     }
 
+    public static void addAttributeMapper(RealmModel realm, String name,
+                                          String userAttribute,
+                                          String samlAttributeName,
+                                          String friendlyName,
+                                          boolean consentRequired, String consentText,
+                                          boolean appliedByDefault) {
+        String mapperId = PROVIDER_ID;
+        AttributeStatementHelper.addAttributeMapper(realm, name, userAttribute, samlAttributeName, friendlyName, consentRequired, consentText, appliedByDefault, mapperId);
+
+    }
 }
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 8bb4d46..bda8659 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
@@ -4,17 +4,29 @@ import org.keycloak.Config;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.AbstractLoginProtocolFactory;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocolFactory;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper;
+import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
+import org.keycloak.protocol.saml.mappers.UserAttributeBasicAttributeStatementMapper;
+import org.keycloak.protocol.saml.mappers.UserModelUriReferenceAttributeStatementMapper;
 import org.keycloak.services.managers.AuthenticationManager;
+import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants;
 import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class SamlProtocolFactory implements LoginProtocolFactory {
+public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
 
     @Override
     public Object createProtocolEndpoint(RealmModel realm, EventBuilder event, AuthenticationManager authManager) {
@@ -33,16 +45,28 @@ public class SamlProtocolFactory implements LoginProtocolFactory {
     }
 
     @Override
-    public void postInit(KeycloakSessionFactory factory) {
-
+    public String getId() {
+        return "saml";
     }
+
     @Override
-    public void close() {
+    protected void addDefaults(RealmModel realm) {
+       UserModelUriReferenceAttributeStatementMapper.addAttributeMapper(realm, "X500 email",
+                "email",
+                X500SAMLProfileConstants.EMAIL.get(), X500SAMLProfileConstants.EMAIL.getFriendlyName(),
+                true, "email",
+                false);
+        UserModelUriReferenceAttributeStatementMapper.addAttributeMapper(realm, "X500 givenName",
+                "firstName",
+                X500SAMLProfileConstants.GIVEN_NAME.get(), X500SAMLProfileConstants.GIVEN_NAME.getFriendlyName(),
+                true, "given name",
+                false);
+        UserModelUriReferenceAttributeStatementMapper.addAttributeMapper(realm, "X500 surname",
+                "lastName",
+                X500SAMLProfileConstants.SURNAME.get(), X500SAMLProfileConstants.SURNAME.getFriendlyName(),
+                true, "family name",
+                false);
 
     }
 
-    @Override
-    public String getId() {
-        return "saml";
-    }
 }
diff --git a/services/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java
new file mode 100755
index 0000000..7483105
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/AbstractLoginProtocolFactory.java
@@ -0,0 +1,54 @@
+package org.keycloak.protocol;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractLoginProtocolFactory implements LoginProtocolFactory {
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        KeycloakSession session = factory.create();
+        session.getTransaction().begin();
+        try {
+            List<RealmModel> realms = session.realms().getRealms();
+            for (RealmModel realm : realms) addDefaults(realm);
+            session.getTransaction().commit();
+        } catch (Exception e) {
+            session.getTransaction().rollback();
+        } finally {
+            session.close();
+        }
+
+        factory.register(new ProviderEventListener() {
+            @Override
+            public void onEvent(ProviderEvent event) {
+                if (event instanceof RealmModel.RealmCreationEvent) {
+                    RealmModel realm = ((RealmModel.RealmCreationEvent)event).getCreatedRealm();
+                    addDefaults(realm);
+                }
+            }
+        });
+
+
+    }
+
+    protected abstract void addDefaults(RealmModel realm);
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
index a48d6ac..a6c98be 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
@@ -1,6 +1,9 @@
 package org.keycloak.protocol.oidc.mappers;
 
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.representations.AccessToken;
 
 import java.util.HashMap;
@@ -56,4 +59,27 @@ public class OIDCAttributeMapperHelper {
             }
         }
     }
+
+    public static void addClaimMapper(RealmModel realm, String name,
+                                  String userAttribute,
+                                  String tokenClaimName, String claimType,
+                                  boolean consentRequired, String consentText,
+                                  boolean appliedByDefault,
+                                  String mapperId) {
+        ProtocolMapperModel mapper = realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, name);
+        if (mapper != null) return;
+        mapper = new ProtocolMapperModel();
+        mapper.setName(name);
+        mapper.setProtocolMapper(mapperId);
+        mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        mapper.setConsentRequired(consentRequired);
+        mapper.setConsentText(consentText);
+        mapper.setAppliedByDefault(appliedByDefault);
+        Map<String, String> config = new HashMap<String, String>();
+        config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
+        config.put(TOKEN_CLAIM_NAME, tokenClaimName);
+        config.put(JSON_TYPE, claimType);
+        mapper.setConfig(config);
+        realm.addProtocolMapper(mapper);
+    }
 }
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 7aadbf3..3586372 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
@@ -3,6 +3,7 @@ package org.keycloak.protocol.oidc.mappers;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -26,8 +27,8 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
         configProperties.add(property);
         property = new ConfigProperty();
@@ -69,11 +70,23 @@ 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(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_NAME);
+        String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
         String attributeValue = user.getAttribute(attributeName);
         if (attributeValue == null) return token;
         OIDCAttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
         return token;
     }
 
+    public static void addClaimMapper(RealmModel realm, String name,
+                                      String userAttribute,
+                                      String tokenClaimName, String claimType,
+                                      boolean consentRequired, String consentText,
+                                      boolean appliedByDefault) {
+        OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
+                tokenClaimName, claimType,
+                consentRequired, consentText,
+                appliedByDefault, PROVIDER_ID);
+    }
+
+
 }
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 693311f..5e97f6d 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
@@ -3,6 +3,7 @@ package org.keycloak.protocol.oidc.mappers;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -25,8 +26,8 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
     static {
         ConfigProperty property;
         property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_MODEL_PROPERTY);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
+        property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
         configProperties.add(property);
         property = new ConfigProperty();
@@ -43,6 +44,7 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
     public List<ConfigProperty> getConfigProperties() {
         return configProperties;
     }
+
     @Override
     public String getId() {
         return PROVIDER_ID;
@@ -67,11 +69,23 @@ 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(ProtocolMapperUtils.USER_MODEL_PROPERTY);
+        String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
         String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
         OIDCAttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
 
         return token;
     }
 
+    public static void addClaimMapper(RealmModel realm, String name,
+                                      String userAttribute,
+                                      String tokenClaimName, String claimType,
+                                      boolean consentRequired, String consentText,
+                                      boolean appliedByDefault) {
+        OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
+                tokenClaimName, claimType,
+                consentRequired, consentText,
+                appliedByDefault, PROVIDER_ID);
+    }
+
+
 }
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 0a9c7c0..a53a759 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -1,92 +1,52 @@
 package org.keycloak.protocol.oidc;
 
-import org.keycloak.Config;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.AbstractLoginProtocolFactory;
 import org.keycloak.protocol.LoginProtocol;
-import org.keycloak.protocol.LoginProtocolFactory;
-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;
-import org.keycloak.provider.ProviderEvent;
-import org.keycloak.provider.ProviderEventListener;
 import org.keycloak.services.managers.AuthenticationManager;
 
-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 OIDCLoginProtocolFactory implements LoginProtocolFactory {
+public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
     @Override
     public LoginProtocol create(KeycloakSession session) {
         return new OIDCLoginProtocol().setSession(session);
     }
 
     @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-        KeycloakSession session = factory.create();
-        session.getTransaction().begin();
-        try {
-            List<RealmModel> realms = session.realms().getRealms();
-            for (RealmModel realm : realms) addMappers(realm);
-            session.getTransaction().commit();
-        } catch (Exception e) {
-            session.getTransaction().rollback();
-        } finally {
-            session.close();
-        }
-
-        factory.register(new ProviderEventListener() {
-            @Override
-            public void onEvent(ProviderEvent event) {
-                if (event instanceof RealmModel.RealmCreationEvent) {
-                    RealmModel realm = ((RealmModel.RealmCreationEvent)event).getCreatedRealm();
-                    addMappers(realm);
-                }
-            }
-        });
-
-
-    }
-
-    protected void addMappers(RealmModel realm) {
+    protected void addDefaults(RealmModel realm) {
         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,
-                ProtocolMapperUtils.USER_MODEL_PROPERTY, "username",
+        OIDCUserModelMapper.addClaimMapper(realm, "username",
+                "username",
                 "preferred_username", "String",
                 true, "username",
                 true);
-        addClaimMapper(realm, "email", OIDCUserModelMapper.PROVIDER_ID,
-                ProtocolMapperUtils.USER_MODEL_PROPERTY, "email",
+        OIDCUserModelMapper.addClaimMapper(realm, "email",
+                "email",
                 "email", "String",
                 true, "email",
                 true);
-        addClaimMapper(realm, "given name", OIDCUserModelMapper.PROVIDER_ID,
-                ProtocolMapperUtils.USER_MODEL_PROPERTY, "firstName",
+        OIDCUserModelMapper.addClaimMapper(realm, "given name",
+                "firstName",
                 "given_name", "String",
                 true, "given name",
                 true);
-        addClaimMapper(realm, "family name", OIDCUserModelMapper.PROVIDER_ID,
-                ProtocolMapperUtils.USER_MODEL_PROPERTY, "lastName",
+        OIDCUserModelMapper.addClaimMapper(realm, "family name",
+                "lastName",
                 "family_name", "String",
                 true, "family name",
                 true);
-        addClaimMapper(realm, "email verified", OIDCUserModelMapper.PROVIDER_ID,
-                ProtocolMapperUtils.USER_MODEL_PROPERTY, "emailVerified",
+        OIDCUserModelMapper.addClaimMapper(realm, "email verified",
+                "emailVerified",
                 "email_verified", "boolean",
                 false, null,
                 false);
@@ -116,39 +76,12 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
 
     }
 
-    protected void addClaimMapper(RealmModel realm, String name, String mapperRef,
-                                  String propertyName, String propertyNameValue,
-                                  String tokenClaimName, String claimType,
-                                  boolean consentRequired, String consentText,
-                                  boolean appliedByDefault) {
-        ProtocolMapperModel mapper = realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, name);
-        if (mapper != null) return;
-        mapper = new ProtocolMapperModel();
-        mapper.setName(name);
-        mapper.setProtocolMapper(mapperRef);
-        mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
-        mapper.setConsentRequired(consentRequired);
-        mapper.setConsentText(consentText);
-        mapper.setAppliedByDefault(appliedByDefault);
-        Map<String, String> config = new HashMap<String, String>();
-        config.put(propertyName, propertyNameValue);
-        config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
-        config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
-        mapper.setConfig(config);
-        realm.addProtocolMapper(mapper);
-    }
-
     @Override
     public Object createProtocolEndpoint(RealmModel realm, EventBuilder event, AuthenticationManager authManager) {
         return new OIDCLoginProtocolService(realm, event, authManager);
     }
 
     @Override
-    public void close() {
-
-    }
-
-    @Override
     public String getId() {
         return "openid-connect";
     }
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
index 8f7c2e9..abb915e 100755
--- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
@@ -9,9 +9,10 @@ import java.lang.reflect.Method;
  * @version $Revision: 1 $
  */
 public class ProtocolMapperUtils {
-    public static final String USER_MODEL_PROPERTY = "User Property";
+    public static final String USER_ATTRIBUTE = "user.attribute";
+    public static final String USER_MODEL_PROPERTY_LABEL = "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_LABEL = "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) {