mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Add validation for Workflwow, Condition and Steps fields
Closes #43559 Signed-off-by: vramik <vramik@redhat.com>
This commit is contained in:
parent
c88e56707b
commit
b1c0c15ad5
@ -34,6 +34,7 @@ import org.keycloak.representations.workflows.WorkflowConditionRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowConstants;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -84,9 +85,10 @@ public class WorkflowsManager {
|
||||
}
|
||||
|
||||
// This method takes an ordered list of steps. First step in the list has the highest priority, last step has the lowest priority
|
||||
private void addSteps(Workflow workflow, List<WorkflowStep> steps) {
|
||||
private void addSteps(Workflow workflow, List<WorkflowStepRepresentation> steps) {
|
||||
steps = ofNullable(steps).orElse(List.of());
|
||||
for (int i = 0; i < steps.size(); i++) {
|
||||
WorkflowStep step = steps.get(i);
|
||||
WorkflowStep step = toModel(steps.get(i));
|
||||
|
||||
// assign priority based on index.
|
||||
step.setPriority(i + 1);
|
||||
@ -441,6 +443,7 @@ public class WorkflowsManager {
|
||||
List<WorkflowConditionRepresentation> conditions = ofNullable(rep.getConditions()).orElse(List.of());
|
||||
|
||||
for (WorkflowConditionRepresentation condition : conditions) {
|
||||
validateField(condition, "uses", condition.getUses());
|
||||
String conditionProviderId = condition.getUses();
|
||||
getConditionProviderFactory(conditionProviderId);
|
||||
config.computeIfAbsent(CONFIG_CONDITIONS, key -> new ArrayList<>()).add(conditionProviderId);
|
||||
@ -456,9 +459,7 @@ public class WorkflowsManager {
|
||||
|
||||
Workflow workflow = addWorkflow(new Workflow(rep.getUses(), config));
|
||||
|
||||
List<WorkflowStep> steps = rep.getSteps().stream().map(this::toModel).toList();
|
||||
|
||||
addSteps(workflow, steps);
|
||||
addSteps(workflow, rep.getSteps());
|
||||
|
||||
return workflow;
|
||||
}
|
||||
@ -470,10 +471,13 @@ public class WorkflowsManager {
|
||||
}
|
||||
|
||||
private void validateWorkflow(WorkflowRepresentation rep) {
|
||||
validateField(rep, "name", rep.getName());
|
||||
|
||||
validateEvents(rep.getOnValues());
|
||||
|
||||
// if a workflow has a restart step, at least one of the previous steps must be scheduled to prevent an infinite loop of immediate executions
|
||||
List<WorkflowStepRepresentation> steps = ofNullable(rep.getSteps()).orElse(List.of());
|
||||
steps.forEach(step -> validateField(step, "uses", step.getUses()));
|
||||
List<WorkflowStepRepresentation> restartSteps = steps.stream()
|
||||
.filter(step -> Objects.equals("restart", step.getUses()))
|
||||
.toList();
|
||||
@ -494,6 +498,12 @@ public class WorkflowsManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateField(Object obj, String fieldName, String value) {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
throw new ModelValidationException("%s field '%s' cannot be null or empty.".formatted(obj.getClass().getCanonicalName(), fieldName));
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateEvents(List<String> events) {
|
||||
for (String event : ofNullable(events).orElse(List.of())) {
|
||||
try {
|
||||
|
||||
@ -30,6 +30,7 @@ public class AddRequiredActionTest {
|
||||
public void testStepRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(AddRequiredActionStepProviderFactory.ID)
|
||||
|
||||
@ -48,6 +48,7 @@ public class AdhocWorkflowTest {
|
||||
public void testCreate() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
@ -67,6 +68,7 @@ public class AdhocWorkflowTest {
|
||||
public void testBindAdHocScheduledWithImmediateWorkflow() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
@ -91,6 +93,7 @@ public class AdhocWorkflowTest {
|
||||
public void testRunAdHocScheduledWorkflow() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -112,6 +115,7 @@ public class AdhocWorkflowTest {
|
||||
public void testRunAdHocImmediateWorkflow() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
@ -141,6 +145,7 @@ public class AdhocWorkflowTest {
|
||||
public void testRunAdHocTimedWorkflow() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
|
||||
@ -129,6 +129,7 @@ public class BrokeredUserSessionRefreshTimeWorkflowTest {
|
||||
public void testInvalidateWorkflowOnIdentityProviderRemoval() {
|
||||
consumerRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(IdentityProviderWorkflowConditionFactory.ID)
|
||||
@ -165,6 +166,7 @@ public class BrokeredUserSessionRefreshTimeWorkflowTest {
|
||||
public void tesRunStepOnFederatedUser() {
|
||||
consumerRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(IdentityProviderWorkflowConditionFactory.ID)
|
||||
|
||||
@ -224,6 +224,7 @@ public class ExpressionConditionWorkflowTest {
|
||||
private String createWorkflow(String expression) {
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.name())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(ExpressionWorkflowConditionFactory.ID)
|
||||
|
||||
@ -70,6 +70,7 @@ public class GroupMembershipJoinWorkflowTest {
|
||||
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_GROUP_MEMBERSHIP_ADD.name())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(GroupMembershipWorkflowConditionFactory.ID)
|
||||
@ -128,6 +129,7 @@ public class GroupMembershipJoinWorkflowTest {
|
||||
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(GroupMembershipWorkflowConditionFactory.ID)
|
||||
|
||||
@ -140,6 +140,7 @@ public class RoleWorkflowConditionTest {
|
||||
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_ROLE_ADD.name())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(RoleWorkflowConditionFactory.ID)
|
||||
|
||||
@ -77,6 +77,7 @@ public class StepRunnerScheduledTaskTest {
|
||||
|
||||
realm.workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
||||
@ -135,6 +135,7 @@ public class UserAttributeWorkflowConditionTest {
|
||||
private void createWorkflow(Map<String, List<String>> attributes) {
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_ADD.name())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(UserAttributeWorkflowConditionFactory.ID)
|
||||
|
||||
@ -64,6 +64,7 @@ public class UserCreationTimeWorkflowTest {
|
||||
public void testDisableUserBasedOnCreationDate() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
||||
@ -91,6 +91,7 @@ public class UserSessionRefreshTimeWorkflowTest {
|
||||
public void testDisabledUserAfterInactivityPeriod() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.concurrency().cancelIfRunning() // this setting enables restarting the workflow
|
||||
.withSteps(
|
||||
@ -174,6 +175,7 @@ public class UserSessionRefreshTimeWorkflowTest {
|
||||
public void testMultipleWorkflows() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID + "_1")
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
@ -181,7 +183,9 @@ public class UserSessionRefreshTimeWorkflowTest {
|
||||
.withConfig("custom_subject_key", "notifier1_subject")
|
||||
.withConfig("custom_message", "notifier1_message")
|
||||
.build()
|
||||
).of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
)
|
||||
.of(UserSessionRefreshTimeWorkflowProviderFactory.ID)
|
||||
.name(UserSessionRefreshTimeWorkflowProviderFactory.ID + "_2")
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
|
||||
@ -99,6 +99,7 @@ public class WorkflowManagementTest {
|
||||
public void testCreate() {
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -128,6 +129,7 @@ public class WorkflowManagementTest {
|
||||
public void testCreateWithNoConditions() {
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -148,6 +150,7 @@ public class WorkflowManagementTest {
|
||||
public void testCreateWithNoWorkflowSetDefaultWorkflow() {
|
||||
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
|
||||
.of(null)
|
||||
.name("default-workflow")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -173,6 +176,7 @@ public class WorkflowManagementTest {
|
||||
|
||||
workflows.create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_ADD.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
@ -180,7 +184,9 @@ public class WorkflowManagementTest {
|
||||
.build(),
|
||||
WorkflowStepRepresentation.create().of(RestartWorkflowStepProviderFactory.ID)
|
||||
.build()
|
||||
).of(EventBasedWorkflowProviderFactory.ID)
|
||||
)
|
||||
.of(EventBasedWorkflowProviderFactory.ID)
|
||||
.name(EventBasedWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_LOGIN.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
@ -277,6 +283,7 @@ public class WorkflowManagementTest {
|
||||
public void testWorkflowDoesNotFallThroughStepsInSingleRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_ADD.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
@ -353,6 +360,7 @@ public class WorkflowManagementTest {
|
||||
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_FEDERATED_IDENTITY_ADD.name())
|
||||
.onConditions(WorkflowConditionRepresentation.create()
|
||||
.of(IdentityProviderWorkflowConditionFactory.ID)
|
||||
@ -569,6 +577,7 @@ public class WorkflowManagementTest {
|
||||
public void testRecurringWorkflow() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.onEvent(ResourceOperationType.USER_ADD.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
@ -616,6 +625,7 @@ public class WorkflowManagementTest {
|
||||
// create a test workflow with no time conditions - should run immediately when scheduled
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
@ -643,6 +653,7 @@ public class WorkflowManagementTest {
|
||||
public void testFailCreateWorkflowWithNegativeTime() {
|
||||
WorkflowSetRepresentation workflows = WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(-5))
|
||||
@ -660,6 +671,7 @@ public class WorkflowManagementTest {
|
||||
// Create workflow: disable at 10 days, notify 3 days before (at day 7)
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(7))
|
||||
@ -698,6 +710,7 @@ public class WorkflowManagementTest {
|
||||
// Create workflow: delete at 30 days, notify 15 days before (at day 15)
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(15))
|
||||
@ -736,6 +749,7 @@ public class WorkflowManagementTest {
|
||||
// Create workflow: disable at 7 days, notify 2 days before (at day 5) with custom message
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -774,6 +788,7 @@ public class WorkflowManagementTest {
|
||||
public void testNotifyUserStepSkipsUsersWithoutEmailButLogsWarning() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
@ -813,6 +828,7 @@ public class WorkflowManagementTest {
|
||||
// Create workflow: just disable at 30 days with one notification before
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.create()
|
||||
.of(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.name(UserCreationTimeWorkflowProviderFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(15))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user