Ensure required action is enabled at the realm level before adding it to the user via workflow step

Closes #45976

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
Stefan Guilhen 2026-02-03 10:41:46 -03:00
parent dde0725206
commit fa3a1fab4b
2 changed files with 45 additions and 3 deletions

View file

@ -27,12 +27,24 @@ public class AddRequiredActionStepProvider implements WorkflowStepProvider {
UserModel user = session.users().getUserById(realm, context.getResourceId());
if (user != null) {
String configuredAction = stepModel.getConfig().getFirst(REQUIRED_ACTION_KEY);
if (configuredAction == null) {
log.warnv("Missing required configuration option '{0}' in {1}", REQUIRED_ACTION_KEY, AddRequiredActionStepProviderFactory.ID);
return;
}
try {
UserModel.RequiredAction action = UserModel.RequiredAction.valueOf(stepModel.getConfig().getFirst(REQUIRED_ACTION_KEY));
// Convert hyphens to underscores and uppercase to match enum naming
configuredAction = configuredAction.replace("-", "_").toUpperCase();
UserModel.RequiredAction action = UserModel.RequiredAction.valueOf(configuredAction);
if (!realm.getRequiredActionProviderByAlias(action.name()).isEnabled()) {
log.warnv("Required action {0} is not enabled in realm {1}", action, realm.getName());
return;
}
log.debugv("Adding required action {0} to user {1})", action, user.getId());
user.addRequiredAction(action);
} catch (IllegalArgumentException e) {
log.warnv("Invalid required action {0} configured in AddRequiredActionStepProvider", stepModel.getConfig().getFirst(REQUIRED_ACTION_KEY));
log.warnv("Invalid required action {0} configured in {1}", stepModel.getConfig().getFirst(REQUIRED_ACTION_KEY),
AddRequiredActionStepProviderFactory.ID);
}
}
}

View file

@ -2,19 +2,24 @@ package org.keycloak.tests.workflow.step;
import java.time.Duration;
import jakarta.ws.rs.core.Response;
import org.keycloak.models.UserModel;
import org.keycloak.models.workflow.AddRequiredActionStepProvider;
import org.keycloak.models.workflow.AddRequiredActionStepProviderFactory;
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.workflows.WorkflowRepresentation;
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.realm.UserConfigBuilder;
import org.keycloak.testframework.util.ApiUtil;
import org.keycloak.tests.workflow.AbstractWorkflowTest;
import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -34,7 +39,7 @@ public class AddRequiredActionTest extends AbstractWorkflowTest {
.withSteps(
WorkflowStepRepresentation.create()
.of(AddRequiredActionStepProviderFactory.ID)
.withConfig(AddRequiredActionStepProvider.REQUIRED_ACTION_KEY, "UPDATE_PASSWORD")
.withConfig(AddRequiredActionStepProvider.REQUIRED_ACTION_KEY, "update-password")
.build()
).build()).close();
@ -52,4 +57,29 @@ public class AddRequiredActionTest extends AbstractWorkflowTest {
assertThat(userRepresentation.getRequiredActions().get(0), is(UserModel.RequiredAction.UPDATE_PASSWORD.name()));
});
}
@Test
@DisplayName("Test that a disabled required action is not added to the user")
public void testDisabledRequiredActionIsNotAdded() {
// create a workflow that adds 'terms-and-conditions' required action - it is disabled by default in the realm, so step should not add it to the user
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
.onEvent(UserCreatedWorkflowEventFactory.ID)
.withSteps(
WorkflowStepRepresentation.create()
.of(AddRequiredActionStepProviderFactory.ID)
.withConfig(AddRequiredActionStepProvider.REQUIRED_ACTION_KEY, "terms-and-conditions")
.build()
).build()).close();
// create a user to trigger the workflow
String userId;
try (Response response = managedRealm.admin().users().create(UserConfigBuilder.create().username("myuser").build())) {
assertThat(201, is(response.getStatus()));
userId = ApiUtil.getCreatedId(response);
}
// check the user does not have the required action added
UserRepresentation userRepresentation = managedRealm.admin().users().get(userId).toRepresentation();
assertThat(userRepresentation.getRequiredActions(), hasSize(0));
}
}