claim mappings next phase
This commit is contained in:
parent
6c5f35720a
commit
c20ad93807
39 changed files with 666 additions and 250 deletions
|
@ -5,14 +5,21 @@
|
|||
<column name="ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="NAME" type="VARCHAR(255)"/>
|
||||
<column name="PROTOCOL" type="VARCHAR(255)"/>
|
||||
<column name="SOURCE" type="VARCHAR(255)"/>
|
||||
<column name="PROTOCOL_MAPPER_NAME" type="VARCHAR(255)"/>
|
||||
<column name="NAME" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="PROTOCOL" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="PROTOCOL_MAPPER_NAME" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="APPLIED_BY_DEFAULT" type="BOOLEAN(1)"/>
|
||||
<column name="CONSENT_REQUIRED" type="BOOLEAN(1)"/>
|
||||
<column name="CONSENT_TEXT" type="VARCHAR(255)"/>
|
||||
<column name="REALM_ID" type="VARCHAR(36)"/>
|
||||
<column name="REALM_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createTable tableName="PROTOCOL_MAPPER_CONFIG">
|
||||
<column name="PROTOCOL_MAPPER_ID" type="VARCHAR(36)">
|
||||
|
|
143
core/src/main/java/org/keycloak/representations/UserClaimSet.java
Normal file → Executable file
143
core/src/main/java/org/keycloak/representations/UserClaimSet.java
Normal file → Executable file
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class ApplicationRepresentation {
|
|||
protected Integer nodeReRegistrationTimeout;
|
||||
protected Map<String, Integer> registeredNodes;
|
||||
protected List<String> allowedIdentityProviders;
|
||||
protected Set<String> protocolClaimMappings;
|
||||
protected Set<String> protocolMappers;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -200,11 +200,11 @@ public class ApplicationRepresentation {
|
|||
this.allowedIdentityProviders = allowedIdentityProviders;
|
||||
}
|
||||
|
||||
public Set<String> getProtocolClaimMappings() {
|
||||
return protocolClaimMappings;
|
||||
public Set<String> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
|
||||
this.protocolClaimMappings = protocolClaimMappings;
|
||||
public void setProtocolMappers(Set<String> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -64,7 +65,7 @@ public class RealmRepresentation {
|
|||
protected List<String> eventsListeners;
|
||||
private List<IdentityProviderRepresentation> identityProviders;
|
||||
private List<ClaimTypeRepresentation> claimTypes;
|
||||
private List<ProtocolMapperRepresentation> protocolClaimMappings;
|
||||
private List<ProtocolMapperRepresentation> protocolMappers;
|
||||
private Boolean identityFederationEnabled;
|
||||
|
||||
public String getId() {
|
||||
|
@ -492,11 +493,16 @@ public class RealmRepresentation {
|
|||
this.claimTypes = claimTypes;
|
||||
}
|
||||
|
||||
public List<ProtocolMapperRepresentation> getProtocolClaimMappings() {
|
||||
return protocolClaimMappings;
|
||||
public List<ProtocolMapperRepresentation> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolClaimMappings(List<ProtocolMapperRepresentation> protocolClaimMappings) {
|
||||
this.protocolClaimMappings = protocolClaimMappings;
|
||||
public void addProtocolMapper(ProtocolMapperRepresentation rep) {
|
||||
if (protocolMappers == null) protocolMappers = new LinkedList<ProtocolMapperRepresentation>();
|
||||
protocolMappers.add(rep);
|
||||
}
|
||||
|
||||
public void setProtocolMappers(List<ProtocolMapperRepresentation> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ public interface ClientModel {
|
|||
boolean hasIdentityProvider(String providerId);
|
||||
|
||||
Set<ProtocolMapperModel> getProtocolMappers();
|
||||
void addProtocolMappers(Set<String> mapperIds);
|
||||
void removeProtocolMappers(Set<String> mapperIds);
|
||||
void addProtocolMappers(Set<String> mapperNames);
|
||||
void removeProtocolMappers(Set<String> mapperNames);
|
||||
void setProtocolMappers(Set<String> mapperNames);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
|||
private List<String> redirectUris = new ArrayList<String>();
|
||||
private List<String> scopeIds = new ArrayList<String>();
|
||||
private List<String> allowedIdentityProviders = new ArrayList<String>();
|
||||
private Set<String> protocolClaimMappings = new HashSet<String>();
|
||||
private Set<String> protocolMappers = new HashSet<String>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -152,11 +152,11 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
|||
this.allowedIdentityProviders = allowedIdentityProviders;
|
||||
}
|
||||
|
||||
public Set<String> getProtocolClaimMappings() {
|
||||
return protocolClaimMappings;
|
||||
public Set<String> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolClaimMappings(Set<String> protocolClaimMappings) {
|
||||
this.protocolClaimMappings = protocolClaimMappings;
|
||||
public void setProtocolMappers(Set<String> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ public class ModelToRepresentation {
|
|||
}
|
||||
|
||||
for (ProtocolMapperModel mapping : realm.getProtocolMappers()) {
|
||||
rep.getProtocolClaimMappings().add(toRepresentation(mapping));
|
||||
rep.addProtocolMapper(toRepresentation(mapping));
|
||||
}
|
||||
|
||||
return rep;
|
||||
|
@ -267,8 +267,8 @@ public class ModelToRepresentation {
|
|||
|
||||
if (!applicationModel.getProtocolMappers().isEmpty()) {
|
||||
Set<String> mappings = new HashSet<String>();
|
||||
for (ProtocolMapperModel model : applicationModel.getProtocolMappers()) mappings.add(model.getId());
|
||||
rep.setProtocolClaimMappings(mappings);
|
||||
for (ProtocolMapperModel model : applicationModel.getProtocolMappers()) mappings.add(model.getName());
|
||||
rep.setProtocolMappers(mappings);
|
||||
}
|
||||
|
||||
return rep;
|
||||
|
@ -302,7 +302,7 @@ public class ModelToRepresentation {
|
|||
|
||||
if (!model.getProtocolMappers().isEmpty()) {
|
||||
Set<String> mappings = new HashSet<String>();
|
||||
for (ProtocolMapperModel mappingMoel : model.getProtocolMappers()) mappings.add(mappingMoel.getId());
|
||||
for (ProtocolMapperModel mappingModel : model.getProtocolMappers()) mappings.add(mappingModel.getName());
|
||||
rep.setProtocolClaimMappings(mappings);
|
||||
}
|
||||
return rep;
|
||||
|
|
|
@ -460,8 +460,8 @@ public class RepresentationToModel {
|
|||
applicationModel.setAllowedClaimsMask(ClaimMask.ALL);
|
||||
}
|
||||
|
||||
if (resourceRep.getProtocolClaimMappings() != null) {
|
||||
applicationModel.addProtocolMappers(resourceRep.getProtocolClaimMappings());
|
||||
if (resourceRep.getProtocolMappers() != null) {
|
||||
applicationModel.setProtocolMappers(resourceRep.getProtocolMappers());
|
||||
}
|
||||
|
||||
return applicationModel;
|
||||
|
@ -773,13 +773,17 @@ public class RepresentationToModel {
|
|||
}
|
||||
|
||||
private static void importProtocolMappers(RealmRepresentation rep, RealmModel newRealm) {
|
||||
if (rep.getProtocolClaimMappings() != null) {
|
||||
if (rep.getProtocolMappers() != null) {
|
||||
// we make sure we don't recreate mappers that are automatically created by the protocol providers.
|
||||
for (ProtocolMapperRepresentation representation : rep.getProtocolClaimMappings()) {
|
||||
if (representation.getId() == null || newRealm.getProtocolMapperById(representation.getId()) == null) {
|
||||
Set<ProtocolMapperModel> mappers = newRealm.getProtocolMappers();
|
||||
for (ProtocolMapperRepresentation representation : rep.getProtocolMappers()) {
|
||||
ProtocolMapperModel existing = newRealm.getProtocolMapperByName(representation.getName());
|
||||
if (existing == null) {
|
||||
newRealm.addProtocolMapper(toModel(representation));
|
||||
} else {
|
||||
newRealm.updateProtocolMapper(toModel(representation));
|
||||
ProtocolMapperModel mapping = toModel(representation);
|
||||
mapping.setId(existing.getId());
|
||||
newRealm.updateProtocolMapper(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,16 +286,23 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
return cachedClient.getProtocolClaimMappings(); }
|
||||
|
||||
@Override
|
||||
public void addProtocolMappers(Set<String> mappingIds) {
|
||||
public void addProtocolMappers(Set<String> mapperNames) {
|
||||
getDelegateForUpdate();
|
||||
updatedClient.addProtocolMappers(mappingIds);
|
||||
updatedClient.addProtocolMappers(mapperNames);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMappers(Set<String> mappingIds) {
|
||||
public void removeProtocolMappers(Set<String> mapperNames) {
|
||||
getDelegateForUpdate();
|
||||
updatedClient.removeProtocolMappers(mappingIds);
|
||||
updatedClient.removeProtocolMappers(mapperNames);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolMappers(Set<String> mapperNames) {
|
||||
getDelegateForUpdate();
|
||||
updatedClient.setProtocolMappers(mapperNames);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.models.RoleModel;
|
|||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
|
||||
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.RealmEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
||||
|
||||
|
@ -17,6 +18,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -364,6 +366,7 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
|
@ -377,16 +380,27 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
return mappings;
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity findProtocolMapperByName(String name) {
|
||||
TypedQuery<ProtocolMapperEntity> query = em.createNamedQuery("getProtocolMapperByName", ProtocolMapperEntity.class);
|
||||
query.setParameter("name", name);
|
||||
query.setParameter("realm", entity.getRealm());
|
||||
List<ProtocolMapperEntity> entities = query.getResultList();
|
||||
if (entities.size() == 0) return null;
|
||||
if (entities.size() > 1) throw new IllegalStateException("Should not be more than one protocol mapper with same name");
|
||||
return query.getResultList().get(0);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProtocolMappers(Set<String> mappings) {
|
||||
Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
|
||||
Set<String> already = new HashSet<String>();
|
||||
for (ProtocolMapperEntity rel : entities) {
|
||||
already.add(rel.getId());
|
||||
already.add(rel.getName());
|
||||
}
|
||||
for (String providerId : mappings) {
|
||||
if (!already.contains(providerId)) {
|
||||
ProtocolMapperEntity mapping = em.find(ProtocolMapperEntity.class, providerId);
|
||||
for (String name : mappings) {
|
||||
if (!already.contains(name)) {
|
||||
ProtocolMapperEntity mapping = findProtocolMapperByName(name);
|
||||
if (mapping != null) {
|
||||
entities.add(mapping);
|
||||
}
|
||||
|
@ -400,13 +414,36 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
|
||||
List<ProtocolMapperEntity> remove = new LinkedList<ProtocolMapperEntity>();
|
||||
for (ProtocolMapperEntity rel : entities) {
|
||||
if (mappings.contains(rel.getId())) remove.add(rel);
|
||||
if (mappings.contains(rel.getName())) remove.add(rel);
|
||||
}
|
||||
for (ProtocolMapperEntity entity : remove) {
|
||||
entities.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
@Override
|
||||
public void setProtocolMappers(Set<String> mappings) {
|
||||
Collection<ProtocolMapperEntity> entities = entity.getProtocolMappers();
|
||||
Iterator<ProtocolMapperEntity> it = entities.iterator();
|
||||
Set<String> already = new HashSet<String>();
|
||||
while (it.hasNext()) {
|
||||
ProtocolMapperEntity mapper = it.next();
|
||||
if (mappings.contains(mapper.getName())) {
|
||||
already.add(mapper.getName());
|
||||
continue;
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
for (String name : mappings) {
|
||||
if (!already.contains(name)) {
|
||||
ProtocolMapperEntity mapping = findProtocolMapperByName(name);
|
||||
if (mapping != null) {
|
||||
entities.add(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -628,6 +628,17 @@ public class RealmAdapter implements RealmModel {
|
|||
return this.addApplication(KeycloakModelUtils.generateId(), name);
|
||||
}
|
||||
|
||||
public void addDefaultClientProtocolMappers(ClientModel client) {
|
||||
Set<String> adding = new HashSet<String>();
|
||||
for (ProtocolMapperEntity mapper : realm.getProtocolMappers()) {
|
||||
if (mapper.isAppliedByDefault()) {
|
||||
adding.add(mapper.getName());
|
||||
}
|
||||
}
|
||||
client.setProtocolMappers(adding);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationModel addApplication(String id, String name) {
|
||||
ApplicationEntity applicationData = new ApplicationEntity();
|
||||
|
@ -639,6 +650,7 @@ public class RealmAdapter implements RealmModel {
|
|||
em.persist(applicationData);
|
||||
em.flush();
|
||||
ApplicationModel resource = new ApplicationAdapter(this, em, session, applicationData);
|
||||
addDefaultClientProtocolMappers(resource);
|
||||
em.flush();
|
||||
return resource;
|
||||
}
|
||||
|
@ -702,7 +714,10 @@ public class RealmAdapter implements RealmModel {
|
|||
data.setRealm(realm);
|
||||
em.persist(data);
|
||||
em.flush();
|
||||
return new OAuthClientAdapter(this, data, em);
|
||||
OAuthClientModel model = new OAuthClientAdapter(this, data, em);
|
||||
addDefaultClientProtocolMappers(model);
|
||||
em.flush();
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1259,7 +1274,7 @@ public class RealmAdapter implements RealmModel {
|
|||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
Set<ProtocolMapperModel> mappings = new HashSet<ProtocolMapperModel>();
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
|
@ -1280,7 +1295,10 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
|
||||
if (getProtocolMapperByName(model.getName()) != null) {
|
||||
throw new RuntimeException("Duplicate protocol mapper with name: " + model.getName());
|
||||
}
|
||||
String id = KeycloakModelUtils.generateId();
|
||||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
entity.setId(id);
|
||||
entity.setName(model.getName());
|
||||
|
@ -1293,20 +1311,12 @@ public class RealmAdapter implements RealmModel {
|
|||
entity.setConsentText(model.getConsentText());
|
||||
|
||||
em.persist(entity);
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(model.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setConfig(model.getConfig());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
return mapping;
|
||||
realm.getProtocolMappers().add(entity);
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapper(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
|
||||
protected ProtocolMapperEntity getProtocolMapperEntity(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
}
|
||||
|
@ -1315,11 +1325,21 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapperEntityByName(String name) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getName().equals(name)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity toDelete = getProtocolMapper(mapping.getId());
|
||||
ProtocolMapperEntity toDelete = getProtocolMapperEntity(mapping.getId());
|
||||
if (toDelete != null) {
|
||||
realm.getProtocolClaimMappings().remove(toDelete);
|
||||
realm.getProtocolMappers().remove(toDelete);
|
||||
em.remove(toDelete);
|
||||
}
|
||||
|
||||
|
@ -1327,7 +1347,7 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntity(mapping.getId());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setAppliedByDefault(mapping.isAppliedByDefault());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
|
@ -1344,12 +1364,24 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolMapper(id);
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntity(id);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String name) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntityByName(name);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
|
|
|
@ -77,7 +77,7 @@ public abstract class ClientEntity {
|
|||
@JoinTable(name="CLIENT_ALLOWED_IDENTITY_PROVIDER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="INTERNAL_ID")})
|
||||
Collection<IdentityProviderEntity> allowedIdentityProviders = new ArrayList<IdentityProviderEntity>();
|
||||
|
||||
@OneToMany(cascade ={CascadeType.REMOVE})
|
||||
@OneToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name="CLIENT_PROTOCOL_MAPPER", joinColumns = { @JoinColumn(name="CLIENT_ID")}, inverseJoinColumns = { @JoinColumn(name="MAPPING_ID")})
|
||||
Collection<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -96,7 +96,7 @@ public class RealmEntity {
|
|||
Collection<ClaimTypeEntity> claimTypes = new ArrayList<ClaimTypeEntity>();
|
||||
|
||||
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||
Collection<ProtocolMapperEntity> protocolClaimMappings = new ArrayList<ProtocolMapperEntity>();
|
||||
Collection<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
|
||||
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||
Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
|
||||
|
@ -447,12 +447,12 @@ public class RealmEntity {
|
|||
this.claimTypes = claimTypes;
|
||||
}
|
||||
|
||||
public Collection<ProtocolMapperEntity> getProtocolClaimMappings() {
|
||||
return protocolClaimMappings;
|
||||
public Collection<ProtocolMapperEntity> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolClaimMappings(Collection<ProtocolMapperEntity> protocolClaimMappings) {
|
||||
this.protocolClaimMappings = protocolClaimMappings;
|
||||
public void setProtocolMappers(Collection<ProtocolMapperEntity> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
|
|||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
Set<ProtocolMapperModel> result = new HashSet<ProtocolMapperModel>();
|
||||
for (String id : getMongoEntityAsClient().getProtocolClaimMappings()) {
|
||||
for (String id : getMongoEntityAsClient().getProtocolMappers()) {
|
||||
ProtocolMapperModel model = getRealm().getProtocolMapperById(id);
|
||||
if (model != null) result.add(model);
|
||||
}
|
||||
|
@ -303,15 +303,22 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addProtocolMappers(Set<String> mappingIds) {
|
||||
getMongoEntityAsClient().getProtocolClaimMappings().addAll(mappingIds);
|
||||
public void addProtocolMappers(Set<String> mapperNames) {
|
||||
getMongoEntityAsClient().getProtocolMappers().addAll(mapperNames);
|
||||
updateMongoEntity();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMappers(Set<String> mappingIds) {
|
||||
getMongoEntityAsClient().getProtocolClaimMappings().removeAll(mappingIds);
|
||||
public void removeProtocolMappers(Set<String> mapperNames) {
|
||||
getMongoEntityAsClient().getProtocolMappers().removeAll(mapperNames);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolMappers(Set<String> mapperNames) {
|
||||
getMongoEntityAsClient().getProtocolMappers().clear();
|
||||
getMongoEntityAsClient().getProtocolMappers().addAll(mapperNames);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -616,6 +616,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
return result;
|
||||
}
|
||||
|
||||
public void addDefaultClientProtocolMappers(ClientModel client) {
|
||||
Set<String> adding = new HashSet<String>();
|
||||
for (ProtocolMapperEntity mapper : realm.getProtocolMappers()) {
|
||||
if (mapper.isAppliedByDefault()) adding.add(mapper.getName());
|
||||
}
|
||||
client.setProtocolMappers(adding);
|
||||
|
||||
}
|
||||
@Override
|
||||
public ApplicationModel addApplication(String name) {
|
||||
return this.addApplication(null, name);
|
||||
|
@ -630,7 +638,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
appData.setEnabled(true);
|
||||
getMongoStore().insertEntity(appData, invocationContext);
|
||||
|
||||
return new ApplicationAdapter(session, this, appData, invocationContext);
|
||||
ApplicationModel model = new ApplicationAdapter(session, this, appData, invocationContext);
|
||||
addDefaultClientProtocolMappers(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -651,7 +661,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
oauthClient.setName(name);
|
||||
getMongoStore().insertEntity(oauthClient, invocationContext);
|
||||
|
||||
return new OAuthClientAdapter(session, this, oauthClient, invocationContext);
|
||||
OAuthClientAdapter model = new OAuthClientAdapter(session, this, oauthClient, invocationContext);
|
||||
addDefaultClientProtocolMappers(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -809,8 +821,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
if (model.getId() != null) entity.setId(model.getId());
|
||||
else entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setProtocol(model.getProtocol());
|
||||
entity.setName(model.getName());
|
||||
entity.setAppliedByDefault(model.isAppliedByDefault());
|
||||
|
@ -820,15 +831,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
entity.setConsentText(model.getConsentText());
|
||||
realm.getProtocolMappers().add(entity);
|
||||
updateRealm();
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setProtocol(model.getProtocol());
|
||||
mapping.setAppliedByDefault(model.isAppliedByDefault());
|
||||
mapping.setProtocolMapper(model.getProtocolMapper());
|
||||
mapping.setConfig(model.getConfig());
|
||||
mapping.setConsentText(model.getConsentText());
|
||||
mapping.setConsentRequired(model.isConsentRequired());
|
||||
return mapping;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -843,7 +846,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapper(String id) {
|
||||
protected ProtocolMapperEntity getProtocolMapperyEntityById(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
|
@ -852,11 +855,20 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
return null;
|
||||
|
||||
}
|
||||
protected ProtocolMapperEntity getProtocolMapperyEntityByName(String name) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getName().equals(name)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
|
||||
ProtocolMapperEntity entity = getProtocolMapperyEntityById(mapping.getId());
|
||||
entity.setAppliedByDefault(mapping.isAppliedByDefault());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
|
@ -873,8 +885,19 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolMapper(id);
|
||||
ProtocolMapperEntity entity = getProtocolMapperyEntityById(id);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String name) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperyEntityById(name);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
|
|
|
@ -4,11 +4,22 @@ import org.keycloak.Config;
|
|||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.protocol.LoginProtocolFactory;
|
||||
import org.keycloak.protocol.oidc.mappers.AttributeMapperHelper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.provider.ProviderEventListener;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -25,8 +36,107 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
|
|||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
KeycloakSession session = factory.create();
|
||||
session.getTransaction().begin();
|
||||
try {
|
||||
List<RealmModel> realms = session.realms().getRealms();
|
||||
for (RealmModel realm : realms) addMappers(realm);
|
||||
session.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
session.getTransaction().rollback();
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
|
||||
factory.register(new ProviderEventListener() {
|
||||
@Override
|
||||
public void onEvent(ProviderEvent event) {
|
||||
if (event instanceof RealmModel.RealmCreationEvent) {
|
||||
RealmModel realm = ((RealmModel.RealmCreationEvent)event).getCreatedRealm();
|
||||
addMappers(realm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected void addMappers(RealmModel realm) {
|
||||
int counter = 0;
|
||||
// the ids must never change!!!! So if you add more default mappers, then add to end with higher counter.
|
||||
addClaimMapper(realm, "username", OIDCUserModelMapper.PROVIDER_ID,
|
||||
OIDCUserModelMapper.USER_MODEL_PROPERTY, "username",
|
||||
"preferred_username", "String",
|
||||
true, "username",
|
||||
true);
|
||||
addClaimMapper(realm, "email", OIDCUserModelMapper.PROVIDER_ID,
|
||||
OIDCUserModelMapper.USER_MODEL_PROPERTY, "email",
|
||||
"email", "String",
|
||||
true, "email",
|
||||
true);
|
||||
addClaimMapper(realm, "given name", OIDCUserModelMapper.PROVIDER_ID,
|
||||
OIDCUserModelMapper.USER_MODEL_PROPERTY, "firstName",
|
||||
"given_name", "String",
|
||||
true, "given name",
|
||||
true);
|
||||
addClaimMapper(realm, "family name", OIDCUserModelMapper.PROVIDER_ID,
|
||||
OIDCUserModelMapper.USER_MODEL_PROPERTY, "lastName",
|
||||
"family_name", "String",
|
||||
true, "family name",
|
||||
true);
|
||||
addClaimMapper(realm, "email verified", OIDCUserModelMapper.PROVIDER_ID,
|
||||
OIDCUserModelMapper.USER_MODEL_PROPERTY, "emailVerified",
|
||||
"email_verified", "boolean",
|
||||
false, null,
|
||||
false);
|
||||
|
||||
ProtocolMapperModel fullName = new ProtocolMapperModel();
|
||||
if (realm.getProtocolMapperByName("full name") == null) {
|
||||
fullName.setName("full name");
|
||||
fullName.setProtocolMapper(OIDCFullNameMapper.PROVIDER_ID);
|
||||
fullName.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
fullName.setConsentRequired(true);
|
||||
fullName.setConsentText("full name");
|
||||
fullName.setAppliedByDefault(true);
|
||||
realm.addProtocolMapper(fullName);
|
||||
}
|
||||
|
||||
ProtocolMapperModel address = new ProtocolMapperModel();
|
||||
if (realm.getProtocolMapperByName("address") == null) {
|
||||
address.setName("address");
|
||||
address.setProtocolMapper(OIDCAddressMapper.PROVIDER_ID);
|
||||
address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
address.setConsentRequired(true);
|
||||
address.setConsentText("address");
|
||||
address.setAppliedByDefault(false);
|
||||
realm.addProtocolMapper(address);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected void addClaimMapper(RealmModel realm, String name, String mapperRef,
|
||||
String propertyName, String propertyNameValue,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean consentRequired, String consentText,
|
||||
boolean appliedByDefault) {
|
||||
ProtocolMapperModel mapper = realm.getProtocolMapperByName(name);
|
||||
if (mapper != null) return;
|
||||
mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperRef);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConsentRequired(consentRequired);
|
||||
mapper.setConsentText(consentText);
|
||||
mapper.setAppliedByDefault(appliedByDefault);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put(propertyName, propertyNameValue);
|
||||
config.put(AttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
|
||||
config.put(AttributeMapperHelper.JSON_TYPE, claimType);
|
||||
mapper.setConfig(config);
|
||||
realm.addProtocolMapper(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createProtocolEndpoint(RealmModel realm, EventBuilder event, AuthenticationManager authManager) {
|
||||
return new OIDCLoginProtocolService(realm, event, authManager);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.keycloak.models.ClaimMask;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -20,6 +21,8 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.ProtocolMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.UserClaimSet;
|
||||
|
@ -104,7 +107,7 @@ public class TokenManager {
|
|||
AccessToken accessToken = initToken(realm, client, user, userSession, clientSession);
|
||||
accessToken.setRealmAccess(refreshToken.getRealmAccess());
|
||||
accessToken.setResourceAccess(refreshToken.getResourceAccess());
|
||||
accessToken = transformToken(accessToken, realm, client, user, userSession, clientSession);
|
||||
accessToken = transformToken(session, accessToken, realm, client, user, userSession, clientSession);
|
||||
|
||||
userSession.setLastSessionRefresh(currentTime);
|
||||
|
||||
|
@ -132,12 +135,12 @@ public class TokenManager {
|
|||
return refreshToken;
|
||||
}
|
||||
|
||||
public AccessToken createClientAccessToken(Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
|
||||
AccessToken token = initToken(realm, client, user, session, clientSession);
|
||||
public AccessToken createClientAccessToken(KeycloakSession session, Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
AccessToken token = initToken(realm, client, user, userSession, clientSession);
|
||||
for (RoleModel role : requestedRoles) {
|
||||
addComposites(token, role);
|
||||
}
|
||||
token = transformToken(token, realm, client, user, session, clientSession);
|
||||
token = transformToken(session, token, realm, client, user, userSession, clientSession);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -232,36 +235,20 @@ public class TokenManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void initClaims(UserClaimSet claimSet, ClientModel model, UserModel user) {
|
||||
claimSet.setSubject(user.getId());
|
||||
|
||||
if (ClaimMask.hasUsername(model.getAllowedClaimsMask())) {
|
||||
claimSet.setPreferredUsername(user.getUsername());
|
||||
}
|
||||
if (ClaimMask.hasEmail(model.getAllowedClaimsMask())) {
|
||||
claimSet.setEmail(user.getEmail());
|
||||
claimSet.setEmailVerified(user.isEmailVerified());
|
||||
}
|
||||
if (ClaimMask.hasName(model.getAllowedClaimsMask())) {
|
||||
claimSet.setFamilyName(user.getLastName());
|
||||
claimSet.setGivenName(user.getFirstName());
|
||||
StringBuilder fullName = new StringBuilder();
|
||||
if (user.getFirstName() != null) fullName.append(user.getFirstName()).append(" ");
|
||||
if (user.getLastName() != null) fullName.append(user.getLastName());
|
||||
claimSet.setName(fullName.toString());
|
||||
}
|
||||
|
||||
Set<ProtocolMapperModel> mappings = model.getProtocolMappers();
|
||||
public AccessToken transformToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
for (ProtocolMapperModel mapping : mappings) {
|
||||
if (!mapping.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) continue;
|
||||
|
||||
}
|
||||
}
|
||||
ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
|
||||
if (mapper == null || !(mapper instanceof OIDCAccessTokenMapper)) continue;
|
||||
token = ((OIDCAccessTokenMapper)mapper).transformToken(token, mapping, session, userSession, clientSession);
|
||||
|
||||
protected AccessToken transformToken(AccessToken token, RealmModel realm, ClientModel client, UserModel user,
|
||||
UserSessionModel session, ClientSessionModel clientSession) {
|
||||
UserClaimSet claimSet = token.getUserClaimSet();
|
||||
initClaims(claimSet, client, user);
|
||||
|
||||
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -350,9 +337,9 @@ public class TokenManager {
|
|||
return this;
|
||||
}
|
||||
|
||||
public AccessTokenResponseBuilder generateAccessToken(String scopeParam, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
|
||||
public AccessTokenResponseBuilder generateAccessToken(KeycloakSession session, String scopeParam, ClientModel client, UserModel user, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
Set<RoleModel> requestedRoles = getAccess(scopeParam, client, user);
|
||||
accessToken = createClientAccessToken(requestedRoles, realm, client, user, session, clientSession);
|
||||
accessToken = createClientAccessToken(session, requestedRoles, realm, client, user, userSession, clientSession);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -395,16 +382,11 @@ public class TokenManager {
|
|||
idToken.getUserClaimSet().setEmail(accessToken.getUserClaimSet().getEmail());
|
||||
idToken.getUserClaimSet().setEmailVerified(accessToken.getUserClaimSet().getEmailVerified());
|
||||
idToken.getUserClaimSet().setLocale(accessToken.getUserClaimSet().getLocale());
|
||||
idToken.getUserClaimSet().setFormattedAddress(accessToken.getUserClaimSet().getFormattedAddress());
|
||||
idToken.getUserClaimSet().setAddress(accessToken.getUserClaimSet().getAddress());
|
||||
idToken.getUserClaimSet().setStreetAddress(accessToken.getUserClaimSet().getStreetAddress());
|
||||
idToken.getUserClaimSet().setLocality(accessToken.getUserClaimSet().getLocality());
|
||||
idToken.getUserClaimSet().setRegion(accessToken.getUserClaimSet().getRegion());
|
||||
idToken.getUserClaimSet().setPostalCode(accessToken.getUserClaimSet().getPostalCode());
|
||||
idToken.getUserClaimSet().setCountry(accessToken.getUserClaimSet().getCountry());
|
||||
idToken.getUserClaimSet().setPhoneNumber(accessToken.getUserClaimSet().getPhoneNumber());
|
||||
idToken.getUserClaimSet().setPhoneNumberVerified(accessToken.getUserClaimSet().getPhoneNumberVerified());
|
||||
idToken.getUserClaimSet().setZoneinfo(accessToken.getUserClaimSet().getZoneinfo());
|
||||
idToken.setOtherClaims(accessToken.getOtherClaims());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ import javax.ws.rs.core.HttpHeaders;
|
|||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author pedroigor
|
||||
|
@ -130,9 +132,8 @@ public class UserInfoService {
|
|||
UserSessionModel userSession = session.sessions().getUserSession(realmModel, accessToken.getSessionState());
|
||||
ClientModel clientModel = realmModel.findClient(accessToken.getIssuedFor());
|
||||
UserModel userModel = userSession.getUser();
|
||||
UserClaimSet userInfo = new UserClaimSet();
|
||||
|
||||
this.tokenManager.initClaims(userInfo, clientModel, userModel);
|
||||
AccessToken userInfo = new AccessToken();
|
||||
this.tokenManager.transformToken(session, userInfo, realmModel, clientModel, userModel, userSession, null);
|
||||
|
||||
event
|
||||
.detail(Details.USERNAME, userModel.getUsername())
|
||||
|
@ -141,7 +142,10 @@ public class UserInfoService {
|
|||
.user(userModel)
|
||||
.success();
|
||||
|
||||
return Cors.add(request, Response.ok(userInfo)).auth().allowedOrigins(accessToken).build();
|
||||
Map<String, Object> claims = new HashMap<String, Object>();
|
||||
claims.putAll(userInfo.getOtherClaims());
|
||||
claims.put("sub", userModel.getId());
|
||||
return Cors.add(request, Response.ok(claims)).auth().allowedOrigins(accessToken).build();
|
||||
} catch (Exception e) {
|
||||
throw new UnauthorizedException("Could not retrieve user info.", e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AttributeMapperHelper {
|
||||
public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
|
||||
public static final String JSON_TYPE = "Claim JSON Type";
|
||||
|
||||
public static Object mapAttributeValue(ProtocolMapperModel mappingModel, Object attributeValue) {
|
||||
if (attributeValue == null) return null;
|
||||
String type = mappingModel.getConfig().get(JSON_TYPE);
|
||||
if (type == null) return attributeValue;
|
||||
if (type.equals("boolean")) {
|
||||
if (attributeValue instanceof Boolean) return attributeValue;
|
||||
if (attributeValue instanceof String) return Boolean.valueOf((String)attributeValue);
|
||||
throw new RuntimeException("cannot map type for token claim");
|
||||
} else if (type.equals("String")) {
|
||||
if (attributeValue instanceof String) return attributeValue;
|
||||
return attributeValue.toString();
|
||||
} else if (type.equals("long")) {
|
||||
if (attributeValue instanceof Long) return attributeValue;
|
||||
if (attributeValue instanceof String) return Long.valueOf((String)attributeValue);
|
||||
throw new RuntimeException("cannot map type for token claim");
|
||||
} else if (type.equals("int")) {
|
||||
if (attributeValue instanceof Integer) return attributeValue;
|
||||
if (attributeValue instanceof String) return Integer.valueOf((String)attributeValue);
|
||||
throw new RuntimeException("cannot map type for token claim");
|
||||
}
|
||||
return attributeValue;
|
||||
}
|
||||
|
||||
public static void mapClaim(AccessToken token, ProtocolMapperModel mappingModel, Object attributeValue) {
|
||||
if (attributeValue == null) return;
|
||||
attributeValue = mapAttributeValue(mappingModel, attributeValue);
|
||||
String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
|
||||
String[] split = protocolClaim.split("\\.");
|
||||
Map<String, Object> jsonObject = token.getOtherClaims();
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (i == split.length - 1) {
|
||||
jsonObject.put(split[i], attributeValue);
|
||||
} else {
|
||||
Map<String, Object> nested = (Map<String, Object>)jsonObject.get(split[i]);
|
||||
if (nested == null) {
|
||||
nested = new HashMap<String, Object>();
|
||||
jsonObject.put(split[i], nested);
|
||||
jsonObject = nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.UserClaimSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Set the 'name' claim to be first + last name.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
static {
|
||||
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-address-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Address Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
UserModel user = userSession.getUser();
|
||||
UserClaimSet.AddressClaimSet addressSet = new UserClaimSet.AddressClaimSet();
|
||||
addressSet.setStreetAddress(user.getAttribute("street"));
|
||||
addressSet.setLocality(user.getAttribute("locality"));
|
||||
addressSet.setRegion(user.getAttribute("region"));
|
||||
addressSet.setPostalCode(user.getAttribute("postal_code"));
|
||||
addressSet.setCountry(user.getAttribute("country"));
|
||||
token.getOtherClaims().put("address", addressSet);
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Set the 'name' claim to be first + last name.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
static {
|
||||
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-full-name-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Full name Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
UserModel user = userSession.getUser();
|
||||
String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
|
||||
String last = user.getLastName() == null ? "" : user.getLastName();
|
||||
token.getOtherClaims().put("name", first + last);
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,11 +7,8 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mappings UserModel.attribute to an ID Token claim. Token claim name can be a full qualified nested object name,
|
||||
|
@ -23,7 +20,6 @@ import java.util.Map;
|
|||
*/
|
||||
public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
|
||||
public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
public static final String USER_MODEL_ATTRIBUTE_NAME = "UserModel Attribute Name";
|
||||
|
||||
|
@ -34,13 +30,15 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
|||
property.setLabel(USER_MODEL_ATTRIBUTE_NAME);
|
||||
property.setHelpText("Name of stored user attribute which is the name of an attribute within the UserModel.attribute map.");
|
||||
configProperties.add(property);
|
||||
property.setName(TOKEN_CLAIM_NAME);
|
||||
property.setLabel(TOKEN_CLAIM_NAME);
|
||||
property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property.setLabel(AttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property.setHelpText("Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created.");
|
||||
configProperties.add(property);
|
||||
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-usermodel-attribute-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
|
@ -48,7 +46,7 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
|||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-usermodel-attribute-mapper";
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,26 +61,8 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
|||
String attributeName = mappingModel.getConfig().get(USER_MODEL_ATTRIBUTE_NAME);
|
||||
String attributeValue = user.getAttribute(attributeName);
|
||||
if (attributeValue == null) return token;
|
||||
mapClaim(token, mappingModel, attributeValue);
|
||||
AttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
|
||||
return token;
|
||||
}
|
||||
|
||||
protected static void mapClaim(AccessToken token, ProtocolMapperModel mappingModel, String attributeValue) {
|
||||
if (attributeValue == null) return;
|
||||
String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
|
||||
String[] split = protocolClaim.split(".");
|
||||
Map<String, Object> jsonObject = token.getOtherClaims();
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
if (i == split.length - 1) {
|
||||
jsonObject.put(split[i], attributeValue);
|
||||
} else {
|
||||
Map<String, Object> nested = (Map<String, Object>)jsonObject.get(split[i]);
|
||||
if (nested == null) {
|
||||
nested = new HashMap<String, Object>();
|
||||
jsonObject.put(split[i], nested);
|
||||
jsonObject = nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ import org.keycloak.representations.AccessToken;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mappings UserModel property (the property name of a getter method) to an ID Token claim. Token claim name can be a full qualified nested object name,
|
||||
|
@ -32,20 +30,22 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
|
|||
property.setLabel(USER_MODEL_PROPERTY);
|
||||
property.setHelpText("Name of the property method in the UserModel interface. For example, a value of 'email' would reference the UserModel.getEmail() method.");
|
||||
configProperties.add(property);
|
||||
property.setName(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
|
||||
property.setLabel(OIDCUserAttributeMapper.TOKEN_CLAIM_NAME);
|
||||
property.setName(AttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property.setLabel(AttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property.setHelpText("Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created.");
|
||||
configProperties.add(property);
|
||||
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-usermodel-property-mapper";
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,7 +59,7 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
|
|||
UserModel user = userSession.getUser();
|
||||
String propertyName = mappingModel.getConfig().get(USER_MODEL_PROPERTY);
|
||||
String propertyValue = getUserModelValue(user,propertyName);
|
||||
OIDCUserAttributeMapper.mapClaim(token, mappingModel, propertyValue);
|
||||
AttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
|
|||
}
|
||||
}
|
||||
}
|
||||
for ( Map<String, ProviderFactory> factories : factoriesMap.values()) {
|
||||
for (ProviderFactory factory : factories.values()) {
|
||||
factory.postInit(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public KeycloakSession create() {
|
||||
|
|
|
@ -1 +1,8 @@
|
|||
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
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
org.keycloak.protocol.LoginProtocolSpi
|
||||
org.keycloak.protocol.ProtocolMapperSpi
|
||||
org.keycloak.exportimport.ApplicationImportSpi
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue