commit
58299d3373
31 changed files with 698 additions and 269 deletions
|
@ -5,14 +5,24 @@
|
|||
<column name="ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="PROTOCOL_CLAIM" type="VARCHAR(255)"/>
|
||||
<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="SOURCE_ATTRIBUTE" type="VARCHAR(255)"/>
|
||||
<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)"/>
|
||||
</createTable>
|
||||
<createTable tableName="PROTOCOL_MAPPER_CONFIG">
|
||||
<column name="PROTOCOL_MAPPER_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="VALUE" type="CLOB"/>
|
||||
<column name="NAME" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createTable tableName="CLAIM_TYPE">
|
||||
<column name="ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
|
@ -80,11 +90,13 @@
|
|||
<addPrimaryKey columnNames="INTERNAL_ID" constraintName="CONSTRAINT_2B" tableName="IDENTITY_PROVIDER"/>
|
||||
<addPrimaryKey columnNames="IDENTITY_PROVIDER, USER_ID" constraintName="CONSTRAINT_40" tableName="FEDERATED_IDENTITY"/>
|
||||
<addPrimaryKey columnNames="IDENTITY_PROVIDER_ID, NAME" constraintName="CONSTRAINT_D" tableName="IDENTITY_PROVIDER_CONFIG"/>
|
||||
<addPrimaryKey columnNames="PROTOCOL_MAPPER_ID, NAME" constraintName="CONSTRAINT_PMConfig" tableName="PROTOCOL_MAPPER_CONFIG"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="IDENTITY_PROVIDER" constraintName="FK2B4EBC52AE5C3B34" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="CLAIM_TYPE" constraintName="FK_CT_REALM" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="PROTOCOL_MAPPER" constraintName="FK_PCM_REALM" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
<addForeignKeyConstraint baseColumnNames="USER_ID" baseTableName="FEDERATED_IDENTITY" constraintName="FK404288B92EF007A6" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="USER_ENTITY"/>
|
||||
<addForeignKeyConstraint baseColumnNames="IDENTITY_PROVIDER_ID" baseTableName="IDENTITY_PROVIDER_CONFIG" constraintName="FKDC4897CF864C4E43" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
|
||||
<addForeignKeyConstraint baseColumnNames="PROTOCOL_MAPPER_ID" baseTableName="PROTOCOL_MAPPER_CONFIG" constraintName="FK_PMConfig" deferrable="false" initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="ID" referencedTableName="PROTOCOL_MAPPER"/>
|
||||
<addForeignKeyConstraint baseColumnNames="INTERNAL_ID" baseTableName="CLIENT_ALLOWED_IDENTITY_PROVIDER" constraintName="FK_7CELWNIBJI49AVXSRTUF6XJ12" referencedColumnNames="INTERNAL_ID" referencedTableName="IDENTITY_PROVIDER"/>
|
||||
<addUniqueConstraint columnNames="INTERNAL_ID,CLIENT_ID" constraintName="UK_7CAELWNIBJI49AVXSRTUF6XJ12" tableName="CLIENT_ALLOWED_IDENTITY_PROVIDER"/>
|
||||
<addForeignKeyConstraint baseColumnNames="MAPPING_ID" baseTableName="CLIENT_PROTOCOL_MAPPER" constraintName="FK_CPCM" referencedColumnNames="ID" referencedTableName="PROTOCOL_MAPPER"/>
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ProtocolMapperRepresentation {
|
||||
protected String id;
|
||||
protected String protocolClaim;
|
||||
protected String name;
|
||||
protected String protocol;
|
||||
protected String source;
|
||||
protected String sourceAttribute;
|
||||
protected String protocolMapper;
|
||||
protected boolean appliedByDefault;
|
||||
protected boolean consentRequired;
|
||||
protected String consentText;
|
||||
protected Map<String, String> config = new HashMap<String, String>();
|
||||
|
||||
|
||||
public String getId() {
|
||||
|
@ -22,12 +26,12 @@ public class ProtocolMapperRepresentation {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getProtocolClaim() {
|
||||
return protocolClaim;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setProtocolClaim(String protocolClaim) {
|
||||
this.protocolClaim = protocolClaim;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
|
@ -38,14 +42,6 @@ public class ProtocolMapperRepresentation {
|
|||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getSourceAttribute() {
|
||||
return sourceAttribute;
|
||||
}
|
||||
|
||||
public void setSourceAttribute(String sourceAttribute) {
|
||||
this.sourceAttribute = sourceAttribute;
|
||||
}
|
||||
|
||||
public boolean isAppliedByDefault() {
|
||||
return appliedByDefault;
|
||||
}
|
||||
|
@ -54,14 +50,6 @@ public class ProtocolMapperRepresentation {
|
|||
this.appliedByDefault = appliedByDefault;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getProtocolMapper() {
|
||||
return protocolMapper;
|
||||
}
|
||||
|
@ -69,4 +57,28 @@ public class ProtocolMapperRepresentation {
|
|||
public void setProtocolMapper(String protocolMapper) {
|
||||
this.protocolMapper = protocolMapper;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
||||
public void setConsentRequired(boolean consentRequired) {
|
||||
this.consentRequired = consentRequired;
|
||||
}
|
||||
|
||||
public String getConsentText() {
|
||||
return consentText;
|
||||
}
|
||||
|
||||
public void setConsentText(String consentText) {
|
||||
this.consentText = consentText;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"use-resource-role-mappings" : false,
|
||||
"enable-cors" : true,
|
||||
"cors-max-age" : 1000,
|
||||
"cors-allowed-methods" : [ "POST", "PUT", "DELETE", "GET" ],
|
||||
"cors-allowed-methods" : "POST, PUT, DELETE, GET",
|
||||
"bearer-only" : false,
|
||||
"enable-basic-auth" : false,
|
||||
"expose-token" : true,
|
||||
|
|
|
@ -218,7 +218,7 @@
|
|||
<span tooltip-placement="right" tooltip="Allowed CORS origins. Only useful if the client adapter has CORS processing enabled." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<fieldset data-ng-show="protocol == 'saml'">
|
||||
<legend collapsed><span class="text">Fine Grain SAML Endpoint Configuration</span> <span tooltip-placement="right" tooltip="Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service." class="fa fa-info-circle"></span></legend>
|
||||
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
|
||||
<label class="col-sm-2 control-label" for="consumerServicePost">Assertion Consumer Service POST Binding URL</label>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Specifies a mapping from user data to a protocol claim assertion. If protocolMapper is set, this points
|
||||
* to a @Provider that will perform the mapping. If you have this set, then no other attributes of this class need to be set.
|
||||
|
@ -10,21 +12,14 @@ package org.keycloak.models;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ProtocolMapperModel {
|
||||
public static enum Source {
|
||||
USER_MODEL,
|
||||
USER_ATTRIBUTE,
|
||||
USER_SESSION_NOTE,
|
||||
CLIENT_SESSION_NOTE
|
||||
}
|
||||
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String protocolClaim;
|
||||
protected String protocol;
|
||||
protected Source source;
|
||||
protected String sourceAttribute;
|
||||
protected String protocolMapper;
|
||||
protected boolean consentRequired;
|
||||
protected String consentText;
|
||||
protected boolean appliedByDefault;
|
||||
protected Map<String, String> config;
|
||||
|
||||
|
||||
public String getId() {
|
||||
|
@ -43,14 +38,6 @@ public class ProtocolMapperModel {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProtocolClaim() {
|
||||
return protocolClaim;
|
||||
}
|
||||
|
||||
public void setProtocolClaim(String protocolClaim) {
|
||||
this.protocolClaim = protocolClaim;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
@ -59,14 +46,6 @@ public class ProtocolMapperModel {
|
|||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getSourceAttribute() {
|
||||
return sourceAttribute;
|
||||
}
|
||||
|
||||
public void setSourceAttribute(String sourceAttribute) {
|
||||
this.sourceAttribute = sourceAttribute;
|
||||
}
|
||||
|
||||
public boolean isAppliedByDefault() {
|
||||
return appliedByDefault;
|
||||
}
|
||||
|
@ -75,14 +54,6 @@ public class ProtocolMapperModel {
|
|||
this.appliedByDefault = appliedByDefault;
|
||||
}
|
||||
|
||||
public Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(Source source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getProtocolMapper() {
|
||||
return protocolMapper;
|
||||
}
|
||||
|
@ -91,6 +62,30 @@ public class ProtocolMapperModel {
|
|||
this.protocolMapper = protocolMapper;
|
||||
}
|
||||
|
||||
public boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
||||
public void setConsentRequired(boolean consentRequired) {
|
||||
this.consentRequired = consentRequired;
|
||||
}
|
||||
|
||||
public String getConsentText() {
|
||||
return consentText;
|
||||
}
|
||||
|
||||
public void setConsentText(String consentText) {
|
||||
this.consentText = consentText;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
31
model/api/src/main/java/org/keycloak/models/RealmListenerHelper.java
Executable file
31
model/api/src/main/java/org/keycloak/models/RealmListenerHelper.java
Executable file
|
@ -0,0 +1,31 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RealmListenerHelper {
|
||||
protected LinkedList<RealmProvider.RealmCreationListener> list = new LinkedList<RealmProvider.RealmCreationListener>();
|
||||
|
||||
public void registerListener(RealmProvider.RealmCreationListener listener) {
|
||||
synchronized (list) {
|
||||
list.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterListener(RealmProvider.RealmCreationListener listener) {
|
||||
synchronized (list) {
|
||||
list.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void executeCreationListeners(RealmModel realm) {
|
||||
synchronized (list) {
|
||||
for (RealmProvider.RealmCreationListener listener : list) {
|
||||
listener.created(realm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,10 +9,16 @@ import java.util.List;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface RealmProvider extends Provider {
|
||||
public interface RealmCreationListener {
|
||||
void created(RealmModel realm);
|
||||
}
|
||||
|
||||
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
|
||||
|
||||
RealmModel createRealm(String name);
|
||||
RealmModel createRealm(String id, String name);
|
||||
void registerListener(RealmCreationListener listener);
|
||||
void unregisterListener(RealmCreationListener listener);
|
||||
RealmModel getRealm(String id);
|
||||
RealmModel getRealmByName(String name);
|
||||
|
||||
|
|
|
@ -2,18 +2,21 @@ package org.keycloak.models.entities;
|
|||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ProtocolMapperEntity {
|
||||
protected String id;
|
||||
protected String protocolClaim;
|
||||
protected String name;
|
||||
protected String protocol;
|
||||
protected ProtocolMapperModel.Source source;
|
||||
protected String sourceAttribute;
|
||||
protected String protocolMapper;
|
||||
protected boolean appliedByDefault;
|
||||
protected boolean consentRequired;
|
||||
protected String consentText;
|
||||
protected Map<String, String> config;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -23,12 +26,12 @@ public class ProtocolMapperEntity {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getProtocolClaim() {
|
||||
return protocolClaim;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setProtocolClaim(String protocolClaim) {
|
||||
this.protocolClaim = protocolClaim;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
|
@ -39,22 +42,6 @@ public class ProtocolMapperEntity {
|
|||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public ProtocolMapperModel.Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(ProtocolMapperModel.Source source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSourceAttribute() {
|
||||
return sourceAttribute;
|
||||
}
|
||||
|
||||
public void setSourceAttribute(String sourceAttribute) {
|
||||
this.sourceAttribute = sourceAttribute;
|
||||
}
|
||||
|
||||
public boolean isAppliedByDefault() {
|
||||
return appliedByDefault;
|
||||
}
|
||||
|
@ -70,4 +57,28 @@ public class ProtocolMapperEntity {
|
|||
public void setProtocolMapper(String protocolMapper) {
|
||||
this.protocolMapper = protocolMapper;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
||||
public void setConsentRequired(boolean consentRequired) {
|
||||
this.consentRequired = consentRequired;
|
||||
}
|
||||
|
||||
public String getConsentText() {
|
||||
return consentText;
|
||||
}
|
||||
|
||||
public void setConsentText(String consentText) {
|
||||
this.consentText = consentText;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
|
|||
private List<UserFederationProviderEntity> userFederationProviders = new ArrayList<UserFederationProviderEntity>();
|
||||
private List<IdentityProviderEntity> identityProviders = new ArrayList<IdentityProviderEntity>();
|
||||
private List<ClaimTypeEntity> claimTypes = new ArrayList<ClaimTypeEntity>();
|
||||
private List<ProtocolMapperEntity> claimMappings = new ArrayList<ProtocolMapperEntity>();
|
||||
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
|
||||
private Map<String, String> browserSecurityHeaders = new HashMap<String, String>();
|
||||
private Map<String, String> smtpConfig = new HashMap<String, String>();
|
||||
|
@ -401,12 +401,12 @@ public class RealmEntity extends AbstractIdentifiableEntity {
|
|||
this.claimTypes = claimTypes;
|
||||
}
|
||||
|
||||
public List<ProtocolMapperEntity> getClaimMappings() {
|
||||
return claimMappings;
|
||||
public List<ProtocolMapperEntity> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setClaimMappings(List<ProtocolMapperEntity> claimMappings) {
|
||||
this.claimMappings = claimMappings;
|
||||
public void setProtocolMappers(List<ProtocolMapperEntity> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -341,11 +341,14 @@ public class ModelToRepresentation {
|
|||
ProtocolMapperRepresentation rep = new ProtocolMapperRepresentation();
|
||||
rep.setId(model.getId());
|
||||
rep.setProtocol(model.getProtocol());
|
||||
rep.setProtocolClaim(model.getProtocolClaim());
|
||||
rep.setSourceAttribute(model.getSourceAttribute());
|
||||
rep.setSource(model.getSource().name());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.putAll(model.getConfig());
|
||||
rep.setConfig(config);
|
||||
rep.setName(model.getName());
|
||||
rep.setProtocolMapper(model.getProtocolMapper());
|
||||
rep.setAppliedByDefault(model.isAppliedByDefault());
|
||||
rep.setConsentText(model.getConsentText());
|
||||
rep.setConsentRequired(model.isConsentRequired());
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ public class RepresentationToModel {
|
|||
|
||||
importIdentityProviders(rep, newRealm);
|
||||
importClaimTypes(rep, newRealm);
|
||||
importProtocolClaimMappings(rep, newRealm);
|
||||
importProtocolMappers(rep, newRealm);
|
||||
|
||||
if (rep.getApplications() != null) {
|
||||
Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
|
||||
|
@ -772,10 +772,15 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
private static void importProtocolClaimMappings(RealmRepresentation rep, RealmModel newRealm) {
|
||||
private static void importProtocolMappers(RealmRepresentation rep, RealmModel newRealm) {
|
||||
if (rep.getProtocolClaimMappings() != 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) {
|
||||
newRealm.addProtocolMapper(toModel(representation));
|
||||
} else {
|
||||
newRealm.updateProtocolMapper(toModel(representation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -808,12 +813,13 @@ public class RepresentationToModel {
|
|||
public static ProtocolMapperModel toModel(ProtocolMapperRepresentation rep) {
|
||||
ProtocolMapperModel model = new ProtocolMapperModel();
|
||||
model.setId(rep.getId());
|
||||
model.setName(rep.getName());
|
||||
model.setAppliedByDefault(rep.isAppliedByDefault());
|
||||
model.setSource(ProtocolMapperModel.Source.valueOf(rep.getSource()));
|
||||
model.setSourceAttribute(rep.getSourceAttribute());
|
||||
model.setConsentRequired(rep.isConsentRequired());
|
||||
model.setConsentText(rep.getConsentText());
|
||||
model.setProtocol(rep.getProtocol());
|
||||
model.setProtocolClaim(rep.getProtocolClaim());
|
||||
model.setProtocolMapper(rep.getProtocolMapper());
|
||||
model.setConfig(rep.getConfig());
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,17 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
session.getTransaction().enlistAfterCompletion(getTransaction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(RealmCreationListener listener) {
|
||||
getDelegate().registerListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(RealmCreationListener listener) {
|
||||
getDelegate().unregisterListener(listener);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cache.isEnabled();
|
||||
|
|
|
@ -38,6 +38,16 @@ public class NoCacheRealmProvider implements CacheRealmProvider {
|
|||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(RealmCreationListener listener) {
|
||||
getDelegate().registerListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(RealmCreationListener listener) {
|
||||
getDelegate().unregisterListener(listener);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void registerRealmInvalidation(String id) {
|
||||
}
|
||||
|
|
|
@ -362,11 +362,16 @@ public abstract class ClientAdapter implements ClientModel {
|
|||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(ProtocolMapperModel.Source.valueOf(entity.getSource()));
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) {
|
||||
config.putAll(entity.getConfig());
|
||||
}
|
||||
mapping.setConfig(config);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
return mappings;
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.models.jpa;
|
|||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmListenerHelper;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -25,10 +26,24 @@ import java.util.List;
|
|||
public class JpaRealmProvider implements RealmProvider {
|
||||
private final KeycloakSession session;
|
||||
protected EntityManager em;
|
||||
protected RealmListenerHelper listeners;
|
||||
|
||||
public JpaRealmProvider(KeycloakSession session, EntityManager em) {
|
||||
|
||||
public JpaRealmProvider(KeycloakSession session, EntityManager em, RealmListenerHelper listeners) {
|
||||
this.session = session;
|
||||
this.em = em;
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(RealmCreationListener listener) {
|
||||
listeners.registerListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(RealmCreationListener listener) {
|
||||
listeners.unregisterListener(listener);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,7 +58,9 @@ public class JpaRealmProvider implements RealmProvider {
|
|||
realm.setId(id);
|
||||
em.persist(realm);
|
||||
em.flush();
|
||||
return new RealmAdapter(session, em, realm);
|
||||
RealmModel model = new RealmAdapter(session, em, realm);
|
||||
listeners.executeCreationListeners(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.models.jpa;
|
|||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmListenerHelper;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RealmProviderFactory;
|
||||
|
||||
|
@ -14,6 +15,8 @@ import javax.persistence.EntityManager;
|
|||
*/
|
||||
public class JpaRealmProviderFactory implements RealmProviderFactory {
|
||||
|
||||
protected RealmListenerHelper listeners = new RealmListenerHelper();
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
@ -26,7 +29,7 @@ public class JpaRealmProviderFactory implements RealmProviderFactory {
|
|||
@Override
|
||||
public RealmProvider create(KeycloakSession session) {
|
||||
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
|
||||
return new JpaRealmProvider(session, em);
|
||||
return new JpaRealmProvider(session, em, listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1262,12 +1262,17 @@ public class RealmAdapter implements RealmModel {
|
|||
for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(ProtocolMapperModel.Source.valueOf(entity.getSource()));
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) {
|
||||
config.putAll(entity.getConfig());
|
||||
}
|
||||
mapping.setConfig(config);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
return mappings;
|
||||
|
@ -1278,26 +1283,29 @@ public class RealmAdapter implements RealmModel {
|
|||
String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
|
||||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
entity.setId(id);
|
||||
entity.setSourceAttribute(model.getSourceAttribute());
|
||||
entity.setName(model.getName());
|
||||
entity.setProtocol(model.getProtocol());
|
||||
entity.setProtocolClaim(model.getProtocolClaim());
|
||||
entity.setSource(model.getSource().name());
|
||||
entity.setProtocolMapper(model.getProtocolMapper());
|
||||
entity.setAppliedByDefault(model.isAppliedByDefault());
|
||||
entity.setRealm(realm);
|
||||
entity.setConfig(model.getConfig());
|
||||
entity.setConsentRequired(model.isConsentRequired());
|
||||
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.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(ProtocolMapperModel.Source.valueOf(entity.getSource()));
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setConfig(model.getConfig());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
return mapping;
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolClaimMapping(String id) {
|
||||
protected ProtocolMapperEntity getProtocolMapper(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolClaimMappings()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
|
@ -1309,7 +1317,7 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity toDelete = getProtocolClaimMapping(mapping.getId());
|
||||
ProtocolMapperEntity toDelete = getProtocolMapper(mapping.getId());
|
||||
if (toDelete != null) {
|
||||
realm.getProtocolClaimMappings().remove(toDelete);
|
||||
em.remove(toDelete);
|
||||
|
@ -1319,27 +1327,35 @@ public class RealmAdapter implements RealmModel {
|
|||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolClaimMapping(mapping.getId());
|
||||
entity.setProtocol(mapping.getProtocol());
|
||||
entity.setProtocolClaim(mapping.getProtocolClaim());
|
||||
ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setAppliedByDefault(mapping.isAppliedByDefault());
|
||||
entity.setSource(mapping.getSource().name());
|
||||
entity.setSourceAttribute(mapping.getSourceAttribute());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
entity.setConsentText(mapping.getConsentText());
|
||||
if (entity.getConfig() == null) {
|
||||
entity.setConfig(mapping.getConfig());
|
||||
} else {
|
||||
entity.getConfig().clear();
|
||||
entity.getConfig().putAll(mapping.getConfig());
|
||||
}
|
||||
em.flush();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolClaimMapping(id);
|
||||
ProtocolMapperEntity entity = getProtocolMapper(id);
|
||||
if (entity == null) return null;
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(ProtocolMapperModel.Source.valueOf(entity.getSource()));
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) config.putAll(entity.getConfig());
|
||||
mapping.setConfig(config);
|
||||
return mapping;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,18 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -25,18 +29,25 @@ public class ProtocolMapperEntity {
|
|||
@Column(name="ID", length = 36)
|
||||
protected String id;
|
||||
|
||||
@Column(name = "PROTOCOL_CLAIM")
|
||||
protected String protocolClaim;
|
||||
@Column(name="NAME")
|
||||
protected String name;
|
||||
|
||||
@Column(name = "PROTOCOL")
|
||||
protected String protocol;
|
||||
@Column(name = "SOURCE")
|
||||
protected String source;
|
||||
@Column(name = "SOURCE_ATTRIBUTE")
|
||||
protected String sourceAttribute;
|
||||
@Column(name = "PROTOCOL_MAPPER_NAME")
|
||||
protected String protocolMapper;
|
||||
@Column(name = "APPLIED_BY_DEFAULT")
|
||||
protected boolean appliedByDefault;
|
||||
@Column(name="CONSENT_REQUIRED")
|
||||
protected boolean consentRequired;
|
||||
@Column(name="CONSENT_TEXT")
|
||||
protected String consentText;
|
||||
|
||||
@ElementCollection
|
||||
@MapKeyColumn(name="name")
|
||||
@Column(name="value")
|
||||
@CollectionTable(name="PROTOCOL_MAPPER_CONFIG", joinColumns={ @JoinColumn(name="PROTOCOL_MAPPER_ID") })
|
||||
private Map<String, String> config;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "REALM_ID")
|
||||
|
@ -50,12 +61,12 @@ public class ProtocolMapperEntity {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
public String getProtocolClaim() {
|
||||
return protocolClaim;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setProtocolClaim(String protocolClaim) {
|
||||
this.protocolClaim = protocolClaim;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
|
@ -66,22 +77,6 @@ public class ProtocolMapperEntity {
|
|||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSourceAttribute() {
|
||||
return sourceAttribute;
|
||||
}
|
||||
|
||||
public void setSourceAttribute(String sourceAttribute) {
|
||||
this.sourceAttribute = sourceAttribute;
|
||||
}
|
||||
|
||||
public String getProtocolMapper() {
|
||||
return protocolMapper;
|
||||
}
|
||||
|
@ -98,6 +93,14 @@ public class ProtocolMapperEntity {
|
|||
this.appliedByDefault = appliedByDefault;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public RealmEntity getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
@ -106,6 +109,22 @@ public class ProtocolMapperEntity {
|
|||
this.realm = realm;
|
||||
}
|
||||
|
||||
public boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
||||
public void setConsentRequired(boolean consentRequired) {
|
||||
this.consentRequired = consentRequired;
|
||||
}
|
||||
|
||||
public String getConsentText() {
|
||||
return consentText;
|
||||
}
|
||||
|
||||
public void setConsentText(String consentText) {
|
||||
this.consentText = consentText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
|||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmListenerHelper;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -27,10 +28,12 @@ public class MongoRealmProvider implements RealmProvider {
|
|||
|
||||
private final MongoStoreInvocationContext invocationContext;
|
||||
private final KeycloakSession session;
|
||||
protected RealmListenerHelper listeners;
|
||||
|
||||
public MongoRealmProvider(KeycloakSession session, MongoStoreInvocationContext invocationContext) {
|
||||
public MongoRealmProvider(KeycloakSession session, MongoStoreInvocationContext invocationContext, RealmListenerHelper listeners) {
|
||||
this.session = session;
|
||||
this.invocationContext = invocationContext;
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,6 +41,18 @@ public class MongoRealmProvider implements RealmProvider {
|
|||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(RealmCreationListener listener) {
|
||||
listeners.registerListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(RealmCreationListener listener) {
|
||||
listeners.unregisterListener(listener);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public RealmModel createRealm(String name) {
|
||||
return createRealm(KeycloakModelUtils.generateId(), name);
|
||||
|
@ -51,7 +66,9 @@ public class MongoRealmProvider implements RealmProvider {
|
|||
|
||||
getMongoStore().insertEntity(newRealm, invocationContext);
|
||||
|
||||
return new RealmAdapter(session, newRealm, invocationContext);
|
||||
RealmModel model = new RealmAdapter(session, newRealm, invocationContext);
|
||||
listeners.executeCreationListeners(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
|
|||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.mongo.MongoConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmListenerHelper;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RealmProviderFactory;
|
||||
|
||||
|
@ -15,6 +16,8 @@ import org.keycloak.models.RealmProviderFactory;
|
|||
public class MongoRealmProviderFactory implements RealmProviderFactory {
|
||||
protected static final Logger logger = Logger.getLogger(MongoRealmProviderFactory.class);
|
||||
|
||||
protected RealmListenerHelper listeners = new RealmListenerHelper();
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "mongo";
|
||||
|
@ -27,7 +30,7 @@ public class MongoRealmProviderFactory implements RealmProviderFactory {
|
|||
@Override
|
||||
public RealmProvider create(KeycloakSession session) {
|
||||
MongoConnectionProvider connection = session.getProvider(MongoConnectionProvider.class);
|
||||
return new MongoRealmProvider(session, connection.getInvocationContext());
|
||||
return new MongoRealmProvider(session, connection.getInvocationContext(), listeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -789,14 +789,19 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
Set<ProtocolMapperModel> result = new HashSet<ProtocolMapperModel>();
|
||||
for (ProtocolMapperEntity entity : realm.getClaimMappings()) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setSource(entity.getSource());
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) {
|
||||
config.putAll(entity.getConfig());
|
||||
}
|
||||
mapping.setConfig(config);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -806,30 +811,31 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
if (model.getId() != null) entity.setId(model.getId());
|
||||
else entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setSourceAttribute(model.getSourceAttribute());
|
||||
entity.setProtocol(model.getProtocol());
|
||||
entity.setProtocolClaim(model.getProtocolClaim());
|
||||
entity.setSource(model.getSource());
|
||||
entity.setName(model.getName());
|
||||
entity.setAppliedByDefault(model.isAppliedByDefault());
|
||||
entity.setProtocolMapper(model.getProtocolMapper());
|
||||
realm.getClaimMappings().add(entity);
|
||||
entity.setConfig(model.getConfig());
|
||||
entity.setConsentRequired(model.isConsentRequired());
|
||||
entity.setConsentText(model.getConsentText());
|
||||
realm.getProtocolMappers().add(entity);
|
||||
updateRealm();
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(entity.getSource());
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
for (ProtocolMapperEntity entity : realm.getClaimMappings()) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getId().equals(mapping.getId())) {
|
||||
realm.getClaimMappings().remove(entity);
|
||||
realm.getProtocolMappers().remove(entity);
|
||||
updateRealm();
|
||||
break;
|
||||
}
|
||||
|
@ -837,8 +843,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolClaimMapping(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getClaimMappings()) {
|
||||
protected ProtocolMapperEntity getProtocolMapper(String id) {
|
||||
for (ProtocolMapperEntity entity : realm.getProtocolMappers()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
}
|
||||
|
@ -850,29 +856,36 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolClaimMapping(mapping.getId());
|
||||
entity.setProtocol(mapping.getProtocol());
|
||||
entity.setProtocolClaim(mapping.getProtocolClaim());
|
||||
ProtocolMapperEntity entity = getProtocolMapper(mapping.getId());
|
||||
entity.setAppliedByDefault(mapping.isAppliedByDefault());
|
||||
entity.setSource(mapping.getSource());
|
||||
entity.setSourceAttribute(mapping.getSourceAttribute());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
entity.setConsentText(mapping.getConsentText());
|
||||
if (entity.getConfig() != null) {
|
||||
entity.getConfig().clear();
|
||||
entity.getConfig().putAll(mapping.getConfig());
|
||||
} else {
|
||||
entity.setConfig(mapping.getConfig());
|
||||
}
|
||||
updateRealm();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolClaimMapping(id);
|
||||
ProtocolMapperEntity entity = getProtocolMapper(id);
|
||||
if (entity == null) return null;
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolClaim(entity.getProtocolClaim());
|
||||
mapping.setAppliedByDefault(entity.isAppliedByDefault());
|
||||
mapping.setSource(entity.getSource());
|
||||
mapping.setSourceAttribute(entity.getSourceAttribute());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) config.putAll(config);
|
||||
mapping.setConfig(config);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.keycloak.protocol;
|
|||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -10,4 +12,36 @@ import org.keycloak.provider.ProviderFactory;
|
|||
public interface ProtocolMapper extends Provider, ProviderFactory<ProtocolMapper> {
|
||||
String getProtocol();
|
||||
String getDisplayType();
|
||||
|
||||
public static class ConfigProperty {
|
||||
protected String name;
|
||||
protected String label;
|
||||
protected String helpText;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getHelpText() {
|
||||
return helpText;
|
||||
}
|
||||
|
||||
public void setHelpText(String helpText) {
|
||||
this.helpText = helpText;
|
||||
}
|
||||
}
|
||||
|
||||
List<ConfigProperty> getConfigProperties();
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package org.keycloak.protocol.oidc;
|
||||
|
||||
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.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mappings user data to an ID Token claim. Source can be from UserModel.getAttributes(), a get method on UserModel, UserSession.getNote
|
||||
* or ClientSession.getNote. Claim can be a full qualified nested object name, i.e. "address.country". This will create a nested
|
||||
* json object within the toke claim.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCAttributeToTokenMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenTransformer {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-attribute-claim-mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Attribute Claim Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
String attributeValue = null;
|
||||
UserModel user = userSession.getUser();
|
||||
switch (mappingModel.getSource()) {
|
||||
case USER_ATTRIBUTE:
|
||||
attributeValue = user.getAttribute(mappingModel.getSourceAttribute());
|
||||
break;
|
||||
case USER_SESSION_NOTE:
|
||||
attributeValue = userSession.getNote(mappingModel.getSourceAttribute());
|
||||
break;
|
||||
case CLIENT_SESSION_NOTE:
|
||||
attributeValue = clientSession.getNote(mappingModel.getSourceAttribute());
|
||||
break;
|
||||
case USER_MODEL:
|
||||
attributeValue = getUserModelValue(user, mappingModel);
|
||||
break;
|
||||
}
|
||||
if (attributeValue == null) return token;
|
||||
String[] split = mappingModel.getProtocolClaim().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
protected String getUserModelValue(UserModel user, ProtocolMapperModel model) {
|
||||
String sourceAttribute = model.getSourceAttribute();
|
||||
if (sourceAttribute == null) return null;
|
||||
|
||||
String methodName = "get" + Character.toUpperCase(sourceAttribute.charAt(0)) + sourceAttribute.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;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ public class OIDCLoginProtocolFactory implements LoginProtocolFactory {
|
|||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
System.out.println("here");
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package org.keycloak.protocol.oidc;
|
||||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.protocol.ProtocolMapper;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -27,7 +28,6 @@ public abstract class AbstractOIDCProtocolMapper implements ProtocolMapper {
|
|||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.protocol.oidc;
|
||||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -10,7 +10,7 @@ import org.keycloak.representations.AccessToken;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface OIDCAccessTokenTransformer {
|
||||
public interface OIDCAccessTokenMapper {
|
||||
|
||||
AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession);
|
|
@ -0,0 +1,60 @@
|
|||
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.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mappings UserSessionModel.note to an ID Token claim. Token claim name can be a full qualified nested object name,
|
||||
* i.e. "address.country". This will create a nested
|
||||
* json object within the toke claim.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCClientSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
public static final String CLIENT_SESSION_NOTE = "ClientSession Note";
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName(CLIENT_SESSION_NOTE);
|
||||
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.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 List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-client-session-note-mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "ClientSession Note Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
String note = mappingModel.getConfig().get(CLIENT_SESSION_NOTE);
|
||||
String noteValue = clientSession.getNote(note);
|
||||
OIDCUserAttributeMapper.mapClaim(token, mappingModel, noteValue);
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
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.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,
|
||||
* i.e. "address.country". This will create a nested
|
||||
* json object within the toke claim.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
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";
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName(USER_MODEL_ATTRIBUTE_NAME);
|
||||
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.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 List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-usermodel-attribute-mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "UserModel Attribute Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
UserModel user = userSession.getUser();
|
||||
String attributeName = mappingModel.getConfig().get(USER_MODEL_ATTRIBUTE_NAME);
|
||||
String attributeValue = user.getAttribute(attributeName);
|
||||
if (attributeValue == null) return token;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
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.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,
|
||||
* i.e. "address.country". This will create a nested
|
||||
* json object within the toke claim.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
public static final String USER_MODEL_PROPERTY = "UserModel Property";
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName(USER_MODEL_PROPERTY);
|
||||
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.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 List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-usermodel-property-mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "UserModel Property Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
UserModel user = userSession.getUser();
|
||||
String propertyName = mappingModel.getConfig().get(USER_MODEL_PROPERTY);
|
||||
String propertyValue = getUserModelValue(user,propertyName);
|
||||
OIDCUserAttributeMapper.mapClaim(token, mappingModel, propertyValue);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
protected String getUserModelValue(UserModel user, String propertyName) {
|
||||
|
||||
String methodName = "get" + 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
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.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mappings UserSessionModel.note to an ID Token claim. Token claim name can be a full qualified nested object name,
|
||||
* i.e. "address.country". This will create a nested
|
||||
* json object within the toke claim.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCUserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
public static final String USER_SESSION_NOTE = "UserSession Note";
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName(USER_SESSION_NOTE);
|
||||
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.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 List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "oidc-user-session-note-mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "UserSession Note Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
String note = mappingModel.getConfig().get(USER_SESSION_NOTE);
|
||||
String noteValue = userSession.getNote(note);
|
||||
OIDCUserAttributeMapper.mapClaim(token, mappingModel, noteValue);
|
||||
return token;
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +1 @@
|
|||
org.keycloak.protocol.oidc.OIDCAttributeToTokenMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper
|
Loading…
Reference in a new issue