From c20ad9380781bad5270e3f471d6e17ea54d72ee3 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 24 Feb 2015 19:37:07 -0500 Subject: [PATCH] claim mappings next phase --- .../META-INF/jpa-changelog-1.2.0.Beta1.xml | 17 ++- .../representations/UserClaimSet.java | 143 +++++++++--------- .../idm/ApplicationRepresentation.java | 10 +- .../idm/RealmRepresentation.java | 16 +- .../java/org/keycloak/models/ClientModel.java | 5 +- .../java/org/keycloak/models/RealmModel.java | 15 ++ .../org/keycloak/models/RealmProvider.java | 3 - .../models/entities/ClientEntity.java | 10 +- .../models/utils/ModelToRepresentation.java | 8 +- .../models/utils/RepresentationToModel.java | 16 +- .../keycloak/models/cache/ClientAdapter.java | 15 +- .../keycloak/models/cache/RealmAdapter.java | 8 + .../keycloak/models/jpa/ClientAdapter.java | 47 +++++- .../keycloak/models/jpa/JpaRealmProvider.java | 2 +- .../org/keycloak/models/jpa/RealmAdapter.java | 70 ++++++--- .../models/jpa/entities/ClientEntity.java | 2 +- .../jpa/entities/ProtocolMapperEntity.java | 2 +- .../models/jpa/entities/RealmEntity.java | 10 +- .../keycloak/adapters/ClientAdapter.java | 17 ++- .../keycloak/adapters/MongoRealmProvider.java | 2 +- .../mongo/keycloak/adapters/RealmAdapter.java | 55 +++++-- .../oidc/OIDCLoginProtocolFactory.java | 110 ++++++++++++++ .../oidc/OIDCLoginProtocolService.java | 4 +- .../keycloak/protocol/oidc/TokenManager.java | 58 +++---- .../protocol/oidc/UserInfoService.java | 12 +- .../oidc/mappers/AttributeMapperHelper.java | 59 ++++++++ .../oidc/mappers/OIDCAddressMapper.java | 59 ++++++++ .../mappers/OIDCClientSessionNoteMapper.java | 6 +- .../oidc/mappers/OIDCFullNameMapper.java | 54 +++++++ .../oidc/mappers/OIDCUserAttributeMapper.java | 32 +--- .../oidc/mappers/OIDCUserModelMapper.java | 20 ++- .../mappers/OIDCUserSessionNoteMapper.java | 6 +- .../DefaultKeycloakSessionFactory.java | 5 + .../org.keycloak.protocol.ProtocolMapper | 9 +- .../services/org.keycloak.provider.Spi | 1 + .../adapter/AdapterTestStrategy.java | 2 +- .../adapter/RelativeUriAdapterTest.java | 2 +- .../testsuite/admin/AdminAPITest.java | 2 +- .../testsuite/saml/SamlBindingTest.java | 2 +- 39 files changed, 666 insertions(+), 250 deletions(-) mode change 100644 => 100755 core/src/main/java/org/keycloak/representations/UserClaimSet.java create mode 100755 services/src/main/java/org/keycloak/protocol/oidc/mappers/AttributeMapperHelper.java create mode 100755 services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAddressMapper.java create mode 100755 services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCFullNameMapper.java 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 71fc2c4be4..6139c3d931 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 @@ - - - - + + + + + + + + + - + + + 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 c6472691a1..4e8f1f9f57 --- 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/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java index 0e42a40ba7..4349a7579b 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 registeredNodes; protected List allowedIdentityProviders; - protected Set protocolClaimMappings; + protected Set protocolMappers; public String getId() { return id; @@ -200,11 +200,11 @@ public class ApplicationRepresentation { this.allowedIdentityProviders = allowedIdentityProviders; } - public Set getProtocolClaimMappings() { - return protocolClaimMappings; + public Set getProtocolMappers() { + return protocolMappers; } - public void setProtocolClaimMappings(Set protocolClaimMappings) { - this.protocolClaimMappings = protocolClaimMappings; + public void setProtocolMappers(Set 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 9b655dc15a..dc5ada6a6d 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 eventsListeners; private List identityProviders; private List claimTypes; - private List protocolClaimMappings; + private List protocolMappers; private Boolean identityFederationEnabled; public String getId() { @@ -492,11 +493,16 @@ public class RealmRepresentation { this.claimTypes = claimTypes; } - public List getProtocolClaimMappings() { - return protocolClaimMappings; + public List getProtocolMappers() { + return protocolMappers; } - public void setProtocolClaimMappings(List protocolClaimMappings) { - this.protocolClaimMappings = protocolClaimMappings; + public void addProtocolMapper(ProtocolMapperRepresentation rep) { + if (protocolMappers == null) protocolMappers = new LinkedList(); + protocolMappers.add(rep); + } + + public void setProtocolMappers(List protocolMappers) { + this.protocolMappers = protocolMappers; } } 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 243de4dc43..edcb44e0bb 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 getProtocolMappers(); - void addProtocolMappers(Set mapperIds); - void removeProtocolMappers(Set mapperIds); + void addProtocolMappers(Set mapperNames); + void removeProtocolMappers(Set mapperNames); + void setProtocolMappers(Set mapperNames); } 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 badc6bdbb9..510d72a9d7 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 f2454d41bd..58328b2cb5 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/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java index 1cfbcfe32d..3d43feeb3d 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 redirectUris = new ArrayList(); private List scopeIds = new ArrayList(); private List allowedIdentityProviders = new ArrayList(); - private Set protocolClaimMappings = new HashSet(); + private Set protocolMappers = new HashSet(); public String getName() { return name; @@ -152,11 +152,11 @@ public class ClientEntity extends AbstractIdentifiableEntity { this.allowedIdentityProviders = allowedIdentityProviders; } - public Set getProtocolClaimMappings() { - return protocolClaimMappings; + public Set getProtocolMappers() { + return protocolMappers; } - public void setProtocolClaimMappings(Set protocolClaimMappings) { - this.protocolClaimMappings = protocolClaimMappings; + public void setProtocolMappers(Set protocolMappers) { + this.protocolMappers = protocolMappers; } } 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 69d5477f07..949f974377 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 mappings = new HashSet(); - 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 mappings = new HashSet(); - 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 2fb49af311..cc0b63d1b3 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 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 83f5490089..0fc38bcc9d 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 mappingIds) { + public void addProtocolMappers(Set mapperNames) { getDelegateForUpdate(); - updatedClient.addProtocolMappers(mappingIds); + updatedClient.addProtocolMappers(mapperNames); } @Override - public void removeProtocolMappers(Set mappingIds) { + public void removeProtocolMappers(Set mapperNames) { getDelegateForUpdate(); - updatedClient.removeProtocolMappers(mappingIds); + updatedClient.removeProtocolMappers(mapperNames); + + } + + @Override + public void setProtocolMappers(Set 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 21d32cc037..d03645685c 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 @@ -919,6 +919,14 @@ public class RealmAdapter implements RealmModel { return null; } + @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; 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 c06cdecf57..f45c08530a 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 query = em.createNamedQuery("getProtocolMapperByName", ProtocolMapperEntity.class); + query.setParameter("name", name); + query.setParameter("realm", entity.getRealm()); + List 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 mappings) { Collection entities = entity.getProtocolMappers(); Set already = new HashSet(); 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 entities = entity.getProtocolMappers(); List remove = new LinkedList(); 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 mappings) { + Collection entities = entity.getProtocolMappers(); + Iterator it = entities.iterator(); + Set already = new HashSet(); + 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/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index 371d0488b4..3091cc9213 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 7578fd0ae0..6c4af3973f 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 adding = new HashSet(); + 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 getProtocolMappers() { Set mappings = new HashSet(); - 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/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 ec8929e2a8..817fd8085c 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 allowedIdentityProviders = new ArrayList(); - @OneToMany(cascade ={CascadeType.REMOVE}) + @OneToMany(fetch = FetchType.LAZY) @JoinTable(name="CLIENT_PROTOCOL_MAPPER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="MAPPING_ID")}) Collection protocolMappers = new ArrayList(); 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 bd8bbe2a0d..822049be0e 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 e9cdda1e78..2f24d06bf7 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 claimTypes = new ArrayList(); @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") - Collection protocolClaimMappings = new ArrayList(); + Collection protocolMappers = new ArrayList(); @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") Collection requiredCredentials = new ArrayList(); @@ -447,12 +447,12 @@ public class RealmEntity { this.claimTypes = claimTypes; } - public Collection getProtocolClaimMappings() { - return protocolClaimMappings; + public Collection getProtocolMappers() { + return protocolMappers; } - public void setProtocolClaimMappings(Collection protocolClaimMappings) { - this.protocolClaimMappings = protocolClaimMappings; + public void setProtocolMappers(Collection protocolMappers) { + this.protocolMappers = protocolMappers; } } 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 1a6990dea0..7bc47a57ce 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 extends A @Override public Set getProtocolMappers() { Set result = new HashSet(); - 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 extends A } @Override - public void addProtocolMappers(Set mappingIds) { - getMongoEntityAsClient().getProtocolClaimMappings().addAll(mappingIds); + public void addProtocolMappers(Set mapperNames) { + getMongoEntityAsClient().getProtocolMappers().addAll(mapperNames); updateMongoEntity(); } @Override - public void removeProtocolMappers(Set mappingIds) { - getMongoEntityAsClient().getProtocolClaimMappings().removeAll(mappingIds); + public void removeProtocolMappers(Set mapperNames) { + getMongoEntityAsClient().getProtocolMappers().removeAll(mapperNames); + updateMongoEntity(); + } + + @Override + public void setProtocolMappers(Set 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 997025e888..61865d6e6e 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 9b20f2a869..065443fe60 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 impleme return result; } + public void addDefaultClientProtocolMappers(ClientModel client) { + Set adding = new HashSet(); + 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 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 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 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 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 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 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 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/OIDCLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java index d8ff2e4b38..08ee15f7f1 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 Bill Burke * @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 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 config = new HashMap(); + 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 ae0ba0a457..5e4080976f 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 4c56df7df7..8e48aeb640 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 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 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 mappings = model.getProtocolMappers(); + public AccessToken transformToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user, + UserSessionModel userSession, ClientSessionModel clientSession) { + Set 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 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 7a0e8a8951..0829d67f8b 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 claims = new HashMap(); + 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/protocol/oidc/mappers/AttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AttributeMapperHelper.java new file mode 100755 index 0000000000..a4fe0fe0c8 --- /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 Bill Burke + * @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 jsonObject = token.getOtherClaims(); + for (int i = 0; i < split.length; i++) { + if (i == split.length - 1) { + jsonObject.put(split[i], attributeValue); + } else { + Map nested = (Map)jsonObject.get(split[i]); + if (nested == null) { + nested = new HashMap(); + 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 0000000000..ee7e8150e3 --- /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 Bill Burke + * @version $Revision: 1 $ + */ +public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { + + private static final List configProperties = new ArrayList(); + + static { + + } + + public static final String PROVIDER_ID = "oidc-address-mapper"; + + + public List 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 3e38ed29e4..216c0fe972 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 0000000000..b77783a647 --- /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 Bill Burke + * @version $Revision: 1 $ + */ +public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { + + private static final List configProperties = new ArrayList(); + + static { + + } + + public static final String PROVIDER_ID = "oidc-full-name-mapper"; + + + public List 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 1c687be3b5..c5435588b9 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 configProperties = new ArrayList(); 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 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 jsonObject = token.getOtherClaims(); - for (int i = 0; i < split.length; i++) { - if (i == split.length - 1) { - jsonObject.put(split[i], attributeValue); - } else { - Map nested = (Map)jsonObject.get(split[i]); - if (nested == null) { - nested = new HashMap(); - 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 4af3178680..6c30080321 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 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; } @@ -73,6 +73,14 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O if (val != null) return val.toString(); } catch (Exception ignore) { + } + methodName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); + try { + Method method = UserModel.class.getMethod(methodName); + Object val = method.invoke(user); + if (val != null) return val.toString(); + } catch (Exception ignore) { + } return null; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserSessionNoteMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCUserSessionNoteMapper.java index 0069d5a25d..e430f4d528 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/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java index 361eb87aec..dc03c490b4 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 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 0f9da65a17..1815b887d4 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 7cea20de62..30eeb3e59b 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 08f57757af..cfe16a8e76 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 0ebb8fc201..cce65bd49e 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 0d6c30fd3f..68e3f13540 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 82c0ec9289..db33eb1340 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);