Ability to define workflows with YAML

Closes #42687

Signed-off-by: vramik <vramik@redhat.com>
Co-authored-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
vramik 2025-10-19 18:32:44 +02:00 committed by Pedro Igor
parent b1c0c15ad5
commit b5ed45f2a0
5 changed files with 56 additions and 2 deletions

View File

@ -787,6 +787,7 @@ class KeycloakProcessor {
void index(BuildProducer<IndexDependencyBuildItem> indexDependencyBuildItemBuildProducer) {
indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.liquibase", "liquibase-core"));
indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.keycloak", "keycloak-services"));
indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("com.fasterxml.jackson.jakarta.rs", "jackson-jakarta-rs-yaml-provider"));
}
@BuildStep

View File

@ -655,6 +655,12 @@
<artifactId>jna</artifactId>
</dependency>
<!-- YAML -->
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-yaml-provider</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@ -183,6 +183,11 @@
<version>${woodstox.version}</version> <!-- this version has to match that of used in Wildfly -->
<scope>test</scope>
</dependency>
<!-- YAML -->
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-yaml-provider</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>

View File

@ -4,6 +4,7 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import com.fasterxml.jackson.jakarta.rs.yaml.YAMLMediaTypes;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
@ -37,7 +38,7 @@ public class WorkflowsResource {
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Consumes({MediaType.APPLICATION_JSON, YAMLMediaTypes.APPLICATION_JACKSON_YAML})
public Response create(WorkflowRepresentation rep) {
try {
Workflow workflow = manager.toModel(rep);
@ -49,7 +50,7 @@ public class WorkflowsResource {
@Path("set")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Consumes({MediaType.APPLICATION_JSON, YAMLMediaTypes.APPLICATION_JACKSON_YAML})
public Response createAll(WorkflowSetRepresentation workflows) {
for (WorkflowRepresentation workflow : Optional.ofNullable(workflows.getWorkflows()).orElse(List.of())) {
create(workflow).close();

View File

@ -34,6 +34,9 @@ import java.util.Collections;
import java.util.List;
import java.util.UUID;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
import org.hamcrest.Matchers;
import jakarta.mail.MessagingException;
@ -42,6 +45,8 @@ import java.io.IOException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.BearerAuthFilter;
import org.keycloak.admin.client.resource.WorkflowsResource;
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
import org.keycloak.common.util.Time;
@ -69,6 +74,8 @@ import org.keycloak.representations.workflows.WorkflowSetRepresentation;
import org.keycloak.representations.workflows.WorkflowStepRepresentation;
import org.keycloak.representations.workflows.WorkflowConditionRepresentation;
import org.keycloak.representations.workflows.WorkflowRepresentation;
import org.keycloak.testframework.annotations.InjectAdminClient;
import org.keycloak.testframework.annotations.InjectKeycloakUrls;
import org.keycloak.testframework.annotations.InjectRealm;
import org.keycloak.testframework.mail.MailServer;
import org.keycloak.testframework.mail.annotations.InjectMailServer;
@ -79,7 +86,9 @@ import org.keycloak.testframework.realm.UserConfigBuilder;
import org.keycloak.testframework.remote.providers.runonserver.RunOnServer;
import org.keycloak.testframework.remote.runonserver.InjectRunOnServer;
import org.keycloak.testframework.remote.runonserver.RunOnServerClient;
import org.keycloak.testframework.server.KeycloakUrls;
import org.keycloak.tests.utils.MailUtils;
import org.keycloak.util.JsonSerialization;
@KeycloakIntegrationTest(config = WorkflowsServerConfig.class)
public class WorkflowManagementTest {
@ -95,6 +104,12 @@ public class WorkflowManagementTest {
@InjectMailServer
private MailServer mailServer;
@InjectKeycloakUrls
KeycloakUrls keycloakUrls;
@InjectAdminClient(ref = "managed", realmRef = "managedRealm")
Keycloak adminClient;
@Test
public void testCreate() {
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
@ -877,6 +892,32 @@ public class WorkflowManagementTest {
mailServer.runCleanup();
}
@Test
public void testCreateUsingYaml() throws IOException {
WorkflowSetRepresentation expectedWorkflows = WorkflowRepresentation.create()
.of(UserCreationTimeWorkflowProviderFactory.ID)
.withSteps(
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
.after(Duration.ofDays(5))
.build(),
WorkflowStepRepresentation.create().of(DisableUserStepProviderFactory.ID)
.after(Duration.ofDays(5))
.build()
).build();
Client httpClient = Keycloak.getClientProvider().newRestEasyClient(null, null, true);;
WebTarget target = httpClient.target(keycloakUrls.getBaseUrl().toString())
.path("admin")
.path("realms")
.path(managedRealm.getName())
.path("workflows")
.path("set")
.register(new BearerAuthFilter(adminClient.tokenManager()));
Response response = target.request().post(Entity.entity(JsonSerialization.writeValueAsString(expectedWorkflows), "application/yaml"));
response.close();
}
public static List<MimeMessage> findEmailsByRecipient(MailServer mailServer, String expectedRecipient) {
return Arrays.stream(mailServer.getReceivedMessages())
.filter(msg -> {