Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ public static String nextRequiredAction(final KeycloakSession session, final Aut

final var kcAction = authSession.getClientNote(Constants.KC_ACTION);
final var nextApplicableAction =
getFirstApplicableRequiredAction(realm, authSession, user, kcAction);
getFirstApplicableRequiredAction(realm, authSession, user, kcAction, new HashSet<>());
if (nextApplicableAction != null) {
return nextApplicableAction.getAlias();
}
Expand Down Expand Up @@ -1232,7 +1232,7 @@ protected static Response executionActions(KeycloakSession session, Authenticati
HttpRequest request, EventBuilder event, RealmModel realm, UserModel user, Set<String> ignoredActions) {
final var kcAction = authSession.getClientNote(Constants.KC_ACTION);
final var firstApplicableRequiredAction =
getFirstApplicableRequiredAction(realm, authSession, user, kcAction);
getFirstApplicableRequiredAction(realm, authSession, user, kcAction, ignoredActions);

if (firstApplicableRequiredAction != null) {
return executeAction(session, authSession, firstApplicableRequiredAction, request, event, realm, user,
Expand Down Expand Up @@ -1265,11 +1265,13 @@ private static Response executeAction(KeycloakSession session, AuthenticationSes
if (actionProvider.initiatedActionSupport() == InitiatedActionSupport.NOT_SUPPORTED) {
logger.debugv("Requested action {0} does not support being invoked with kc_action", factory.getId());
setKcActionStatus(factory.getId(), RequiredActionContext.KcActionStatus.ERROR, authSession);
return null;
ignoredActions.add(factory.getId());
return nextActionAfterAuthentication(session, authSession, session.getContext().getConnection(), request, session.getContext().getUri(), event, ignoredActions);
} else if (!model.isEnabled()) {
logger.debugv("Requested action {0} is disabled and can't be invoked with kc_action", factory.getId());
setKcActionStatus(factory.getId(), RequiredActionContext.KcActionStatus.ERROR, authSession);
return null;
ignoredActions.add(factory.getId());
return nextActionAfterAuthentication(session, authSession, session.getContext().getConnection(), request, session.getContext().getUri(), event, ignoredActions);
} else {
authSession.setClientNote(Constants.KC_ACTION_EXECUTING, factory.getId());
}
Expand Down Expand Up @@ -1311,9 +1313,9 @@ else if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
}

private static RequiredActionProviderModel getFirstApplicableRequiredAction(final RealmModel realm,
final AuthenticationSessionModel authSession, final UserModel user, final String kcAction) {
final AuthenticationSessionModel authSession, final UserModel user, final String kcAction, final Set<String> ignoredActions) {
final var applicableRequiredActionsSorted =
getApplicableRequiredActionsSorted(realm, authSession, user, kcAction);
getApplicableRequiredActionsSorted(realm, authSession, user, kcAction, ignoredActions);

final RequiredActionProviderModel firstApplicableRequiredAction;
if (applicableRequiredActionsSorted.isEmpty()) {
Expand All @@ -1328,14 +1330,15 @@ private static RequiredActionProviderModel getFirstApplicableRequiredAction(fina
}

private static List<RequiredActionProviderModel> getApplicableRequiredActionsSorted(final RealmModel realm,
final AuthenticationSessionModel authSession, final UserModel user, final String kcActionAlias) {
final AuthenticationSessionModel authSession, final UserModel user, final String kcActionAlias, final Set<String> ignoredActions) {
final Set<String> nonInitiatedActionAliases = new HashSet<>();
nonInitiatedActionAliases.addAll(user.getRequiredActionsStream().toList());
nonInitiatedActionAliases.addAll(authSession.getRequiredActions());

final var applicableNonInitiatedActions = nonInitiatedActionAliases.stream()
.map(alias -> getApplicableRequiredAction(realm, alias))
.filter(Objects::nonNull)
.filter(model -> !ignoredActions.contains(model.getProviderId()))
.collect(Collectors.toMap(RequiredActionProviderModel::getAlias, Function.identity()));

RequiredActionProviderModel kcAction = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
*/
package org.keycloak.testsuite.actions;

import java.io.IOException;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.authentication.requiredactions.TermsAndConditions;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
Expand All @@ -27,6 +29,8 @@
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.VerifyEmailPage;
import org.keycloak.testsuite.updaters.UserAttributeUpdater;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
Expand All @@ -49,6 +53,9 @@ public void configureTestRealm(RealmRepresentation testRealm) {
@Page
protected LoginPage loginPage;

@Page
protected VerifyEmailPage verifyEmailPage;

@Test
public void executeUnknownAction() {
oauth.kcAction("nosuch").openLoginForm();
Expand Down Expand Up @@ -93,4 +100,32 @@ public void executeDisabledAction() {
testRealm().flows().updateRequiredAction("CONFIGURE_TOTP", configureTotp);
}
}

@Test
public void executeActionWithVerifyEmailUnsupportedAIA() throws IOException {
RealmResource realm = testRealm();
RequiredActionProviderRepresentation model = realm.flows().getRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.name());
int prevPriority = model.getPriority();

try (UserAttributeUpdater userUpdater = UserAttributeUpdater
.forUserByUsername(realm, "test-user@localhost")
.setRequiredActions(UserModel.RequiredAction.VERIFY_EMAIL).update()) {
// Set max priority for verify email (AIA not supported) to be executed before update password
model.setPriority(1);
realm.flows().updateRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.name(), model);

oauth.kcAction(UserModel.RequiredAction.UPDATE_PASSWORD.name()).openLoginForm();
loginPage.login("test-user@localhost", "password");

// the update password should be displayed
passwordUpdatePage.assertCurrent();
passwordUpdatePage.changePassword("password", "password");

// once the AIA password is executed the verify profile should be displayed for the login
verifyEmailPage.assertCurrent();
} finally {
model.setPriority(prevPriority);
realm.flows().updateRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL.name(), model);
}
}
}