mirror of
https://github.com/keycloak/keycloak.git
synced 2026-02-03 20:39:33 -05:00
Introduce WorkflowEventSpi
- supports custom event handling beyond the built-in workflow capabilities. Closes #43916 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
43b5b3484b
commit
6e408dd7bc
103 changed files with 1134 additions and 558 deletions
|
|
@ -2,8 +2,7 @@ package org.keycloak.representations.workflows;
|
|||
|
||||
public final class WorkflowConstants {
|
||||
|
||||
public static final String DEFAULT_WORKFLOW = "event-based-workflow";
|
||||
|
||||
public static final String AD_HOC = "adhoc";
|
||||
public static final String CONFIG_USES = "uses";
|
||||
public static final String CONFIG_WITH = "with";
|
||||
public static final String CONFIG_SUPPORTS = "supports";
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ public final class WorkflowRepresentation extends AbstractWorkflowComponentRepre
|
|||
}
|
||||
|
||||
public Builder onEvent(String... operation) {
|
||||
return onEvent(String.join(" or ", operation).toUpperCase());
|
||||
return onEvent(String.join(" or ", operation));
|
||||
}
|
||||
|
||||
public Builder onCondition(String condition) {
|
||||
|
|
|
|||
|
|
@ -900,7 +900,17 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc
|
|||
|
||||
resource = toClientModel(realm, entity);
|
||||
|
||||
session.getKeycloakSessionFactory().publish((ClientModel.ClientCreationEvent) () -> resource);
|
||||
session.getKeycloakSessionFactory().publish(new ClientModel.ClientCreationEvent() {
|
||||
@Override
|
||||
public ClientModel getCreatedClient() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getKeycloakSession() {
|
||||
return session;
|
||||
}
|
||||
});
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import org.keycloak.connections.jpa.JpaConnectionProvider;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.workflow.conditions.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.conditions.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.conditions.expression.PredicateEvaluator;
|
||||
import org.keycloak.models.workflow.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.expression.PredicateEvaluator;
|
||||
import org.keycloak.representations.workflows.WorkflowConstants;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ package org.keycloak.models.workflow;
|
|||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.conditions.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.conditions.expression.ConditionEvaluator;
|
||||
import org.keycloak.models.workflow.conditions.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.conditions.expression.EventEvaluator;
|
||||
import org.keycloak.models.workflow.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.expression.ConditionEvaluator;
|
||||
import org.keycloak.models.workflow.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.expression.EventEvaluator;
|
||||
import org.keycloak.representations.workflows.WorkflowConstants;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
import static org.keycloak.representations.workflows.WorkflowConstants.CONFIG_CANCEL_IN_PROGRESS;
|
||||
|
|
@ -41,7 +42,7 @@ final class EventBasedWorkflow {
|
|||
if (event == null) {
|
||||
return false;
|
||||
}
|
||||
return supports(event.getResourceType()) && activateOnEvent(event) && validateResourceConditions(executionContext);
|
||||
return supports(event.getResourceType()) && activateOnEvent(executionContext) && validateResourceConditions(executionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,19 +90,19 @@ final class EventBasedWorkflow {
|
|||
/**
|
||||
* Determines whether the workflow should be activated based on the given event or not.
|
||||
*
|
||||
* @param event a reference to the workflow event.
|
||||
* @param executionContext a reference to the workflow execution context.
|
||||
* @return {@code true} if the workflow should be activated, {@code false} otherwise.
|
||||
*/
|
||||
private boolean activateOnEvent(WorkflowEvent event) {
|
||||
private boolean activateOnEvent(WorkflowExecutionContext executionContext) {
|
||||
// AD_HOC is a special case that always triggers the workflow regardless of the configured activation events
|
||||
if (ResourceOperationType.AD_HOC.equals(event.getOperation())) {
|
||||
if (WorkflowConstants.AD_HOC.equals(executionContext.getEvent().getEventProviderId())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String eventConditions = model.getConfig().getFirst(CONFIG_ON_EVENT);
|
||||
if (StringUtil.isNotBlank(eventConditions)) {
|
||||
BooleanConditionParser.EvaluatorContext context = EvaluatorUtils.createEvaluatorContext(model, eventConditions);
|
||||
EventEvaluator eventEvaluator = new EventEvaluator(event);
|
||||
EventEvaluator eventEvaluator = new EventEvaluator(session, executionContext);
|
||||
return eventEvaluator.visit(context);
|
||||
} else {
|
||||
return false;
|
||||
|
|
@ -131,7 +132,7 @@ final class EventBasedWorkflow {
|
|||
else {
|
||||
// the flag has an event expression - parse and evaluate it
|
||||
BooleanConditionParser.EvaluatorContext context = EvaluatorUtils.createEvaluatorContext(model, concurrencySetting);
|
||||
EventEvaluator eventEvaluator = new EventEvaluator(executionContext.getEvent());
|
||||
EventEvaluator eventEvaluator = new EventEvaluator(session, executionContext);
|
||||
return eventEvaluator.visit(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public final class RestartWorkflowStepProviderFactory implements WorkflowStepPro
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
// Usable for all resource types.
|
||||
return Set.of(ResourceType.values());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ final class ScheduleWorkflowTask extends WorkflowTransactionalTask {
|
|||
WorkflowEvent event = workflowContext.getEvent();
|
||||
WorkflowStep firstStep = workflow.getSteps().findFirst().orElseThrow(() -> new WorkflowInvalidStateException("No steps found for workflow " + workflow.getName()));
|
||||
log.debugf("Scheduling first step '%s' of workflow '%s' for resource %s based on on event %s with notBefore %d",
|
||||
firstStep.getProviderId(), workflow.getName(), event.getResourceId(), event.getOperation(), workflow.getNotBefore());
|
||||
firstStep.getProviderId(), workflow.getName(), event.getResourceId(), event.getEventProviderId(), workflow.getNotBefore());
|
||||
String originalAfter = firstStep.getAfter();
|
||||
try {
|
||||
firstStep.setAfter(workflow.getNotBefore());
|
||||
|
|
@ -46,7 +46,7 @@ final class ScheduleWorkflowTask extends WorkflowTransactionalTask {
|
|||
@Override
|
||||
public String toString() {
|
||||
WorkflowEvent event = context.getEvent();
|
||||
return "eventType=" + event.getOperation() +
|
||||
return "eventType=" + event.getEventProviderId() +
|
||||
",resourceType=" + event.getResourceType() +
|
||||
",resourceId=" + event.getResourceId();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ import org.keycloak.connections.jpa.JpaConnectionProvider;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.jpa.entities.UserEntity;
|
||||
import org.keycloak.models.workflow.conditions.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.conditions.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.conditions.expression.PredicateEvaluator;
|
||||
import org.keycloak.models.workflow.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.expression.PredicateEvaluator;
|
||||
import org.keycloak.representations.workflows.WorkflowConstants;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import java.util.stream.Collectors;
|
|||
import org.keycloak.common.util.DurationConverter;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.conditions.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.conditions.expression.ConditionNameCollector;
|
||||
import org.keycloak.models.workflow.conditions.expression.ConditionTypeCollector;
|
||||
import org.keycloak.models.workflow.conditions.expression.EvaluatorUtils;
|
||||
import org.keycloak.models.workflow.expression.BooleanConditionParser;
|
||||
import org.keycloak.models.workflow.expression.ConditionNameCollector;
|
||||
import org.keycloak.models.workflow.expression.ConditionTypeCollector;
|
||||
import org.keycloak.models.workflow.expression.EvaluatorUtils;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
|
@ -93,9 +93,9 @@ public class WorkflowValidator {
|
|||
// ConditionTypeCollector.visit(ctx) throws a WorkflowInvalidStateException if a provider is not found
|
||||
typeCollector.visit(context);
|
||||
|
||||
Set<ResourceType> supporteds = typeCollector.getConditionTypes();
|
||||
if (!supporteds.contains(workflowType)) {
|
||||
String formatted = supporteds.stream().map(Enum::name).collect(Collectors.joining(", "));
|
||||
Set<ResourceType> supportedTypes = typeCollector.getConditionTypes();
|
||||
if (!supportedTypes.contains(workflowType)) {
|
||||
String formatted = supportedTypes.stream().map(Enum::name).collect(Collectors.joining(", "));
|
||||
throw new WorkflowInvalidStateException("Provided condition types (%s) are not compatible with workflow type (%s).".formatted(formatted, workflowType));
|
||||
}
|
||||
}
|
||||
|
|
@ -135,19 +135,12 @@ public class WorkflowValidator {
|
|||
ConditionNameCollector collector = new ConditionNameCollector();
|
||||
collector.visit(context);
|
||||
|
||||
// check if there are providers for the conditions used in the expression
|
||||
// check if the providers referenced in the condition and event expressions are valid
|
||||
if ("on".equals(fieldName) || "restart-in-progress".equals(fieldName) || "cancel-in-progress".equals(fieldName)) {
|
||||
// check if we can get a ResourceOperationType for the events in the expression
|
||||
for (String name : collector.getConditionNames()) {
|
||||
try {
|
||||
ResourceOperationType.valueOf(name.replace("-", "_").toUpperCase());
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new WorkflowInvalidStateException("Could not find event: " + name);
|
||||
}
|
||||
}
|
||||
collector.getConditionNames().forEach(name -> Workflows.getEventProviderFactory(session, name.replace("_", "-").toLowerCase()));
|
||||
} else if ("if".equals(fieldName)) {
|
||||
// try to get an instance of the provider -> method throws a WorkflowInvalidStateException if provider is not found
|
||||
collector.getConditionNames().forEach(name -> Workflows.getConditionProvider(session, name, expression));
|
||||
// try to get an instance of the provider factory -> method throws a WorkflowInvalidStateException if provider factory is not found
|
||||
collector.getConditionNames().forEach(name -> Workflows.getConditionProviderFactory(session, name.replace("_", "-").toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.models.workflow.conditions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
|
|
@ -31,8 +29,8 @@ public class GroupMembershipWorkflowConditionProvider implements WorkflowConditi
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> supportedTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.keycloak.models.workflow.conditions;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
|
|
@ -31,8 +30,8 @@ public class IdentityProviderWorkflowConditionProvider implements WorkflowCondit
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> supportedTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public class RoleWorkflowConditionProvider implements WorkflowConditionProvider
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> supportedTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import java.io.StringReader;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
|
@ -35,8 +34,8 @@ public class UserAttributeWorkflowConditionProvider implements WorkflowCondition
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> supportedTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.WorkflowEvent;
|
||||
|
||||
public class EventEvaluator extends AbstractBooleanEvaluator {
|
||||
|
||||
private final WorkflowEvent event;
|
||||
|
||||
public EventEvaluator(WorkflowEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitConditionCall(BooleanConditionParser.ConditionCallContext ctx) {
|
||||
String name = ctx.Identifier().getText();
|
||||
ResourceOperationType operation = ResourceOperationType.valueOf(name.replace("-", "_").toUpperCase());
|
||||
String param = super.extractParameter(ctx.parameter());
|
||||
return operation.test(event, param);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class ClientAuthenticatedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "client-authenticated";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new ClientAuthenticatedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
|
||||
public class ClientAuthenticatedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public ClientAuthenticatedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.CLIENTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Event event) {
|
||||
return EventType.CLIENT_LOGIN.equals(event.getType());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class ClientCreatedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "client-created";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new ClientCreatedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public class ClientCreatedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public ClientCreatedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.CLIENTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof ClientModel.ClientCreationEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof ClientModel.ClientCreationEvent cce) {
|
||||
return cce.getCreatedClient().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserAuthenticatedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-authenticated";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserAuthenticatedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
|
||||
public class UserAuthenticatedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserAuthenticatedWorkflowEventProvider(KeycloakSession session, String configParameter, String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Event event) {
|
||||
return EventType.LOGIN.equals(event.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
// this is the case when the clientId is passed as a parameter to the event provider - like user-logged-in(account-console)
|
||||
Event loginEvent = (Event) context.getEvent().getEvent();
|
||||
return loginEvent != null && configParameter.equals(loginEvent.getClientId());
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserCreatedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-created";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserCreatedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
|
||||
public class UserCreatedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserCreatedWorkflowEventProvider(KeycloakSession session, String configParameter, String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Event event) {
|
||||
return EventType.REGISTER.equals(event.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(AdminEvent adminEvent) {
|
||||
return org.keycloak.events.admin.ResourceType.USER.equals(adminEvent.getResourceType())
|
||||
&& OperationType.CREATE.equals(adminEvent.getOperationType());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserFedIdentityAddedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-federated-identity-added";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserFedIdentityAddedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.FederatedIdentityModel.FederatedIdentityCreatedEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public class UserFedIdentityAddedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserFedIdentityAddedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof FederatedIdentityCreatedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof FederatedIdentityCreatedEvent fie) {
|
||||
return fie.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
// this is the case when the idp alias is passed as a parameter to the event provider - like user-federated-identity-added(myidp)
|
||||
ProviderEvent fedIdentityEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (fedIdentityEvent instanceof FederatedIdentityCreatedEvent fie) {
|
||||
return configParameter.equals(fie.getFederatedIdentity().getIdentityProvider());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserFedIdentityRemovedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-federated-identity-removed";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserFedIdentityRemovedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.FederatedIdentityModel.FederatedIdentityRemovedEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public class UserFedIdentityRemovedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserFedIdentityRemovedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof FederatedIdentityRemovedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof FederatedIdentityRemovedEvent fie) {
|
||||
return fie.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
// this is the case when the idp alias is passed as a parameter to the event provider - like user-federated-identity-removed(myidp)
|
||||
ProviderEvent fedIdentityEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (fedIdentityEvent instanceof FederatedIdentityRemovedEvent fie) {
|
||||
return configParameter.equals(fie.getFederatedIdentity().getIdentityProvider());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserGroupMembershipAddedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-group-membership-added";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserGroupMembershipAddedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.GroupModel.GroupMemberJoinEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
import static org.keycloak.models.utils.KeycloakModelUtils.GROUP_PATH_SEPARATOR;
|
||||
|
||||
public class UserGroupMembershipAddedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserGroupMembershipAddedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof GroupMemberJoinEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof GroupMemberJoinEvent gme) {
|
||||
return gme.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
String groupName = configParameter;
|
||||
// this is the case when the group name is passed as a parameter to the event provider - like user-group-membership-added(mygroup)
|
||||
if (!groupName.startsWith(GROUP_PATH_SEPARATOR))
|
||||
groupName = GROUP_PATH_SEPARATOR + groupName;
|
||||
ProviderEvent groupEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (groupEvent instanceof GroupMemberJoinEvent joinEvent) {
|
||||
return groupName.equals(KeycloakModelUtils.buildGroupPath(joinEvent.getGroup()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserGroupMembershipRemovedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-group-membership-removed";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserGroupMembershipRemovedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.GroupModel.GroupMemberLeaveEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
import static org.keycloak.models.utils.KeycloakModelUtils.GROUP_PATH_SEPARATOR;
|
||||
|
||||
public class UserGroupMembershipRemovedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserGroupMembershipRemovedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof GroupMemberLeaveEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof GroupMemberLeaveEvent gme) {
|
||||
return gme.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
String groupName = configParameter;
|
||||
// this is the case when the group name is passed as a parameter to the event provider - like user-group-membership-removed(mygroup)
|
||||
if (!groupName.startsWith(GROUP_PATH_SEPARATOR))
|
||||
groupName = GROUP_PATH_SEPARATOR + groupName;
|
||||
ProviderEvent groupEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (groupEvent instanceof GroupMemberLeaveEvent leaveEvent) {
|
||||
return groupName.equals(KeycloakModelUtils.buildGroupPath(leaveEvent.getGroup()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserRoleGrantedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-role-granted";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserRoleGrantedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RoleModel.RoleGrantedEvent;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public class UserRoleGrantedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserRoleGrantedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof RoleGrantedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof RoleGrantedEvent rge) {
|
||||
return rge.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
// this is the case when the role name is passed as a parameter to the event provider - like user-role-granted(myrole)
|
||||
ProviderEvent roleEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (roleEvent instanceof RoleGrantedEvent roleGrantedEvent) {
|
||||
return configParameter.equals(roleGrantedEvent.getRole().getName());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowEventProviderFactory;
|
||||
|
||||
public class UserRoleRevokedWorkflowEventFactory implements WorkflowEventProviderFactory<WorkflowEventProvider> {
|
||||
|
||||
public static final String ID = "user-role-revoked";
|
||||
|
||||
@Override
|
||||
public WorkflowEventProvider create(KeycloakSession session, String configParameter) {
|
||||
return new UserRoleRevokedWorkflowEventProvider(session, configParameter, this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package org.keycloak.models.workflow.events;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RoleModel.RoleRevokedEvent;
|
||||
import org.keycloak.models.workflow.AbstractWorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public class UserRoleRevokedWorkflowEventProvider extends AbstractWorkflowEventProvider {
|
||||
|
||||
public UserRoleRevokedWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
super(session, configParameter, providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getSupportedResourceType() {
|
||||
return ResourceType.USERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return providerEvent instanceof RoleRevokedEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
if (providerEvent instanceof RoleRevokedEvent rre) {
|
||||
return rre.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
if (!super.evaluate(context)) {
|
||||
return false;
|
||||
}
|
||||
if (super.configParameter != null) {
|
||||
// this is the case when the role name is passed as a parameter to the event provider - like user-role-revoked(myrole)
|
||||
ProviderEvent roleEvent = (ProviderEvent) context.getEvent().getEvent();
|
||||
if (roleEvent instanceof RoleRevokedEvent roleRevokedEvent) {
|
||||
return configParameter.equals(roleRevokedEvent.getRole().getName());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// nothing else to check
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
public abstract class AbstractBooleanEvaluator extends BooleanConditionParserBaseVisitor<Boolean> {
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowConditionProvider;
|
||||
|
|
@ -19,7 +19,7 @@ public class ConditionEvaluator extends AbstractBooleanEvaluator {
|
|||
@Override
|
||||
public Boolean visitConditionCall(BooleanConditionParser.ConditionCallContext ctx) {
|
||||
String conditionName = ctx.Identifier().getText();
|
||||
WorkflowConditionProvider conditionProvider = getConditionProvider(session, conditionName, super.extractParameter(ctx.parameter()));
|
||||
WorkflowConditionProvider conditionProvider = getConditionProvider(session, conditionName.replace("_", "-").toLowerCase(), super.extractParameter(ctx.parameter()));
|
||||
return conditionProvider.evaluate(context);
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
final class ConditionParserUtil {
|
||||
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
|
@ -9,7 +10,7 @@ import org.keycloak.models.workflow.ResourceType;
|
|||
import org.keycloak.models.workflow.WorkflowConditionProvider;
|
||||
|
||||
import static org.keycloak.models.workflow.Workflows.getConditionProvider;
|
||||
import static org.keycloak.models.workflow.conditions.expression.ConditionParserUtil.extractParameter;
|
||||
import static org.keycloak.models.workflow.expression.ConditionParserUtil.extractParameter;
|
||||
|
||||
/**
|
||||
* This visitor traverses the entire parse tree and collects the supported types of all conditionCalls.
|
||||
|
|
@ -45,7 +46,7 @@ public class ConditionTypeCollector extends BooleanConditionParserBaseVisitor<Vo
|
|||
|
||||
String conditionName = ctx.Identifier().getText();
|
||||
WorkflowConditionProvider conditionProvider = getConditionProvider(session, conditionName, extractParameter(ctx.parameter()));
|
||||
resourceTypes.retainAll(conditionProvider.supportedTypes());
|
||||
resourceTypes.retainAll(List.of(conditionProvider.getSupportedResourceType()));
|
||||
|
||||
// We don't need to visit children (like 'parameter')
|
||||
return null;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.workflow.WorkflowInvalidStateException;
|
||||
import org.keycloak.models.workflow.conditions.expression.BooleanConditionParser.EvaluatorContext;
|
||||
import org.keycloak.models.workflow.expression.BooleanConditionParser.EvaluatorContext;
|
||||
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.workflow.WorkflowEventProvider;
|
||||
import org.keycloak.models.workflow.WorkflowExecutionContext;
|
||||
|
||||
import static org.keycloak.models.workflow.Workflows.getEventProvider;
|
||||
|
||||
public class EventEvaluator extends AbstractBooleanEvaluator {
|
||||
|
||||
private final WorkflowExecutionContext context;
|
||||
private final KeycloakSession session;
|
||||
|
||||
public EventEvaluator(KeycloakSession session, WorkflowExecutionContext context) {
|
||||
this.context = context;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitConditionCall(BooleanConditionParser.ConditionCallContext ctx) {
|
||||
String name = ctx.Identifier().getText();
|
||||
WorkflowEventProvider provider = getEventProvider(session, name.replace("_", "-").toLowerCase(), super.extractParameter(ctx.parameter()));
|
||||
return provider.evaluate(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.models.workflow.conditions.expression;
|
||||
package org.keycloak.models.workflow.expression;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# user event providers
|
||||
org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserFedIdentityAddedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserFedIdentityRemovedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserGroupMembershipAddedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserGroupMembershipRemovedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserRoleGrantedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.UserRoleRevokedWorkflowEventFactory
|
||||
|
||||
# client event providers
|
||||
org.keycloak.models.workflow.events.ClientAuthenticatedWorkflowEventFactory
|
||||
org.keycloak.models.workflow.events.ClientCreatedWorkflowEventFactory
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public abstract class AbstractWorkflowEventProvider implements WorkflowEventProvider {
|
||||
|
||||
protected final String providerId;
|
||||
protected final String configParameter;
|
||||
protected final KeycloakSession session;
|
||||
|
||||
public AbstractWorkflowEventProvider(final KeycloakSession session, final String configParameter, final String providerId) {
|
||||
this.providerId = providerId;
|
||||
this.configParameter = configParameter;
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowEvent create(Event event) {
|
||||
if (supports(event)) {
|
||||
ResourceType resourceType = getSupportedResourceType();
|
||||
String resourceIdFromEvent = resourceType.resolveResourceId(session, event);
|
||||
return resourceIdFromEvent != null ? new WorkflowEvent(resourceType, resourceIdFromEvent, event, providerId) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowEvent create(AdminEvent adminEvent) {
|
||||
if (supports(adminEvent)) {
|
||||
return new WorkflowEvent(getSupportedResourceType(), adminEvent.getResourceId(), adminEvent, providerId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowEvent create(ProviderEvent providerEvent) {
|
||||
if (supports(providerEvent)) {
|
||||
String resourceId = resolveResourceId(providerEvent);
|
||||
return resourceId != null ? new WorkflowEvent(getSupportedResourceType(), resourceId, providerEvent, providerId) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WorkflowExecutionContext context) {
|
||||
WorkflowEvent event = context.getEvent();
|
||||
return event != null && Objects.equals(this.providerId, event.getEventProviderId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(AdminEvent adminEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(ProviderEvent providerEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String resolveResourceId(ProviderEvent providerEvent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import org.keycloak.representations.workflows.WorkflowConstants;
|
||||
|
||||
final class AdhocWorkflowEvent extends WorkflowEvent {
|
||||
|
||||
AdhocWorkflowEvent(ResourceType type, String resourceId) {
|
||||
super(type, ResourceOperationType.AD_HOC, resourceId, null);
|
||||
super(type, resourceId, null, WorkflowConstants.AD_HOC);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.ClientModel.ClientCreationEvent;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.FederatedIdentityModel.FederatedIdentityCreatedEvent;
|
||||
import org.keycloak.models.FederatedIdentityModel.FederatedIdentityRemovedEvent;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.GroupModel.GroupMemberJoinEvent;
|
||||
import org.keycloak.models.GroupModel.GroupMemberLeaveEvent;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.RoleModel.RoleGrantedEvent;
|
||||
import org.keycloak.models.RoleModel.RoleRevokedEvent;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
import static org.keycloak.models.utils.KeycloakModelUtils.GROUP_PATH_SEPARATOR;
|
||||
|
||||
public enum ResourceOperationType {
|
||||
|
||||
USER_CREATED(ResourceType.USERS, List.of(OperationType.CREATE, EventType.REGISTER)),
|
||||
USER_AUTHENTICATED(ResourceType.USERS,List.of(EventType.LOGIN), userLoginPredicate()),
|
||||
USER_FEDERATED_IDENTITY_ADDED(ResourceType.USERS,List.of(FederatedIdentityCreatedEvent.class), fedIdentityPredicate()),
|
||||
USER_FEDERATED_IDENTITY_REMOVED(ResourceType.USERS,List.of(FederatedIdentityRemovedEvent.class), fedIdentityPredicate()),
|
||||
USER_GROUP_MEMBERSHIP_ADDED(ResourceType.USERS,List.of(GroupMemberJoinEvent.class), groupMembershipPredicate()),
|
||||
USER_GROUP_MEMBERSHIP_REMOVED(ResourceType.USERS,List.of(GroupModel.GroupMemberLeaveEvent.class), groupMembershipPredicate()),
|
||||
USER_ROLE_GRANTED(ResourceType.USERS,List.of(RoleGrantedEvent.class), roleMembershipPredicate()),
|
||||
USER_ROLE_REVOKED(ResourceType.USERS,List.of(RoleModel.RoleRevokedEvent.class), roleMembershipPredicate()),
|
||||
|
||||
CLIENT_ADDED(ResourceType.CLIENTS, List.of(OperationType.CREATE, ClientCreationEvent.class)),
|
||||
CLIENT_LOGGED_IN(ResourceType.CLIENTS, List.of(EventType.CLIENT_LOGIN)),
|
||||
|
||||
AD_HOC(ResourceType.USERS, List.of(new Class[] {}));
|
||||
|
||||
private final ResourceType resourceType;
|
||||
private final List<Object> eventTypes;
|
||||
private final List<Object> deactivationTypes;
|
||||
private final BiPredicate<WorkflowEvent, String> conditionPredicate;
|
||||
|
||||
ResourceOperationType(ResourceType resourceType, List<Object> eventTypes) {
|
||||
this.resourceType = resourceType;
|
||||
this.eventTypes = eventTypes;
|
||||
this.deactivationTypes = List.of();
|
||||
this.conditionPredicate = defaultPredicate();
|
||||
}
|
||||
|
||||
ResourceOperationType(ResourceType resourceType, List<Object> eventTypes, BiPredicate<WorkflowEvent, String> conditionPredicate) {
|
||||
this.resourceType = resourceType;
|
||||
this.eventTypes = eventTypes;
|
||||
this.deactivationTypes = List.of();
|
||||
this.conditionPredicate = defaultPredicate().and(conditionPredicate);
|
||||
}
|
||||
|
||||
public ResourceType getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public static ResourceOperationType toOperationType(Enum<?> from) {
|
||||
return toOperationType(null, from);
|
||||
}
|
||||
|
||||
public static ResourceOperationType toOperationType(Class<?> from) {
|
||||
return toOperationType(null, from);
|
||||
}
|
||||
|
||||
public static ResourceOperationType toOperationType(ResourceType resourceType, Object from) {
|
||||
for (ResourceOperationType value : values()) {
|
||||
if (resourceType != null && !resourceType.equals(value.resourceType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value.eventTypes.contains(from)) {
|
||||
return value;
|
||||
}
|
||||
for (Object type : value.eventTypes) {
|
||||
Class<?> fromClass = from instanceof Class ? (Class<?>) from : from.getClass();
|
||||
if (type instanceof Class<?> cls && cls.isAssignableFrom(fromClass)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getResourceId(ProviderEvent event) {
|
||||
if (event instanceof GroupMemberJoinEvent gme) {
|
||||
return gme.getUser().getId();
|
||||
}
|
||||
if (event instanceof GroupMemberLeaveEvent gme) {
|
||||
return gme.getUser().getId();
|
||||
}
|
||||
if (event instanceof FederatedIdentityModel.FederatedIdentityCreatedEvent fie) {
|
||||
return fie.getUser().getId();
|
||||
}
|
||||
if (event instanceof FederatedIdentityModel.FederatedIdentityRemovedEvent fie) {
|
||||
return fie.getUser().getId();
|
||||
}
|
||||
if (event instanceof RoleGrantedEvent rge) {
|
||||
return rge.getUser().getId();
|
||||
}
|
||||
if (event instanceof RoleRevokedEvent rre) {
|
||||
return rre.getUser().getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean test(WorkflowEvent event, String detail) {
|
||||
return conditionPredicate.test(event, detail);
|
||||
}
|
||||
|
||||
private BiPredicate<WorkflowEvent, String> defaultPredicate() {
|
||||
return (event, detail) -> event.getOperation().equals(this);
|
||||
}
|
||||
|
||||
private static BiPredicate<WorkflowEvent, String> userLoginPredicate() {
|
||||
return (event, detail) -> {
|
||||
if (detail != null) {
|
||||
Event loginEvent = (Event) event.getEvent();
|
||||
return detail.equals(loginEvent.getClientId());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static BiPredicate<WorkflowEvent, String> groupMembershipPredicate() {
|
||||
return (event, groupName) -> {
|
||||
if (groupName != null) {
|
||||
if (!groupName.startsWith(GROUP_PATH_SEPARATOR))
|
||||
groupName = GROUP_PATH_SEPARATOR + groupName;
|
||||
ProviderEvent groupEvent = (ProviderEvent) event.getEvent();
|
||||
if (groupEvent instanceof GroupMemberJoinEvent joinEvent) {
|
||||
return groupName.equals(KeycloakModelUtils.buildGroupPath(joinEvent.getGroup()));
|
||||
} else if (groupEvent instanceof GroupModel.GroupMemberLeaveEvent leaveEvent) {
|
||||
return groupName.equals(KeycloakModelUtils.buildGroupPath(leaveEvent.getGroup()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static BiPredicate<WorkflowEvent, String> roleMembershipPredicate() {
|
||||
return (event, roleName) -> {
|
||||
if (roleName != null) {
|
||||
ProviderEvent roleEvent = (ProviderEvent) event.getEvent();
|
||||
if (roleEvent instanceof RoleGrantedEvent roleGrantedEvent) {
|
||||
return roleName.equals(roleGrantedEvent.getRole().getName());
|
||||
} else if (roleEvent instanceof RoleModel.RoleRevokedEvent roleRevokedEvent) {
|
||||
return roleName.equals(roleRevokedEvent.getRole().getName());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static BiPredicate<WorkflowEvent, String> fedIdentityPredicate() {
|
||||
return (event, idpAlias) -> {
|
||||
if (idpAlias != null) {
|
||||
ProviderEvent fedIdentityEvent = (ProviderEvent) event.getEvent();
|
||||
if (fedIdentityEvent instanceof FederatedIdentityModel.FederatedIdentityCreatedEvent fedIdentityCreatedEvent) {
|
||||
return idpAlias.equals(fedIdentityCreatedEvent.getFederatedIdentity().getIdentityProvider());
|
||||
} else if (fedIdentityEvent instanceof FederatedIdentityRemovedEvent fedIdentityRemovedEvent) {
|
||||
return idpAlias.equals(fedIdentityRemovedEvent.getFederatedIdentity().getIdentityProvider());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,52 +18,52 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
public enum ResourceType {
|
||||
|
||||
USERS(
|
||||
org.keycloak.events.admin.ResourceType.USER,
|
||||
List.of(OperationType.CREATE),
|
||||
List.of(EventType.LOGIN, EventType.REGISTER),
|
||||
(session, id) -> session.users().getUserById(session.getContext().getRealm(), id)
|
||||
(session, id) -> session.users().getUserById(session.getContext().getRealm(), id),
|
||||
(session, event) -> event.getUserId()
|
||||
),
|
||||
CLIENTS(
|
||||
org.keycloak.events.admin.ResourceType.CLIENT,
|
||||
List.of(OperationType.CREATE),
|
||||
List.of(EventType.CLIENT_LOGIN, EventType.CLIENT_REGISTER),
|
||||
(session, id) -> session.clients().getClientById(session.getContext().getRealm(), id)
|
||||
(session, id) -> session.clients().getClientById(session.getContext().getRealm(), id),
|
||||
(session, event) -> findClientResourceId(session, event.getClientId())
|
||||
);
|
||||
|
||||
private final org.keycloak.events.admin.ResourceType supportedAdminResourceType;
|
||||
private final List<OperationType> supportedAdminOperationTypes;
|
||||
private final List<EventType> supportedEventTypes;
|
||||
private final BiFunction<KeycloakSession, String, ?> resourceResolver;
|
||||
private final BiFunction<KeycloakSession, Event, String> resourceIdResolver;
|
||||
|
||||
ResourceType(org.keycloak.events.admin.ResourceType supportedAdminResourceType,
|
||||
List<OperationType> supportedAdminOperationTypes,
|
||||
List<EventType> supportedEventTypes,
|
||||
BiFunction<KeycloakSession, String, ?> resourceResolver) {
|
||||
this.supportedAdminResourceType = supportedAdminResourceType;
|
||||
this.supportedAdminOperationTypes = supportedAdminOperationTypes;
|
||||
this.supportedEventTypes = supportedEventTypes;
|
||||
ResourceType(BiFunction<KeycloakSession, String, ?> resourceResolver,
|
||||
BiFunction<KeycloakSession, Event, String> resourceIdResolver) {
|
||||
this.resourceResolver = resourceResolver;
|
||||
}
|
||||
|
||||
public boolean supportsEvent(EventType eventType) {
|
||||
return supportedEventTypes.contains(eventType);
|
||||
}
|
||||
|
||||
public boolean supportsAdminEvent(org.keycloak.events.admin.ResourceType resourceType, OperationType operationType) {
|
||||
return supportedAdminResourceType.equals(resourceType) && supportedAdminOperationTypes.contains(operationType);
|
||||
this.resourceIdResolver = resourceIdResolver;
|
||||
}
|
||||
|
||||
public Object resolveResource(KeycloakSession session, String id) {
|
||||
return resourceResolver.apply(session, id);
|
||||
}
|
||||
|
||||
public String resolveResourceId(KeycloakSession session, Event event) {
|
||||
return resourceIdResolver.apply(session, event);
|
||||
}
|
||||
|
||||
private static String findClientResourceId(KeycloakSession session, String clientClientId) {
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
if (realm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientClientId);
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return client.getId();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,8 +180,8 @@ public class Workflow {
|
|||
addStep(step);
|
||||
|
||||
// update allowed types
|
||||
WorkflowStepProviderFactory<WorkflowStepProvider> stepProvider = getStepProviderFactory(step);
|
||||
allowedTypes.retainAll(stepProvider.getTypes());
|
||||
WorkflowStepProviderFactory<WorkflowStepProvider> stepProvider = Workflows.getStepProviderFactory(session, step);
|
||||
allowedTypes.retainAll(stepProvider.getSupportedResourceTypes());
|
||||
}
|
||||
|
||||
if (allowedTypes.isEmpty()) {
|
||||
|
|
@ -225,9 +225,4 @@ public class Workflow {
|
|||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
private WorkflowStepProviderFactory<WorkflowStepProvider> getStepProviderFactory(WorkflowStep step) {
|
||||
return (WorkflowStepProviderFactory<WorkflowStepProvider>) session
|
||||
.getKeycloakSessionFactory().getProviderFactory(WorkflowStepProvider.class, step.getProviderId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
|
@ -11,7 +10,7 @@ import org.keycloak.provider.Provider;
|
|||
|
||||
public interface WorkflowConditionProvider extends Provider {
|
||||
|
||||
Set<ResourceType> supportedTypes();
|
||||
ResourceType getSupportedResourceType();
|
||||
|
||||
boolean evaluate(WorkflowExecutionContext context);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public interface WorkflowConditionProviderFactory<P extends WorkflowConditionPro
|
|||
|
||||
@Override
|
||||
default P create(KeycloakSession session) {
|
||||
throw new IllegalStateException("Use create(KeycloakSession session, MultivaluedHashMap<String, String> config) instead.");
|
||||
throw new IllegalStateException("Use create(KeycloakSession session, String configParameter) instead.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -3,29 +3,29 @@ package org.keycloak.models.workflow;
|
|||
public class WorkflowEvent {
|
||||
|
||||
private final ResourceType type;
|
||||
private final ResourceOperationType operation;
|
||||
private final String resourceId;
|
||||
private final Object event;
|
||||
private final String eventProviderId;
|
||||
|
||||
public WorkflowEvent(ResourceType type, ResourceOperationType operation, String resourceId, Object event) {
|
||||
public WorkflowEvent(ResourceType type, String resourceId, Object event, String eventProviderId) {
|
||||
this.type = type;
|
||||
this.operation = operation;
|
||||
this.resourceId = resourceId;
|
||||
this.event = event;
|
||||
this.eventProviderId = eventProviderId;
|
||||
}
|
||||
|
||||
public ResourceType getResourceType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ResourceOperationType getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public String getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
public String getEventProviderId() {
|
||||
return eventProviderId;
|
||||
}
|
||||
|
||||
public Object getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.toOperationType;
|
||||
|
||||
public final class WorkflowEventConverter {
|
||||
|
||||
static Optional<WorkflowEvent> fromEvent(KeycloakSession session, Event event) {
|
||||
return resourceOfEvent(event)
|
||||
.map(r -> {
|
||||
ResourceOperationType resourceOperationType = toOperationType(event.getType());
|
||||
String resourceId = switch (r) {
|
||||
case USERS -> event.getUserId();
|
||||
case CLIENTS -> findClientResourceId(session, event.getClientId());
|
||||
};
|
||||
if (resourceOperationType != null && resourceId != null) {
|
||||
return new WorkflowEvent(r, resourceOperationType, resourceId, event);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
static Optional<WorkflowEvent> fromEvent(AdminEvent event) {
|
||||
return resourceOfEvent(event)
|
||||
.map(r -> {
|
||||
ResourceOperationType resourceOperationType = toOperationType(r, event.getOperationType());
|
||||
if (resourceOperationType != null) {
|
||||
return new WorkflowEvent(r, resourceOperationType, event.getResourceId(), event);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
static Optional<WorkflowEvent> fromEvent(ProviderEvent event) {
|
||||
ResourceOperationType resourceOperationType = toOperationType(event.getClass());
|
||||
if (resourceOperationType == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String resourceId = resourceOperationType.getResourceId(event);
|
||||
if (resourceId == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
WorkflowEvent workflowEvent = new WorkflowEvent(resourceOperationType.getResourceType(), resourceOperationType, resourceId, event);
|
||||
return Optional.of(workflowEvent);
|
||||
}
|
||||
|
||||
|
||||
private static Optional<ResourceType> resourceOfEvent(Event event) {
|
||||
// Is it possible for an event to have multiple resources, thus triggering multiple workflows?
|
||||
return Arrays.stream(ResourceType.values())
|
||||
.filter(r -> r.supportsEvent(event.getType()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private static Optional<ResourceType> resourceOfEvent(AdminEvent event) {
|
||||
return Arrays.stream(ResourceType.values())
|
||||
.filter(r -> r.supportsAdminEvent(event.getResourceType(), event.getOperationType()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private static String findClientResourceId(KeycloakSession session, String clientClientId) {
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
if (realm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientClientId);
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return client.getId();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public interface WorkflowEventProvider extends Provider {
|
||||
|
||||
ResourceType getSupportedResourceType();
|
||||
|
||||
WorkflowEvent create(Event event);
|
||||
|
||||
WorkflowEvent create(AdminEvent adminEvent);
|
||||
|
||||
WorkflowEvent create(ProviderEvent providerEvent);
|
||||
|
||||
boolean supports(Event event);
|
||||
|
||||
boolean supports(AdminEvent adminEvent);
|
||||
|
||||
boolean supports(ProviderEvent providerEvent);
|
||||
|
||||
boolean evaluate(WorkflowExecutionContext context);
|
||||
|
||||
@Override
|
||||
default void close() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
public interface WorkflowEventProviderFactory <P extends WorkflowEventProvider> extends ProviderFactory<P>, EnvironmentDependentProviderFactory {
|
||||
|
||||
P create(KeycloakSession session, String configParameter);
|
||||
|
||||
@Override
|
||||
default P create(KeycloakSession session) {
|
||||
return create(session, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isSupported(Config.Scope config) {
|
||||
return Profile.isFeatureEnabled(Profile.Feature.WORKFLOWS);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void init(Config.Scope config) {
|
||||
// no-op default
|
||||
}
|
||||
|
||||
@Override
|
||||
default void postInit(KeycloakSessionFactory factory) {
|
||||
// no-op default
|
||||
}
|
||||
|
||||
@Override
|
||||
default void close() {
|
||||
// no-op default
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.keycloak.models.workflow;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
public class WorkflowEventSpi implements Spi {
|
||||
|
||||
public static final String NAME = "workflow-event";
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return WorkflowEventProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return WorkflowEventProviderFactory.class;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ import org.keycloak.provider.Provider;
|
|||
public interface WorkflowStepProvider extends Provider {
|
||||
|
||||
/**
|
||||
* Run this workflow step.
|
||||
* Runs this workflow step.
|
||||
*
|
||||
* @param context the workflow execution context
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public interface WorkflowStepProviderFactory<P extends WorkflowStepProvider> ext
|
|||
/**
|
||||
* Supported types, usually one type but could be more (RestartStep for example)
|
||||
*/
|
||||
Set<ResourceType> getTypes();
|
||||
Set<ResourceType> getSupportedResourceTypes();
|
||||
|
||||
@Override
|
||||
default void init(Config.Scope config) {
|
||||
|
|
|
|||
|
|
@ -3,22 +3,24 @@ package org.keycloak.models.workflow;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
public final class Workflows {
|
||||
|
||||
public static WorkflowConditionProvider getConditionProvider(KeycloakSession session, String name, String expression) {
|
||||
return getConditionProviderFactory(session, name).create(session, expression);
|
||||
public static WorkflowConditionProvider getConditionProvider(KeycloakSession session, String name, String configParameter) {
|
||||
return getConditionProviderFactory(session, name).create(session, configParameter);
|
||||
}
|
||||
|
||||
private static WorkflowConditionProviderFactory<WorkflowConditionProvider> getConditionProviderFactory(KeycloakSession session, String providerId) {
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
WorkflowConditionProviderFactory<WorkflowConditionProvider> providerFactory = (WorkflowConditionProviderFactory<WorkflowConditionProvider>) sessionFactory.getProviderFactory(WorkflowConditionProvider.class, providerId);
|
||||
public static WorkflowConditionProviderFactory<WorkflowConditionProvider> getConditionProviderFactory(KeycloakSession session, String providerId) {
|
||||
return getProviderFactory(session, WorkflowConditionProvider.class, providerId);
|
||||
}
|
||||
|
||||
if (providerFactory == null) {
|
||||
throw new WorkflowInvalidStateException("Could not find condition provider: " + providerId);
|
||||
}
|
||||
public static WorkflowEventProvider getEventProvider(KeycloakSession session, String name, String configParameter) {
|
||||
return getEventProviderFactory(session, name).create(session, configParameter);
|
||||
}
|
||||
|
||||
return providerFactory;
|
||||
public static WorkflowEventProviderFactory<WorkflowEventProvider> getEventProviderFactory(KeycloakSession session, String providerId) {
|
||||
return getProviderFactory(session, WorkflowEventProvider.class, providerId);
|
||||
}
|
||||
|
||||
public static WorkflowStepProvider getStepProvider(KeycloakSession session, WorkflowStep step) {
|
||||
|
|
@ -27,13 +29,17 @@ public final class Workflows {
|
|||
}
|
||||
|
||||
public static WorkflowStepProviderFactory<WorkflowStepProvider> getStepProviderFactory(KeycloakSession session, WorkflowStep step) {
|
||||
WorkflowStepProviderFactory<WorkflowStepProvider> factory = (WorkflowStepProviderFactory<WorkflowStepProvider>) session
|
||||
.getKeycloakSessionFactory().getProviderFactory(WorkflowStepProvider.class, step.getProviderId());
|
||||
return getProviderFactory(session, WorkflowStepProvider.class, step.getProviderId());
|
||||
}
|
||||
|
||||
if (factory == null) {
|
||||
throw new WorkflowInvalidStateException("Step not found: " + step.getProviderId());
|
||||
private static <P extends Provider, F> F getProviderFactory(KeycloakSession session, Class<P> providerClass, String providerId) {
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
@SuppressWarnings("unchecked")
|
||||
F providerFactory = (F) sessionFactory.getProviderFactory(providerClass, providerId);
|
||||
|
||||
if (providerFactory == null) {
|
||||
throw new WorkflowInvalidStateException("Could not find provider factory with id: " + providerId);
|
||||
}
|
||||
|
||||
return factory;
|
||||
return providerFactory;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,9 +105,10 @@ org.keycloak.cookie.CookieSpi
|
|||
org.keycloak.organization.OrganizationSpi
|
||||
org.keycloak.securityprofile.SecurityProfileSpi
|
||||
org.keycloak.logging.MappedDiagnosticContextSpi
|
||||
org.keycloak.models.workflow.WorkflowConditionSpi
|
||||
org.keycloak.models.workflow.WorkflowEventSpi
|
||||
org.keycloak.models.workflow.WorkflowStepSpi
|
||||
org.keycloak.models.workflow.WorkflowSpi
|
||||
org.keycloak.models.workflow.WorkflowConditionSpi
|
||||
org.keycloak.protocol.oidc.rar.AuthorizationDetailsProcessorSpi
|
||||
org.keycloak.cache.AlternativeLookupSPI
|
||||
org.keycloak.cache.LocalCacheSPI
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class AddRequiredActionStepProviderFactory implements WorkflowStepProvide
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class DeleteUserStepProviderFactory implements WorkflowStepProviderFactor
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class DisableUserStepProviderFactory implements WorkflowStepProviderFacto
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class GrantRoleStepProviderFactory implements WorkflowStepProviderFactory
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class JoinGroupStepProviderFactory implements WorkflowStepProviderFactory
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class LeaveGroupStepProviderFactory implements WorkflowStepProviderFactor
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class NotifyUserStepProviderFactory implements WorkflowStepProviderFactor
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class RemoveRequiredActionStepProviderFactory implements WorkflowStepProv
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class RemoveUserAttributeStepProviderFactory implements WorkflowStepProvi
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class RevokeRoleStepProviderFactory implements WorkflowStepProviderFactor
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class SetUserAttributeStepProviderFactory implements WorkflowStepProvider
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.USERS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
|
|
@ -28,12 +30,18 @@ public class WorkflowEventListener implements EventListenerProvider, ProviderEve
|
|||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
WorkflowEventConverter.fromEvent(session, event).ifPresent(this::trySchedule);
|
||||
session.getAllProviders(WorkflowEventProvider.class).stream()
|
||||
.map(provider -> provider.create(event))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(this::trySchedule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(AdminEvent event, boolean includeRepresentation) {
|
||||
WorkflowEventConverter.fromEvent(event).ifPresent(this::trySchedule);
|
||||
session.getAllProviders(WorkflowEventProvider.class).stream()
|
||||
.map(provider -> provider.create(event))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(this::trySchedule);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -42,8 +50,10 @@ public class WorkflowEventListener implements EventListenerProvider, ProviderEve
|
|||
if (realm == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkflowEventConverter.fromEvent(event).ifPresent(this::trySchedule);
|
||||
session.getAllProviders(WorkflowEventProvider.class).stream()
|
||||
.map(provider -> provider.create(event))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(this::trySchedule);
|
||||
}
|
||||
|
||||
private void trySchedule(WorkflowEvent event) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class DeleteClientStepProviderFactory implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.CLIENTS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class DisableClientStepProviderFactory implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceType> getTypes() {
|
||||
public Set<ResourceType> getSupportedResourceTypes() {
|
||||
return Set.of(ResourceType.CLIENTS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import org.keycloak.admin.client.resource.WorkflowsResource;
|
|||
import org.keycloak.models.workflow.DeleteUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.RestartWorkflowStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
|
|
@ -42,6 +41,8 @@ import org.keycloak.models.workflow.WorkflowStateProvider;
|
|||
import org.keycloak.models.workflow.WorkflowStateProvider.ScheduledStep;
|
||||
import org.keycloak.models.workflow.conditions.IdentityProviderWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.conditions.RoleWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.ErrorRepresentation;
|
||||
import org.keycloak.representations.workflows.StepExecutionStatus;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -68,9 +69,6 @@ import com.fasterxml.jackson.jakarta.rs.yaml.JacksonYAMLProvider;
|
|||
import com.fasterxml.jackson.jakarta.rs.yaml.YAMLMediaTypes;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_AUTHENTICATED;
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
|
@ -103,7 +101,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testCreate() {
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -230,7 +228,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testFailCreateWorkflowWithNegativeTime() {
|
||||
WorkflowRepresentation workflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(-5))
|
||||
|
|
@ -247,7 +245,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
public void testFailCreateWorkflowWithDuplicateName() {
|
||||
// create first workflow
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -257,7 +255,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
|
||||
// try to create second workflow with same name
|
||||
try (Response response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.name())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(DisableUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(10))
|
||||
|
|
@ -276,7 +274,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
|
||||
String workflowId;
|
||||
try (Response response = workflows.create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -288,7 +286,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
}
|
||||
|
||||
workflows.create(WorkflowRepresentation.withName("another-workflow")
|
||||
.onEvent(ResourceOperationType.USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -511,7 +509,7 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
|||
String[] workflowNames = {"alpha-workflow", "beta-workflow", "gamma-workflow", "delta-workflow"};
|
||||
for (String name : workflowNames) {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName(name)
|
||||
.onEvent(ResourceOperationType.USER_CREATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
|||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.client.DeleteClientStepProviderFactory;
|
||||
import org.keycloak.models.workflow.conditions.UserAttributeWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.ClientCreatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.workflows.StepExecutionStatus;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -25,9 +27,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.CLIENT_ADDED;
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
|
@ -42,7 +41,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
public void testMigrationFailsIfWorkflowsNotCompatible() {
|
||||
// create two incompatible workflows - one that operates on users, another on clients
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("client-workflow")
|
||||
.onEvent(CLIENT_ADDED.name())
|
||||
.onEvent(ClientCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DeleteClientStepProviderFactory.ID)
|
||||
|
|
@ -54,7 +53,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
response.close();
|
||||
|
||||
response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("user-workflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(AddRequiredActionStepProviderFactory.ID)
|
||||
|
|
@ -93,7 +92,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
public void testMigrationFailsIfResourcesDontMeetWorkflowConditions() {
|
||||
// create two user workflows, the second having a condition that the users don't meet
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow-1")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DisableUserStepProviderFactory.ID)
|
||||
|
|
@ -144,7 +143,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
public void testMigrateToScheduledStepInDifferentWorkflow() {
|
||||
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow-1")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DisableUserStepProviderFactory.ID)
|
||||
|
|
@ -210,7 +209,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testMigrateToImmediateStepInDifferentWorkflow() {
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow-1")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DisableUserStepProviderFactory.ID)
|
||||
|
|
@ -275,7 +274,7 @@ public class WorkflowMigrationTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testMigrateToStepInSameWorkflow() {
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(AddRequiredActionStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
|||
import org.keycloak.models.workflow.ResourceType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
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;
|
||||
|
|
@ -22,8 +23,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
|
|
@ -160,7 +159,7 @@ public class AdhocWorkflowTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testDeactivateWorkflowForResource() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("One")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
@ -174,7 +173,7 @@ public class AdhocWorkflowTest extends AbstractWorkflowTest {
|
|||
)
|
||||
.build()).close();
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("Two")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import jakarta.ws.rs.core.Response.Status;
|
|||
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.WorkflowsResource;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserGroupMembershipAddedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserGroupMembershipRemovedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
|
||||
|
|
@ -52,7 +53,7 @@ public class GroupMembershipWorkflowTest extends AbstractWorkflowTest {
|
|||
}
|
||||
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_GROUP_MEMBERSHIP_ADDED.name() + "(" + GROUP_NAME + ")")
|
||||
.onEvent(UserGroupMembershipAddedWorkflowEventFactory.ID + "(" + GROUP_NAME + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
@ -100,7 +101,7 @@ public class GroupMembershipWorkflowTest extends AbstractWorkflowTest {
|
|||
}
|
||||
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_GROUP_MEMBERSHIP_REMOVED.name() + "(" + GROUP_NAME + ")")
|
||||
.onEvent(UserGroupMembershipRemovedWorkflowEventFactory.ID + "(" + GROUP_NAME + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import jakarta.ws.rs.core.Response;
|
|||
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.WorkflowsResource;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserFedIdentityAddedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserFedIdentityRemovedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -42,7 +43,7 @@ public class IdpLinkingWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on IdP linking
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_FEDERATED_IDENTITY_ADDED.name() + "(" + IDP_ALIAS + ")")
|
||||
.onEvent(UserFedIdentityAddedWorkflowEventFactory.ID + "(" + IDP_ALIAS + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
@ -81,7 +82,7 @@ public class IdpLinkingWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on IdP unlinking
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_FEDERATED_IDENTITY_REMOVED.name() + "(" + IDP_ALIAS + ")")
|
||||
.onEvent(UserFedIdentityRemovedWorkflowEventFactory.ID + "(" + IDP_ALIAS + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import jakarta.ws.rs.core.Response;
|
|||
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.WorkflowsResource;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserRoleGrantedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserRoleRevokedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
|
|
@ -45,7 +46,7 @@ public class RoleMembershipWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on role grant
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_ROLE_GRANTED.name() + "(" + ROLE_NAME + ")")
|
||||
.onEvent(UserRoleGrantedWorkflowEventFactory.ID + "(" + ROLE_NAME + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
@ -85,7 +86,7 @@ public class RoleMembershipWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on role revoke
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_ROLE_REVOKED.name() + "(" + ROLE_NAME + ")")
|
||||
.onEvent(UserRoleRevokedWorkflowEventFactory.ID + "(" + ROLE_NAME + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
|
|
@ -41,8 +43,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_AUTHENTICATED;
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.findEmailByRecipient;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.findEmailsByRecipient;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.verifyEmailContent;
|
||||
|
|
@ -68,7 +68,7 @@ public class UserAuthenticationWorkflowTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testActivateWorkflowOnUserAuthentication() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().restartInProgress("true") // this setting enables restarting the workflow
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
|
|
@ -143,7 +143,7 @@ public class UserAuthenticationWorkflowTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testMultipleWorkflows() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.toString(), USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID, UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -152,7 +152,7 @@ public class UserAuthenticationWorkflowTest extends AbstractWorkflowTest {
|
|||
.build())
|
||||
.build()).close();
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow_2")
|
||||
.onEvent(USER_CREATED.toString(), USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID, UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(10))
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package org.keycloak.tests.workflow.activation;
|
|||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -35,7 +35,7 @@ public class UserCreationWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on user creation
|
||||
WorkflowRepresentation workflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.conditions.GroupMembershipWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -56,7 +56,7 @@ public class GroupWorkflowConditionTest extends AbstractWorkflowTest {
|
|||
|
||||
// create workflow that activates on user creation with a group membership condition
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("group-membership-workflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.onCondition(GROUP_CONDITION)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
|
|
@ -36,6 +35,8 @@ import org.keycloak.models.workflow.WorkflowStateProvider;
|
|||
import org.keycloak.models.workflow.WorkflowStateProvider.ScheduledStep;
|
||||
import org.keycloak.models.workflow.WorkflowStep;
|
||||
import org.keycloak.models.workflow.conditions.IdentityProviderWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserFedIdentityAddedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
|
|
@ -53,8 +54,6 @@ import org.keycloak.testsuite.util.IdentityProviderBuilder;
|
|||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
|
@ -84,7 +83,7 @@ public class IdpLinkConditionWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create the workflow that triggers on IdP linking with a condition for the specific IdP
|
||||
WorkflowRepresentation workflow = WorkflowRepresentation.withName("idp-members-workflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.onCondition(IdentityProviderWorkflowConditionFactory.ID + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
@ -133,7 +132,7 @@ public class IdpLinkConditionWorkflowTest extends AbstractWorkflowTest {
|
|||
setupIdentityProvider();
|
||||
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_FEDERATED_IDENTITY_ADDED.name())
|
||||
.onEvent(UserFedIdentityAddedWorkflowEventFactory.ID)
|
||||
.onCondition(IdentityProviderWorkflowConditionFactory.ID + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.schedule(WorkflowScheduleRepresentation.create().after("1s").build())
|
||||
.withSteps(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.RestartWorkflowStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
|
|
@ -20,6 +19,7 @@ import org.keycloak.models.workflow.WorkflowProvider;
|
|||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider.ScheduledStep;
|
||||
import org.keycloak.models.workflow.conditions.RoleWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserRoleGrantedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
|
|
@ -172,7 +172,7 @@ public class RoleWorkflowConditionTest extends AbstractWorkflowTest {
|
|||
.reduce((a, b) -> a + " AND " + b).orElse(null);
|
||||
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_ROLE_GRANTED.name())
|
||||
.onEvent(UserRoleGrantedWorkflowEventFactory.ID)
|
||||
.onCondition(roleCondition)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import jakarta.ws.rs.core.Response.Status;
|
|||
import org.keycloak.admin.client.resource.WorkflowsResource;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.RestartWorkflowStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
|
|
@ -19,6 +18,7 @@ import org.keycloak.models.workflow.WorkflowProvider;
|
|||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider.ScheduledStep;
|
||||
import org.keycloak.models.workflow.conditions.UserAttributeWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -161,7 +161,7 @@ public class UserAttributeWorkflowConditionTest extends AbstractWorkflowTest {
|
|||
.orElse(null);
|
||||
|
||||
WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.schedule(WorkflowScheduleRepresentation.create().after("1s").build())
|
||||
.onCondition(attributeCondition)
|
||||
.withSteps(
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.workflow.DeleteUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.conditions.IdentityProviderWorkflowConditionFactory;
|
||||
import org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserFedIdentityAddedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserFedIdentityRemovedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
|
@ -55,8 +58,6 @@ import org.awaitility.Awaitility;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_AUTHENTICATED;
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.findEmailByRecipient;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.verifyEmailContent;
|
||||
|
||||
|
|
@ -129,7 +130,7 @@ public class BrokeredUserLifecycleWorkflowTest extends AbstractWorkflowTest {
|
|||
// create a workflow that notifies inactive users after 7 days, disables them 30 days after that if the user doesn't
|
||||
// log back in, and finally deletes them also 30 days after being disabled.
|
||||
consumerRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.onCondition(IDP_CONDITION)
|
||||
.concurrency().restartInProgress("true")
|
||||
.withSteps(
|
||||
|
|
@ -198,7 +199,7 @@ public class BrokeredUserLifecycleWorkflowTest extends AbstractWorkflowTest {
|
|||
public void testNonBrokeredUserNotAffectedByWorkflow() {
|
||||
// create a workflow that deletes inactive users after 10 days.
|
||||
consumerRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.onCondition(IDP_CONDITION)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(DeleteUserStepProviderFactory.ID)
|
||||
|
|
@ -221,7 +222,7 @@ public class BrokeredUserLifecycleWorkflowTest extends AbstractWorkflowTest {
|
|||
public void testInvalidateWorkflowOnIdentityProviderRemoval() {
|
||||
String workflowId;
|
||||
try (Response response = consumerRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.toString(), USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID, UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.onCondition(IDP_CONDITION)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(DeleteUserStepProviderFactory.ID)
|
||||
|
|
@ -266,8 +267,8 @@ public class BrokeredUserLifecycleWorkflowTest extends AbstractWorkflowTest {
|
|||
|
||||
// create a workflow that deletes users 1 day after a federated identity is added, and that is cancelled if the identity is removed
|
||||
consumerRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_FEDERATED_IDENTITY_ADDED.name() + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.concurrency().cancelInProgress(ResourceOperationType.USER_FEDERATED_IDENTITY_REMOVED.name() + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.onEvent(UserFedIdentityAddedWorkflowEventFactory.ID + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.concurrency().cancelInProgress(UserFedIdentityRemovedWorkflowEventFactory.ID + "(" + IDP_OIDC_ALIAS + ")")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(DeleteUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(1))
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
|
@ -52,7 +52,7 @@ public class DisableActiveWorkflowTest extends AbstractWorkflowTest {
|
|||
// create a test workflow
|
||||
String workflowId;
|
||||
try (Response response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("test-workflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.keycloak.tests.workflow.execution;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
|
@ -12,8 +13,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
|
@ -29,7 +28,7 @@ public class ImmediateWorkflowExecutionTest extends AbstractWorkflowTest {
|
|||
public void testRunImmediateWorkflow() {
|
||||
// create a test workflow with no time conditions - should run immediately when scheduled
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.withConfig("message", "message")
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStep;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
|
@ -44,7 +44,7 @@ public class ScheduledWorkflowExecutionTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testWorkflowDoesNotFallThroughStepsInSingleRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_CREATED.toString())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.keycloak.models.UserProvider;
|
|||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.WorkflowStepRunnerSuccessEvent;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.provider.ProviderEventListener;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -45,8 +46,6 @@ import org.keycloak.tests.workflow.config.WorkflowsScheduledTaskServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@KeycloakIntegrationTest(config = WorkflowsScheduledTaskServerConfig.class)
|
||||
|
|
@ -73,7 +72,7 @@ public class StepRunnerScheduledTaskTest extends AbstractWorkflowTest {
|
|||
RealmResource realm = adminClient.realm(realmName);
|
||||
|
||||
realm.workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(SetUserAttributeStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
|
|
@ -25,8 +26,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_AUTHENTICATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
|
@ -47,7 +46,7 @@ public class WorkflowConcurrencyTest extends AbstractWorkflowTest {
|
|||
public void testWorkflowIsRestartedOnSameEvent() {
|
||||
// create a workflow that can be restarted on the same event - i.e. has concurrency setting with restart-in-progress=true
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().restartInProgress("true")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
@ -89,7 +88,7 @@ public class WorkflowConcurrencyTest extends AbstractWorkflowTest {
|
|||
// create a workflow that can be restarted on a different event - i.e. restart-in-progress is set to an event expression
|
||||
// in this case we will use user-group-membership-added event to restart the workflow when user joins the group "testgroup"
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().restartInProgress("user-group-membership-added(testgroup)")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
@ -112,7 +111,7 @@ public class WorkflowConcurrencyTest extends AbstractWorkflowTest {
|
|||
public void testWorkflowIsCancelledOnSameEvent() {
|
||||
// create a workflow that can be cancelled on the same event - i.e. has concurrency setting with cancel-in-progress=true
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().cancelInProgress("true")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
@ -154,7 +153,7 @@ public class WorkflowConcurrencyTest extends AbstractWorkflowTest {
|
|||
// create a workflow that can be cancelled on a different event - i.e. cancel-in-progress is set to an event expression
|
||||
// in this case we will use user-group-membership-added event to cancel the workflow when user joins the group "testgroup"
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().cancelInProgress("user-group-membership-added(testgroup)")
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
|
|
@ -189,7 +188,7 @@ public class WorkflowConcurrencyTest extends AbstractWorkflowTest {
|
|||
|
||||
// create workflow with both settings - restart-in-progress on same event, cancel-in-progress on different event
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency().restartInProgress("true")
|
||||
.cancelInProgress("user-group-membership-added(testgroup)")
|
||||
.withSteps(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.time.Duration;
|
|||
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.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
|
@ -16,8 +17,6 @@ import org.awaitility.Awaitility;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
|
@ -31,7 +30,7 @@ public class AddRequiredActionTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testStepRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(AddRequiredActionStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.tests.admin.model.workflow;
|
||||
package org.keycloak.tests.workflow.step;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
|
|
@ -9,6 +9,8 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.workflow.RestartWorkflowStepProviderFactory;
|
||||
import org.keycloak.models.workflow.client.DeleteClientStepProviderFactory;
|
||||
import org.keycloak.models.workflow.client.DisableClientStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.ClientAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.ClientCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
|
|
@ -21,9 +23,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.CLIENT_ADDED;
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.CLIENT_LOGGED_IN;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
|
@ -42,7 +41,7 @@ public class DeleteClientStepTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testStepRun() {
|
||||
var response = managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(CLIENT_ADDED.name())
|
||||
.onEvent(ClientCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DeleteClientStepProviderFactory.ID)
|
||||
|
|
@ -75,7 +74,7 @@ public class DeleteClientStepTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testDisabledClientAfterInactivityPeriod() {
|
||||
WorkflowRepresentation workflowRepresentation = WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(CLIENT_ADDED.toString(), CLIENT_LOGGED_IN.toString())
|
||||
.onEvent(ClientCreatedWorkflowEventFactory.ID, ClientAuthenticatedWorkflowEventFactory.ID)
|
||||
.concurrency()
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(DisableClientStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.workflow.DeleteUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
|
||||
import org.keycloak.models.workflow.Workflow;
|
||||
import org.keycloak.models.workflow.WorkflowProvider;
|
||||
import org.keycloak.models.workflow.WorkflowStateProvider;
|
||||
import org.keycloak.models.workflow.events.UserAuthenticatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
|
@ -52,7 +52,7 @@ import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;
|
|||
import org.keycloak.testframework.util.ApiUtil;
|
||||
import org.keycloak.tests.workflow.AbstractWorkflowTest;
|
||||
import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
||||
import org.keycloak.tests.workflow.step.DeleteUserWorkflowStepTest.DeleteUserWorkflowServerConf;
|
||||
import org.keycloak.tests.workflow.step.DeleteUserStepTest.DeleteUserWorkflowServerConf;
|
||||
import org.keycloak.testsuite.federation.DummyUserFederationProvider;
|
||||
import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
* Tests the execution of the 'delete-user' workflow step.
|
||||
*/
|
||||
@KeycloakIntegrationTest(config = DeleteUserWorkflowServerConf.class)
|
||||
public class DeleteUserWorkflowStepTest extends AbstractWorkflowTest {
|
||||
public class DeleteUserStepTest extends AbstractWorkflowTest {
|
||||
|
||||
@InjectWebDriver
|
||||
ManagedWebDriver driver;
|
||||
|
|
@ -110,7 +110,7 @@ public class DeleteUserWorkflowStepTest extends AbstractWorkflowTest {
|
|||
}
|
||||
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(ResourceOperationType.USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(builder.build()).build()).close();
|
||||
|
||||
String componentId = addDummyFederationProvider();
|
||||
|
|
@ -170,7 +170,7 @@ public class DeleteUserWorkflowStepTest extends AbstractWorkflowTest {
|
|||
// create a couple of workflows that will activate for the test user
|
||||
// the first one will run the delete user step before the second one runs its first step
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow1")
|
||||
.onEvent(ResourceOperationType.USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(DeleteUserStepProviderFactory.ID)
|
||||
|
|
@ -178,7 +178,7 @@ public class DeleteUserWorkflowStepTest extends AbstractWorkflowTest {
|
|||
.build()
|
||||
).build()).close();
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("workflow2")
|
||||
.onEvent(ResourceOperationType.USER_AUTHENTICATED.toString())
|
||||
.onEvent(UserAuthenticatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(SetUserAttributeStepProviderFactory.ID)
|
||||
|
|
@ -15,7 +15,8 @@ import org.keycloak.models.workflow.JoinGroupStepProvider;
|
|||
import org.keycloak.models.workflow.JoinGroupStepProviderFactory;
|
||||
import org.keycloak.models.workflow.LeaveGroupStepProvider;
|
||||
import org.keycloak.models.workflow.LeaveGroupStepProviderFactory;
|
||||
import org.keycloak.models.workflow.ResourceOperationType;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.models.workflow.events.UserGroupMembershipRemovedWorkflowEventFactory;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
|
|
@ -31,8 +32,6 @@ import org.awaitility.Awaitility;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ public class GroupBasedStepTest extends AbstractWorkflowTest {
|
|||
List<String> expectedGroups = List.of("/a", "/b/b1", "c");
|
||||
|
||||
create(WorkflowRepresentation.withName("join-group")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(JoinGroupStepProviderFactory.ID)
|
||||
|
|
@ -95,7 +94,7 @@ public class GroupBasedStepTest extends AbstractWorkflowTest {
|
|||
joinGroup(user, "a", "/a/a1", "b/b1", "b/b2", "/c");
|
||||
|
||||
create(WorkflowRepresentation.withName("leave-group")
|
||||
.onEvent(ResourceOperationType.USER_GROUP_MEMBERSHIP_REMOVED.name())
|
||||
.onEvent(UserGroupMembershipRemovedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(LeaveGroupStepProviderFactory.ID)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.workflow.DeleteUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.DisableUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.NotifyUserStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.StepExecutionStatus;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
|
|
@ -47,7 +48,6 @@ import org.keycloak.tests.workflow.config.WorkflowsBlockingServerConfig;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.findEmailByRecipient;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.findEmailByRecipientContaining;
|
||||
import static org.keycloak.tests.workflow.util.EmailTestUtils.verifyEmailContent;
|
||||
|
|
@ -80,7 +80,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
public void testNotifyUserStepSendsEmailWithDefaultDisableMessage() {
|
||||
// Create workflow: disable at 10 days, notify 3 days before (at day 7)
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(7))
|
||||
|
|
@ -108,7 +108,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
public void testNotifyUserStepSendsEmailWithDefaultDeleteMessage() {
|
||||
// Create workflow: delete at 30 days, notify 15 days before (at day 15)
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(15))
|
||||
|
|
@ -135,7 +135,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testNotifyUserStepSkipsUsersWithoutEmailButLogsWarning() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
|
|
@ -169,7 +169,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
public void testCompleteUserLifecycleWithMultipleNotifications() {
|
||||
// Create workflow: just disable at 30 days with one notification before
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(15))
|
||||
|
|
@ -218,7 +218,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
public void testNotifyUserStepWithCustomMessageOverride() throws IOException {
|
||||
// Create workflow: disable at 7 days, notify 2 days before (at day 5) with custom message
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.withConfig("message", "<p>Dear ${user.firstName} ${user.lastName}, </p>\n" +
|
||||
|
|
@ -265,7 +265,7 @@ public class NotificationStepTest extends AbstractWorkflowTest {
|
|||
public void testNotifyUserStepWithSendToConfiguration() throws Exception {
|
||||
// Create workflow: notify immediately with send_to
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.withConfig("to", "admin@example.com")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.time.Duration;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.workflow.RemoveRequiredActionStepProvider;
|
||||
import org.keycloak.models.workflow.RemoveRequiredActionStepProviderFactory;
|
||||
import org.keycloak.models.workflow.events.UserCreatedWorkflowEventFactory;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
|
|
@ -16,8 +17,6 @@ import org.awaitility.Awaitility;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.keycloak.models.workflow.ResourceOperationType.USER_CREATED;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ public class RemoveRequiredActionTest extends AbstractWorkflowTest {
|
|||
@Test
|
||||
public void testStepRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("remove-action-workflow")
|
||||
.onEvent(USER_CREATED.name())
|
||||
.onEvent(UserCreatedWorkflowEventFactory.ID)
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create()
|
||||
.of(RemoveRequiredActionStepProviderFactory.ID)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue