KEYCLOAK-3499 More fixes for IncludeInUserInfo. Fixing tests and migration
This commit is contained in:
parent
c3b577de11
commit
a7287aad36
24 changed files with 491 additions and 277 deletions
|
@ -30,6 +30,7 @@ import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
|||
import org.keycloak.migration.migrators.MigrateTo2_0_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo2_1_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo2_2_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo2_3_0;
|
||||
import org.keycloak.migration.migrators.Migration;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
|
@ -53,6 +54,7 @@ public class MigrationModelManager {
|
|||
new MigrateTo2_0_0(),
|
||||
new MigrateTo2_1_0(),
|
||||
new MigrateTo2_2_0(),
|
||||
new MigrateTo2_3_0(),
|
||||
};
|
||||
|
||||
public static void migrate(KeycloakSession session) {
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.migration.migrators;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.migration.ModelVersion;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperContainerModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class MigrateTo2_3_0 implements Migration {
|
||||
|
||||
public static final ModelVersion VERSION = new ModelVersion("2.3.0");
|
||||
|
||||
@Override
|
||||
public void migrate(KeycloakSession session) {
|
||||
for (RealmModel realm : session.realms().getRealms()) {
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
updateProtocolMappers(client);
|
||||
}
|
||||
|
||||
for (ClientTemplateModel clientTemplate : realm.getClientTemplates()) {
|
||||
updateProtocolMappers(clientTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProtocolMappers(ProtocolMapperContainerModel client) {
|
||||
List<ProtocolMapperModel> toUpdate = new LinkedList<>();
|
||||
for (ProtocolMapperModel mapper : client.getProtocolMappers()) {
|
||||
if (!mapper.getConfig().containsKey("userinfo.token.claim") && mapper.getConfig().containsKey("id.token.claim")) {
|
||||
mapper.getConfig().put("userinfo.token.claim", mapper.getConfig().get("id.token.claim"));
|
||||
toUpdate.add(mapper);
|
||||
}
|
||||
}
|
||||
|
||||
for (ProtocolMapperModel mapper : toUpdate) {
|
||||
client.updateProtocolMapper(mapper);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelVersion getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ import java.util.Set;
|
|||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper {
|
||||
abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
|
||||
/**
|
||||
* Returns the role names extracted from the given {@code roleModels} while recursively traversing "Composite Roles".
|
||||
|
|
|
@ -44,21 +44,7 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
|
|||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, AddressMapper.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-address-mapper";
|
||||
|
|
|
@ -43,21 +43,7 @@ public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, FullNameMapper.class);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -45,16 +45,8 @@ public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements
|
|||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
ProviderConfigProperty property1;
|
||||
property1 = new ProviderConfigProperty();
|
||||
property1.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property1.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL);
|
||||
property1.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property1.setDefaultValue("groups");
|
||||
property1.setHelpText(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_TOOLTIP);
|
||||
configProperties.add(property1);
|
||||
property1 = new ProviderConfigProperty();
|
||||
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
|
||||
ProviderConfigProperty property1 = new ProviderConfigProperty();
|
||||
property1.setName("full.path");
|
||||
property1.setLabel("Full group path");
|
||||
property1.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
|
@ -62,23 +54,7 @@ public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements
|
|||
property1.setHelpText("Include full path to group i.e. /top/level1/level2, false will just specify the group name");
|
||||
configProperties.add(property1);
|
||||
|
||||
property1 = new ProviderConfigProperty();
|
||||
property1.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||
property1.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property1.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property1.setDefaultValue("true");
|
||||
property1.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property1);
|
||||
property1 = new ProviderConfigProperty();
|
||||
property1.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||
property1.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property1.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property1.setDefaultValue("true");
|
||||
property1.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property1);
|
||||
|
||||
|
||||
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, GroupMembershipMapper.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-group-membership-mapper";
|
||||
|
|
|
@ -44,46 +44,17 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
public static final String CLAIM_VALUE = "claim.value";
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
|
||||
property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL);
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setHelpText("Claim name you want to hard code 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);
|
||||
property = new ProviderConfigProperty();
|
||||
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
|
||||
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(CLAIM_VALUE);
|
||||
property.setLabel("Claim value");
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setHelpText("Value of the claim you want to hard code. 'true' and 'false can be used for boolean values.");
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||
property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
|
||||
List<String> types = new ArrayList(3);
|
||||
types.add("String");
|
||||
types.add("long");
|
||||
types.add("int");
|
||||
types.add("boolean");
|
||||
property.setType(ProviderConfigProperty.LIST_TYPE);
|
||||
property.setOptions(types);
|
||||
property.setHelpText("JSON type that should be used for the value of the claim. long, int, boolean, and String are valid values.");
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
|
||||
property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
|
||||
OIDCAttributeMapperHelper.addJsonTypeConfig(configProperties);
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, HardcodedClaim.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-hardcoded-claim-mapper";
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.protocol.ProtocolMapper;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
@ -162,20 +163,34 @@ public class OIDCAttributeMapperHelper {
|
|||
}
|
||||
|
||||
public static boolean includeInUserInfo(ProtocolMapperModel mappingModel){
|
||||
return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_USERINFO));
|
||||
String includeInUserInfo = mappingModel.getConfig().get(INCLUDE_IN_USERINFO);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInUserInfo == null && includeInIDToken(mappingModel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInUserInfo);
|
||||
}
|
||||
|
||||
public static void addAttributeConfig(List<ProviderConfigProperty> configProperties) {
|
||||
public static void addAttributeConfig(List<ProviderConfigProperty> configProperties, Class<? extends ProtocolMapper> protocolMapperClass) {
|
||||
addTokenClaimNameConfig(configProperties);
|
||||
addJsonTypeConfig(configProperties);
|
||||
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
addIncludeInTokensConfig(configProperties, protocolMapperClass);
|
||||
}
|
||||
|
||||
public static void addTokenClaimNameConfig(List<ProviderConfigProperty> configProperties) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(TOKEN_CLAIM_NAME);
|
||||
property.setLabel(TOKEN_CLAIM_NAME_LABEL);
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setHelpText(TOKEN_CLAIM_NAME_TOOLTIP);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
property = new ProviderConfigProperty();
|
||||
public static void addJsonTypeConfig(List<ProviderConfigProperty> configProperties) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(JSON_TYPE);
|
||||
property.setLabel(JSON_TYPE);
|
||||
List<String> types = new ArrayList(3);
|
||||
|
@ -187,29 +202,37 @@ public class OIDCAttributeMapperHelper {
|
|||
property.setOptions(types);
|
||||
property.setHelpText(JSON_TYPE_TOOLTIP);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_ID_TOKEN);
|
||||
property.setLabel(INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
public static void addIncludeInTokensConfig(List<ProviderConfigProperty> configProperties, Class<? extends ProtocolMapper> protocolMapperClass) {
|
||||
if (OIDCIDTokenMapper.class.isAssignableFrom(protocolMapperClass)) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_ID_TOKEN);
|
||||
property.setLabel(INCLUDE_IN_ID_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_ID_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_ACCESS_TOKEN);
|
||||
property.setLabel(INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
if (OIDCAccessTokenMapper.class.isAssignableFrom(protocolMapperClass)) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_ACCESS_TOKEN);
|
||||
property.setLabel(INCLUDE_IN_ACCESS_TOKEN_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_USERINFO);
|
||||
property.setLabel(INCLUDE_IN_USERINFO_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_USERINFO_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
if (UserInfoTokenMapper.class.isAssignableFrom(protocolMapperClass)) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_USERINFO);
|
||||
property.setLabel(INCLUDE_IN_USERINFO_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_USERINFO_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
|
|||
property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
configProperties.add(property);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties, UserAttributeMapper.class);
|
||||
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(ProtocolMapperUtils.MULTIVALUED);
|
||||
|
|
|
@ -47,7 +47,7 @@ public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
clientId.setName(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
|
||||
clientId.setLabel(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_LABEL);
|
||||
clientId.setHelpText(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_HELP_TEXT);
|
||||
clientId.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
clientId.setType(ProviderConfigProperty.CLIENT_LIST_TYPE);
|
||||
CONFIG_PROPERTIES.add(clientId);
|
||||
|
||||
ProviderConfigProperty clientRolePrefix = new ProviderConfigProperty();
|
||||
|
@ -57,7 +57,7 @@ public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
clientRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
CONFIG_PROPERTIES.add(clientRolePrefix);
|
||||
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES, UserClientRoleMappingMapper.class);
|
||||
}
|
||||
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
|
@ -100,4 +100,21 @@ public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, clientRoleNames);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperModel create(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, "foo",
|
||||
tokenClaimName, "String",
|
||||
true, name,
|
||||
accessToken, idToken,
|
||||
PROVIDER_ID);
|
||||
|
||||
mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID, clientId);
|
||||
mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX, clientRolePrefix);
|
||||
return mapper;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
|
@ -49,7 +49,7 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI
|
|||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties, UserPropertyMapper.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
|
||||
|
|
|
@ -21,11 +21,14 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -48,7 +51,7 @@ public class UserRealmRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
realmRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
CONFIG_PROPERTIES.add(realmRolePrefix);
|
||||
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES, UserRealmRoleMappingMapper.class);
|
||||
}
|
||||
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
|
@ -80,8 +83,23 @@ public class UserRealmRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
UserModel user = userSession.getUser();
|
||||
|
||||
String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
|
||||
Set<String> realmRoleNames = flattenRoleModelToRoleNames(user.getRoleMappings(), rolePrefix);
|
||||
Set<String> realmRoleNames = flattenRoleModelToRoleNames(user.getRealmRoleMappings(), rolePrefix);
|
||||
|
||||
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, realmRoleNames);
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperModel create(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName, boolean accessToken, boolean idToken) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, "foo",
|
||||
tokenClaimName, "String",
|
||||
true, name,
|
||||
accessToken, idToken,
|
||||
PROVIDER_ID);
|
||||
|
||||
mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX, realmRolePrefix);
|
||||
return mapper;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
|
|||
property.setHelpText(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_HELP_TEXT);
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
configProperties.add(property);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties);
|
||||
OIDCAttributeMapperHelper.addAttributeConfig(configProperties, UserSessionNoteMapper.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-usersessionmodel-note-mapper";
|
||||
|
|
|
@ -49,7 +49,7 @@ public class UserInfoClientUtil {
|
|||
return client.target(userInfoUri);
|
||||
}
|
||||
|
||||
public static void testSuccessfulUserInfoResponse(Response response, String expectedUsername, String expectedEmail) {
|
||||
public static UserInfo testSuccessfulUserInfoResponse(Response response, String expectedUsername, String expectedEmail) {
|
||||
Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
|
||||
Assert.assertEquals(response.getHeaderString(HttpHeaders.CONTENT_TYPE), MediaType.APPLICATION_JSON);
|
||||
|
||||
|
@ -61,6 +61,7 @@ public class UserInfoClientUtil {
|
|||
Assert.assertNotNull(userInfo.getSubject());
|
||||
Assert.assertEquals(expectedEmail, userInfo.getEmail());
|
||||
Assert.assertEquals(expectedUsername, userInfo.getPreferredUsername());
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.client.registration.ClientRegistrationException;
|
|||
import org.keycloak.client.registration.HttpErrorException;
|
||||
import org.keycloak.protocol.oidc.mappers.SHA256PairwiseSubMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.UserInfo;
|
||||
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
|
||||
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
|
@ -38,7 +39,9 @@ import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
|
|||
import org.keycloak.testsuite.client.resources.TestOIDCEndpointsApplicationResource;
|
||||
import org.keycloak.testsuite.util.ClientManager;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.UserInfoClientUtil;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -323,5 +326,17 @@ public class OIDCPairwiseClientRegistrationTest extends AbstractClientRegistrati
|
|||
// Assert pairwise client has different subject like userId
|
||||
String pairwiseUserId = accessToken.getSubject();
|
||||
Assert.assertNotEquals(pairwiseUserId, user.getId());
|
||||
|
||||
// Send request to userInfo endpoint
|
||||
Client jaxrsClient = javax.ws.rs.client.ClientBuilder.newClient();
|
||||
try {
|
||||
// Check that userInfo contains pairwise subjectId as well
|
||||
Response userInfoResponse = UserInfoClientUtil.executeUserInfoRequest_getMethod(jaxrsClient, accessTokenResponse.getAccessToken());
|
||||
UserInfo userInfo = UserInfoClientUtil.testSuccessfulUserInfoResponse(userInfoResponse, "test-user", "test-user@localhost");
|
||||
String userInfoSubId = userInfo.getSubject();
|
||||
Assert.assertEquals(pairwiseUserId, userInfoSubId);
|
||||
} finally {
|
||||
jaxrsClient.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -673,138 +673,6 @@ public class AccessTokenTest extends AbstractKeycloakTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenMapping() throws Exception {
|
||||
Client client = javax.ws.rs.client.ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
|
||||
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||
WebTarget grantTarget = client.target(grantUri);
|
||||
{
|
||||
UserResource userResource = findUserByUsernameId(adminClient.realm("test"), "test-user@localhost");
|
||||
UserRepresentation user = userResource.toRepresentation();
|
||||
|
||||
user.singleAttribute("street", "5 Yawkey Way");
|
||||
user.singleAttribute("locality", "Boston");
|
||||
user.singleAttribute("region", "MA");
|
||||
user.singleAttribute("postal_code", "02115");
|
||||
user.singleAttribute("country", "USA");
|
||||
user.singleAttribute("phone", "617-777-6666");
|
||||
|
||||
List<String> departments = Arrays.asList("finance", "development");
|
||||
user.getAttributes().put("departments", departments);
|
||||
userResource.update(user);
|
||||
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
ProtocolMapperRepresentation mapper = createAddressMapper(true, true);
|
||||
app.getProtocolMappers().createMapper(mapper);
|
||||
|
||||
ProtocolMapperRepresentation hard = createHardcodedClaim("hard", "hard", "coded", "String", false, null, true, true);
|
||||
app.getProtocolMappers().createMapper(hard);
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("hard-nested", "nested.hard", "coded-nested", "String", false, null, true, true));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true, false));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true, false));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("departments", "departments", "department", "String", true, "", true, true, true));
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-realm", "hardcoded"));
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-app", "app.hardcoded"));
|
||||
app.getProtocolMappers().createMapper(createRoleNameMapper("rename-app-role", "test-app.customer-user", "realm-user"));
|
||||
}
|
||||
|
||||
{
|
||||
Response response = executeGrantAccessTokenRequest(grantTarget);
|
||||
assertEquals(200, response.getStatus());
|
||||
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
assertNotNull(idToken.getAddress());
|
||||
assertEquals(idToken.getName(), "Tom Brady");
|
||||
assertEquals(idToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
assertEquals(idToken.getAddress().getLocality(), "Boston");
|
||||
assertEquals(idToken.getAddress().getRegion(), "MA");
|
||||
assertEquals(idToken.getAddress().getPostalCode(), "02115");
|
||||
assertEquals(idToken.getAddress().getCountry(), "USA");
|
||||
assertNotNull(idToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("coded", idToken.getOtherClaims().get("hard"));
|
||||
Map nested = (Map) idToken.getOtherClaims().get("nested");
|
||||
assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map) idToken.getOtherClaims().get("home");
|
||||
assertEquals("617-777-6666", nested.get("phone"));
|
||||
List<String> departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
assertEquals(2, departments.size());
|
||||
assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
|
||||
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||
assertEquals(accessToken.getName(), "Tom Brady");
|
||||
assertNotNull(accessToken.getAddress());
|
||||
assertEquals(accessToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
assertEquals(accessToken.getAddress().getLocality(), "Boston");
|
||||
assertEquals(accessToken.getAddress().getRegion(), "MA");
|
||||
assertEquals(accessToken.getAddress().getPostalCode(), "02115");
|
||||
assertEquals(accessToken.getAddress().getCountry(), "USA");
|
||||
assertNotNull(accessToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||
nested = (Map) accessToken.getOtherClaims().get("nested");
|
||||
assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map) accessToken.getOtherClaims().get("home");
|
||||
assertEquals("617-777-6666", nested.get("phone"));
|
||||
departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
assertEquals(2, departments.size());
|
||||
assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded"));
|
||||
assertTrue(accessToken.getRealmAccess().getRoles().contains("realm-user"));
|
||||
Assert.assertFalse(accessToken.getResourceAccess("test-app").getRoles().contains("customer-user"));
|
||||
assertTrue(accessToken.getResourceAccess("app").getRoles().contains("hardcoded"));
|
||||
|
||||
|
||||
response.close();
|
||||
}
|
||||
|
||||
// undo mappers
|
||||
{
|
||||
ClientResource app = findClientByClientId(adminClient.realm("test"), "test-app");
|
||||
ClientRepresentation clientRepresentation = app.toRepresentation();
|
||||
for (ProtocolMapperRepresentation model : clientRepresentation.getProtocolMappers()) {
|
||||
if (model.getName().equals("address")
|
||||
|| model.getName().equals("hard")
|
||||
|| model.getName().equals("hard-nested")
|
||||
|| model.getName().equals("custom phone")
|
||||
|| model.getName().equals("departments")
|
||||
|| model.getName().equals("nested phone")
|
||||
|| model.getName().equals("rename-app-role")
|
||||
|| model.getName().equals("hard-realm")
|
||||
|| model.getName().equals("hard-app")
|
||||
) {
|
||||
app.getProtocolMappers().delete(model.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
events.clear();
|
||||
|
||||
|
||||
{
|
||||
Response response = executeGrantAccessTokenRequest(grantTarget);
|
||||
assertEquals(200, response.getStatus());
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
assertNull(idToken.getAddress());
|
||||
assertNull(idToken.getOtherClaims().get("home_phone"));
|
||||
assertNull(idToken.getOtherClaims().get("hard"));
|
||||
assertNull(idToken.getOtherClaims().get("nested"));
|
||||
assertNull(idToken.getOtherClaims().get("department"));
|
||||
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
events.clear();
|
||||
client.close();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientTemplate() throws Exception {
|
||||
RealmResource realm = adminClient.realm("test");
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.oauth;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.util.ClientManager;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.ProtocolMapperUtil;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientResourceByClientId;
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsernameId;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createAddressMapper;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createClaimMapper;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedRole;
|
||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createRoleNameMapper;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeAbstractKeycloakTest() throws Exception {
|
||||
super.beforeAbstractKeycloakTest();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void clientConfiguration() {
|
||||
ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true);
|
||||
/*
|
||||
* Configure the default client ID. Seems like OAuthClient is keeping the state of clientID
|
||||
* For example: If some test case configure oauth.clientId("sample-public-client"), other tests
|
||||
* will faile and the clientID will always be "sample-public-client
|
||||
* @see AccessTokenTest#testAuthorizationNegotiateHeaderIgnored()
|
||||
*/
|
||||
oauth.clientId("test-app");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
|
||||
testRealms.add(realm);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTokenMapping() throws Exception {
|
||||
{
|
||||
UserResource userResource = findUserByUsernameId(adminClient.realm("test"), "test-user@localhost");
|
||||
UserRepresentation user = userResource.toRepresentation();
|
||||
|
||||
user.singleAttribute("street", "5 Yawkey Way");
|
||||
user.singleAttribute("locality", "Boston");
|
||||
user.singleAttribute("region", "MA");
|
||||
user.singleAttribute("postal_code", "02115");
|
||||
user.singleAttribute("country", "USA");
|
||||
user.singleAttribute("phone", "617-777-6666");
|
||||
|
||||
List<String> departments = Arrays.asList("finance", "development");
|
||||
user.getAttributes().put("departments", departments);
|
||||
userResource.update(user);
|
||||
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
ProtocolMapperRepresentation mapper = createAddressMapper(true, true);
|
||||
app.getProtocolMappers().createMapper(mapper);
|
||||
|
||||
ProtocolMapperRepresentation hard = createHardcodedClaim("hard", "hard", "coded", "String", false, null, true, true);
|
||||
app.getProtocolMappers().createMapper(hard);
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("hard-nested", "nested.hard", "coded-nested", "String", false, null, true, true));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true, false));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true, false));
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("departments", "departments", "department", "String", true, "", true, true, true));
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-realm", "hardcoded"));
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-app", "app.hardcoded"));
|
||||
app.getProtocolMappers().createMapper(createRoleNameMapper("rename-app-role", "test-app.customer-user", "realm-user"));
|
||||
}
|
||||
|
||||
{
|
||||
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
|
||||
|
||||
IDToken idToken = oauth.verifyIDToken(response.getIdToken());
|
||||
assertNotNull(idToken.getAddress());
|
||||
assertEquals(idToken.getName(), "Tom Brady");
|
||||
assertEquals(idToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
assertEquals(idToken.getAddress().getLocality(), "Boston");
|
||||
assertEquals(idToken.getAddress().getRegion(), "MA");
|
||||
assertEquals(idToken.getAddress().getPostalCode(), "02115");
|
||||
assertEquals(idToken.getAddress().getCountry(), "USA");
|
||||
assertNotNull(idToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("coded", idToken.getOtherClaims().get("hard"));
|
||||
Map nested = (Map) idToken.getOtherClaims().get("nested");
|
||||
assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map) idToken.getOtherClaims().get("home");
|
||||
assertEquals("617-777-6666", nested.get("phone"));
|
||||
List<String> departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
assertEquals(2, departments.size());
|
||||
assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
|
||||
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
|
||||
assertEquals(accessToken.getName(), "Tom Brady");
|
||||
assertNotNull(accessToken.getAddress());
|
||||
assertEquals(accessToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
assertEquals(accessToken.getAddress().getLocality(), "Boston");
|
||||
assertEquals(accessToken.getAddress().getRegion(), "MA");
|
||||
assertEquals(accessToken.getAddress().getPostalCode(), "02115");
|
||||
assertEquals(accessToken.getAddress().getCountry(), "USA");
|
||||
assertNotNull(accessToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
|
||||
assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||
nested = (Map) accessToken.getOtherClaims().get("nested");
|
||||
assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map) accessToken.getOtherClaims().get("home");
|
||||
assertEquals("617-777-6666", nested.get("phone"));
|
||||
departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
assertEquals(2, departments.size());
|
||||
assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded"));
|
||||
assertTrue(accessToken.getRealmAccess().getRoles().contains("realm-user"));
|
||||
Assert.assertFalse(accessToken.getResourceAccess("test-app").getRoles().contains("customer-user"));
|
||||
assertTrue(accessToken.getResourceAccess("app").getRoles().contains("hardcoded"));
|
||||
}
|
||||
|
||||
// undo mappers
|
||||
{
|
||||
ClientResource app = findClientByClientId(adminClient.realm("test"), "test-app");
|
||||
ClientRepresentation clientRepresentation = app.toRepresentation();
|
||||
for (ProtocolMapperRepresentation model : clientRepresentation.getProtocolMappers()) {
|
||||
if (model.getName().equals("address")
|
||||
|| model.getName().equals("hard")
|
||||
|| model.getName().equals("hard-nested")
|
||||
|| model.getName().equals("custom phone")
|
||||
|| model.getName().equals("departments")
|
||||
|| model.getName().equals("nested phone")
|
||||
|| model.getName().equals("rename-app-role")
|
||||
|| model.getName().equals("hard-realm")
|
||||
|| model.getName().equals("hard-app")
|
||||
) {
|
||||
app.getProtocolMappers().delete(model.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
events.clear();
|
||||
|
||||
|
||||
{
|
||||
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
|
||||
IDToken idToken = oauth.verifyIDToken(response.getIdToken());
|
||||
assertNull(idToken.getAddress());
|
||||
assertNull(idToken.getOtherClaims().get("home_phone"));
|
||||
assertNull(idToken.getOtherClaims().get("hard"));
|
||||
assertNull(idToken.getOtherClaims().get("nested"));
|
||||
assertNull(idToken.getOtherClaims().get("department"));
|
||||
}
|
||||
|
||||
|
||||
events.clear();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUserRoleToAttributeMappers() throws Exception {
|
||||
// Add mapper for realm roles
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper("test-app", null, "Client roles mapper", "roles-custom.test-app", true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
||||
// Login user
|
||||
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
|
||||
IDToken idToken = oauth.verifyIDToken(response.getIdToken());
|
||||
|
||||
// Verify attribute is filled
|
||||
Map<String, Object> roleMappings = (Map<String, Object>)idToken.getOtherClaims().get("roles-custom");
|
||||
Assert.assertEquals(2, roleMappings.size());
|
||||
String realmRoleMappings = (String) roleMappings.get("realm");
|
||||
String testAppMappings = (String) roleMappings.get("test-app");
|
||||
Assert.assertTrue(realmRoleMappings.contains("pref.user"));
|
||||
Assert.assertEquals("[customer-user]", testAppMappings);
|
||||
}
|
||||
|
||||
|
||||
private ProtocolMapperRepresentation makeMapper(String name, String mapperType, Map<String, String> config) {
|
||||
ProtocolMapperRepresentation rep = new ProtocolMapperRepresentation();
|
||||
rep.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
rep.setName(name);
|
||||
rep.setProtocolMapper(mapperType);
|
||||
rep.setConfig(config);
|
||||
rep.setConsentRequired(true);
|
||||
rep.setConsentText("Test Consent Text");
|
||||
return rep;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,8 @@ import org.keycloak.protocol.oidc.mappers.HardcodedClaim;
|
|||
import org.keycloak.protocol.oidc.mappers.HardcodedRole;
|
||||
import org.keycloak.protocol.oidc.mappers.RoleNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserAttributeMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserClientRoleMappingMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserRealmRoleMappingMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
|
||||
|
@ -103,4 +105,22 @@ public class ProtocolMapperUtil {
|
|||
consentRequired, consentText,
|
||||
accessToken, idToken));
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperRepresentation createUserRealmRoleMappingMapper(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(UserRealmRoleMappingMapper.create(realmRolePrefix, name, tokenClaimName, accessToken, idToken));
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperRepresentation createUserClientRoleMappingMapper(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(UserClientRoleMappingMapper.create(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
|
|||
* Test for KEYCLOAK-1053 - verify email action is not performed if email is not provided, login is normal, but action stays in set to be performed later
|
||||
*/
|
||||
@Test
|
||||
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
|
||||
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() throws Exception {
|
||||
RealmModel realm = getRealm();
|
||||
realm.setVerifyEmail(true);
|
||||
setUpdateProfileFirstLogin(realm, IdentityProviderRepresentation.UPFLM_OFF);
|
||||
|
|
|
@ -151,7 +151,7 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() {
|
||||
public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() throws Exception {
|
||||
super.testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
"claim.name": "mobile",
|
||||
"Claim JSON Type": "String",
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
"id.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -40,8 +40,8 @@
|
|||
"claim.name": "preferred_username",
|
||||
"Claim JSON Type": "String",
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
"id.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -54,8 +54,8 @@
|
|||
"claim.name": "email",
|
||||
"Claim JSON Type": "String",
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
"id.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -68,8 +68,8 @@
|
|||
"claim.name": "given_name",
|
||||
"Claim JSON Type": "String",
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
"id.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -83,7 +83,6 @@
|
|||
"Claim JSON Type": "String",
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -93,8 +92,8 @@
|
|||
"consentRequired": false,
|
||||
"config": {
|
||||
"access.token.claim": "true",
|
||||
"id.token.claim": "true"
|
||||
|
||||
"id.token.claim": "true",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -953,6 +953,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
mapper : function(ClientProtocolMapperLoader) {
|
||||
return ClientProtocolMapperLoader();
|
||||
},
|
||||
clients : function(ClientListLoader) {
|
||||
return ClientListLoader();
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -969,6 +972,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
client : function(ClientLoader) {
|
||||
return ClientLoader();
|
||||
},
|
||||
clients : function(ClientListLoader) {
|
||||
return ClientListLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientProtocolMapperCreateCtrl'
|
||||
|
@ -1017,6 +1023,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
mapper : function(ClientTemplateProtocolMapperLoader) {
|
||||
return ClientTemplateProtocolMapperLoader();
|
||||
},
|
||||
clients : function(ClientListLoader) {
|
||||
return ClientListLoader();
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -1033,6 +1042,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
template : function(ClientTemplateLoader) {
|
||||
return ClientTemplateLoader();
|
||||
},
|
||||
clients : function(ClientListLoader) {
|
||||
return ClientListLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ClientTemplateProtocolMapperCreateCtrl'
|
||||
|
|
|
@ -1705,8 +1705,10 @@ module.controller('ClientProtocolMapperListCtrl', function($scope, realm, client
|
|||
updateMappers();
|
||||
});
|
||||
|
||||
module.controller('ClientProtocolMapperCtrl', function($scope, realm, serverInfo, client, mapper, ClientProtocolMapper, Notifications, Dialog, $location) {
|
||||
module.controller('ClientProtocolMapperCtrl', function($scope, realm, serverInfo, client, clients, mapper, ClientProtocolMapper, Notifications, Dialog, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
|
||||
/*
|
||||
$scope.client = client;
|
||||
$scope.create = false;
|
||||
|
@ -1786,8 +1788,9 @@ module.controller('ClientProtocolMapperCtrl', function($scope, realm, serverInfo
|
|||
|
||||
});
|
||||
|
||||
module.controller('ClientProtocolMapperCreateCtrl', function($scope, realm, serverInfo, client, ClientProtocolMapper, Notifications, Dialog, $location) {
|
||||
module.controller('ClientProtocolMapperCreateCtrl', function($scope, realm, serverInfo, client, clients, ClientProtocolMapper, Notifications, Dialog, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
|
||||
if (client.protocol == null) {
|
||||
client.protocol = 'openid-connect';
|
||||
|
@ -2001,8 +2004,10 @@ module.controller('ClientTemplateProtocolMapperListCtrl', function($scope, realm
|
|||
updateMappers();
|
||||
});
|
||||
|
||||
module.controller('ClientTemplateProtocolMapperCtrl', function($scope, realm, serverInfo, template, mapper, ClientTemplateProtocolMapper, Notifications, Dialog, $location) {
|
||||
module.controller('ClientTemplateProtocolMapperCtrl', function($scope, realm, serverInfo, template, mapper, clients, ClientTemplateProtocolMapper, Notifications, Dialog, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
|
||||
if (template.protocol == null) {
|
||||
template.protocol = 'openid-connect';
|
||||
}
|
||||
|
@ -2068,8 +2073,10 @@ module.controller('ClientTemplateProtocolMapperCtrl', function($scope, realm, se
|
|||
|
||||
});
|
||||
|
||||
module.controller('ClientTemplateProtocolMapperCreateCtrl', function($scope, realm, serverInfo, template, ClientTemplateProtocolMapper, Notifications, Dialog, $location) {
|
||||
module.controller('ClientTemplateProtocolMapperCreateCtrl', function($scope, realm, serverInfo, template, clients, ClientTemplateProtocolMapper, Notifications, Dialog, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.clients = clients;
|
||||
|
||||
if (template.protocol == null) {
|
||||
template.protocol = 'openid-connect';
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
</div>
|
||||
<kc-tooltip>{{model.mapperType.helpText}}</kc-tooltip>
|
||||
</div>
|
||||
<kc-provider-config config="model.mapper.config" properties="model.mapperType.properties" realm="model.realm"></kc-provider-config>
|
||||
<kc-provider-config config="model.mapper.config" properties="model.mapperType.properties" realm="model.realm" clients="clients"></kc-provider-config>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group">
|
||||
|
|
Loading…
Reference in a new issue