This commit is contained in:
Bill Burke 2015-03-02 21:39:43 -05:00
parent 5e12ee3e7a
commit 753feae49e
15 changed files with 406 additions and 206 deletions

View file

@ -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;
} }

View file

@ -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());
} }

View file

@ -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;
} }

View file

@ -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) {

View file

@ -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);

View file

@ -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);
} }

View file

@ -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;
} }
} }

View file

@ -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));
}
} }

View file

@ -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;
}
} }

View file

@ -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);
}

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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) {