Skip to content

Commit

Permalink
KEYCLOAK-2311 - Allow to specify role to skip conditional OTP authent…
Browse files Browse the repository at this point in the history
…ication.

We now allow specify a role to skip OTP.
Previously it was  not possible to specify that OTP authentication should be skipped via a role but the
ConditionalOtpAuthenticator allowed to specify to show/skip OTP via a user attribute or HTTP request header pattern.
Having the "skip role" aligns the role based configuration options with the user attribute and HTTP request header configuration.
  • Loading branch information
thomasdarimont committed Jan 14, 2016
1 parent 714e2fa commit 92c2ec3
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
Expand Up @@ -37,8 +37,9 @@
* </p>
* <p>
* <h2>Role</h2>
* A role can be used to control the OTP authentication. If the user has the specified role the OTP authentication is forced.
* Otherwise if no role is selected the setting is ignored.
* A role can be used to control the OTP authentication. If the user has the specified skip OTP role then OTP authentication is skipped for the user.
* If the user has the specified force OTP role, then the OTP authentication is required for the user.
* If not configured, e.g. if no role is selected, then this setting is ignored.
* <p>
* </p>
* <p>
Expand Down Expand Up @@ -67,6 +68,8 @@ public class ConditionalOtpFormAuthenticator extends OTPFormAuthenticator {

public static final String OTP_CONTROL_USER_ATTRIBUTE = "otpControlAttribute";

public static final String SKIP_OTP_ROLE = "skipOtpRole";

public static final String FORCE_OTP_ROLE = "forceOtpRole";

public static final String NO_OTP_REQUIRED_FOR_HTTP_HEADER = "noOtpRequiredForHeaderPattern";
Expand All @@ -88,7 +91,7 @@ public void authenticate(AuthenticationFlowContext context) {
return;
}

if (tryConcludeBasedOn(voteForUserForceOtpRole(context, config), context)) {
if (tryConcludeBasedOn(voteForUserRole(context, config), context)) {
return;
}

Expand Down Expand Up @@ -216,19 +219,32 @@ private boolean containsMatchingRequestHeader(MultivaluedMap<String, String> req
return false;
}

private OtpDecision voteForUserForceOtpRole(AuthenticationFlowContext context, Map<String, String> config) {
private OtpDecision voteForUserRole(AuthenticationFlowContext context, Map<String, String> config) {

if (!config.containsKey(FORCE_OTP_ROLE)) {
if (!config.containsKey(SKIP_OTP_ROLE) && !config.containsKey(FORCE_OTP_ROLE)) {
return ABSTAIN;
}

RoleModel forceOtpRole = getRoleFromString(context.getRealm(), config.get(FORCE_OTP_ROLE));
UserModel user = context.getUser();
if (userHasRole(context, config.get(SKIP_OTP_ROLE))) {
return SKIP_OTP;
}

if (hasRole(user.getRoleMappings(), forceOtpRole)) {
if (userHasRole(context, config.get(FORCE_OTP_ROLE))) {
return SHOW_OTP;
}

return ABSTAIN;
}

private boolean userHasRole(AuthenticationFlowContext context, String roleName) {

if (roleName == null) {
return false;
}

RoleModel role = getRoleFromString(context.getRealm(), roleName);
UserModel user = context.getUser();

return hasRole(user.getRoleMappings(), role);
}
}
Expand Up @@ -98,6 +98,12 @@ public List<ProviderConfigProperty> getConfigProperties() {
"If attribute value is 'force' then OTP is always required. " +
"If value is 'skip' the OTP auth is skipped. Otherwise this check is ignored.");

ProviderConfigProperty skipOtpRole = new ProviderConfigProperty();
skipOtpRole.setType(ROLE_TYPE);
skipOtpRole.setName(SKIP_OTP_ROLE);
skipOtpRole.setLabel("Skip OTP for Role");
skipOtpRole.setHelpText("OTP is always skipped if user has the given Role.");

ProviderConfigProperty forceOtpRole = new ProviderConfigProperty();
forceOtpRole.setType(ROLE_TYPE);
forceOtpRole.setName(FORCE_OTP_ROLE);
Expand Down Expand Up @@ -127,6 +133,6 @@ public List<ProviderConfigProperty> getConfigProperties() {
defaultOutcome.setDefaultValue(asList(SKIP, FORCE));
defaultOutcome.setHelpText("What to do in case of every check abstains. Defaults to force OTP authentication.");

return asList(forceOtpUserAttribute, forceOtpRole, noOtpRequiredForHttpHeader, forceOtpForHttpHeader, defaultOutcome);
return asList(forceOtpUserAttribute, skipOtpRole, forceOtpRole, noOtpRequiredForHttpHeader, forceOtpForHttpHeader, defaultOutcome);
}
}

0 comments on commit 92c2ec3

Please sign in to comment.