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>
* <p> * <p>
* <h2>Role</h2> * <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. * 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.
* Otherwise if no role is selected the setting is ignored. * 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> * </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 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 FORCE_OTP_ROLE = "forceOtpRole";


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


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


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


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


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


return ABSTAIN; 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 attribute value is 'force' then OTP is always required. " +
"If value is 'skip' the OTP auth is skipped. Otherwise this check is ignored."); "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(); ProviderConfigProperty forceOtpRole = new ProviderConfigProperty();
forceOtpRole.setType(ROLE_TYPE); forceOtpRole.setType(ROLE_TYPE);
forceOtpRole.setName(FORCE_OTP_ROLE); forceOtpRole.setName(FORCE_OTP_ROLE);
Expand Down Expand Up @@ -127,6 +133,6 @@ public List<ProviderConfigProperty> getConfigProperties() {
defaultOutcome.setDefaultValue(asList(SKIP, FORCE)); defaultOutcome.setDefaultValue(asList(SKIP, FORCE));
defaultOutcome.setHelpText("What to do in case of every check abstains. Defaults to force OTP authentication."); 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.