keycloak-aplcache

claim mappings next phase

2/24/2015 9:37:07 PM

Changes

Details

diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
index 71fc2c4..6139c3d 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.Beta1.xml
@@ -5,14 +5,21 @@
             <column name="ID" type="VARCHAR(36)">
                 <constraints nullable="false"/>
             </column>
-            <column name="NAME" type="VARCHAR(255)"/>
-            <column name="PROTOCOL" type="VARCHAR(255)"/>
-            <column name="SOURCE" type="VARCHAR(255)"/>
-            <column name="PROTOCOL_MAPPER_NAME" type="VARCHAR(255)"/>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="PROTOCOL" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="PROTOCOL_MAPPER_NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
             <column name="APPLIED_BY_DEFAULT" type="BOOLEAN(1)"/>
             <column name="CONSENT_REQUIRED" type="BOOLEAN(1)"/>
             <column name="CONSENT_TEXT" type="VARCHAR(255)"/>
-            <column name="REALM_ID" type="VARCHAR(36)"/>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
         </createTable>
         <createTable tableName="PROTOCOL_MAPPER_CONFIG">
             <column name="PROTOCOL_MAPPER_ID" type="VARCHAR(36)">
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index 0e42a40..4349a75 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -30,7 +30,7 @@ public class ApplicationRepresentation {
     protected Integer nodeReRegistrationTimeout;
     protected Map<String, Integer> registeredNodes;
     protected List<String> allowedIdentityProviders;
-    protected Set<String> protocolClaimMappings;
+    protected Set<String> protocolMappers;
 
     public String getId() {
         return id;
@@ -200,11 +200,11 @@ public class ApplicationRepresentation {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
 
-    public Set<String> getProtocolClaimMappings() {
-        return protocolClaimMappings;
+    public Set<String> getProtocolMappers() {
+        return protocolMappers;
     }
 
-    public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
-        this.protocolClaimMappings = protocolClaimMappings;
+    public void setProtocolMappers(Set<String> protocolMappers) {
+        this.protocolMappers = protocolMappers;
     }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 9b655dc..dc5ada6 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -1,6 +1,7 @@
 package org.keycloak.representations.idm;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -64,7 +65,7 @@ public class RealmRepresentation {
     protected List<String> eventsListeners;
     private List<IdentityProviderRepresentation> identityProviders;
     private List<ClaimTypeRepresentation> claimTypes;
-    private List<ProtocolMapperRepresentation> protocolClaimMappings;
+    private List<ProtocolMapperRepresentation> protocolMappers;
     private Boolean identityFederationEnabled;
 
     public String getId() {
@@ -492,11 +493,16 @@ public class RealmRepresentation {
         this.claimTypes = claimTypes;
     }
 
-    public List<ProtocolMapperRepresentation> getProtocolClaimMappings() {
-        return protocolClaimMappings;
+    public List<ProtocolMapperRepresentation> getProtocolMappers() {
+        return protocolMappers;
     }
 
-    public void setProtocolClaimMappings(List<ProtocolMapperRepresentation> protocolClaimMappings) {
-        this.protocolClaimMappings = protocolClaimMappings;
+    public void addProtocolMapper(ProtocolMapperRepresentation rep) {
+        if (protocolMappers == null) protocolMappers = new LinkedList<ProtocolMapperRepresentation>();
+        protocolMappers.add(rep);
+    }
+
+    public void setProtocolMappers(List<ProtocolMapperRepresentation> protocolMappers) {
+        this.protocolMappers = protocolMappers;
     }
 }
diff --git a/core/src/main/java/org/keycloak/representations/UserClaimSet.java b/core/src/main/java/org/keycloak/representations/UserClaimSet.java
old mode 100644
new mode 100755
index c647269..4e8f1f9
--- a/core/src/main/java/org/keycloak/representations/UserClaimSet.java
+++ b/core/src/main/java/org/keycloak/representations/UserClaimSet.java
@@ -24,6 +24,75 @@ import org.codehaus.jackson.annotate.JsonProperty;
  */
 public class UserClaimSet {
 
+    public static class AddressClaimSet {
+        @JsonProperty("formatted")
+        protected String formattedAddress;
+
+        @JsonProperty("street_address")
+        protected String streetAddress;
+
+        @JsonProperty("locality")
+        protected String locality;
+
+        @JsonProperty("region")
+        protected String region;
+
+        @JsonProperty("postal_code")
+        protected String postalCode;
+
+        @JsonProperty("country")
+        protected String country;
+
+        public String getFormattedAddress() {
+            return this.formattedAddress;
+        }
+
+        public void setFormattedAddress(String formattedAddress) {
+            this.formattedAddress = formattedAddress;
+        }
+
+        public String getStreetAddress() {
+            return this.streetAddress;
+        }
+
+        public void setStreetAddress(String streetAddress) {
+            this.streetAddress = streetAddress;
+        }
+
+        public String getLocality() {
+            return this.locality;
+        }
+
+        public void setLocality(String locality) {
+            this.locality = locality;
+        }
+
+        public String getRegion() {
+            return this.region;
+        }
+
+        public void setRegion(String region) {
+            this.region = region;
+        }
+
+        public String getPostalCode() {
+            return this.postalCode;
+        }
+
+        public void setPostalCode(String postalCode) {
+            this.postalCode = postalCode;
+        }
+
+        public String getCountry() {
+            return this.country;
+        }
+
+        public void setCountry(String country) {
+            this.country = country;
+        }
+
+    }
+
     @JsonProperty("sub")
     protected String sub;
 
@@ -79,29 +148,11 @@ public class UserClaimSet {
     protected Boolean phoneNumberVerified;
 
     @JsonProperty("address")
-    protected String address;
+    protected AddressClaimSet address;
 
     @JsonProperty("updated_at")
     protected Long updatedAt;
 
-    @JsonProperty("formatted")
-    protected String formattedAddress;
-
-    @JsonProperty("street_address")
-    protected String streetAddress;
-
-    @JsonProperty("locality")
-    protected String locality;
-
-    @JsonProperty("region")
-    protected String region;
-
-    @JsonProperty("postal_code")
-    protected String postalCode;
-
-    @JsonProperty("country")
-    protected String country;
-
     @JsonProperty("claims_locales")
     protected String claimsLocales;
 
@@ -249,11 +300,11 @@ public class UserClaimSet {
         this.phoneNumberVerified = phoneNumberVerified;
     }
 
-    public String getAddress() {
-        return this.address;
+    public AddressClaimSet getAddress() {
+        return address;
     }
 
-    public void setAddress(String address) {
+    public void setAddress(AddressClaimSet address) {
         this.address = address;
     }
 
@@ -273,54 +324,6 @@ public class UserClaimSet {
         this.sub = sub;
     }
 
-    public String getFormattedAddress() {
-        return this.formattedAddress;
-    }
-
-    public void setFormattedAddress(String formattedAddress) {
-        this.formattedAddress = formattedAddress;
-    }
-
-    public String getStreetAddress() {
-        return this.streetAddress;
-    }
-
-    public void setStreetAddress(String streetAddress) {
-        this.streetAddress = streetAddress;
-    }
-
-    public String getLocality() {
-        return this.locality;
-    }
-
-    public void setLocality(String locality) {
-        this.locality = locality;
-    }
-
-    public String getRegion() {
-        return this.region;
-    }
-
-    public void setRegion(String region) {
-        this.region = region;
-    }
-
-    public String getPostalCode() {
-        return this.postalCode;
-    }
-
-    public void setPostalCode(String postalCode) {
-        this.postalCode = postalCode;
-    }
-
-    public String getCountry() {
-        return this.country;
-    }
-
-    public void setCountry(String country) {
-        this.country = country;
-    }
-
     public String getClaimsLocales() {
         return this.claimsLocales;
     }
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 243de4d..edcb44e 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -105,6 +105,7 @@ public interface ClientModel {
     boolean hasIdentityProvider(String providerId);
 
     Set<ProtocolMapperModel> getProtocolMappers();
-    void addProtocolMappers(Set<String> mapperIds);
-    void removeProtocolMappers(Set<String> mapperIds);
+    void addProtocolMappers(Set<String> mapperNames);
+    void removeProtocolMappers(Set<String> mapperNames);
+    void setProtocolMappers(Set<String> mapperNames);
 }
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index 1cfbcfe..3d43fee 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -30,7 +30,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     private List<String> redirectUris = new ArrayList<String>();
     private List<String> scopeIds = new ArrayList<String>();
     private List<String> allowedIdentityProviders = new ArrayList<String>();
-    private Set<String> protocolClaimMappings = new HashSet<String>();
+    private Set<String> protocolMappers = new HashSet<String>();
 
     public String getName() {
         return name;
@@ -152,11 +152,11 @@ public class ClientEntity extends AbstractIdentifiableEntity {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
 
-    public Set<String> getProtocolClaimMappings() {
-        return protocolClaimMappings;
+    public Set<String> getProtocolMappers() {
+        return protocolMappers;
     }
 
-    public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
-        this.protocolClaimMappings = protocolClaimMappings;
+    public void setProtocolMappers(Set<String> protocolMappers) {
+        this.protocolMappers = protocolMappers;
     }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index badc6bd..510d72a 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -1,6 +1,7 @@
 package org.keycloak.models;
 
 import org.keycloak.enums.SslRequired;
+import org.keycloak.provider.ProviderEvent;
 
 import java.security.Key;
 import java.security.PrivateKey;
@@ -15,6 +16,19 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public interface RealmModel extends RoleContainerModel {
+    interface RealmCreationEvent extends ProviderEvent {
+        RealmModel getCreatedRealm();
+    }
+    interface ClientCreationEvent extends ProviderEvent {
+        RealmModel getCreatedRealm();
+        ClientModel getCreatedClient();
+    }
+    interface ApplicationCreationEvent extends ClientCreationEvent {
+        ApplicationModel getCreatedApplication();
+    }
+    interface OAuthClientCreationEvent extends ClientCreationEvent {
+        OAuthClientModel getCreatedOAuthClient();
+    }
 
     String getId();
 
@@ -235,6 +249,7 @@ public interface RealmModel extends RoleContainerModel {
     void removeProtocolMapper(ProtocolMapperModel mapping);
     void updateProtocolMapper(ProtocolMapperModel mapping);
     public ProtocolMapperModel getProtocolMapperById(String id);
+    public ProtocolMapperModel getProtocolMapperByName(String name);
 
 
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmProvider.java b/model/api/src/main/java/org/keycloak/models/RealmProvider.java
index f2454d4..58328b2 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmProvider.java
@@ -10,9 +10,6 @@ import java.util.List;
  * @version $Revision: 1 $
  */
 public interface RealmProvider extends Provider {
-    public interface RealmCreationEvent extends ProviderEvent {
-        RealmModel getCreatedRealm();
-    }
 
     // Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
 
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 69d5477..949f974 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -158,7 +158,7 @@ public class ModelToRepresentation {
         }
 
         for (ProtocolMapperModel mapping : realm.getProtocolMappers()) {
-            rep.getProtocolClaimMappings().add(toRepresentation(mapping));
+            rep.addProtocolMapper(toRepresentation(mapping));
         }
 
         return rep;
@@ -267,8 +267,8 @@ public class ModelToRepresentation {
 
         if (!applicationModel.getProtocolMappers().isEmpty()) {
             Set<String> mappings = new HashSet<String>();
-            for (ProtocolMapperModel model : applicationModel.getProtocolMappers()) mappings.add(model.getId());
-            rep.setProtocolClaimMappings(mappings);
+            for (ProtocolMapperModel model : applicationModel.getProtocolMappers()) mappings.add(model.getName());
+            rep.setProtocolMappers(mappings);
         }
 
         return rep;
@@ -302,7 +302,7 @@ public class ModelToRepresentation {
 
         if (!model.getProtocolMappers().isEmpty()) {
             Set<String> mappings = new HashSet<String>();
-            for (ProtocolMapperModel mappingMoel : model.getProtocolMappers()) mappings.add(mappingMoel.getId());
+            for (ProtocolMapperModel mappingModel : model.getProtocolMappers()) mappings.add(mappingModel.getName());
             rep.setProtocolClaimMappings(mappings);
         }
         return rep;
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 2fb49af..cc0b63d 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -460,8 +460,8 @@ public class RepresentationToModel {
             applicationModel.setAllowedClaimsMask(ClaimMask.ALL);
         }
 
-        if (resourceRep.getProtocolClaimMappings() != null) {
-            applicationModel.addProtocolMappers(resourceRep.getProtocolClaimMappings());
+        if (resourceRep.getProtocolMappers() != null) {
+            applicationModel.setProtocolMappers(resourceRep.getProtocolMappers());
         }
 
         return applicationModel;
@@ -773,13 +773,17 @@ public class RepresentationToModel {
     }
 
     private static void importProtocolMappers(RealmRepresentation rep, RealmModel newRealm) {
-        if (rep.getProtocolClaimMappings() != null) {
+        if (rep.getProtocolMappers() != null) {
             // we make sure we don't recreate mappers that are automatically created by the protocol providers.
-            for (ProtocolMapperRepresentation representation : rep.getProtocolClaimMappings()) {
-                if (representation.getId() == null || newRealm.getProtocolMapperById(representation.getId()) == null) {
+            Set<ProtocolMapperModel> mappers = newRealm.getProtocolMappers();
+            for (ProtocolMapperRepresentation representation : rep.getProtocolMappers()) {
+                ProtocolMapperModel existing = newRealm.getProtocolMapperByName(representation.getName());
+                if (existing == null) {
                     newRealm.addProtocolMapper(toModel(representation));
                 } else {
-                    newRealm.updateProtocolMapper(toModel(representation));
+                    ProtocolMapperModel mapping = toModel(representation);
+                    mapping.setId(existing.getId());
+                    newRealm.updateProtocolMapper(mapping);
                 }
             }
         }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index 83f5490..0fc38bc 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -286,16 +286,23 @@ public abstract class ClientAdapter implements ClientModel {
         return cachedClient.getProtocolClaimMappings();    }
 
     @Override
-    public void addProtocolMappers(Set<String> mappingIds) {
+    public void addProtocolMappers(Set<String> mapperNames) {
         getDelegateForUpdate();
-        updatedClient.addProtocolMappers(mappingIds);
+        updatedClient.addProtocolMappers(mapperNames);
 
     }
 
     @Override
-    public void removeProtocolMappers(Set<String> mappingIds) {
+    public void removeProtocolMappers(Set<String> mapperNames) {
         getDelegateForUpdate();
-        updatedClient.removeProtocolMappers(mappingIds);
+        updatedClient.removeProtocolMappers(mapperNames);
+
+    }
+
+    @Override
+    public void setProtocolMappers(Set<String> mapperNames) {
+        getDelegateForUpdate();
+        updatedClient.setProtocolMappers(mapperNames);
 
     }
 }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index 21d32cc..d036456 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -920,6 +920,14 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public ProtocolMapperModel getProtocolMapperByName(String name) {
+        for (ProtocolMapperModel mapping : cached.getClaimMappings()) {
+            if (mapping.getName().equals(name)) return mapping;
+        }
+        return null;
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof RealmModel)) return false;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index c06cdec..f45c085 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -8,6 +8,7 @@ import org.keycloak.models.RoleModel;
 import org.keycloak.models.jpa.entities.ClientEntity;
 import org.keycloak.models.jpa.entities.IdentityProviderEntity;
 import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
+import org.keycloak.models.jpa.entities.RealmEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 
@@ -17,6 +18,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -364,6 +366,7 @@ public abstract class ClientAdapter implements ClientModel {
             mapping.setId(entity.getId());
             mapping.setName(entity.getName());
             mapping.setProtocol(entity.getProtocol());
+            mapping.setProtocolMapper(entity.getProtocolMapper());
             mapping.setAppliedByDefault(entity.isAppliedByDefault());
             mapping.setConsentRequired(entity.isConsentRequired());
             mapping.setConsentText(entity.getConsentText());
@@ -377,16 +380,27 @@ public abstract class ClientAdapter implements ClientModel {
         return mappings;
     }
 
+    protected ProtocolMapperEntity findProtocolMapperByName(String name) {
+        TypedQuery<ProtocolMapperEntity> query = em.createNamedQuery("getProtocolMapperByName", ProtocolMapperEntity.class);
+        query.setParameter("name", name);
+        query.setParameter("realm", entity.getRealm());
+        List<ProtocolMapperEntity> entities = query.getResultList();
+        if (entities.size() == 0) return null;
+        if (entities.size() > 1) throw new IllegalStateException("Should not be more than one protocol mapper with same name");
+        return query.getResultList().get(0);
+
+    }
+
     @Override
     public void addProtocolMappers(Set<String> mappings) {
         Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
         Set<String> already = new HashSet<String>();
         for (ProtocolMapperEntity rel : entities) {
-            already.add(rel.getId());
+            already.add(rel.getName());
         }
-        for (String providerId : mappings) {
-            if (!already.contains(providerId)) {
-                ProtocolMapperEntity mapping = em.find(ProtocolMapperEntity.class, providerId);
+        for (String name : mappings) {
+            if (!already.contains(name)) {
+                ProtocolMapperEntity mapping = findProtocolMapperByName(name);
                 if (mapping != null) {
                     entities.add(mapping);
                 }
@@ -400,13 +414,36 @@ public abstract class ClientAdapter implements ClientModel {
         Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
         List<ProtocolMapperEntity> remove = new LinkedList<ProtocolMapperEntity>();
         for (ProtocolMapperEntity rel : entities) {
-            if (mappings.contains(rel.getId())) remove.add(rel);
+            if (mappings.contains(rel.getName())) remove.add(rel);
         }
         for (ProtocolMapperEntity entity : remove) {
             entities.remove(entity);
         }
         em.flush();
     }
+    @Override
+    public void setProtocolMappers(Set<String> mappings) {
+        Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
+        Iterator<ProtocolMapperEntity> it = entities.iterator();
+        Set<String> already = new HashSet<String>();
+        while (it.hasNext()) {
+            ProtocolMapperEntity mapper = it.next();
+            if (mappings.contains(mapper.getName())) {
+                already.add(mapper.getName());
+                continue;
+            }
+            it.remove();
+        }
+        for (String name : mappings) {
+            if (!already.contains(name)) {
+                ProtocolMapperEntity mapping = findProtocolMapperByName(name);
+                if (mapping != null) {
+                    entities.add(mapping);
+                }
+            }
+        }
+        em.flush();
+    }
 
 
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index ec8929e..817fd80 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -77,7 +77,7 @@ public abstract class ClientEntity {
     @JoinTable(name="CLIENT_ALLOWED_IDENTITY_PROVIDER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="INTERNAL_ID")})
     Collection<IdentityProviderEntity> allowedIdentityProviders = new ArrayList<IdentityProviderEntity>();
 
-    @OneToMany(cascade ={CascadeType.REMOVE})
+    @OneToMany(fetch = FetchType.LAZY)
     @JoinTable(name="CLIENT_PROTOCOL_MAPPER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="MAPPING_ID")})
     Collection<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolMapperEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolMapperEntity.java
index bd8bbe2..822049b 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolMapperEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolMapperEntity.java
@@ -20,7 +20,7 @@ import java.util.Map;
  */
 @Entity
 @NamedQueries({
-        @NamedQuery(name="deleteProtocolClaimMappersByRealm", query="delete from ProtocolMapperEntity attr where attr.realm = :realm")
+        @NamedQuery(name="getProtocolMapperByName", query="select mapper from ProtocolMapperEntity mapper where mapper.name = :name and mapper.realm = :realm")
 })
 @Table(name="PROTOCOL_MAPPER")
 public class ProtocolMapperEntity {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index e9cdda1..2f24d06 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -96,7 +96,7 @@ public class RealmEntity {
     Collection<ClaimTypeEntity> claimTypes = new ArrayList<ClaimTypeEntity>();
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
-    Collection<ProtocolMapperEntity> protocolClaimMappings = new ArrayList<ProtocolMapperEntity>();
+    Collection<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
     Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
@@ -447,12 +447,12 @@ public class RealmEntity {
         this.claimTypes = claimTypes;
     }
 
-    public Collection<ProtocolMapperEntity> getProtocolClaimMappings() {
-        return protocolClaimMappings;
+    public Collection<ProtocolMapperEntity> getProtocolMappers() {
+        return protocolMappers;
     }
 
-    public void setProtocolClaimMappings(Collection<ProtocolMapperEntity> protocolClaimMappings) {
-        this.protocolClaimMappings = protocolClaimMappings;
+    public void setProtocolMappers(Collection<ProtocolMapperEntity> protocolMappers) {
+        this.protocolMappers = protocolMappers;
     }
 }
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
index 371d048..3091cc9 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
@@ -45,7 +45,7 @@ public class JpaRealmProvider implements RealmProvider {
         em.persist(realm);
         em.flush();
         final RealmModel model = new RealmAdapter(session, em, realm);
-        session.getKeycloakSessionFactory().publish(new RealmCreationEvent() {
+        session.getKeycloakSessionFactory().publish(new RealmModel.RealmCreationEvent() {
             @Override
             public RealmModel getCreatedRealm() {
                 return model;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 7578fd0..6c4af39 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -628,6 +628,17 @@ public class RealmAdapter implements RealmModel {
         return this.addApplication(KeycloakModelUtils.generateId(), name);
     }
 
+    public void addDefaultClientProtocolMappers(ClientModel client) {
+        Set<String> adding = new HashSet<String>();
+        for (ProtocolMapperEntity mapper : realm.getProtocolMappers()) {
+            if (mapper.isAppliedByDefault()) {
+                adding.add(mapper.getName());
+            }
+        }
+        client.setProtocolMappers(adding);
+
+    }
+
     @Override
     public ApplicationModel addApplication(String id, String name) {
         ApplicationEntity applicationData = new ApplicationEntity();
@@ -639,6 +650,7 @@ public class RealmAdapter implements RealmModel {
         em.persist(applicationData);
         em.flush();
         ApplicationModel resource = new ApplicationAdapter(this, em, session, applicationData);
+        addDefaultClientProtocolMappers(resource);
         em.flush();
         return resource;
     }
@@ -702,7 +714,10 @@ public class RealmAdapter implements RealmModel {
         data.setRealm(realm);
         em.persist(data);
         em.flush();
-        return new OAuthClientAdapter(this, data, em);
+        OAuthClientModel model = new OAuthClientAdapter(this, data, em);
+        addDefaultClientProtocolMappers(model);
+        em.flush();
+        return model;
     }
 
     @Override
@@ -1259,7 +1274,7 @@ public class RealmAdapter implements RealmModel {
     @Override
     public Set<ProtocolMapperModel> getProtocolMappers() {
         Set<ProtocolMapperModel> mappings = new HashSet<ProtocolMapperModel>();
-        for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
+        for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
             ProtocolMapperModel mapping = new ProtocolMapperModel();
             mapping.setId(entity.getId());
             mapping.setName(entity.getName());
@@ -1280,7 +1295,10 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
-        String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
+        if (getProtocolMapperByName(model.getName()) != null) {
+            throw new RuntimeException("Duplicate protocol mapper with name: " + model.getName());
+        }
+        String id = KeycloakModelUtils.generateId();
         ProtocolMapperEntity entity = new ProtocolMapperEntity();
         entity.setId(id);
         entity.setName(model.getName());
@@ -1293,20 +1311,12 @@ public class RealmAdapter implements RealmModel {
         entity.setConsentText(model.getConsentText());
 
         em.persist(entity);
-        ProtocolMapperModel mapping = new ProtocolMapperModel();
-        mapping.setId(entity.getId());
-        mapping.setName(model.getName());
-        mapping.setProtocol(entity.getProtocol());
-        mapping.setProtocolMapper(entity.getProtocolMapper());
-        mapping.setAppliedByDefault(entity.isAppliedByDefault());
-        mapping.setConfig(model.getConfig());
-        mapping.setConsentRequired(entity.isConsentRequired());
-        mapping.setConsentText(entity.getConsentText());
-        return mapping;
+        realm.getProtocolMappers().add(entity);
+        return entityToModel(entity);
     }
 
-    protected ProtocolMapperEntity getProtocolMapper(String id) {
-        for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
+    protected ProtocolMapperEntity getProtocolMapperEntity(String id) {
+        for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
             if (entity.getId().equals(id)) {
                 return entity;
             }
@@ -1315,11 +1325,21 @@ public class RealmAdapter implements RealmModel {
 
     }
 
+    protected ProtocolMapperEntity getProtocolMapperEntityByName(String name) {
+        for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
+            if (entity.getName().equals(name)) {
+                return entity;
+            }
+        }
+        return null;
+
+    }
+
     @Override
     public void removeProtocolMapper(ProtocolMapperModel mapping) {
-        ProtocolMapperEntity toDelete = getProtocolMapper(mapping.getId());
+        ProtocolMapperEntity toDelete = getProtocolMapperEntity(mapping.getId());
         if (toDelete != null) {
-            realm.getProtocolClaimMappings().remove(toDelete);
+            realm.getProtocolMappers().remove(toDelete);
             em.remove(toDelete);
         }
 
@@ -1327,7 +1347,7 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public void updateProtocolMapper(ProtocolMapperModel mapping) {
-        ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
+        ProtocolMapperEntity entity = getProtocolMapperEntity(mapping.getId());
         entity.setProtocolMapper(mapping.getProtocolMapper());
         entity.setAppliedByDefault(mapping.isAppliedByDefault());
         entity.setConsentRequired(mapping.isConsentRequired());
@@ -1344,12 +1364,24 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public ProtocolMapperModel getProtocolMapperById(String id) {
-        ProtocolMapperEntity entity = getProtocolMapper(id);
+        ProtocolMapperEntity entity = getProtocolMapperEntity(id);
+        if (entity == null) return null;
+        return entityToModel(entity);
+    }
+
+    @Override
+    public ProtocolMapperModel getProtocolMapperByName(String name) {
+        ProtocolMapperEntity entity = getProtocolMapperEntityByName(name);
         if (entity == null) return null;
+        return entityToModel(entity);
+    }
+
+    protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
         ProtocolMapperModel mapping = new ProtocolMapperModel();
         mapping.setId(entity.getId());
         mapping.setName(entity.getName());
         mapping.setProtocol(entity.getProtocol());
+        mapping.setProtocolMapper(entity.getProtocolMapper());
         mapping.setAppliedByDefault(entity.isAppliedByDefault());
         mapping.setConsentRequired(entity.isConsentRequired());
         mapping.setConsentText(entity.getConsentText());
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 1a6990d..7bc47a5 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -295,7 +295,7 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
     @Override
     public Set<ProtocolMapperModel> getProtocolMappers() {
         Set<ProtocolMapperModel> result = new HashSet<ProtocolMapperModel>();
-        for (String id : getMongoEntityAsClient().getProtocolClaimMappings()) {
+        for (String id : getMongoEntityAsClient().getProtocolMappers()) {
             ProtocolMapperModel model = getRealm().getProtocolMapperById(id);
             if (model != null) result.add(model);
         }
@@ -303,15 +303,22 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
     }
 
     @Override
-    public void addProtocolMappers(Set<String> mappingIds) {
-        getMongoEntityAsClient().getProtocolClaimMappings().addAll(mappingIds);
+    public void addProtocolMappers(Set<String> mapperNames) {
+        getMongoEntityAsClient().getProtocolMappers().addAll(mapperNames);
         updateMongoEntity();
 
     }
 
     @Override
-    public void removeProtocolMappers(Set<String> mappingIds) {
-        getMongoEntityAsClient().getProtocolClaimMappings().removeAll(mappingIds);
+    public void removeProtocolMappers(Set<String> mapperNames) {
+        getMongoEntityAsClient().getProtocolMappers().removeAll(mapperNames);
+        updateMongoEntity();
+    }
+
+    @Override
+    public void setProtocolMappers(Set<String> mapperNames) {
+        getMongoEntityAsClient().getProtocolMappers().clear();
+        getMongoEntityAsClient().getProtocolMappers().addAll(mapperNames);
         updateMongoEntity();
     }
 
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
index 997025e..61865d6 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
@@ -52,7 +52,7 @@ public class MongoRealmProvider implements RealmProvider {
         getMongoStore().insertEntity(newRealm, invocationContext);
 
         final RealmModel model = new RealmAdapter(session, newRealm, invocationContext);
-        session.getKeycloakSessionFactory().publish(new RealmCreationEvent() {
+        session.getKeycloakSessionFactory().publish(new RealmModel.RealmCreationEvent() {
             @Override
             public RealmModel getCreatedRealm() {
                 return model;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 9b20f2a..065443f 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -616,6 +616,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         return result;
     }
 
+    public void addDefaultClientProtocolMappers(ClientModel client) {
+        Set<String> adding = new HashSet<String>();
+        for (ProtocolMapperEntity mapper : realm.getProtocolMappers()) {
+            if (mapper.isAppliedByDefault()) adding.add(mapper.getName());
+        }
+        client.setProtocolMappers(adding);
+
+    }
     @Override
     public ApplicationModel addApplication(String name) {
         return this.addApplication(null, name);
@@ -630,7 +638,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         appData.setEnabled(true);
         getMongoStore().insertEntity(appData, invocationContext);
 
-        return new ApplicationAdapter(session, this, appData, invocationContext);
+        ApplicationModel model = new ApplicationAdapter(session, this, appData, invocationContext);
+        addDefaultClientProtocolMappers(model);
+        return model;
     }
 
     @Override
@@ -651,7 +661,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         oauthClient.setName(name);
         getMongoStore().insertEntity(oauthClient, invocationContext);
 
-        return new OAuthClientAdapter(session, this, oauthClient, invocationContext);
+        OAuthClientAdapter model = new OAuthClientAdapter(session, this, oauthClient, invocationContext);
+        addDefaultClientProtocolMappers(model);
+        return model;
     }
 
     @Override
@@ -809,8 +821,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
         ProtocolMapperEntity entity = new ProtocolMapperEntity();
-        if (model.getId() != null) entity.setId(model.getId());
-        else entity.setId(KeycloakModelUtils.generateId());
+        entity.setId(KeycloakModelUtils.generateId());
         entity.setProtocol(model.getProtocol());
         entity.setName(model.getName());
         entity.setAppliedByDefault(model.isAppliedByDefault());
@@ -820,15 +831,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         entity.setConsentText(model.getConsentText());
         realm.getProtocolMappers().add(entity);
         updateRealm();
-        ProtocolMapperModel mapping = new ProtocolMapperModel();
-        mapping.setId(entity.getId());
-        mapping.setProtocol(model.getProtocol());
-        mapping.setAppliedByDefault(model.isAppliedByDefault());
-        mapping.setProtocolMapper(model.getProtocolMapper());
-        mapping.setConfig(model.getConfig());
-        mapping.setConsentText(model.getConsentText());
-        mapping.setConsentRequired(model.isConsentRequired());
-        return mapping;
+        return entityToModel(entity);
     }
 
     @Override
@@ -843,7 +846,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     }
 
-    protected ProtocolMapperEntity getProtocolMapper(String id) {
+    protected ProtocolMapperEntity getProtocolMapperyEntityById(String id) {
         for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
             if (entity.getId().equals(id)) {
                 return entity;
@@ -852,11 +855,20 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         return null;
 
     }
+    protected ProtocolMapperEntity getProtocolMapperyEntityByName(String name) {
+        for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
+            if (entity.getName().equals(name)) {
+                return entity;
+            }
+        }
+        return null;
+
+    }
 
 
     @Override
     public void updateProtocolMapper(ProtocolMapperModel mapping) {
-        ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
+        ProtocolMapperEntity entity = getProtocolMapperyEntityById(mapping.getId());
         entity.setAppliedByDefault(mapping.isAppliedByDefault());
         entity.setProtocolMapper(mapping.getProtocolMapper());
         entity.setConsentRequired(mapping.isConsentRequired());
@@ -873,8 +885,19 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public ProtocolMapperModel getProtocolMapperById(String id) {
-        ProtocolMapperEntity entity = getProtocolMapper(id);
+        ProtocolMapperEntity entity = getProtocolMapperyEntityById(id);
         if (entity == null) return null;
+        return entityToModel(entity);
+    }
+
+    @Override
+    public ProtocolMapperModel getProtocolMapperByName(String name) {
+        ProtocolMapperEntity entity = getProtocolMapperyEntityById(name);
+        if (entity == null) return null;
+        return entityToModel(entity);
+    }
+
+    protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
         ProtocolMapperModel mapping = new ProtocolMapperModel();
         mapping.setId(entity.getId());
         mapping.setName(entity.getName());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AttributeMapperHelper.java
new file mode 100755
index 0000000..a4fe0fe
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AttributeMapperHelper.java
@@ -0,0 +1,59 @@
+package org.keycloak.protocol.oidc.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.representations.AccessToken;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AttributeMapperHelper {
+    public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
+    public static final String JSON_TYPE = "Claim JSON Type";
+
+    public static Object mapAttributeValue(ProtocolMapperModel mappingModel, Object attributeValue) {
+        if (attributeValue == null) return null;
+        String type = mappingModel.getConfig().get(JSON_TYPE);
+        if (type == null) return attributeValue;
+        if (type.equals("boolean")) {
+            if (attributeValue instanceof Boolean) return attributeValue;
+            if (attributeValue instanceof String) return Boolean.valueOf((String)attributeValue);
+            throw new RuntimeException("cannot map type for token claim");
+        } else if (type.equals("String")) {
+            if (attributeValue instanceof String) return attributeValue;
+            return attributeValue.toString();
+        } else if (type.equals("long")) {
+            if (attributeValue instanceof Long) return attributeValue;
+            if (attributeValue instanceof String) return Long.valueOf((String)attributeValue);
+            throw new RuntimeException("cannot map type for token claim");
+        } else if (type.equals("int")) {
+            if (attributeValue instanceof Integer) return attributeValue;
+            if (attributeValue instanceof String) return Integer.valueOf((String)attributeValue);
+            throw new RuntimeException("cannot map type for token claim");
+        }
+        return attributeValue;
+    }
+
+    public static void mapClaim(AccessToken token, ProtocolMapperModel mappingModel, Object attributeValue) {
+        if (attributeValue == null) return;
+        attributeValue = mapAttributeValue(mappingModel, attributeValue);
+        String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
+        String[] split = protocolClaim.split("\\.");
+        Map<String, Object> jsonObject = token.getOtherClaims();
+        for (int i = 0; i < split.length; i++) {
+            if (i == split.length - 1) {
+                jsonObject.put(split[i], attributeValue);
+            } else {
+                Map<String, Object> nested = (Map<String, Object>)jsonObject.get(split[i]);
+                if (nested == null) {
+                    nested = new HashMap<String, Object>();
+                    jsonObject.put(split[i], nested);
+                    jsonObject = nested;
+                }
+            }
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddressMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddressMapper.java
new file mode 100755
index 0000000..ee7e815
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddressMapper.java
@@ -0,0 +1,59 @@
+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.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.UserClaimSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Set the 'name' claim to be first + last name.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
+
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+
+    }
+
+    public static final String PROVIDER_ID = "oidc-address-mapper";
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Address Mapper";
+    }
+
+    @Override
+    public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
+                                      UserSessionModel userSession, ClientSessionModel clientSession) {
+        UserModel user = userSession.getUser();
+        UserClaimSet.AddressClaimSet addressSet = new UserClaimSet.AddressClaimSet();
+        addressSet.setStreetAddress(user.getAttribute("street"));
+        addressSet.setLocality(user.getAttribute("locality"));
+        addressSet.setRegion(user.getAttribute("region"));
+        addressSet.setPostalCode(user.getAttribute("postal_code"));
+        addressSet.setCountry(user.getAttribute("country"));
+        token.getOtherClaims().put("address", addressSet);
+        return token;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCClientSessionNoteMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCClientSessionNoteMapper.java
index 3e38ed2..216c0fe 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCClientSessionNoteMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCClientSessionNoteMapper.java
@@ -28,8 +28,8 @@ public class OIDCClientSessionNoteMapper extends AbstractOIDCProtocolMapper impl
         property.setLabel(CLIENT_SESSION_NOTE);
         property.setHelpText("Name of the note to map in the UserSessionModel");
         configProperties.add(property);
-        property.setName(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
+        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(AttributeMapperHelper.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);
 
@@ -53,7 +53,7 @@ public class OIDCClientSessionNoteMapper extends AbstractOIDCProtocolMapper impl
                                       UserSessionModel userSession, ClientSessionModel clientSession) {
         String note = mappingModel.getConfig().get(CLIENT_SESSION_NOTE);
         String noteValue = clientSession.getNote(note);
-        OIDCUserAttributeMapper.mapClaim(token, mappingModel, noteValue);
+        AttributeMapperHelper.mapClaim(token, mappingModel, noteValue);
         return token;
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCFullNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCFullNameMapper.java
new file mode 100755
index 0000000..b77783a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCFullNameMapper.java
@@ -0,0 +1,54 @@
+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.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.AccessToken;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Set the 'name' claim to be first + last name.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
+
+    private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
+
+    static {
+
+    }
+
+    public static final String PROVIDER_ID = "oidc-full-name-mapper";
+
+
+    public List<ConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Full name Mapper";
+    }
+
+    @Override
+    public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
+                                      UserSessionModel userSession, ClientSessionModel clientSession) {
+        UserModel user = userSession.getUser();
+        String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
+        String last = user.getLastName() == null ? "" : user.getLastName();
+        token.getOtherClaims().put("name", first + last);
+        return token;
+    }
+
+}
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 1c687be..c543558 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
@@ -7,11 +7,8 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.representations.AccessToken;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Mappings UserModel.attribute to an ID Token claim.  Token claim name can be a full qualified nested object name,
@@ -23,7 +20,6 @@ import java.util.Map;
  */
 public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
 
-    public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
     private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
     public static final String USER_MODEL_ATTRIBUTE_NAME = "UserModel Attribute Name";
 
@@ -34,13 +30,15 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
         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.");
         configProperties.add(property);
-        property.setName(TOKEN_CLAIM_NAME);
-        property.setLabel(TOKEN_CLAIM_NAME);
+        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(AttributeMapperHelper.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);
 
     }
 
+    public static final String PROVIDER_ID = "oidc-usermodel-attribute-mapper";
+
 
     public List<ConfigProperty> getConfigProperties() {
         return configProperties;
@@ -48,7 +46,7 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
 
     @Override
     public String getId() {
-        return "oidc-usermodel-attribute-mapper";
+        return PROVIDER_ID;
     }
 
     @Override
@@ -63,26 +61,8 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
         String attributeName = mappingModel.getConfig().get(USER_MODEL_ATTRIBUTE_NAME);
         String attributeValue = user.getAttribute(attributeName);
         if (attributeValue == null) return token;
-        mapClaim(token, mappingModel, attributeValue);
+        AttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
         return token;
     }
 
-    protected static void mapClaim(AccessToken token, ProtocolMapperModel mappingModel, String attributeValue) {
-        if (attributeValue == null) return;
-        String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
-        String[] split = protocolClaim.split(".");
-        Map<String, Object> jsonObject = token.getOtherClaims();
-        for (int i = 0; i < split.length; i++) {
-            if (i == split.length - 1) {
-                jsonObject.put(split[i], attributeValue);
-            } else {
-                Map<String, Object> nested = (Map<String, Object>)jsonObject.get(split[i]);
-                if (nested == null) {
-                    nested = new HashMap<String, Object>();
-                    jsonObject.put(split[i], nested);
-                    jsonObject = nested;
-                }
-            }
-        }
-    }
 }
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 4af3178..6c30080 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
@@ -9,9 +9,7 @@ import org.keycloak.representations.AccessToken;
 
 import java.lang.reflect.Method;
 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 ID Token claim.  Token claim name can be a full qualified nested object name,
@@ -32,20 +30,22 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
         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.");
         configProperties.add(property);
-        property.setName(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
+        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(AttributeMapperHelper.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);
 
     }
 
+    public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
+
 
     public List<ConfigProperty> getConfigProperties() {
         return configProperties;
     }
     @Override
     public String getId() {
-        return "oidc-usermodel-property-mapper";
+        return PROVIDER_ID;
     }
 
     @Override
@@ -59,7 +59,7 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
         UserModel user = userSession.getUser();
         String propertyName = mappingModel.getConfig().get(USER_MODEL_PROPERTY);
         String propertyValue = getUserModelValue(user,propertyName);
-        OIDCUserAttributeMapper.mapClaim(token, mappingModel, propertyValue);
+        AttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
 
         return token;
     }
@@ -74,6 +74,14 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
         } 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/mappers/OIDCUserSessionNoteMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserSessionNoteMapper.java
index 0069d5a..e430f4d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserSessionNoteMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserSessionNoteMapper.java
@@ -28,8 +28,8 @@ public class OIDCUserSessionNoteMapper extends AbstractOIDCProtocolMapper implem
         property.setLabel("UserSession Note");
         property.setHelpText("Name of the note to map in the UserSessionModel");
         configProperties.add(property);
-        property.setName(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
+        property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(AttributeMapperHelper.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);
 
@@ -54,7 +54,7 @@ public class OIDCUserSessionNoteMapper extends AbstractOIDCProtocolMapper implem
                                       UserSessionModel userSession, ClientSessionModel clientSession) {
         String note = mappingModel.getConfig().get(USER_SESSION_NOTE);
         String noteValue = userSession.getNote(note);
-        OIDCUserAttributeMapper.mapClaim(token, mappingModel, noteValue);
+        AttributeMapperHelper.mapClaim(token, mappingModel, noteValue);
         return token;
     }
 
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 d8ff2e4..08ee15f 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -4,11 +4,22 @@ 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.LoginProtocol;
 import org.keycloak.protocol.LoginProtocolFactory;
+import org.keycloak.protocol.oidc.mappers.AttributeMapperHelper;
+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 $
@@ -25,8 +36,107 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
 
     @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) {
+        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",
+                "preferred_username", "String",
+                true, "username",
+                true);
+        addClaimMapper(realm, "email", OIDCUserModelMapper.PROVIDER_ID,
+                OIDCUserModelMapper.USER_MODEL_PROPERTY, "email",
+                "email", "String",
+                true, "email",
+                true);
+        addClaimMapper(realm, "given name", OIDCUserModelMapper.PROVIDER_ID,
+                OIDCUserModelMapper.USER_MODEL_PROPERTY, "firstName",
+                "given_name", "String",
+                true, "given name",
+                true);
+        addClaimMapper(realm, "family name", OIDCUserModelMapper.PROVIDER_ID,
+                OIDCUserModelMapper.USER_MODEL_PROPERTY, "lastName",
+                "family_name", "String",
+                true, "family name",
+                true);
+        addClaimMapper(realm, "email verified", OIDCUserModelMapper.PROVIDER_ID,
+                OIDCUserModelMapper.USER_MODEL_PROPERTY, "emailVerified",
+                "email_verified", "boolean",
+                false, null,
+                false);
+
+        ProtocolMapperModel fullName = new ProtocolMapperModel();
+        if (realm.getProtocolMapperByName("full name") == null) {
+            fullName.setName("full name");
+            fullName.setProtocolMapper(OIDCFullNameMapper.PROVIDER_ID);
+            fullName.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+            fullName.setConsentRequired(true);
+            fullName.setConsentText("full name");
+            fullName.setAppliedByDefault(true);
+            realm.addProtocolMapper(fullName);
+        }
+
+        ProtocolMapperModel address = new ProtocolMapperModel();
+        if (realm.getProtocolMapperByName("address") == null) {
+            address.setName("address");
+            address.setProtocolMapper(OIDCAddressMapper.PROVIDER_ID);
+            address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+            address.setConsentRequired(true);
+            address.setConsentText("address");
+            address.setAppliedByDefault(false);
+            realm.addProtocolMapper(address);
+        }
+
 
     }
+
+    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(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(AttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
+        config.put(AttributeMapperHelper.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);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index ae0ba0a..5e40809 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -340,7 +340,7 @@ public class OIDCLoginProtocolService {
         TokenManager.attachClientSession(userSession, clientSession);
 
         AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
-                .generateAccessToken(scope, client, user, userSession, clientSession)
+                .generateAccessToken(session, scope, client, user, userSession, clientSession)
                 .generateRefreshToken()
                 .generateIDToken()
                 .build();
@@ -668,7 +668,7 @@ public class OIDCLoginProtocolService {
             clientSession.setNote(AdapterConstants.APPLICATION_SESSION_HOST, adapterSessionHost);
         }
 
-        AccessToken token = tokenManager.createClientAccessToken(accessCode.getRequestedRoles(), realm, client, user, userSession, clientSession);
+        AccessToken token = tokenManager.createClientAccessToken(session, accessCode.getRequestedRoles(), realm, client, user, userSession, clientSession);
 
         try {
             tokenManager.verifyAccess(token, realm, client, user);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 4c56df7..8e48aeb 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -13,6 +13,7 @@ import org.keycloak.models.ClaimMask;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
@@ -20,6 +21,8 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.UserSessionProvider;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.ProtocolMapper;
+import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.UserClaimSet;
@@ -104,7 +107,7 @@ public class TokenManager {
         AccessToken accessToken = initToken(realm, client, user, userSession, clientSession);
         accessToken.setRealmAccess(refreshToken.getRealmAccess());
         accessToken.setResourceAccess(refreshToken.getResourceAccess());
-        accessToken = transformToken(accessToken, realm, client, user, userSession, clientSession);
+        accessToken = transformToken(session, accessToken, realm, client, user, userSession, clientSession);
 
         userSession.setLastSessionRefresh(currentTime);
 
@@ -132,12 +135,12 @@ public class TokenManager {
         return refreshToken;
     }
 
-    public AccessToken createClientAccessToken(Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
-        AccessToken token = initToken(realm, client, user, session, clientSession);
+    public AccessToken createClientAccessToken(KeycloakSession session, Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
+        AccessToken token = initToken(realm, client, user, userSession, clientSession);
         for (RoleModel role : requestedRoles) {
             addComposites(token, role);
         }
-        token = transformToken(token, realm, client, user, session, clientSession);
+        token = transformToken(session, token, realm, client, user, userSession, clientSession);
         return token;
     }
 
@@ -232,36 +235,20 @@ public class TokenManager {
         }
     }
 
-    public void initClaims(UserClaimSet claimSet, ClientModel model, UserModel user) {
-        claimSet.setSubject(user.getId());
-
-        if (ClaimMask.hasUsername(model.getAllowedClaimsMask())) {
-            claimSet.setPreferredUsername(user.getUsername());
-        }
-        if (ClaimMask.hasEmail(model.getAllowedClaimsMask())) {
-            claimSet.setEmail(user.getEmail());
-            claimSet.setEmailVerified(user.isEmailVerified());
-        }
-        if (ClaimMask.hasName(model.getAllowedClaimsMask())) {
-            claimSet.setFamilyName(user.getLastName());
-            claimSet.setGivenName(user.getFirstName());
-            StringBuilder fullName = new StringBuilder();
-            if (user.getFirstName() != null) fullName.append(user.getFirstName()).append(" ");
-            if (user.getLastName() != null) fullName.append(user.getLastName());
-            claimSet.setName(fullName.toString());
-        }
-
-        Set<ProtocolMapperModel> mappings = model.getProtocolMappers();
+    public AccessToken transformToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
+                                         UserSessionModel userSession, ClientSessionModel clientSession) {
+        Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
+        KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
         for (ProtocolMapperModel mapping : mappings) {
             if (!mapping.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) continue;
 
-        }
-    }
+            ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
+            if (mapper == null || !(mapper instanceof OIDCAccessTokenMapper)) continue;
+            token = ((OIDCAccessTokenMapper)mapper).transformToken(token, mapping, session, userSession, clientSession);
+
 
-    protected AccessToken transformToken(AccessToken token, RealmModel realm, ClientModel client, UserModel user,
-                                         UserSessionModel session, ClientSessionModel clientSession) {
-        UserClaimSet claimSet = token.getUserClaimSet();
-        initClaims(claimSet, client, user);
+
+        }
         return token;
     }
 
@@ -350,9 +337,9 @@ public class TokenManager {
             return this;
         }
 
-        public AccessTokenResponseBuilder generateAccessToken(String scopeParam, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
+        public AccessTokenResponseBuilder generateAccessToken(KeycloakSession session, String scopeParam, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
             Set<RoleModel> requestedRoles = getAccess(scopeParam, client, user);
-            accessToken = createClientAccessToken(requestedRoles, realm, client, user, session, clientSession);
+            accessToken = createClientAccessToken(session, requestedRoles, realm, client, user, userSession, clientSession);
             return this;
         }
 
@@ -395,16 +382,11 @@ public class TokenManager {
             idToken.getUserClaimSet().setEmail(accessToken.getUserClaimSet().getEmail());
             idToken.getUserClaimSet().setEmailVerified(accessToken.getUserClaimSet().getEmailVerified());
             idToken.getUserClaimSet().setLocale(accessToken.getUserClaimSet().getLocale());
-            idToken.getUserClaimSet().setFormattedAddress(accessToken.getUserClaimSet().getFormattedAddress());
             idToken.getUserClaimSet().setAddress(accessToken.getUserClaimSet().getAddress());
-            idToken.getUserClaimSet().setStreetAddress(accessToken.getUserClaimSet().getStreetAddress());
-            idToken.getUserClaimSet().setLocality(accessToken.getUserClaimSet().getLocality());
-            idToken.getUserClaimSet().setRegion(accessToken.getUserClaimSet().getRegion());
-            idToken.getUserClaimSet().setPostalCode(accessToken.getUserClaimSet().getPostalCode());
-            idToken.getUserClaimSet().setCountry(accessToken.getUserClaimSet().getCountry());
             idToken.getUserClaimSet().setPhoneNumber(accessToken.getUserClaimSet().getPhoneNumber());
             idToken.getUserClaimSet().setPhoneNumberVerified(accessToken.getUserClaimSet().getPhoneNumberVerified());
             idToken.getUserClaimSet().setZoneinfo(accessToken.getUserClaimSet().getZoneinfo());
+            idToken.setOtherClaims(accessToken.getOtherClaims());
             return this;
         }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java b/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java
index 7a0e8a8..0829d67 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java
@@ -48,6 +48,8 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author pedroigor
@@ -130,9 +132,8 @@ public class UserInfoService {
             UserSessionModel userSession = session.sessions().getUserSession(realmModel, accessToken.getSessionState());
             ClientModel clientModel = realmModel.findClient(accessToken.getIssuedFor());
             UserModel userModel = userSession.getUser();
-            UserClaimSet userInfo = new UserClaimSet();
-
-            this.tokenManager.initClaims(userInfo, clientModel, userModel);
+            AccessToken userInfo = new AccessToken();
+            this.tokenManager.transformToken(session, userInfo, realmModel, clientModel, userModel, userSession, null);
 
             event
                 .detail(Details.USERNAME, userModel.getUsername())
@@ -141,7 +142,10 @@ public class UserInfoService {
                 .user(userModel)
                 .success();
 
-            return Cors.add(request, Response.ok(userInfo)).auth().allowedOrigins(accessToken).build();
+            Map<String, Object> claims = new HashMap<String, Object>();
+            claims.putAll(userInfo.getOtherClaims());
+            claims.put("sub", userModel.getId());
+            return Cors.add(request, Response.ok(claims)).auth().allowedOrigins(accessToken).build();
         } catch (Exception e) {
             throw new UnauthorizedException("Could not retrieve user info.", e);
         }
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index 361eb87..dc03c49 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -87,6 +87,11 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
                 }
             }
         }
+        for ( Map<String, ProviderFactory> factories : factoriesMap.values()) {
+            for (ProviderFactory factory : factories.values()) {
+                factory.postInit(this);
+            }
+        }
     }
 
     public KeycloakSession create() {
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 0f9da65..1815b88 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 +1,8 @@
-org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper
\ No newline at end of file
+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/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 7cea20d..30eeb3e 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -1,2 +1,3 @@
 org.keycloak.protocol.LoginProtocolSpi
+org.keycloak.protocol.ProtocolMapperSpi
 org.keycloak.exportimport.ApplicationImportSpi
\ No newline at end of file
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 08f5775..cfe16a8 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -139,7 +139,7 @@ public class AdapterTestStrategy extends ExternalResource {
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername("admin", adminRealm);
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
-            AccessToken token = tm.createClientAccessToken(TokenManager.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
+            AccessToken token = tm.createClientAccessToken(session, TokenManager.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
index 0ebb8fc..cce65bd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
@@ -87,7 +87,7 @@ public class RelativeUriAdapterTest {
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername("admin", adminRealm);
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "user", null, "form", false);
-            AccessToken token = tm.createClientAccessToken(tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
             adminToken = tm.encodeToken(adminRealm, token);
 
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
index 0d6c30f..68e3f13 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java
@@ -79,7 +79,7 @@ public class AdminAPITest {
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername("admin", adminRealm);
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
-            AccessToken token = tm.createClientAccessToken(tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);
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 82c0ec9..db33eb1 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
@@ -247,7 +247,7 @@ public class SamlBindingTest {
             TokenManager tm = new TokenManager();
             UserModel admin = session.users().getUserByUsername("admin", adminRealm);
             UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
-            AccessToken token = tm.createClientAccessToken(tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
+            AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null);
             return tm.encodeToken(adminRealm, token);
         } finally {
             keycloakRule.stopSession(session, true);