KEYCLOAK-13959 Add AdvancedAttribute mapper for SAML to allow regexes
This commit is contained in:
parent
f639cc82b7
commit
8fe25948f7
14 changed files with 552 additions and 225 deletions
|
@ -38,6 +38,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.utils.RegexUtils.valueMatchesRegex;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke, Benjamin Weimer</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -108,9 +110,9 @@ public class AdvancedClaimToRoleMapper extends AbstractClaimMapper {
|
|||
@Override
|
||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String roleName = mapperModel.getConfig().get(ConfigConstants.ROLE);
|
||||
RoleModel role = getRoleModel(realm, roleName);
|
||||
|
||||
if (hasAllClaimValues(mapperModel, context)) {
|
||||
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
|
@ -118,9 +120,9 @@ public class AdvancedClaimToRoleMapper extends AbstractClaimMapper {
|
|||
@Override
|
||||
public void updateBrokeredUserLegacy(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String roleName = mapperModel.getConfig().get(ConfigConstants.ROLE);
|
||||
RoleModel role = getRoleModel(realm, roleName);
|
||||
|
||||
if (!hasAllClaimValues(mapperModel, context)) {
|
||||
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||
user.deleteRoleMapping(role);
|
||||
}
|
||||
|
||||
|
@ -129,18 +131,22 @@ public class AdvancedClaimToRoleMapper extends AbstractClaimMapper {
|
|||
@Override
|
||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String roleName = mapperModel.getConfig().get(ConfigConstants.ROLE);
|
||||
RoleModel role = getRoleModel(realm, roleName);
|
||||
if (hasAllClaimValues(mapperModel, context)) {
|
||||
user.grantRole(role);
|
||||
} else {
|
||||
user.deleteRoleMapping(role);
|
||||
}
|
||||
}
|
||||
|
||||
private RoleModel getRoleModel(RealmModel realm, String roleName) {
|
||||
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||
if (role == null) {
|
||||
throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||
}
|
||||
if (!hasAllClaimValues(mapperModel, context)) {
|
||||
user.deleteRoleMapping(role);
|
||||
} else {
|
||||
user.grantRole(role);
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "If all claims exists, grant the user the specified realm or application role.";
|
||||
|
@ -148,7 +154,7 @@ public class AdvancedClaimToRoleMapper extends AbstractClaimMapper {
|
|||
|
||||
protected boolean hasAllClaimValues(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
Map<String, String> claims = mapperModel.getConfigMap(CLAIM_PROPERTY_NAME);
|
||||
Boolean areClaimValuesRegex = Boolean.valueOf(mapperModel.getConfig().get(ARE_CLAIM_VALUES_REGEX_PROPERTY_NAME));
|
||||
boolean areClaimValuesRegex = Boolean.parseBoolean(mapperModel.getConfig().get(ARE_CLAIM_VALUES_REGEX_PROPERTY_NAME));
|
||||
|
||||
for (Map.Entry<String, String> claim : claims.entrySet()) {
|
||||
Object value = getClaimValue(context, claim.getKey());
|
||||
|
@ -161,23 +167,4 @@ public class AdvancedClaimToRoleMapper extends AbstractClaimMapper {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean valueMatchesRegex(String regex, Object value) {
|
||||
if (value instanceof List) {
|
||||
List list = (List) value;
|
||||
for (Object val : list) {
|
||||
if (valueMatchesRegex(regex, val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value != null) {
|
||||
String stringValue = value.toString();
|
||||
if (stringValue != null && stringValue.matches(regex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright 2020 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.broker.saml.mappers;
|
||||
|
||||
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.broker.provider.ConfigConstants;
|
||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||
import org.keycloak.broker.saml.SAMLEndpoint;
|
||||
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderSyncMode;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.keycloak.utils.RegexUtils.valueMatchesRegex;
|
||||
|
||||
/**
|
||||
* <a href="mailto:external.benjamin.weimer@bosch.io">Benjamin Weimer</a>,
|
||||
* <a href="mailto:external.martin.idel@bosch.io">Martin Idel</a>,
|
||||
*/
|
||||
public class AdvancedAttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||
|
||||
public static final String PROVIDER_ID = "saml-advanced-role-idp-mapper";
|
||||
public static final String ATTRIBUTE_PROPERTY_NAME = "attributes";
|
||||
public static final String ARE_ATTRIBUTE_VALUES_REGEX_PROPERTY_NAME = "are.attribute.values.regex";
|
||||
|
||||
private static final Set<IdentityProviderSyncMode> IDENTITY_PROVIDER_SYNC_MODES = new HashSet<>(Arrays.asList(IdentityProviderSyncMode.values()));
|
||||
|
||||
public static final String[] COMPATIBLE_PROVIDERS = {
|
||||
SAMLIdentityProviderFactory.PROVIDER_ID
|
||||
};
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties =
|
||||
new ArrayList<>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty attributeMappingProperty = new ProviderConfigProperty();
|
||||
attributeMappingProperty.setName(ATTRIBUTE_PROPERTY_NAME);
|
||||
attributeMappingProperty.setLabel("Attributes");
|
||||
attributeMappingProperty.setHelpText(
|
||||
"Name and (regex) value of the attributes to search for in token. "
|
||||
+ " The configured name of an attribute is searched in SAML attribute name and attribute friendly name fields."
|
||||
+ " Every given attribute description must be met to set the role."
|
||||
+ " If the attribute is an array, then the value must be contained in the array."
|
||||
+ " If an attribute can be found several times, then one match is sufficient.");
|
||||
attributeMappingProperty.setType(ProviderConfigProperty.MAP_TYPE);
|
||||
configProperties.add(attributeMappingProperty);
|
||||
|
||||
ProviderConfigProperty isAttributeRegexProperty = new ProviderConfigProperty();
|
||||
isAttributeRegexProperty.setName(ARE_ATTRIBUTE_VALUES_REGEX_PROPERTY_NAME);
|
||||
isAttributeRegexProperty.setLabel("Regex Attribute Values");
|
||||
isAttributeRegexProperty.setHelpText("If enabled attribute values are interpreted as regular expressions.");
|
||||
isAttributeRegexProperty.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
configProperties.add(isAttributeRegexProperty);
|
||||
|
||||
ProviderConfigProperty roleProperty = new ProviderConfigProperty();
|
||||
roleProperty.setName(ConfigConstants.ROLE);
|
||||
roleProperty.setLabel("Role");
|
||||
roleProperty.setHelpText("Role to grant to user if all attributes are present."
|
||||
+ " Click 'Select Role' button to browse roles, or just type it in the textbox."
|
||||
+ " To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||
roleProperty.setType(ProviderConfigProperty.ROLE_TYPE);
|
||||
configProperties.add(roleProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSyncMode(IdentityProviderSyncMode syncMode) {
|
||||
return IDENTITY_PROVIDER_SYNC_MODES.contains(syncMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCompatibleProviders() {
|
||||
return COMPATIBLE_PROVIDERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Role Importer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Advanced Attribute to Role";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String roleName = mapperModel.getConfig().get(ConfigConstants.ROLE);
|
||||
RoleModel role = getRoleModel(realm, roleName);
|
||||
|
||||
if (hasAllValues(mapperModel, context)) {
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String roleName = mapperModel.getConfig().get(ConfigConstants.ROLE);
|
||||
RoleModel role = getRoleModel(realm, roleName);
|
||||
if (hasAllValues(mapperModel, context)) {
|
||||
user.grantRole(role);
|
||||
} else {
|
||||
user.deleteRoleMapping(role);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "If the set of attributes exists and can be matched, grant the user the specified realm or application role.";
|
||||
}
|
||||
|
||||
static RoleModel getRoleModel(RealmModel realm, String roleName) {
|
||||
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||
if (role == null) {
|
||||
throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
boolean hasAllValues(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
Map<String, String> attributes = mapperModel.getConfigMap(ATTRIBUTE_PROPERTY_NAME);
|
||||
boolean areAttributeValuesRegexes = Boolean.parseBoolean(mapperModel.getConfig().get(ARE_ATTRIBUTE_VALUES_REGEX_PROPERTY_NAME));
|
||||
|
||||
AssertionType assertion = (AssertionType) context.getContextData().get(SAMLEndpoint.SAML_ASSERTION);
|
||||
Set<AttributeStatementType> attributeAssertions = assertion.getAttributeStatements();
|
||||
if (attributeAssertions == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
String attributeKey = attribute.getKey();
|
||||
List<Object> attributeValues = attributeAssertions.stream()
|
||||
.flatMap(statements -> statements.getAttributes().stream())
|
||||
.filter(choiceType -> attributeKey.equals(choiceType.getAttribute().getName())
|
||||
|| attributeKey.equals(choiceType.getAttribute().getFriendlyName()))
|
||||
// Several statements with same name are treated like one with several values
|
||||
.flatMap(choiceType -> choiceType.getAttribute().getAttributeValue().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
boolean attributeValueMatch = areAttributeValuesRegexes ? valueMatchesRegex(attribute.getValue(), attributeValues) : attributeValues.contains(attribute.getValue());
|
||||
if (!attributeValueMatch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -164,7 +164,7 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "If a claim exists, grant the user the specified realm or application role.";
|
||||
return "If an attribute exists, grant the user the specified realm or application role.";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
42
services/src/main/java/org/keycloak/utils/RegexUtils.java
Normal file
42
services/src/main/java/org/keycloak/utils/RegexUtils.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2020 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.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <a href="mailto:external.benjamin.weimer@bosch-si.com">Benjamin Weimer</a>,
|
||||
*/
|
||||
public class RegexUtils {
|
||||
public static boolean valueMatchesRegex(String regex, Object value) {
|
||||
if (value instanceof List) {
|
||||
List list = (List) value;
|
||||
for (Object val : list) {
|
||||
if (valueMatchesRegex(regex, val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value != null) {
|
||||
String stringValue = value.toString();
|
||||
return stringValue != null && stringValue.matches(regex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ org.keycloak.broker.oidc.mappers.AdvancedClaimToRoleMapper
|
|||
org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper
|
||||
org.keycloak.broker.oidc.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.oidc.mappers.UsernameTemplateMapper
|
||||
org.keycloak.broker.saml.mappers.AdvancedAttributeToRoleMapper
|
||||
org.keycloak.broker.saml.mappers.AttributeToRoleMapper
|
||||
org.keycloak.broker.saml.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.saml.mappers.UsernameTemplateMapper
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package org.keycloak.utils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* <a href="mailto:external.benjamin.weimer@bosch-si.com">Benjamin Weimer</a>,
|
||||
*/
|
||||
public class RegexUtilsTest {
|
||||
@Test
|
||||
public void valueMatchesRegexTest() {
|
||||
assertThat(RegexUtils.valueMatchesRegex("AB.*", "AB_ADMIN"), is(true));
|
||||
assertThat(RegexUtils.valueMatchesRegex("AB.*", "AA_ADMIN"), is(false));
|
||||
assertThat(RegexUtils.valueMatchesRegex("99.*", 999), is(true));
|
||||
assertThat(RegexUtils.valueMatchesRegex("98.*", 999), is(false));
|
||||
assertThat(RegexUtils.valueMatchesRegex("99\\..*", 99.9), is(true));
|
||||
assertThat(RegexUtils.valueMatchesRegex("AB.*", null), is(false));
|
||||
assertThat(RegexUtils.valueMatchesRegex("AB.*", Arrays.asList("AB_ADMIN", "AA_ADMIN")), is(true));
|
||||
}
|
||||
|
||||
}
|
|
@ -569,7 +569,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
|||
create(createRep("saml", "saml"));
|
||||
provider = realm.identityProviders().get("saml");
|
||||
mapperTypes = provider.getMapperTypes();
|
||||
assertMapperTypes(mapperTypes, "saml-user-attribute-idp-mapper", "saml-role-idp-mapper", "saml-username-idp-mapper");
|
||||
assertMapperTypes(mapperTypes, "saml-user-attribute-idp-mapper", "saml-role-idp-mapper", "saml-username-idp-mapper", "saml-advanced-role-idp-mapper");
|
||||
}
|
||||
|
||||
private void assertMapperTypes(Map<String, IdentityProviderMapperTypeRepresentation> mapperTypes, String ... mapperIds) {
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.models.IdentityProviderMapperSyncMode.FORCE;
|
||||
import static org.keycloak.models.IdentityProviderMapperSyncMode.IMPORT;
|
||||
|
||||
/**
|
||||
* @author hmlnarik,
|
||||
* <a href="mailto:external.benjamin.weimer@bosch-si.com">Benjamin Weimer</a>,
|
||||
* <a href="mailto:external.martin.idel@bosch.io">Martin Idel</a>
|
||||
*/
|
||||
public abstract class AbstractAdvancedRoleMapperTest extends AbstractRoleMapperTest {
|
||||
|
||||
private static final String CLAIMS_OR_ATTRIBUTES = "[\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME + "\",\n" +
|
||||
" \"value\": \"value 1\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2 + "\",\n" +
|
||||
" \"value\": \"value 2\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
private static final String CLAIMS_OR_ATTRIBUTES_REGEX = "[\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME + "\",\n" +
|
||||
" \"value\": \"va.*\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2 + "\",\n" +
|
||||
" \"value\": \"value 2\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
private String newValueForAttribute2 = "";
|
||||
|
||||
@Test
|
||||
public void allValuesMatch() {
|
||||
createAdvancedRoleMapper(CLAIMS_OR_ATTRIBUTES, false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valuesMismatch() {
|
||||
createAdvancedRoleMapper(CLAIMS_OR_ATTRIBUTES, false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value mismatch").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valuesMatchIfNoClaimsSpecified() {
|
||||
createAdvancedRoleMapper("[]", false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("some value").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("some value").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allValuesMatchRegex() {
|
||||
createAdvancedRoleMapper(CLAIMS_OR_ATTRIBUTES_REGEX, true);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valuesMismatchRegex() {
|
||||
createAdvancedRoleMapper(CLAIMS_OR_ATTRIBUTES_REGEX, true);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("mismatch").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMismatchDeletesRole() {
|
||||
newValueForAttribute2 = "value mismatch";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, false);
|
||||
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMismatchDoesNotDeleteRoleInImportMode() {
|
||||
newValueForAttribute2 = "value mismatch";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(IMPORT, false);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMatchDoesntDeleteRole() {
|
||||
newValueForAttribute2 = "value 2";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, false);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserAssignsRoleInForceModeWhenCreatingTheMapperAfterFirstLogin() {
|
||||
newValueForAttribute2 = "value 2";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, true);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
public UserRepresentation createMapperAndLoginAsUserTwiceWithMapper(IdentityProviderMapperSyncMode syncMode, boolean createAfterFirstLogin) {
|
||||
return loginAsUserTwiceWithMapper(syncMode, createAfterFirstLogin, ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateUser() {
|
||||
UserRepresentation user = findUser(bc.providerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
ImmutableMap<String, List<String>> matchingAttributes = ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add(newValueForAttribute2).build())
|
||||
.put("some.other.attribute", ImmutableList.<String>builder().add("some value").build())
|
||||
.build();
|
||||
user.setAttributes(matchingAttributes);
|
||||
adminClient.realm(bc.providerRealmName()).users().get(user.getId()).update(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createMapperInIdp(IdentityProviderRepresentation idp, IdentityProviderMapperSyncMode syncMode) {
|
||||
createMapperInIdp(idp, CLAIMS_OR_ATTRIBUTES, false, syncMode);
|
||||
}
|
||||
|
||||
protected void createAdvancedRoleMapper(String claimsOrAttributeRepresentation, boolean areClaimsOrAttributeValuesRegexes) {
|
||||
IdentityProviderRepresentation idp = setupIdentityProvider();
|
||||
createMapperInIdp(idp, claimsOrAttributeRepresentation, areClaimsOrAttributeValuesRegexes, IMPORT);
|
||||
}
|
||||
|
||||
abstract protected void createMapperInIdp(
|
||||
IdentityProviderRepresentation idp, String claimsOrAttributeRepresentation, boolean areClaimsOrAttributeValuesRegexes, IdentityProviderMapperSyncMode syncMode);
|
||||
}
|
|
@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot;
|
||||
import static org.keycloak.testsuite.broker.KcSamlBrokerConfiguration.ATTRIBUTE_TO_MAP_FRIENDLY_NAME;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -31,7 +32,6 @@ public abstract class AbstractUserAttributeMapperTest extends AbstractIdentityPr
|
|||
|
||||
protected static final String MAPPED_ATTRIBUTE_NAME = "mapped-user-attribute";
|
||||
protected static final String MAPPED_ATTRIBUTE_FRIENDLY_NAME = "mapped-user-attribute-friendly";
|
||||
protected static final String ATTRIBUTE_TO_MAP_FRIENDLY_NAME = "user-attribute-friendly";
|
||||
|
||||
private static final Set<String> PROTECTED_NAMES = ImmutableSet.<String>builder().add("email").add("lastName").add("firstName").build();
|
||||
private static final Map<String, String> ATTRIBUTE_NAME_TRANSLATION = ImmutableMap.<String, String>builder()
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.broker.provider.ConfigConstants;
|
||||
import org.keycloak.broker.saml.mappers.AdvancedAttributeToRoleMapper;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.broker.KcSamlBrokerConfiguration.ATTRIBUTE_TO_MAP_FRIENDLY_NAME;
|
||||
|
||||
/**
|
||||
* <a href="mailto:external.martin.idel@bosch.io">Martin Idel</a>
|
||||
*/
|
||||
public class KcSamlAdvancedAttributeToRoleMapperTest extends AbstractAdvancedRoleMapperTest {
|
||||
|
||||
private static final String ATTRIBUTES = "[\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + ATTRIBUTE_TO_MAP_FRIENDLY_NAME + "\",\n" +
|
||||
" \"value\": \"value 1\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2 + "\",\n" +
|
||||
" \"value\": \"value 2\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
|
||||
@Override
|
||||
protected BrokerConfiguration getBrokerConfiguration() {
|
||||
return new KcSamlBrokerConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createMapperInIdp(IdentityProviderRepresentation idp, String claimsOrAttributeRepresentation, boolean areClaimsOrAttributeValuesRegexes, IdentityProviderMapperSyncMode syncMode) {
|
||||
IdentityProviderMapperRepresentation advancedAttributeToRoleMapper = new IdentityProviderMapperRepresentation();
|
||||
advancedAttributeToRoleMapper.setName("advanced-attribute-to-role-mapper");
|
||||
advancedAttributeToRoleMapper.setIdentityProviderMapper(AdvancedAttributeToRoleMapper.PROVIDER_ID);
|
||||
advancedAttributeToRoleMapper.setConfig(ImmutableMap.<String, String>builder()
|
||||
.put(IdentityProviderMapperModel.SYNC_MODE, syncMode.toString())
|
||||
.put(AdvancedAttributeToRoleMapper.ATTRIBUTE_PROPERTY_NAME, claimsOrAttributeRepresentation)
|
||||
.put(AdvancedAttributeToRoleMapper.ARE_ATTRIBUTE_VALUES_REGEX_PROPERTY_NAME, areClaimsOrAttributeValuesRegexes ? "true" : "false")
|
||||
.put(ConfigConstants.ROLE, CLIENT_ROLE_MAPPER_REPRESENTATION)
|
||||
.build());
|
||||
|
||||
IdentityProviderResource idpResource = realm.identityProviders().get(idp.getAlias());
|
||||
advancedAttributeToRoleMapper.setIdentityProviderAlias(bc.getIDPAlias());
|
||||
idpResource.addMapper(advancedAttributeToRoleMapper).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void attributeFriendlyNameGetsConsideredAndMatchedToRole() {
|
||||
createAdvancedRoleMapper(ATTRIBUTES, false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(ATTRIBUTE_TO_MAP_FRIENDLY_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
}
|
|
@ -35,6 +35,7 @@ import static org.keycloak.testsuite.broker.BrokerTestTools.*;
|
|||
public class KcSamlBrokerConfiguration implements BrokerConfiguration {
|
||||
|
||||
public static final KcSamlBrokerConfiguration INSTANCE = new KcSamlBrokerConfiguration();
|
||||
public static final String ATTRIBUTE_TO_MAP_FRIENDLY_NAME = "user-attribute-friendly";
|
||||
|
||||
@Override
|
||||
public RealmRepresentation createProviderRealm() {
|
||||
|
@ -131,18 +132,29 @@ public class KcSamlBrokerConfiguration implements BrokerConfiguration {
|
|||
userAttrMapperConfig.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC);
|
||||
userAttrMapperConfig.put(AttributeStatementHelper.FRIENDLY_NAME, "");
|
||||
|
||||
ProtocolMapperRepresentation userAttrMapper2 = new ProtocolMapperRepresentation();
|
||||
userAttrMapper2.setName("attribute - name 2");
|
||||
userAttrMapper2.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
|
||||
userAttrMapper2.setProtocolMapper(UserAttributeStatementMapper.PROVIDER_ID);
|
||||
|
||||
Map<String, String> userAttrMapper2Config = userAttrMapper2.getConfig();
|
||||
userAttrMapper2Config.put(ProtocolMapperUtils.USER_ATTRIBUTE, KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2);
|
||||
userAttrMapper2Config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2);
|
||||
userAttrMapper2Config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC);
|
||||
userAttrMapper2Config.put(AttributeStatementHelper.FRIENDLY_NAME, "");
|
||||
|
||||
ProtocolMapperRepresentation userFriendlyAttrMapper = new ProtocolMapperRepresentation();
|
||||
userFriendlyAttrMapper.setName("attribute - friendly name");
|
||||
userFriendlyAttrMapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
|
||||
userFriendlyAttrMapper.setProtocolMapper(UserAttributeStatementMapper.PROVIDER_ID);
|
||||
|
||||
Map<String, String> userFriendlyAttrMapperConfig = userFriendlyAttrMapper.getConfig();
|
||||
userFriendlyAttrMapperConfig.put(ProtocolMapperUtils.USER_ATTRIBUTE, AbstractUserAttributeMapperTest.ATTRIBUTE_TO_MAP_FRIENDLY_NAME);
|
||||
userFriendlyAttrMapperConfig.put(ProtocolMapperUtils.USER_ATTRIBUTE, ATTRIBUTE_TO_MAP_FRIENDLY_NAME);
|
||||
userFriendlyAttrMapperConfig.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "urn:oid:1.2.3.4.5.6.7");
|
||||
userFriendlyAttrMapperConfig.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, AttributeStatementHelper.BASIC);
|
||||
userFriendlyAttrMapperConfig.put(AttributeStatementHelper.FRIENDLY_NAME, AbstractUserAttributeMapperTest.ATTRIBUTE_TO_MAP_FRIENDLY_NAME);
|
||||
userFriendlyAttrMapperConfig.put(AttributeStatementHelper.FRIENDLY_NAME, ATTRIBUTE_TO_MAP_FRIENDLY_NAME);
|
||||
|
||||
client.setProtocolMappers(Arrays.asList(emailMapper, dottedAttrMapper, nestedAttrMapper, userAttrMapper, userFriendlyAttrMapper));
|
||||
client.setProtocolMappers(Arrays.asList(emailMapper, dottedAttrMapper, nestedAttrMapper, userAttrMapper, userAttrMapper2, userFriendlyAttrMapper));
|
||||
|
||||
return client;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ public final class KcSamlBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
attrMapper3.setIdentityProviderMapper(AttributeToRoleMapper.PROVIDER_ID);
|
||||
attrMapper3.setConfig(ImmutableMap.<String,String>builder()
|
||||
.put(IdentityProviderMapperModel.SYNC_MODE, syncMode.toString())
|
||||
.put(UserAttributeMapper.ATTRIBUTE_FRIENDLY_NAME, AbstractUserAttributeMapperTest.ATTRIBUTE_TO_MAP_FRIENDLY_NAME)
|
||||
.put(UserAttributeMapper.ATTRIBUTE_FRIENDLY_NAME, KcSamlBrokerConfiguration.ATTRIBUTE_TO_MAP_FRIENDLY_NAME)
|
||||
.put(ATTRIBUTE_VALUE, ROLE_FRIENDLY_MANAGER)
|
||||
.put("role", ROLE_FRIENDLY_MANAGER)
|
||||
.build());
|
||||
|
@ -216,7 +216,7 @@ public final class KcSamlBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
|
||||
UserRepresentation urp = userResourceProv.toRepresentation();
|
||||
urp.setAttributes(new HashMap<>());
|
||||
urp.getAttributes().put(AbstractUserAttributeMapperTest.ATTRIBUTE_TO_MAP_FRIENDLY_NAME, Collections.singletonList(ROLE_FRIENDLY_MANAGER));
|
||||
urp.getAttributes().put(KcSamlBrokerConfiguration.ATTRIBUTE_TO_MAP_FRIENDLY_NAME, Collections.singletonList(ROLE_FRIENDLY_MANAGER));
|
||||
userResourceProv.update(urp);
|
||||
userResourceProv.roles().realmLevel().add(Collections.singletonList(userRole));
|
||||
userResourceProv.roles().realmLevel().add(Collections.singletonList(userRoleDotGuide));
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.keycloak.models.IdentityProviderMapperSyncMode.FORCE;
|
||||
import static org.keycloak.models.IdentityProviderMapperSyncMode.IMPORT;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.broker.oidc.mappers.AdvancedClaimToRoleMapper;
|
||||
import org.keycloak.broker.provider.ConfigConstants;
|
||||
|
@ -16,200 +8,26 @@ import org.keycloak.models.IdentityProviderMapperModel;
|
|||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author hmlnarik,
|
||||
* <a href="mailto:external.benjamin.weimer@bosch-si.com">Benjamin Weimer</a>,
|
||||
* <a href="mailto:external.martin.idel@bosch.io">Martin Idel</a>
|
||||
*/
|
||||
public class OidcAdvancedClaimToRoleMapperTest extends AbstractRoleMapperTest {
|
||||
|
||||
private static final String CLAIMS = "[\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME + "\",\n" +
|
||||
" \"value\": \"value 1\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2 + "\",\n" +
|
||||
" \"value\": \"value 2\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
private static final String CLAIMS_REGEX = "[\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME + "\",\n" +
|
||||
" \"value\": \"va.*\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"key\": \"" + KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2 + "\",\n" +
|
||||
" \"value\": \"value 2\"\n" +
|
||||
" }\n" +
|
||||
"]";
|
||||
|
||||
private String newValueForAttribute2 = "";
|
||||
|
||||
public class OidcAdvancedClaimToRoleMapperTest extends AbstractAdvancedRoleMapperTest {
|
||||
@Override
|
||||
protected BrokerConfiguration getBrokerConfiguration() {
|
||||
return new KcOidcBrokerConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueMatchesRegexTest() {
|
||||
AdvancedClaimToRoleMapper advancedClaimToRoleMapper = new AdvancedClaimToRoleMapper();
|
||||
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("AB.*", "AB_ADMIN"), is(true));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("AB.*", "AA_ADMIN"), is(false));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("99.*", 999), is(true));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("98.*", 999), is(false));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("99\\..*", 99.9), is(true));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("AB.*", null), is(false));
|
||||
assertThat(advancedClaimToRoleMapper.valueMatchesRegex("AB.*", Arrays.asList("AB_ADMIN", "AA_ADMIN")), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allClaimValuesMatch() {
|
||||
createAdvancedClaimToRoleMapper(CLAIMS, false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void claimValuesMismatch() {
|
||||
createAdvancedClaimToRoleMapper(CLAIMS, false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value mismatch").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void claimValuesMatchIfNoClaimsSpecified() {
|
||||
createAdvancedClaimToRoleMapper("[]", false);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("some value").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("some value").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allClaimValuesMatchRegex() {
|
||||
createAdvancedClaimToRoleMapper(CLAIMS_REGEX, true);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void claimValuesMismatchRegex() {
|
||||
createAdvancedClaimToRoleMapper(CLAIMS_REGEX, true);
|
||||
createUserInProviderRealm(ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("mismatch").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
|
||||
logInAsUserInIDPForFirstTime();
|
||||
|
||||
UserRepresentation user = findUser(bc.consumerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMismatchDeletesRole() {
|
||||
newValueForAttribute2 = "value mismatch";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, false);
|
||||
|
||||
assertThatRoleHasNotBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMismatchDoesNotDeleteRoleInImportMode() {
|
||||
newValueForAttribute2 = "value mismatch";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(IMPORT, false);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserMatchDoesntDeleteRole() {
|
||||
newValueForAttribute2 = "value 2";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, false);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBrokeredUserAssignsRoleInForceModeWhenCreatingTheMapperAfterFirstLogin() {
|
||||
newValueForAttribute2 = "value 2";
|
||||
UserRepresentation user = createMapperAndLoginAsUserTwiceWithMapper(FORCE, true);
|
||||
|
||||
assertThatRoleHasBeenAssignedInConsumerRealmTo(user);
|
||||
}
|
||||
|
||||
public UserRepresentation createMapperAndLoginAsUserTwiceWithMapper(IdentityProviderMapperSyncMode syncMode, boolean createAfterFirstLogin) {
|
||||
return loginAsUserTwiceWithMapper(syncMode, createAfterFirstLogin, ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add("value 2").build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateUser() {
|
||||
UserRepresentation user = findUser(bc.providerRealmName(), bc.getUserLogin(), bc.getUserEmail());
|
||||
ImmutableMap<String, List<String>> matchingAttributes = ImmutableMap.<String, List<String>>builder()
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("value 1").build())
|
||||
.put(KcOidcBrokerConfiguration.ATTRIBUTE_TO_MAP_NAME_2, ImmutableList.<String>builder().add(newValueForAttribute2).build())
|
||||
.put("some.other.attribute", ImmutableList.<String>builder().add("some value").build())
|
||||
.build();
|
||||
user.setAttributes(matchingAttributes);
|
||||
adminClient.realm(bc.providerRealmName()).users().get(user.getId()).update(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createMapperInIdp(IdentityProviderRepresentation idp, IdentityProviderMapperSyncMode syncMode) {
|
||||
createAdvancedClaimToRoleMapperInIdp(idp, CLAIMS, false, syncMode);
|
||||
}
|
||||
|
||||
private void createAdvancedClaimToRoleMapper(String claimsRepresentation, boolean areClaimValuesRegex) {
|
||||
IdentityProviderRepresentation idp = setupIdentityProvider();
|
||||
createAdvancedClaimToRoleMapperInIdp(idp, claimsRepresentation, areClaimValuesRegex, IMPORT);
|
||||
}
|
||||
|
||||
protected void createAdvancedClaimToRoleMapperInIdp(IdentityProviderRepresentation idp , String claimsRepresentation, boolean areClaimValuesRegex, IdentityProviderMapperSyncMode syncMode) {
|
||||
protected void createMapperInIdp(IdentityProviderRepresentation idp, String claimsOrAttributeRepresentation, boolean areClaimsOrAttributeValuesRegexes, IdentityProviderMapperSyncMode syncMode) {
|
||||
IdentityProviderMapperRepresentation advancedClaimToRoleMapper = new IdentityProviderMapperRepresentation();
|
||||
advancedClaimToRoleMapper.setName("advanced-claim-to-role-mapper");
|
||||
advancedClaimToRoleMapper.setIdentityProviderMapper(AdvancedClaimToRoleMapper.PROVIDER_ID);
|
||||
advancedClaimToRoleMapper.setConfig(ImmutableMap.<String, String>builder()
|
||||
.put(IdentityProviderMapperModel.SYNC_MODE, syncMode.toString())
|
||||
.put(AdvancedClaimToRoleMapper.CLAIM_PROPERTY_NAME, claimsRepresentation)
|
||||
.put(AdvancedClaimToRoleMapper.ARE_CLAIM_VALUES_REGEX_PROPERTY_NAME, areClaimValuesRegex ? "true" : "false")
|
||||
.put(AdvancedClaimToRoleMapper.CLAIM_PROPERTY_NAME, claimsOrAttributeRepresentation)
|
||||
.put(AdvancedClaimToRoleMapper.ARE_CLAIM_VALUES_REGEX_PROPERTY_NAME, areClaimsOrAttributeValuesRegexes ? "true" : "false")
|
||||
.put(ConfigConstants.ROLE, CLIENT_ROLE_MAPPER_REPRESENTATION)
|
||||
.build());
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import static org.keycloak.testsuite.broker.KcSamlBrokerConfiguration.ATTRIBUTE_TO_MAP_FRIENDLY_NAME;
|
||||
|
||||
public class SamlUserAttributeMapperTest extends AbstractUserAttributeMapperTest {
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue