Add regex support in 'Condition - User attribute' execution
Closes #265
This commit is contained in:
parent
48ab2b1688
commit
0044472f87
3 changed files with 48 additions and 3 deletions
|
@ -27,6 +27,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
|||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ConditionalUserAttributeValue implements ConditionalAuthenticator {
|
||||
|
||||
|
@ -40,15 +41,16 @@ public class ConditionalUserAttributeValue implements ConditionalAuthenticator {
|
|||
String attributeValue = config.get(ConditionalUserAttributeValueFactory.CONF_ATTRIBUTE_EXPECTED_VALUE);
|
||||
boolean includeGroupAttributes = Boolean.parseBoolean(config.get(ConditionalUserAttributeValueFactory.CONF_INCLUDE_GROUP_ATTRIBUTES));
|
||||
boolean negateOutput = Boolean.parseBoolean(config.get(ConditionalUserAttributeValueFactory.CONF_NOT));
|
||||
boolean regexOutput = Boolean.parseBoolean(config.get(ConditionalUserAttributeValueFactory.REGEX));
|
||||
|
||||
UserModel user = context.getUser();
|
||||
if (user == null) {
|
||||
throw new AuthenticationFlowException("Cannot find user for obtaining particular user attributes. Authenticator: " + ConditionalUserAttributeValueFactory.PROVIDER_ID, AuthenticationFlowError.UNKNOWN_USER);
|
||||
}
|
||||
|
||||
boolean result = user.getAttributeStream(attributeName).anyMatch(attr -> Objects.equals(attr, attributeValue));
|
||||
boolean result = user.getAttributeStream(attributeName).anyMatch(attr -> regexOutput ? Pattern.compile(attributeValue).matcher(attr).matches() : Objects.equals(attr, attributeValue));
|
||||
if (!result && includeGroupAttributes) {
|
||||
result = KeycloakModelUtils.resolveAttribute(user, attributeName, true).stream().anyMatch(attr -> Objects.equals(attr, attributeValue));
|
||||
result = KeycloakModelUtils.resolveAttribute(user, attributeName, true).stream().anyMatch(attr -> regexOutput ? Pattern.compile(attributeValue).matcher(attr).matches() : Objects.equals(attr, attributeValue));
|
||||
}
|
||||
return negateOutput != result;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public class ConditionalUserAttributeValueFactory implements ConditionalAuthenti
|
|||
public static final String CONF_ATTRIBUTE_EXPECTED_VALUE = "attribute_expected_value";
|
||||
public static final String CONF_INCLUDE_GROUP_ATTRIBUTES = "include_group_attributes";
|
||||
public static final String CONF_NOT = "not";
|
||||
public static final String REGEX = "regex";
|
||||
|
||||
private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.DISABLED
|
||||
|
@ -109,7 +110,13 @@ public class ConditionalUserAttributeValueFactory implements ConditionalAuthenti
|
|||
negateOutput.setLabel("Negate output");
|
||||
negateOutput.setHelpText("Apply a not to the check result");
|
||||
|
||||
return Arrays.asList(authNoteName, authNoteExpectedValue, includeGroupAttributes, negateOutput);
|
||||
ProviderConfigProperty regexOutput = new ProviderConfigProperty();
|
||||
regexOutput.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
regexOutput.setName(REGEX);
|
||||
regexOutput.setLabel(REGEX);
|
||||
regexOutput.setHelpText("Check equality with regex");
|
||||
|
||||
return Arrays.asList(authNoteName, authNoteExpectedValue, includeGroupAttributes, negateOutput, regexOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -146,6 +146,42 @@ public class AllowDenyAuthenticatorTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDenyAccessWithRegexUserAttributeCondition() {
|
||||
final String flowAlias = "browser - user attribute condition";
|
||||
final String userWithoutAttribute = "test-user@localhost";
|
||||
final String errorMessage = "You don't have necessary attribute.";
|
||||
|
||||
Map<String, String> attributeConfigMap = new HashMap<>();
|
||||
attributeConfigMap.put(ConditionalUserAttributeValueFactory.CONF_ATTRIBUTE_NAME, "firstName");
|
||||
attributeConfigMap.put(ConditionalUserAttributeValueFactory.CONF_ATTRIBUTE_EXPECTED_VALUE, "T(.*)");
|
||||
attributeConfigMap.put(ConditionalUserAttributeValueFactory.REGEX, "true");
|
||||
|
||||
Map<String, String> denyAccessConfigMap = new HashMap<>();
|
||||
denyAccessConfigMap.put(DenyAccessAuthenticatorFactory.ERROR_MESSAGE, errorMessage);
|
||||
|
||||
configureBrowserFlowWithDenyAccessInConditionalFlow(flowAlias, ConditionalUserAttributeValueFactory.PROVIDER_ID, attributeConfigMap, denyAccessConfigMap);
|
||||
|
||||
try {
|
||||
loginUsernameOnlyPage.open();
|
||||
loginUsernameOnlyPage.assertCurrent();
|
||||
loginUsernameOnlyPage.login(userWithoutAttribute);
|
||||
|
||||
errorPage.assertCurrent();
|
||||
assertThat(errorPage.getError(), is(errorMessage));
|
||||
|
||||
events.expectLogin()
|
||||
.user((String) null)
|
||||
.session((String) null)
|
||||
.error(Errors.ACCESS_DENIED)
|
||||
.detail(Details.USERNAME, userWithoutAttribute)
|
||||
.removeDetail(Details.CONSENT)
|
||||
.assertEvent();
|
||||
} finally {
|
||||
revertFlows(testRealm(), flowAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access, if user has defined the role and print error message.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue