Introduce profile 'feature' for step-up authentication enabled by default
Closes #10315
This commit is contained in:
parent
48565832d4
commit
d394e51674
6 changed files with 47 additions and 6 deletions
|
@ -65,7 +65,8 @@ public class Profile {
|
|||
MAP_STORAGE("New store", Type.EXPERIMENTAL),
|
||||
PAR("OAuth 2.0 Pushed Authorization Requests (PAR)", Type.DEFAULT),
|
||||
DECLARATIVE_USER_PROFILE("Configure user profiles using a declarative style", Type.PREVIEW),
|
||||
DYNAMIC_SCOPES("Dynamic OAuth 2.0 scopes", Type.EXPERIMENTAL);
|
||||
DYNAMIC_SCOPES("Dynamic OAuth 2.0 scopes", Type.EXPERIMENTAL),
|
||||
STEP_UP_AUTHENTICATION("Step-up Authentication", Type.DEFAULT);
|
||||
|
||||
private String label;
|
||||
private final Type typeProject;
|
||||
|
|
|
@ -21,13 +21,15 @@ import java.util.List;
|
|||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthenticationFlowCallbackFactory;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
|
||||
public class ConditionalLoaAuthenticatorFactory implements ConditionalAuthenticatorFactory, AuthenticationFlowCallbackFactory {
|
||||
public class ConditionalLoaAuthenticatorFactory implements ConditionalAuthenticatorFactory, AuthenticationFlowCallbackFactory, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "conditional-level-of-authentication";
|
||||
private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = new AuthenticationExecutionModel.Requirement[]{
|
||||
|
@ -105,4 +107,9 @@ public class ConditionalLoaAuthenticatorFactory implements ConditionalAuthentica
|
|||
// NOP - instance created in create() method
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.STEP_UP_AUTHENTICATION);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -884,7 +884,13 @@ public class TokenManager {
|
|||
token.setNonce(clientSessionCtx.getAttribute(OIDCLoginProtocol.NONCE_PARAM, String.class));
|
||||
token.setScope(clientSessionCtx.getScopeString());
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.STEP_UP_AUTHENTICATION)) {
|
||||
token.setAcr(getAcr(clientSession));
|
||||
} else {
|
||||
// Backwards compatibility behaviour prior step-up authentication was introduced
|
||||
String acr = AuthenticationManager.isSSOAuthentication(clientSession) ? "0" : "1";
|
||||
token.setAcr(acr);
|
||||
}
|
||||
|
||||
String authTime = session.getNote(AuthenticationManager.AUTH_TIME);
|
||||
if (authTime != null) {
|
||||
|
|
|
@ -31,11 +31,13 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory;
|
||||
import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.conditional.ConditionalLoaAuthenticatorFactory;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.models.AuthenticationExecutionModel.Requirement;
|
||||
import org.keycloak.models.Constants;
|
||||
|
@ -44,6 +46,7 @@ import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
|||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.ClaimsRepresentation;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -51,9 +54,12 @@ import org.keycloak.representations.idm.UserRepresentation;
|
|||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.admin.authentication.AbstractAuthenticationTest;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
||||
import org.keycloak.testsuite.authentication.PushButtonAuthenticatorFactory;
|
||||
import org.keycloak.testsuite.client.KeycloakTestingClient;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.ErrorPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.LoginTotpPage;
|
||||
|
@ -66,6 +72,7 @@ import org.keycloak.testsuite.util.WaitUtils;
|
|||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||
|
||||
/**
|
||||
|
@ -617,6 +624,26 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisableFeature(value = Profile.Feature.STEP_UP_AUTHENTICATION, skipRestart = true)
|
||||
public void testDisableStepupFeatureTest() {
|
||||
BrowserFlowTest.revertFlows(testRealm(), "browser - Level of Authentication FLow");
|
||||
|
||||
// Login normal way - should return 1 (backwards compatibility before step-up was introduced)
|
||||
loginPage.open();
|
||||
authenticateWithUsernamePassword();
|
||||
authenticateWithTotp(); // OTP required due the user has it
|
||||
assertLoggedInWithAcr("1");
|
||||
|
||||
// SSO login - should return 0 (backwards compatibility before step-up was introduced)
|
||||
oauth.openLoginForm();
|
||||
assertLoggedInWithAcr("0");
|
||||
|
||||
// Flow is needed due the "after()" method
|
||||
testingClient.server(TEST_REALM_NAME).run(session -> FlowUtil.inCurrentRealm(session).copyBrowserFlow("browser - Level of Authentication FLow"));
|
||||
}
|
||||
|
||||
|
||||
public void openLoginFormWithAcrClaim(boolean essential, String... acrValues) {
|
||||
openLoginFormWithAcrClaim(oauth, essential, acrValues);
|
||||
}
|
||||
|
|
|
@ -932,7 +932,7 @@
|
|||
<kc-tooltip>{{:: 'require-pushed-authorization-requests.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group clearfix block" data-ng-show="!clientEdit.bearerOnly && protocol == 'openid-connect'">
|
||||
<div class="form-group clearfix block" data-ng-show="!clientEdit.bearerOnly && protocol == 'openid-connect' && serverInfo.featureEnabled('STEP_UP_AUTHENTICATION')">
|
||||
<label class="col-md-2 control-label" for="newAcr">{{:: 'acr-loa-map' | translate}}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group input-map" ng-repeat="(acr, loa) in acrLoaMap">
|
||||
|
@ -953,7 +953,7 @@
|
|||
<kc-tooltip>{{:: 'acr-loa-map-client.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group" data-ng-show="!clientEdit.bearerOnly && protocol == 'openid-connect'">
|
||||
<div class="form-group" data-ng-show="!clientEdit.bearerOnly && protocol == 'openid-connect' && serverInfo.featureEnabled('STEP_UP_AUTHENTICATION')">
|
||||
<label class="col-md-2 control-label" for="newDefaultAcrValue">{{:: 'default-acr-values' | translate}}</label>
|
||||
|
||||
<div class="col-sm-6">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</div>
|
||||
<kc-tooltip>{{:: 'sslRequired.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<div class="form-group clearfix block" data-ng-show="serverInfo.featureEnabled('STEP_UP_AUTHENTICATION')">
|
||||
<label class="col-md-2 control-label" for="newAcr">{{:: 'acr-loa-map' | translate}}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group input-map" ng-repeat="(acr, loa) in acrLoaMap">
|
||||
|
|
Loading…
Reference in a new issue