fixes
This commit is contained in:
parent
5e12ee3e7a
commit
753feae49e
15 changed files with 406 additions and 206 deletions
|
@ -16,6 +16,8 @@ public class ProtocolMapperTypeRepresentation {
|
||||||
protected String name;
|
protected String name;
|
||||||
protected String label;
|
protected String label;
|
||||||
protected String helpText;
|
protected String helpText;
|
||||||
|
protected String type;
|
||||||
|
protected String defaultValue;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
|
@ -33,6 +35,22 @@ public class ProtocolMapperTypeRepresentation {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultValue(String defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return helpText;
|
return helpText;
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,12 +457,6 @@ public class RepresentationToModel {
|
||||||
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resourceRep.getClaims() != null) {
|
|
||||||
setClaims(applicationModel, resourceRep.getClaims());
|
|
||||||
} else {
|
|
||||||
applicationModel.setAllowedClaimsMask(ClaimMask.ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resourceRep.getProtocolMappers() != null) {
|
if (resourceRep.getProtocolMappers() != null) {
|
||||||
Set<String> ids = new HashSet<String>();
|
Set<String> ids = new HashSet<String>();
|
||||||
for (ClientProtocolMappingRepresentation map : resourceRep.getProtocolMappers()) {
|
for (ClientProtocolMappingRepresentation map : resourceRep.getProtocolMappers()) {
|
||||||
|
@ -524,10 +518,6 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep.getClaims() != null) {
|
|
||||||
setClaims(resource, rep.getClaims());
|
|
||||||
}
|
|
||||||
|
|
||||||
updateClientIdentityProvides(rep.getIdentityProviders(), resource);
|
updateClientIdentityProvides(rep.getIdentityProviders(), resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,10 +623,6 @@ public class RepresentationToModel {
|
||||||
model.setWebOrigins(new HashSet<String>(webOrigins));
|
model.setWebOrigins(new HashSet<String>(webOrigins));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep.getClaims() != null) {
|
|
||||||
setClaims(model, rep.getClaims());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rep.getNotBefore() != null) {
|
if (rep.getNotBefore() != null) {
|
||||||
model.setNotBefore(rep.getNotBefore());
|
model.setNotBefore(rep.getNotBefore());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,14 @@ public interface ProtocolMapper extends Provider, ProviderFactory<ProtocolMapper
|
||||||
String getHelpText();
|
String getHelpText();
|
||||||
|
|
||||||
public static class ConfigProperty {
|
public static class ConfigProperty {
|
||||||
|
public static final String BOOLEAN_TYPE="boolean";
|
||||||
|
public static final String STRING_TYPE="String";
|
||||||
|
|
||||||
protected String name;
|
protected String name;
|
||||||
protected String label;
|
protected String label;
|
||||||
protected String helpText;
|
protected String helpText;
|
||||||
|
protected String type;
|
||||||
|
protected String defaultValue;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
|
@ -36,6 +41,22 @@ public interface ProtocolMapper extends Provider, ProviderFactory<ProtocolMapper
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultValue(String defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return helpText;
|
return helpText;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,27 +29,32 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
||||||
"username",
|
"username",
|
||||||
"preferred_username", "String",
|
"preferred_username", "String",
|
||||||
true, "username",
|
true, "username",
|
||||||
true);
|
true,
|
||||||
|
true, true);
|
||||||
OIDCUserModelMapper.addClaimMapper(realm, "email",
|
OIDCUserModelMapper.addClaimMapper(realm, "email",
|
||||||
"email",
|
"email",
|
||||||
"email", "String",
|
"email", "String",
|
||||||
true, "email",
|
true, "email",
|
||||||
true);
|
true,
|
||||||
|
true, true);
|
||||||
OIDCUserModelMapper.addClaimMapper(realm, "given name",
|
OIDCUserModelMapper.addClaimMapper(realm, "given name",
|
||||||
"firstName",
|
"firstName",
|
||||||
"given_name", "String",
|
"given_name", "String",
|
||||||
true, "given name",
|
true, "given name",
|
||||||
true);
|
true,
|
||||||
|
true, true);
|
||||||
OIDCUserModelMapper.addClaimMapper(realm, "family name",
|
OIDCUserModelMapper.addClaimMapper(realm, "family name",
|
||||||
"lastName",
|
"lastName",
|
||||||
"family_name", "String",
|
"family_name", "String",
|
||||||
true, "family name",
|
true, "family name",
|
||||||
true);
|
true,
|
||||||
|
true, true);
|
||||||
OIDCUserModelMapper.addClaimMapper(realm, "email verified",
|
OIDCUserModelMapper.addClaimMapper(realm, "email verified",
|
||||||
"emailVerified",
|
"emailVerified",
|
||||||
"email_verified", "boolean",
|
"email_verified", "boolean",
|
||||||
false, null,
|
false, null,
|
||||||
false);
|
false,
|
||||||
|
true, true);
|
||||||
|
|
||||||
ProtocolMapperModel fullName = new ProtocolMapperModel();
|
ProtocolMapperModel fullName = new ProtocolMapperModel();
|
||||||
if (realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "full name") == null) {
|
if (realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "full name") == null) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.keycloak.jose.jws.JWSBuilder;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.ClaimMask;
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientSessionModel;
|
import org.keycloak.models.ClientSessionModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -25,7 +24,6 @@ import org.keycloak.protocol.ProtocolMapper;
|
||||||
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.UserClaimSet;
|
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
@ -244,7 +242,7 @@ public class TokenManager {
|
||||||
|
|
||||||
ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
|
ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
|
||||||
if (mapper == null || !(mapper instanceof OIDCAccessTokenMapper)) continue;
|
if (mapper == null || !(mapper instanceof OIDCAccessTokenMapper)) continue;
|
||||||
token = ((OIDCAccessTokenMapper)mapper).transformToken(token, mapping, session, userSession, clientSession);
|
token = ((OIDCAccessTokenMapper)mapper).transformAccessToken(token, mapping, session, userSession, clientSession);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,6 @@ import org.keycloak.representations.AccessToken;
|
||||||
*/
|
*/
|
||||||
public interface OIDCAccessTokenMapper {
|
public interface OIDCAccessTokenMapper {
|
||||||
|
|
||||||
AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession);
|
UserSessionModel userSession, ClientSessionModel clientSession);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
import org.keycloak.representations.UserClaimSet;
|
import org.keycloak.representations.UserClaimSet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -17,12 +18,26 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||||
|
|
||||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
ConfigProperty property;
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "oidc-address-mapper";
|
public static final String PROVIDER_ID = "oidc-address-mapper";
|
||||||
|
@ -53,8 +68,21 @@ public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OID
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token;
|
||||||
|
setClaim(token, userSession);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token;
|
||||||
|
setClaim(token, userSession);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setClaim(IDToken token, UserSessionModel userSession) {
|
||||||
UserModel user = userSession.getUser();
|
UserModel user = userSession.getUser();
|
||||||
UserClaimSet.AddressClaimSet addressSet = new UserClaimSet.AddressClaimSet();
|
UserClaimSet.AddressClaimSet addressSet = new UserClaimSet.AddressClaimSet();
|
||||||
addressSet.setStreetAddress(user.getAttribute("street"));
|
addressSet.setStreetAddress(user.getAttribute("street"));
|
||||||
|
@ -63,7 +91,6 @@ public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OID
|
||||||
addressSet.setPostalCode(user.getAttribute("postal_code"));
|
addressSet.setPostalCode(user.getAttribute("postal_code"));
|
||||||
addressSet.setCountry(user.getAttribute("country"));
|
addressSet.setCountry(user.getAttribute("country"));
|
||||||
token.getOtherClaims().put("address", addressSet);
|
token.getOtherClaims().put("address", addressSet);
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -16,6 +17,12 @@ import java.util.Map;
|
||||||
public class OIDCAttributeMapperHelper {
|
public class OIDCAttributeMapperHelper {
|
||||||
public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
|
public static final String TOKEN_CLAIM_NAME = "Token Claim Name";
|
||||||
public static final String JSON_TYPE = "Claim JSON Type";
|
public static final String JSON_TYPE = "Claim JSON Type";
|
||||||
|
public static final String INCLUDE_IN_ACCESS_TOKEN = "access.token.claim";
|
||||||
|
public static final String INCLUDE_IN_ACCESS_TOKEN_LABEL = "Add to access token";
|
||||||
|
public static final String INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT = "Should the claim be added to the access token?";
|
||||||
|
public static final String INCLUDE_IN_ID_TOKEN = "id.token.claim";
|
||||||
|
public static final String INCLUDE_IN_ID_TOKEN_LABEL = "Add to ID token";
|
||||||
|
public static final String INCLUDE_IN_ID_TOKEN_HELP_TEXT = "Should the claim be added to the ID token?";
|
||||||
|
|
||||||
public static Object mapAttributeValue(ProtocolMapperModel mappingModel, Object attributeValue) {
|
public static Object mapAttributeValue(ProtocolMapperModel mappingModel, Object attributeValue) {
|
||||||
if (attributeValue == null) return null;
|
if (attributeValue == null) return null;
|
||||||
|
@ -40,7 +47,7 @@ public class OIDCAttributeMapperHelper {
|
||||||
return attributeValue;
|
return attributeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void mapClaim(AccessToken token, ProtocolMapperModel mappingModel, Object attributeValue) {
|
public static void mapClaim(IDToken token, ProtocolMapperModel mappingModel, Object attributeValue) {
|
||||||
if (attributeValue == null) return;
|
if (attributeValue == null) return;
|
||||||
attributeValue = mapAttributeValue(mappingModel, attributeValue);
|
attributeValue = mapAttributeValue(mappingModel, attributeValue);
|
||||||
String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
|
String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
|
||||||
|
@ -65,6 +72,7 @@ public class OIDCAttributeMapperHelper {
|
||||||
String tokenClaimName, String claimType,
|
String tokenClaimName, String claimType,
|
||||||
boolean consentRequired, String consentText,
|
boolean consentRequired, String consentText,
|
||||||
boolean appliedByDefault,
|
boolean appliedByDefault,
|
||||||
|
boolean accessToken, boolean idToken,
|
||||||
String mapperId) {
|
String mapperId) {
|
||||||
ProtocolMapperModel mapper = realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, name);
|
ProtocolMapperModel mapper = realm.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, name);
|
||||||
if (mapper != null) return;
|
if (mapper != null) return;
|
||||||
|
@ -79,7 +87,17 @@ public class OIDCAttributeMapperHelper {
|
||||||
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
|
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
|
||||||
config.put(TOKEN_CLAIM_NAME, tokenClaimName);
|
config.put(TOKEN_CLAIM_NAME, tokenClaimName);
|
||||||
config.put(JSON_TYPE, claimType);
|
config.put(JSON_TYPE, claimType);
|
||||||
|
if (accessToken) config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||||
|
if (idToken) config.put(INCLUDE_IN_ID_TOKEN, "true");
|
||||||
mapper.setConfig(config);
|
mapper.setConfig(config);
|
||||||
realm.addProtocolMapper(mapper);
|
realm.addProtocolMapper(mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean includeInIDToken(ProtocolMapperModel mappingModel) {
|
||||||
|
return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_ID_TOKEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean includeInAccessToken(ProtocolMapperModel mappingModel) {
|
||||||
|
return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -16,11 +17,26 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||||
|
|
||||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
ConfigProperty property;
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +68,24 @@ public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OI
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token;
|
||||||
|
setClaim(token, userSession);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setClaim(IDToken token, UserSessionModel userSession) {
|
||||||
UserModel user = userSession.getUser();
|
UserModel user = userSession.getUser();
|
||||||
String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
|
String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
|
||||||
String last = user.getLastName() == null ? "" : user.getLastName();
|
String last = user.getLastName() == null ? "" : user.getLastName();
|
||||||
token.getOtherClaims().put("name", first + last);
|
token.getOtherClaims().put("name", first + last);
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token;
|
||||||
|
setClaim(token, userSession);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
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 org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface OIDCIDTokenMapper {
|
||||||
|
|
||||||
|
IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
|
UserSessionModel userSession, ClientSessionModel clientSession);
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -20,7 +21,7 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||||
|
|
||||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||||
|
|
||||||
|
@ -30,12 +31,35 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
||||||
property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
|
property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
|
||||||
property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
|
property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
|
||||||
property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
|
property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
property = new ConfigProperty();
|
property = new ConfigProperty();
|
||||||
property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||||
property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
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.");
|
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);
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
|
property.setDefaultValue(ConfigProperty.STRING_TYPE);
|
||||||
|
property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values.");
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,13 +91,26 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token;
|
||||||
|
|
||||||
|
setClaim(token, mappingModel, userSession);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
|
||||||
UserModel user = userSession.getUser();
|
UserModel user = userSession.getUser();
|
||||||
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
|
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
|
||||||
String attributeValue = user.getAttribute(attributeName);
|
String attributeValue = user.getAttribute(attributeName);
|
||||||
if (attributeValue == null) return token;
|
if (attributeValue == null) return;
|
||||||
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
|
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token;
|
||||||
|
setClaim(token, mappingModel, userSession);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,11 +118,13 @@ public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implemen
|
||||||
String userAttribute,
|
String userAttribute,
|
||||||
String tokenClaimName, String claimType,
|
String tokenClaimName, String claimType,
|
||||||
boolean consentRequired, String consentText,
|
boolean consentRequired, String consentText,
|
||||||
boolean appliedByDefault) {
|
boolean appliedByDefault,
|
||||||
|
boolean accessToken, boolean idToken) {
|
||||||
OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
|
OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
|
||||||
tokenClaimName, claimType,
|
tokenClaimName, claimType,
|
||||||
consentRequired, consentText,
|
consentRequired, consentText,
|
||||||
appliedByDefault, PROVIDER_ID);
|
appliedByDefault, accessToken, idToken,
|
||||||
|
PROVIDER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -20,7 +21,7 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -28,14 +29,43 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
|
||||||
property = new ConfigProperty();
|
property = new ConfigProperty();
|
||||||
property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
|
property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
|
||||||
property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
|
property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
|
property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
property = new ConfigProperty();
|
property = new ConfigProperty();
|
||||||
property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||||
property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
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.");
|
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);
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setType(ConfigProperty.STRING_TYPE);
|
||||||
|
property.setDefaultValue(ConfigProperty.STRING_TYPE);
|
||||||
|
property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values.");
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values.");
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ConfigProperty();
|
||||||
|
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||||
|
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||||
|
property.setType(ConfigProperty.BOOLEAN_TYPE);
|
||||||
|
property.setDefaultValue("true");
|
||||||
|
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||||
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
|
public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
|
||||||
|
@ -66,25 +96,40 @@ public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements O
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccessToken transformToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token;
|
||||||
|
setClaim(token, mappingModel, userSession);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token;
|
||||||
|
setClaim(token, mappingModel, userSession);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
|
||||||
UserModel user = userSession.getUser();
|
UserModel user = userSession.getUser();
|
||||||
String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
|
String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
|
||||||
String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
|
String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
|
||||||
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
|
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, propertyValue);
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addClaimMapper(RealmModel realm, String name,
|
public static void addClaimMapper(RealmModel realm, String name,
|
||||||
String userAttribute,
|
String userAttribute,
|
||||||
String tokenClaimName, String claimType,
|
String tokenClaimName, String claimType,
|
||||||
boolean consentRequired, String consentText,
|
boolean consentRequired, String consentText,
|
||||||
boolean appliedByDefault) {
|
boolean appliedByDefault,
|
||||||
|
boolean accessToken, boolean idToken) {
|
||||||
OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
|
OIDCAttributeMapperHelper.addClaimMapper(realm, name, userAttribute,
|
||||||
tokenClaimName, claimType,
|
tokenClaimName, claimType,
|
||||||
consentRequired, consentText,
|
consentRequired, consentText,
|
||||||
appliedByDefault, PROVIDER_ID);
|
appliedByDefault, accessToken, idToken,
|
||||||
|
PROVIDER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,8 @@ public class ServerInfoAdminResource {
|
||||||
ProtocolMapperTypeRepresentation.ConfigProperty propRep = new ProtocolMapperTypeRepresentation.ConfigProperty();
|
ProtocolMapperTypeRepresentation.ConfigProperty propRep = new ProtocolMapperTypeRepresentation.ConfigProperty();
|
||||||
propRep.setName(prop.getName());
|
propRep.setName(prop.getName());
|
||||||
propRep.setLabel(prop.getLabel());
|
propRep.setLabel(prop.getLabel());
|
||||||
|
propRep.setType(prop.getType());
|
||||||
|
propRep.setDefaultValue(prop.getDefaultValue());
|
||||||
propRep.setHelpText(prop.getHelpText());
|
propRep.setHelpText(prop.getHelpText());
|
||||||
rep.getProperties().add(propRep);
|
rep.getProperties().add(propRep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,10 +214,6 @@ public class AdminAPITest {
|
||||||
|
|
||||||
Assert.assertEquals(set, storedSet);
|
Assert.assertEquals(set, storedSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appRep.getClaims() != null) {
|
|
||||||
Assert.assertEquals(appRep.getClaims(), storedApp.getClaims());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void checkRealmRep(RealmRepresentation rep, RealmRepresentation storedRealm) {
|
protected void checkRealmRep(RealmRepresentation rep, RealmRepresentation storedRealm) {
|
||||||
|
|
Loading…
Reference in a new issue