keycloak-aplcache

Merge pull request #976 from patriot1burke/master client

2/15/2015 10:50:56 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 f48615b..9434203 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
@@ -63,6 +63,14 @@
                 <constraints nullable="false"/>
             </column>
         </createTable>
+        <createTable tableName="CLIENT_PROTOCOL_CLAIM_MAPPING">
+            <column name="CLIENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="MAPPING_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
         <addColumn tableName="CLIENT">
             <column name="FRONTCHANNEL_LOGOUT" type="BOOLEAN" defaultValueBoolean="false"/>
         </addColumn>
@@ -78,6 +86,8 @@
         <addForeignKeyConstraint baseColumnNames="IDENTITY_PROVIDER_ID" baseTableName="IDENTITY_PROVIDER_CONFIG" constraintName="FKDC4897CF864C4E43" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
         <addForeignKeyConstraint baseColumnNames="INTERNAL_ID" baseTableName="CLIENT_ALLOWED_IDENTITY_PROVIDER" constraintName="FK_7CELWNIBJI49AVXSRTUF6XJ12" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
         <addUniqueConstraint columnNames="INTERNAL_ID,CLIENT_ID" constraintName="UK_7CAELWNIBJI49AVXSRTUF6XJ12" tableName="CLIENT_ALLOWED_IDENTITY_PROVIDER"/>
+        <addForeignKeyConstraint baseColumnNames="MAPPING_ID" baseTableName="CLIENT_PROTOCOL_CLAIM_MAPPING" constraintName="FK_CPCM" referencedColumnNames="ID" referencedTableName="PROTOCOL_CLAIM_MAPPING"/>
+        <addUniqueConstraint columnNames="CLIENT_ID,MAPPING_ID" constraintName="UK_CPCM" tableName="CLIENT_PROTOCOL_CLAIM_MAPPING"/>
         <addUniqueConstraint columnNames="PROVIDER_NONIMAL_ID" constraintName="UK_2DAELWNIBJI49AVXSRTUF6XJ33" tableName="IDENTITY_PROVIDER"/>
     </changeSet>
 </databaseChangeLog>
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 3369893..0e42a40 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -2,6 +2,7 @@ package org.keycloak.representations.idm;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -29,6 +30,7 @@ public class ApplicationRepresentation {
     protected Integer nodeReRegistrationTimeout;
     protected Map<String, Integer> registeredNodes;
     protected List<String> allowedIdentityProviders;
+    protected Set<String> protocolClaimMappings;
 
     public String getId() {
         return id;
@@ -197,4 +199,12 @@ public class ApplicationRepresentation {
     public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
+
+    public Set<String> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
+
+    public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
+        this.protocolClaimMappings = protocolClaimMappings;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
index 12ce2f4..dcb6ba8 100755
--- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
@@ -2,6 +2,7 @@ package org.keycloak.representations.idm;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -23,6 +24,7 @@ public class OAuthClientRepresentation {
     protected Boolean fullScopeAllowed;
     protected Boolean frontchannelLogout;
     protected List<String> allowedIdentityProviders;
+    protected Set<String> protocolClaimMappings;
 
 
     public String getId() {
@@ -144,4 +146,12 @@ public class OAuthClientRepresentation {
     public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
+
+    public Set<String> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
+
+    public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
+        this.protocolClaimMappings = protocolClaimMappings;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/ProtocolClaimMappingRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ProtocolClaimMappingRepresentation.java
new file mode 100755
index 0000000..3505035
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ProtocolClaimMappingRepresentation.java
@@ -0,0 +1,64 @@
+package org.keycloak.representations.idm;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProtocolClaimMappingRepresentation {
+    protected String id;
+    protected String protocolClaim;
+    protected String protocol;
+    protected String source;
+    protected String sourceAttribute;
+    protected boolean appliedByDefault;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getProtocolClaim() {
+        return protocolClaim;
+    }
+
+    public void setProtocolClaim(String protocolClaim) {
+        this.protocolClaim = protocolClaim;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getSourceAttribute() {
+        return sourceAttribute;
+    }
+
+    public void setSourceAttribute(String sourceAttribute) {
+        this.sourceAttribute = sourceAttribute;
+    }
+
+    public boolean isAppliedByDefault() {
+        return appliedByDefault;
+    }
+
+    public void setAppliedByDefault(boolean appliedByDefault) {
+        this.appliedByDefault = appliedByDefault;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+}
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 b33312d..4ee9c8b 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -64,6 +64,7 @@ public class RealmRepresentation {
     protected List<String> eventsListeners;
     private List<IdentityProviderRepresentation> identityProviders;
     private List<ClaimTypeRepresentation> claimTypes;
+    private List<ProtocolClaimMappingRepresentation> protocolClaimMappings;
     private Boolean identityFederationEnabled;
 
     public String getId() {
@@ -490,4 +491,12 @@ public class RealmRepresentation {
     public void setClaimTypes(List<ClaimTypeRepresentation> claimTypes) {
         this.claimTypes = claimTypes;
     }
+
+    public List<ProtocolClaimMappingRepresentation> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
+
+    public void setProtocolClaimMappings(List<ProtocolClaimMappingRepresentation> protocolClaimMappings) {
+        this.protocolClaimMappings = protocolClaimMappings;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/ClaimTypeModel.java b/model/api/src/main/java/org/keycloak/models/ClaimTypeModel.java
index c4bee9c..21c9234 100755
--- a/model/api/src/main/java/org/keycloak/models/ClaimTypeModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClaimTypeModel.java
@@ -12,10 +12,10 @@ public class ClaimTypeModel {
         STRING
     }
 
-    private final String id;
-    private final String name;
-    private final boolean builtIn;
-    private final ValueType type;
+    private String id;
+    private String name;
+    private boolean builtIn;
+    private ValueType type;
 
     public ClaimTypeModel(ClaimTypeModel copy) {
         this(copy.getId(), copy.getName(), copy.isBuiltIn(), copy.getType());
@@ -28,6 +28,9 @@ public class ClaimTypeModel {
         this.type = type;
     }
 
+    public ClaimTypeModel() {
+    }
+
     public String getId() {
         return id;
     }
@@ -44,6 +47,22 @@ public class ClaimTypeModel {
         return type;
     }
 
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setBuiltIn(boolean builtIn) {
+        this.builtIn = builtIn;
+    }
+
+    public void setType(ValueType type) {
+        this.type = type;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
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 5fa685f..3e3c53d 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -104,10 +104,7 @@ public interface ClientModel {
 
     boolean hasIdentityProvider(String providerId);
 
-    /*
-    Set<ProtocolClaimMapping> getClaimMappings();
-    ProtocolClaimMapping getClaimMapping(String protocolClaim);
-    ProtocolClaimMapping addClaimMapping(String assertion, String protocol, ClaimTypeModel claimType);
-    void removeClaimMapping(ProtocolClaimMapping mapping);
-    */
+    Set<ProtocolClaimMappingModel> getProtocolClaimMappings();
+    void addProtocolClaimMappings(Set<String> mappingIds);
+    void removeProtocolClaimMappings(Set<String> mappingIds);
 }
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 f6e428f..1cfbcfe 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
@@ -2,8 +2,10 @@ package org.keycloak.models.entities;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -28,6 +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>();
 
     public String getName() {
         return name;
@@ -148,4 +151,12 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     public void setAllowedIdentityProviders(List<String> allowedIdentityProviders) {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
+
+    public Set<String> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
+
+    public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
+        this.protocolClaimMappings = protocolClaimMappings;
+    }
 }
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 d41fc3d..881f102 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -225,14 +225,13 @@ public interface RealmModel extends RoleContainerModel {
     boolean isIdentityFederationEnabled();
 
     Set<ClaimTypeModel> getClaimTypes();
-    ClaimTypeModel addClaimType(String name, ClaimTypeModel.ValueType type, boolean builtIn);
+    ClaimTypeModel addClaimType(ClaimTypeModel model);
     void removeClaimType(ClaimTypeModel claimType);
     ClaimTypeModel getClaimType(String name);
     void updateClaimType(ClaimTypeModel claimType);
 
     Set<ProtocolClaimMappingModel> getProtocolClaimMappings();
-    ProtocolClaimMappingModel addProtocolClaimMapping(String protocolClaim, String protocol, String sourceAttribute,
-                                                      ProtocolClaimMappingModel.Source source, boolean appliedByDefault);
+    ProtocolClaimMappingModel addProtocolClaimMapping(ProtocolClaimMappingModel model);
     void removeProtocolClaimMapping(ProtocolClaimMappingModel mapping);
     void updateProtocolClaimMapping(ProtocolClaimMappingModel mapping);
     public ProtocolClaimMappingModel getProtocolClaimMappingById(String id);
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 72b62d2..6bff99e 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
@@ -8,6 +8,7 @@ import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
@@ -22,6 +23,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.OAuthClientRepresentation;
+import org.keycloak.representations.idm.ProtocolClaimMappingRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
@@ -155,6 +157,10 @@ public class ModelToRepresentation {
             rep.getClaimTypes().add(toRepresentation(claimType));
         }
 
+        for (ProtocolClaimMappingModel mapping : realm.getProtocolClaimMappings()) {
+            rep.getProtocolClaimMappings().add(toRepresentation(mapping));
+        }
+
         return rep;
     }
 
@@ -259,6 +265,12 @@ public class ModelToRepresentation {
             rep.setAllowedIdentityProviders(applicationModel.getAllowedIdentityProviders());
         }
 
+        if (!applicationModel.getProtocolClaimMappings().isEmpty()) {
+            Set<String> mappings = new HashSet<String>();
+            for (ProtocolClaimMappingModel model : applicationModel.getProtocolClaimMappings()) mappings.add(model.getId());
+            rep.setProtocolClaimMappings(mappings);
+        }
+
         return rep;
     }
 
@@ -288,6 +300,11 @@ public class ModelToRepresentation {
             rep.setAllowedIdentityProviders(model.getAllowedIdentityProviders());
         }
 
+        if (!model.getProtocolClaimMappings().isEmpty()) {
+            Set<String> mappings = new HashSet<String>();
+            for (ProtocolClaimMappingModel mappingMoel : model.getProtocolClaimMappings()) mappings.add(mappingMoel.getId());
+            rep.setProtocolClaimMappings(mappings);
+        }
         return rep;
     }
 
@@ -320,6 +337,17 @@ public class ModelToRepresentation {
         return providerRep;
     }
 
+    public static ProtocolClaimMappingRepresentation toRepresentation(ProtocolClaimMappingModel model) {
+        ProtocolClaimMappingRepresentation rep = new ProtocolClaimMappingRepresentation();
+        rep.setId(model.getId());
+        rep.setProtocol(model.getProtocol());
+        rep.setProtocolClaim(model.getProtocolClaim());
+        rep.setSourceAttribute(model.getSourceAttribute());
+        rep.setSource(model.getSource().name());
+        rep.setAppliedByDefault(model.isAppliedByDefault());
+        return rep;
+    }
+
     public static ClaimTypeRepresentation toRepresentation(ClaimTypeModel claimType) {
         ClaimTypeRepresentation rep = new ClaimTypeRepresentation();
         rep.setId(claimType.getId());
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 8a0fc26..a4b87ba 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
@@ -6,12 +6,14 @@ import org.keycloak.enums.SslRequired;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.BrowserSecurityHeaders;
 import org.keycloak.models.ClaimMask;
+import org.keycloak.models.ClaimTypeModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.OAuthClientModel;
 import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
@@ -20,10 +22,12 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.ClaimRepresentation;
+import org.keycloak.representations.idm.ClaimTypeRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.OAuthClientRepresentation;
+import org.keycloak.representations.idm.ProtocolClaimMappingRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.representations.idm.ScopeMappingRepresentation;
@@ -113,6 +117,8 @@ public class RepresentationToModel {
         if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
 
         importIdentityProviders(rep, newRealm);
+        importClaimTypes(rep, newRealm);
+        importProtocolClaimMappings(rep, newRealm);
 
         if (rep.getApplications() != null) {
             Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
@@ -454,6 +460,10 @@ public class RepresentationToModel {
             applicationModel.setAllowedClaimsMask(ClaimMask.ALL);
         }
 
+        if (resourceRep.getProtocolClaimMappings() != null) {
+            applicationModel.addProtocolClaimMappings(resourceRep.getProtocolClaimMappings());
+        }
+
         return applicationModel;
     }
 
@@ -626,6 +636,11 @@ public class RepresentationToModel {
         if (rep.getAllowedIdentityProviders() != null) {
             model.updateAllowedIdentityProviders(rep.getAllowedIdentityProviders());
         }
+
+        if (rep.getProtocolClaimMappings() != null) {
+            model.addProtocolClaimMappings(rep.getProtocolClaimMappings());
+        }
+
     }
 
     // Scope mappings
@@ -749,6 +764,21 @@ public class RepresentationToModel {
             }
         }
     }
+    private static void importClaimTypes(RealmRepresentation rep, RealmModel newRealm) {
+        if (rep.getClaimTypes() != null) {
+            for (ClaimTypeRepresentation representation : rep.getClaimTypes()) {
+                newRealm.addClaimType(toModel(representation));
+            }
+        }
+    }
+
+    private static void importProtocolClaimMappings(RealmRepresentation rep, RealmModel newRealm) {
+        if (rep.getProtocolClaimMappings() != null) {
+            for (ProtocolClaimMappingRepresentation representation : rep.getProtocolClaimMappings()) {
+                newRealm.addProtocolClaimMapping(toModel(representation));
+            }
+        }
+    }
 
     public static IdentityProviderModel toModel(IdentityProviderRepresentation representation) {
         IdentityProviderModel identityProviderModel = new IdentityProviderModel();
@@ -765,4 +795,24 @@ public class RepresentationToModel {
 
         return identityProviderModel;
     }
+
+    public static ClaimTypeModel toModel(ClaimTypeRepresentation rep) {
+        ClaimTypeModel model = new ClaimTypeModel();
+        model.setId(rep.getId());
+        model.setType(ClaimTypeModel.ValueType.valueOf(rep.getType()));
+        model.setBuiltIn(rep.isBuiltIn());
+        model.setName(rep.getName());
+        return model;
+    }
+
+    public static ProtocolClaimMappingModel toModel(ProtocolClaimMappingRepresentation rep) {
+        ProtocolClaimMappingModel model = new ProtocolClaimMappingModel();
+        model.setId(rep.getId());
+        model.setAppliedByDefault(rep.isAppliedByDefault());
+        model.setSource(ProtocolClaimMappingModel.Source.valueOf(rep.getSource()));
+        model.setSourceAttribute(rep.getSourceAttribute());
+        model.setProtocol(rep.getProtocol());
+        model.setProtocolClaim(rep.getProtocolClaim());
+        return model;
+    }
 }
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 11696c5..9055fa7 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
@@ -1,6 +1,7 @@
 package org.keycloak.models.cache;
 
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
@@ -278,4 +279,23 @@ public abstract class ClientAdapter implements ClientModel {
         if (updatedClient != null) return updatedClient.hasIdentityProvider(providerId);
         return cachedClient.hasIdentityProvider(providerId);
     }
+
+    @Override
+    public Set<ProtocolClaimMappingModel> getProtocolClaimMappings() {
+        if (updatedClient != null) return updatedClient.getProtocolClaimMappings();
+        return cachedClient.getProtocolClaimMappings();    }
+
+    @Override
+    public void addProtocolClaimMappings(Set<String> mappingIds) {
+        getDelegateForUpdate();
+        updatedClient.addProtocolClaimMappings(mappingIds);
+
+    }
+
+    @Override
+    public void removeProtocolClaimMappings(Set<String> mappingIds) {
+        getDelegateForUpdate();
+        updatedClient.removeProtocolClaimMappings(mappingIds);
+
+    }
 }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index ac7341d..f6c7096 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -1,6 +1,7 @@
 package org.keycloak.models.cache.entities;
 
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RoleModel;
@@ -35,6 +36,7 @@ public class CachedClient {
     protected Set<String> scope = new HashSet<String>();
     protected Set<String> webOrigins = new HashSet<String>();
     private List<String> allowedIdentityProviders = new ArrayList<String>();
+    private Set<ProtocolClaimMappingModel> protocolClaimMappings = new HashSet<ProtocolClaimMappingModel>();
 
     public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
         id = model.getId();
@@ -56,6 +58,7 @@ public class CachedClient {
             scope.add(role.getId());
         }
         this.allowedIdentityProviders = model.getAllowedIdentityProviders();
+        protocolClaimMappings.addAll(model.getProtocolClaimMappings());
     }
 
     public String getId() {
@@ -122,10 +125,6 @@ public class CachedClient {
         return frontchannelLogout;
     }
 
-    public void setFrontchannelLogout(boolean frontchannelLogout) {
-        this.frontchannelLogout = frontchannelLogout;
-    }
-
     public List<String> getAllowedIdentityProviders() {
         return this.allowedIdentityProviders;
     }
@@ -137,4 +136,8 @@ public class CachedClient {
 
         return this.allowedIdentityProviders.contains(providerId);
     }
+
+    public Set<ProtocolClaimMappingModel> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
 }
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 573ba68..8c83451 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
@@ -857,9 +857,9 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public ClaimTypeModel addClaimType(String name, ClaimTypeModel.ValueType type, boolean builtIn) {
+    public ClaimTypeModel addClaimType(ClaimTypeModel claimType) {
         getDelegateForUpdate();
-        return updated.addClaimType(name, type, builtIn);
+        return updated.addClaimType(claimType);
     }
 
     @Override
@@ -892,9 +892,9 @@ public class RealmAdapter implements RealmModel {
      }
 
     @Override
-    public ProtocolClaimMappingModel addProtocolClaimMapping(String protocolClaim, String protocol, String sourceAttribute, ProtocolClaimMappingModel.Source source, boolean appliedByDefault) {
+    public ProtocolClaimMappingModel addProtocolClaimMapping(ProtocolClaimMappingModel model) {
         getDelegateForUpdate();
-        return updated.addProtocolClaimMapping(protocolClaim, protocol, sourceAttribute, source, appliedByDefault);
+        return updated.addProtocolClaimMapping(model);
     }
 
     @Override
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 e8fb943..8410cfc 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
@@ -1,11 +1,13 @@
 package org.keycloak.models.jpa;
 
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 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.ProtocolClaimMappingEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 
@@ -15,6 +17,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -352,4 +355,53 @@ public abstract class ClientAdapter implements ClientModel {
         }
         return false;
     }
+
+    @Override
+    public Set<ProtocolClaimMappingModel> getProtocolClaimMappings() {
+        Set<ProtocolClaimMappingModel> mappings = new HashSet<ProtocolClaimMappingModel>();
+        for (ProtocolClaimMappingEntity entity : this.entity.getProtocolClaimMappings()) {
+            ProtocolClaimMappingModel mapping = new ProtocolClaimMappingModel();
+            mapping.setId(entity.getId());
+            mapping.setProtocol(entity.getProtocol());
+            mapping.setProtocolClaim(entity.getProtocolClaim());
+            mapping.setAppliedByDefault(entity.isAppliedByDefault());
+            mapping.setSource(ProtocolClaimMappingModel.Source.valueOf(entity.getSource()));
+            mapping.setSourceAttribute(entity.getSourceAttribute());
+            mappings.add(mapping);
+        }
+        return mappings;
+    }
+
+    @Override
+    public void addProtocolClaimMappings(Set<String> mappings) {
+        Collection<ProtocolClaimMappingEntity> entities = entity.getProtocolClaimMappings();
+        Set<String> already = new HashSet<String>();
+        for (ProtocolClaimMappingEntity rel : entities) {
+            already.add(rel.getId());
+        }
+        for (String providerId : mappings) {
+            if (!already.contains(providerId)) {
+                ProtocolClaimMappingEntity mapping = em.find(ProtocolClaimMappingEntity.class, providerId);
+                if (mapping != null) {
+                    entities.add(mapping);
+                }
+            }
+        }
+        em.flush();
+    }
+
+    @Override
+    public void removeProtocolClaimMappings(Set<String> mappings) {
+        Collection<ProtocolClaimMappingEntity> entities = entity.getProtocolClaimMappings();
+        List<ProtocolClaimMappingEntity> remove = new LinkedList<ProtocolClaimMappingEntity>();
+        for (ProtocolClaimMappingEntity rel : entities) {
+            if (mappings.contains(rel.getId())) remove.add(rel);
+        }
+        for (ProtocolClaimMappingEntity entity : remove) {
+            entities.remove(entity);
+        }
+        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 ac43656..36e5888 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
@@ -1,5 +1,6 @@
 package org.keycloak.models.jpa.entities;
 
+import javax.persistence.CascadeType;
 import javax.persistence.CollectionTable;
 import javax.persistence.Column;
 import javax.persistence.ElementCollection;
@@ -76,6 +77,10 @@ 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})
+    @JoinTable(name="CLIENT_PROTOCOL_CLAIM_MAPPING", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="MAPPING_ID")})
+    Collection<ProtocolClaimMappingEntity> protocolClaimMappings = new ArrayList<ProtocolClaimMappingEntity>();
+
     public RealmEntity getRealm() {
         return realm;
     }
@@ -195,4 +200,12 @@ public abstract class ClientEntity {
     public void setAllowedIdentityProviders(Collection<IdentityProviderEntity> allowedIdentityProviders) {
         this.allowedIdentityProviders = allowedIdentityProviders;
     }
+
+    public Collection<ProtocolClaimMappingEntity> getProtocolClaimMappings() {
+        return protocolClaimMappings;
+    }
+
+    public void setProtocolClaimMappings(Collection<ProtocolClaimMappingEntity> protocolClaimMappings) {
+        this.protocolClaimMappings = protocolClaimMappings;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
index b1a9f10..cf85fad 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
@@ -138,4 +138,6 @@ public class IdentityProviderEntity {
     public void setConfig(Map<String, String> config) {
         this.config = config;
     }
+
+
 }
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolClaimMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolClaimMappingEntity.java
index 7a429dc..c3fb6c0 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolClaimMappingEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ProtocolClaimMappingEntity.java
@@ -95,4 +95,21 @@ public class ProtocolClaimMappingEntity {
     public void setRealm(RealmEntity realm) {
         this.realm = realm;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ProtocolClaimMappingEntity that = (ProtocolClaimMappingEntity) o;
+
+        if (!id.equals(that.id)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
 }
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 c62a9c9..755fb6b 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
@@ -93,7 +93,7 @@ public class JpaRealmProvider implements RealmProvider {
             adapter.removeOAuthClient(oauth.getId());
         }
 
-       em.remove(realm);
+        em.remove(realm);
         return true;
     }
 
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 bbc885e..af9d916 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
@@ -1206,15 +1206,16 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public ClaimTypeModel addClaimType(String name, ClaimTypeModel.ValueType type, boolean builtIn) {
+    public ClaimTypeModel addClaimType(ClaimTypeModel model) {
+        String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
         ClaimTypeEntity claimEntity = new ClaimTypeEntity();
-        claimEntity.setId(KeycloakModelUtils.generateId());
-        claimEntity.setType(type.name());
-        claimEntity.setBuiltIn(builtIn);
+        claimEntity.setId(id);
+        claimEntity.setType(model.getType().name());
+        claimEntity.setBuiltIn(model.isBuiltIn());
         claimEntity.setRealm(realm);
         em.persist(claimEntity);
         realm.getClaimTypes().add(claimEntity);
-        return new ClaimTypeModel(claimEntity.getId(), name, builtIn, type);
+        return new ClaimTypeModel(claimEntity.getId(), model.getName(), model.isBuiltIn(), model.getType());
     }
 
     protected ClaimTypeEntity getClaimTypeEntity(ClaimTypeModel claim) {
@@ -1272,14 +1273,15 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public ProtocolClaimMappingModel addProtocolClaimMapping(String protocolClaim, String protocol, String sourceAttribute, ProtocolClaimMappingModel.Source source, boolean appliedByDefault) {
+    public ProtocolClaimMappingModel addProtocolClaimMapping(ProtocolClaimMappingModel model) {
+        String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
         ProtocolClaimMappingEntity entity = new ProtocolClaimMappingEntity();
-        entity.setId(KeycloakModelUtils.generateId());
-        entity.setSourceAttribute(sourceAttribute);
-        entity.setProtocol(protocol);
-        entity.setProtocolClaim(protocolClaim);
-        entity.setSource(source.name());
-        entity.setAppliedByDefault(appliedByDefault);
+        entity.setId(id);
+        entity.setSourceAttribute(model.getSourceAttribute());
+        entity.setProtocol(model.getProtocol());
+        entity.setProtocolClaim(model.getProtocolClaim());
+        entity.setSource(model.getSource().name());
+        entity.setAppliedByDefault(model.isAppliedByDefault());
         entity.setRealm(realm);
         em.persist(entity);
         ProtocolClaimMappingModel mapping = new ProtocolClaimMappingModel();
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 d3f93db..11ecd61 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
@@ -4,6 +4,7 @@ import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolClaimMappingModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RoleModel;
@@ -292,6 +293,29 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
     }
 
     @Override
+    public Set<ProtocolClaimMappingModel> getProtocolClaimMappings() {
+        Set<ProtocolClaimMappingModel> result = new HashSet<ProtocolClaimMappingModel>();
+        for (String id : getMongoEntityAsClient().getProtocolClaimMappings()) {
+            ProtocolClaimMappingModel model = getRealm().getProtocolClaimMappingById(id);
+            if (model != null) result.add(model);
+        }
+        return result;
+    }
+
+    @Override
+    public void addProtocolClaimMappings(Set<String> mappingIds) {
+        getMongoEntityAsClient().getProtocolClaimMappings().addAll(mappingIds);
+        updateMongoEntity();
+
+    }
+
+    @Override
+    public void removeProtocolClaimMappings(Set<String> mappingIds) {
+        getMongoEntityAsClient().getProtocolClaimMappings().removeAll(mappingIds);
+        updateMongoEntity();
+    }
+
+    @Override
     public void updateAllowedIdentityProviders(List<String> identityProviders) {
         List<String> providerIds = new ArrayList<String>();
         for (String providerId : identityProviders) {
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 f24cc02..da4766c 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
@@ -802,14 +802,15 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public ProtocolClaimMappingModel addProtocolClaimMapping(String protocolClaim, String protocol, String sourceAttribute, ProtocolClaimMappingModel.Source source, boolean appliedByDefault) {
+    public ProtocolClaimMappingModel addProtocolClaimMapping(ProtocolClaimMappingModel model) {
         ProtocolClaimMappingEntity entity = new ProtocolClaimMappingEntity();
-        entity.setId(KeycloakModelUtils.generateId());
-        entity.setSourceAttribute(sourceAttribute);
-        entity.setProtocol(protocol);
-        entity.setProtocolClaim(protocolClaim);
-        entity.setSource(source);
-        entity.setAppliedByDefault(appliedByDefault);
+        if (model.getId() != null) entity.setId(model.getId());
+        else entity.setId(KeycloakModelUtils.generateId());
+        entity.setSourceAttribute(model.getSourceAttribute());
+        entity.setProtocol(model.getProtocol());
+        entity.setProtocolClaim(model.getProtocolClaim());
+        entity.setSource(model.getSource());
+        entity.setAppliedByDefault(model.isAppliedByDefault());
         realm.getClaimMappings().add(entity);
         updateRealm();
         ProtocolClaimMappingModel mapping = new ProtocolClaimMappingModel();
@@ -881,13 +882,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public ClaimTypeModel addClaimType(String name, ClaimTypeModel.ValueType type, boolean builtIn) {
-        ClaimTypeModel claim = new ClaimTypeModel(KeycloakModelUtils.generateId(), name, builtIn, type);
+    public ClaimTypeModel addClaimType(ClaimTypeModel model) {
+        String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
+        ClaimTypeModel claim = new ClaimTypeModel(id, model.getName(), model.isBuiltIn(), model.getType());
         ClaimTypeEntity entity = new ClaimTypeEntity();
         entity.setId(claim.getId());
-        entity.setType(type);
-        entity.setBuiltIn(builtIn);
-        entity.setName(name);
+        entity.setType(model.getType());
+        entity.setBuiltIn(model.isBuiltIn());
+        entity.setName(model.getName());
         realm.getClaimTypes().add(entity);
         updateRealm();
         return claim;