diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.RC1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.RC1.xml new file mode 100755 index 0000000000..7c506009c5 --- /dev/null +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.2.0.RC1.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml old mode 100644 new mode 100755 index 3d8b67189f..42a702aef2 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml @@ -4,4 +4,5 @@ + diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java index f3355e01d8..2b942434d4 100755 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java @@ -12,7 +12,7 @@ public interface JpaUpdaterProvider extends Provider { public String FIRST_VERSION = "1.0.0.Final"; - public String LAST_VERSION = "1.2.0.Beta1"; + public String LAST_VERSION = "1.2.0.RC1"; public String getCurrentVersionSql(); diff --git a/connections/jpa/src/main/resources/META-INF/persistence.xml b/connections/jpa/src/main/resources/META-INF/persistence.xml index 8baedb3ddf..aca54ef9c2 100755 --- a/connections/jpa/src/main/resources/META-INF/persistence.xml +++ b/connections/jpa/src/main/resources/META-INF/persistence.xml @@ -18,6 +18,7 @@ org.keycloak.models.jpa.entities.UserRoleMappingEntity org.keycloak.models.jpa.entities.ScopeMappingEntity org.keycloak.models.jpa.entities.IdentityProviderEntity + org.keycloak.models.jpa.entities.IdentityProviderMapperEntity org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity org.keycloak.models.jpa.entities.ProtocolMapperEntity diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java new file mode 100755 index 0000000000..982f102a97 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderMapperModel.java @@ -0,0 +1,75 @@ +package org.keycloak.models; + +import java.util.Map; + +/** + * Specifies a mapping from broker login to user data. + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class IdentityProviderMapperModel { + protected String id; + protected String name; + protected String identityProviderAlias; + protected String identityProviderMapper; + protected Map config; + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIdentityProviderAlias() { + return identityProviderAlias; + } + + public void setIdentityProviderAlias(String identityProviderAlias) { + this.identityProviderAlias = identityProviderAlias; + } + + public String getIdentityProviderMapper() { + return identityProviderMapper; + } + + public void setIdentityProviderMapper(String identityProviderMapper) { + this.identityProviderMapper = identityProviderMapper; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IdentityProviderMapperModel that = (IdentityProviderMapperModel) o; + + if (!id.equals(that.id)) return false; + + return true; + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java b/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java index 34294751aa..c72d5e10e0 100755 --- a/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java +++ b/model/api/src/main/java/org/keycloak/models/ProtocolMapperModel.java @@ -3,10 +3,7 @@ package org.keycloak.models; import java.util.Map; /** - * Specifies a mapping from user data to a protocol claim assertion. If protocolMapper is set, this points - * to a @Provider that will perform the mapping. If you have this set, then no other attributes of this class need to be set. - * If you don't have it set, then this is a simple one to one mapping between the protocolClaim and the sourceAttribute. - * SourceAttribute is the user data, protocolClaim is the name of the data you want to store in the protocols document or token. + * Specifies a mapping from user data to a protocol claim assertion. * * @author Bill Burke * @version $Revision: 1 $ 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 f0c5ebfbd9..81d53a669e 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -189,6 +189,14 @@ public interface RealmModel extends RoleContainerModel { void addIdentityProvider(IdentityProviderModel identityProvider); void removeIdentityProviderByAlias(String alias); void updateIdentityProvider(IdentityProviderModel identityProvider); + Set getIdentityProviderMappers(); + Set getIdentityProviderMappersByAlias(String brokerAlias); + IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model); + void removeIdentityProviderMapper(IdentityProviderMapperModel mapping); + void updateIdentityProviderMapper(IdentityProviderMapperModel mapping); + public IdentityProviderMapperModel getIdentityProviderMapperById(String id); + public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name); + List getUserFederationProviders(); diff --git a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderMapperEntity.java b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderMapperEntity.java new file mode 100755 index 0000000000..edc50615bc --- /dev/null +++ b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderMapperEntity.java @@ -0,0 +1,55 @@ +package org.keycloak.models.entities; + +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class IdentityProviderMapperEntity { + protected String id; + protected String name; + protected String identityProviderAlias; + protected String identityProviderMapper; + protected Map config; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } + + public String getIdentityProviderAlias() { + return identityProviderAlias; + } + + public void setIdentityProviderAlias(String identityProviderAlias) { + this.identityProviderAlias = identityProviderAlias; + } + + public String getIdentityProviderMapper() { + return identityProviderMapper; + } + + public void setIdentityProviderMapper(String identityProviderMapper) { + this.identityProviderMapper = identityProviderMapper; + } +} diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java index 50d2892c9e..bba27c887c 100755 --- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java @@ -69,6 +69,8 @@ public class RealmEntity extends AbstractIdentifiableEntity { private boolean internationalizationEnabled; private List supportedLocales = new ArrayList(); private String defaultLocale; + private List identityProviderMappers = new ArrayList(); + public String getName() { return name; @@ -444,6 +446,14 @@ public class RealmEntity extends AbstractIdentifiableEntity { public void setDefaultLocale(String defaultLocale) { this.defaultLocale = defaultLocale; } + + public List getIdentityProviderMappers() { + return identityProviderMappers; + } + + public void setIdentityProviderMappers(List identityProviderMappers) { + this.identityProviderMappers = identityProviderMappers; + } } diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java index 448871b452..a1490ed9e6 100755 --- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java +++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java @@ -19,6 +19,7 @@ package org.keycloak.models.file.adapter; import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.OAuthClientModel; @@ -27,6 +28,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationProviderModel; +import org.keycloak.models.entities.IdentityProviderMapperEntity; import org.keycloak.models.entities.RequiredCredentialEntity; import org.keycloak.models.entities.UserFederationProviderEntity; import org.keycloak.models.utils.KeycloakModelUtils; @@ -1132,4 +1134,131 @@ public class RealmAdapter implements RealmModel { public int hashCode() { return getId().hashCode(); } + + @Override + public Set getIdentityProviderMappers() { + Set mappings = new HashSet<>(); + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + @Override + public Set getIdentityProviderMappersByAlias(String brokerAlias) { + Set mappings = new HashSet<>(); + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (!entity.getIdentityProviderAlias().equals(brokerAlias)) { + continue; + } + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + + @Override + public IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model) { + if (getIdentityProviderMapperByName(model.getIdentityProviderAlias(), model.getIdentityProviderMapper()) != null) { + throw new RuntimeException("protocol mapper name must be unique per protocol"); + } + String id = KeycloakModelUtils.generateId(); + IdentityProviderMapperEntity entity = new IdentityProviderMapperEntity(); + entity.setId(id); + entity.setName(model.getName()); + entity.setIdentityProviderAlias(model.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(model.getIdentityProviderMapper()); + entity.setConfig(model.getConfig()); + + this.realm.getIdentityProviderMappers().add(entity); + return entityToModel(entity); + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntity(String id) { + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (entity.getId().equals(id)) { + return entity; + } + } + return null; + + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntityByName(String alias, String name) { + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (entity.getIdentityProviderAlias().equals(alias) && entity.getName().equals(name)) { + return entity; + } + } + return null; + + } + + @Override + public void removeIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity toDelete = getIdentityProviderMapperEntity(mapping.getId()); + if (toDelete != null) { + this.realm.getIdentityProviderMappers().remove(toDelete); + } + + } + + @Override + public void updateIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(mapping.getId()); + entity.setIdentityProviderAlias(mapping.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(mapping.getIdentityProviderMapper()); + if (entity.getConfig() == null) { + entity.setConfig(mapping.getConfig()); + } else { + entity.getConfig().clear(); + entity.getConfig().putAll(mapping.getConfig()); + } + + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperById(String id) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(id); + if (entity == null) return null; + return entityToModel(entity); + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperByName(String alias, String name) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntityByName(alias, name); + if (entity == null) return null; + return entityToModel(entity); + } + + protected IdentityProviderMapperModel entityToModel(IdentityProviderMapperEntity entity) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) config.putAll(entity.getConfig()); + mapping.setConfig(config); + return mapping; + } + } 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 0cafa72535..ef18caa6df 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 @@ -5,6 +5,7 @@ import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClaimTypeModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.PasswordPolicy; @@ -14,6 +15,7 @@ import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.cache.entities.CachedRealm; +import org.keycloak.models.entities.IdentityProviderMapperEntity; import org.keycloak.models.utils.KeycloakModelUtils; import java.security.Key; @@ -935,4 +937,67 @@ public class RealmAdapter implements RealmModel { public void setDefaultLocale(String locale) { updated.setDefaultLocale(locale); } + + @Override + public Set getIdentityProviderMappers() { + if (updated != null) return updated.getIdentityProviderMappers(); + Set mappings = new HashSet<>(); + for (List models : cached.getIdentityProviderMappers().values()) { + for (IdentityProviderMapperModel model : models) { + mappings.add(model); + } + } + return mappings; + } + + @Override + public Set getIdentityProviderMappersByAlias(String brokerAlias) { + if (updated != null) return updated.getIdentityProviderMappersByAlias(brokerAlias); + Set mappings = new HashSet<>(); + List list = cached.getIdentityProviderMappers().getList(brokerAlias); + for (IdentityProviderMapperModel entity : list) { + mappings.add(entity); + } + return mappings; + } + + @Override + public IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model) { + getDelegateForUpdate(); + return updated.addIdentityProviderMapper(model); + } + + @Override + public void removeIdentityProviderMapper(IdentityProviderMapperModel mapping) { + getDelegateForUpdate(); + updated.removeIdentityProviderMapper(mapping); + } + + @Override + public void updateIdentityProviderMapper(IdentityProviderMapperModel mapping) { + getDelegateForUpdate(); + updated.updateIdentityProviderMapper(mapping); + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperById(String id) { + if (updated != null) return updated.getIdentityProviderMapperById(id); + for (List models : cached.getIdentityProviderMappers().values()) { + for (IdentityProviderMapperModel model : models) { + if (model.getId().equals(id)) return model; + } + } + return null; + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperByName(String alias, String name) { + if (updated != null) return updated.getIdentityProviderMapperByName(alias, name); + List models = cached.getIdentityProviderMappers().getList(alias); + if (models == null) return null; + for (IdentityProviderMapperModel model : models) { + if (model.getName().equals(name)) return model; + } + return null; + } } diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java index 5bbe90565b..a88cf47f3f 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java @@ -2,17 +2,17 @@ package org.keycloak.models.cache.entities; import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; -import org.keycloak.models.ClaimTypeModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.PasswordPolicy; -import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.cache.RealmCache; +import org.keycloak.util.MultivaluedHashMap; import java.util.ArrayList; import java.util.HashMap; @@ -87,6 +87,7 @@ public class CachedRealm { private boolean internationalizationEnabled; private Set supportedLocales = new HashSet(); private String defaultLocale; + private MultivaluedHashMap identityProviderMappers = new MultivaluedHashMap<>(); public CachedRealm() { } @@ -135,12 +136,18 @@ public class CachedRealm { requiredCredentials = model.getRequiredCredentials(); userFederationProviders = model.getUserFederationProviders(); - this.identityProviders = new ArrayList(); + this.identityProviders = new ArrayList<>(); for (IdentityProviderModel identityProviderModel : model.getIdentityProviders()) { this.identityProviders.add(new IdentityProviderModel(identityProviderModel)); } + for (IdentityProviderMapperModel mapper : model.getIdentityProviderMappers()) { + identityProviderMappers.add(mapper.getIdentityProviderAlias(), mapper); + } + + + smtpConfig.putAll(model.getSmtpConfig()); browserSecurityHeaders.putAll(model.getBrowserSecurityHeaders()); @@ -378,4 +385,8 @@ public class CachedRealm { public String getDefaultLocale() { return defaultLocale; } + + public MultivaluedHashMap getIdentityProviderMappers() { + return identityProviderMappers; + } } 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 9f6245abcf..1f45e48371 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 @@ -3,16 +3,19 @@ package org.keycloak.models.jpa; import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.PasswordPolicy; +import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.jpa.entities.ApplicationEntity; import org.keycloak.models.jpa.entities.IdentityProviderEntity; +import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity; import org.keycloak.models.jpa.entities.OAuthClientEntity; import org.keycloak.models.jpa.entities.RealmAttributeEntity; import org.keycloak.models.jpa.entities.RealmEntity; @@ -1278,4 +1281,135 @@ public class RealmAdapter implements RealmModel { realm.setDefaultLocale(locale); em.flush(); } + + @Override + public Set getIdentityProviderMappers() { + Set mappings = new HashSet(); + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + + @Override + public Set getIdentityProviderMappersByAlias(String brokerAlias) { + Set mappings = new HashSet(); + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (!entity.getIdentityProviderAlias().equals(brokerAlias)) { + continue; + } + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + + @Override + public IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model) { + if (getIdentityProviderMapperByName(model.getIdentityProviderAlias(), model.getIdentityProviderMapper()) != null) { + throw new RuntimeException("protocol mapper name must be unique per protocol"); + } + String id = KeycloakModelUtils.generateId(); + IdentityProviderMapperEntity entity = new IdentityProviderMapperEntity(); + entity.setId(id); + entity.setName(model.getName()); + entity.setIdentityProviderAlias(model.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(model.getIdentityProviderMapper()); + entity.setRealm(this.realm); + entity.setConfig(model.getConfig()); + + em.persist(entity); + this.realm.getIdentityProviderMappers().add(entity); + return entityToModel(entity); + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntity(String id) { + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (entity.getId().equals(id)) { + return entity; + } + } + return null; + + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntityByName(String alias, String name) { + for (IdentityProviderMapperEntity entity : this.realm.getIdentityProviderMappers()) { + if (entity.getIdentityProviderAlias().equals(alias) && entity.getName().equals(name)) { + return entity; + } + } + return null; + + } + + @Override + public void removeIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity toDelete = getIdentityProviderMapperEntity(mapping.getId()); + if (toDelete != null) { + this.realm.getIdentityProviderMappers().remove(toDelete); + em.remove(toDelete); + } + + } + + @Override + public void updateIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(mapping.getId()); + entity.setIdentityProviderAlias(mapping.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(mapping.getIdentityProviderMapper()); + if (entity.getConfig() == null) { + entity.setConfig(mapping.getConfig()); + } else { + entity.getConfig().clear(); + entity.getConfig().putAll(mapping.getConfig()); + } + em.flush(); + + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperById(String id) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(id); + if (entity == null) return null; + return entityToModel(entity); + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperByName(String alias, String name) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntityByName(alias, name); + if (entity == null) return null; + return entityToModel(entity); + } + + protected IdentityProviderMapperModel entityToModel(IdentityProviderMapperEntity entity) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) config.putAll(entity.getConfig()); + mapping.setConfig(config); + return mapping; + } } \ No newline at end of file diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderMapperEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderMapperEntity.java new file mode 100755 index 0000000000..feaa8b9236 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderMapperEntity.java @@ -0,0 +1,109 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@Table(name="IDENTITY_PROVIDER_MAPPER") +public class IdentityProviderMapperEntity { + + @Id + @Column(name="ID", length = 36) + protected String id; + + @Column(name="NAME") + protected String name; + + @Column(name = "IDP_ALIAS") + protected String identityProviderAlias; + @Column(name = "IDP_MAPPER_NAME") + protected String identityProviderMapper; + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable(name="IDP_MAPPER_CONFIG", joinColumns={ @JoinColumn(name="IDP_MAPPER_ID") }) + private Map config; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "REALM_ID") + private RealmEntity realm; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIdentityProviderAlias() { + return identityProviderAlias; + } + + public void setIdentityProviderAlias(String identityProviderAlias) { + this.identityProviderAlias = identityProviderAlias; + } + + public String getIdentityProviderMapper() { + return identityProviderMapper; + } + + public void setIdentityProviderMapper(String identityProviderMapper) { + this.identityProviderMapper = identityProviderMapper; + } + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IdentityProviderMapperEntity that = (IdentityProviderMapperEntity) 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/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index b2a851ab1e..a656f761ce 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 @@ -142,6 +142,11 @@ public class RealmEntity { @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") protected List identityProviders = new ArrayList(); + @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") + Collection identityProviderMappers = new ArrayList(); + + + @Column(name="INTERNATIONALIZATION_ENABLED") protected boolean internationalizationEnabled; @@ -500,5 +505,13 @@ public class RealmEntity { public void setDefaultLocale(String defaultLocale) { this.defaultLocale = defaultLocale; } + + public Collection getIdentityProviderMappers() { + return identityProviderMappers; + } + + public void setIdentityProviderMappers(Collection identityProviderMappers) { + this.identityProviderMappers = identityProviderMappers; + } } 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 cff2ae58be..eac95832a4 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 @@ -6,6 +6,7 @@ import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.enums.SslRequired; import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.OAuthClientModel; @@ -16,6 +17,7 @@ import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.entities.IdentityProviderEntity; +import org.keycloak.models.entities.IdentityProviderMapperEntity; import org.keycloak.models.entities.RequiredCredentialEntity; import org.keycloak.models.entities.UserFederationProviderEntity; import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity; @@ -1133,4 +1135,134 @@ public class RealmAdapter extends AbstractMongoAdapter impleme realm.setDefaultLocale(locale); updateRealm(); } + + @Override + public Set getIdentityProviderMappers() { + Set mappings = new HashSet(); + for (IdentityProviderMapperEntity entity : getMongoEntity().getIdentityProviderMappers()) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + + @Override + public Set getIdentityProviderMappersByAlias(String brokerAlias) { + Set mappings = new HashSet(); + for (IdentityProviderMapperEntity entity : getMongoEntity().getIdentityProviderMappers()) { + if (!entity.getIdentityProviderAlias().equals(brokerAlias)) { + continue; + } + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) { + config.putAll(entity.getConfig()); + } + mapping.setConfig(config); + mappings.add(mapping); + } + return mappings; + } + + @Override + public IdentityProviderMapperModel addIdentityProviderMapper(IdentityProviderMapperModel model) { + if (getIdentityProviderMapperByName(model.getIdentityProviderAlias(), model.getIdentityProviderMapper()) != null) { + throw new RuntimeException("protocol mapper name must be unique per protocol"); + } + String id = KeycloakModelUtils.generateId(); + IdentityProviderMapperEntity entity = new IdentityProviderMapperEntity(); + entity.setId(id); + entity.setName(model.getName()); + entity.setIdentityProviderAlias(model.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(model.getIdentityProviderMapper()); + entity.setConfig(model.getConfig()); + + getMongoEntity().getIdentityProviderMappers().add(entity); + updateMongoEntity(); + return entityToModel(entity); + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntity(String id) { + for (IdentityProviderMapperEntity entity : getMongoEntity().getIdentityProviderMappers()) { + if (entity.getId().equals(id)) { + return entity; + } + } + return null; + + } + + protected IdentityProviderMapperEntity getIdentityProviderMapperEntityByName(String alias, String name) { + for (IdentityProviderMapperEntity entity : getMongoEntity().getIdentityProviderMappers()) { + if (entity.getIdentityProviderAlias().equals(alias) && entity.getName().equals(name)) { + return entity; + } + } + return null; + + } + + @Override + public void removeIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity toDelete = getIdentityProviderMapperEntity(mapping.getId()); + if (toDelete != null) { + this.realm.getIdentityProviderMappers().remove(toDelete); + } + + } + + @Override + public void updateIdentityProviderMapper(IdentityProviderMapperModel mapping) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(mapping.getId()); + entity.setIdentityProviderAlias(mapping.getIdentityProviderAlias()); + entity.setIdentityProviderMapper(mapping.getIdentityProviderMapper()); + if (entity.getConfig() == null) { + entity.setConfig(mapping.getConfig()); + } else { + entity.getConfig().clear(); + entity.getConfig().putAll(mapping.getConfig()); + } + updateMongoEntity(); + + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperById(String id) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntity(id); + if (entity == null) return null; + return entityToModel(entity); + } + + @Override + public IdentityProviderMapperModel getIdentityProviderMapperByName(String alias, String name) { + IdentityProviderMapperEntity entity = getIdentityProviderMapperEntityByName(alias, name); + if (entity == null) return null; + return entityToModel(entity); + } + + protected IdentityProviderMapperModel entityToModel(IdentityProviderMapperEntity entity) { + IdentityProviderMapperModel mapping = new IdentityProviderMapperModel(); + mapping.setId(entity.getId()); + mapping.setName(entity.getName()); + mapping.setIdentityProviderAlias(entity.getIdentityProviderAlias()); + mapping.setIdentityProviderMapper(entity.getIdentityProviderMapper()); + Map config = new HashMap(); + if (entity.getConfig() != null) config.putAll(entity.getConfig()); + mapping.setConfig(config); + return mapping; + } + } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java index 8482ce0e4f..ce61d3351c 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java @@ -157,7 +157,7 @@ public class AccountTest { }); } - @Test @Ignore + //@Test @Ignore public void runit() throws Exception { Thread.sleep(10000000); }