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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 14 additions & 26 deletions impl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,24 @@ This SDK is modular by design—pull in only what you need:
* **openworkflow-impl-jackson**
👉 **Most users add this one.** Contains implementation of core features using Jackson library, like JQ expressions, JSON Schema validation, and CloudEvents (de)serialization. Internally, it is an aggregation of smaller modules:

* **openworkflow-impl-jq** JQ expression implementation
* **openworkflow-impl-model** Jackson model implementation and Jackson JWT converter for oauth2 calls.
* **openworkflow-impl-validation** Schema validation implementation
* **openworkflow-impl-lifecycle-events** Enable publication of lifecycle events as Json cloud events.
* **openworkflow-impl-function** Jackson Function support.
* **openworkflow-impl-json** Jackson common utilities shared by all modules in this list
* **openworkflow-impl-cron** Cron parsing for workflow scheduled execution
* **openworkflow-impl-openapi** Deserialization support of OpenAPI schemas using Jackson (required for OpenAPI call task to work)

* **openworkflow-impl-jq** JQ expression implementation
* **openworkflow-impl-model** Jackson model implementation
* **openworkflow-impl-validation** Schema validation implementation
* **openworkflow-impl-lifecycle-events** Enable publication of lifecycle events as Json cloud events.
* **openworkflow-impl-function** Jackson Function support.
* **openworkflow-impl-json** Jackson common utilities shared by all modules in this list
* **openworkflow-impl-cron** Cron parsing for workflow scheduled execution

Additionally, The OpenWokflow specification defines a set of [call task](https://github.com/open-workflow-specification/specification/blob/main/dsl-reference.md#call), which requires additional dependencies, with the exception of HTTP (see section below). You might add those ones needed depending on the feature you are using in your definition:
Additionally, The OpenWokflow specification defines a set of [call task](https://github.com/open-workflow-specification/specification/blob/main/dsl-reference.md#call), which requires additional dependencies, with the exception of HTTP (see section below). You might add those ones needed depending on the feature you are using in your definition:


* **openworkflow-impl-openapi** OpenAPI support using Jackson
* **openworkflow-impl-openapi-base** Base OpenAPI support intended to be extended for a specific JSON library
* **openworkflow-impl-grpc** gRPC support
* **openworkflow-impl-script-python** Python support
* **openworkflow-impl-script-js** Javascript support
* **openworkflow-impl-container** Docker container support
* **openworkflow-impl-container** Docker container support
* **openworkflow-impl-a2a** A2A protocol support.

There are also companion modules/docs for:

Expand All @@ -111,12 +112,12 @@ There are also companion modules/docs for:

### Http dependencies

By default, the SDK reference implementation use `java.net.HttpRequest` to support Http calls. Therefore, no dependency needs to be added for using Http Call task or downloading of http resources, like OpenAPI schemas.
By default, the SDK reference implementation use `java.net.HttpRequest` to support Http/OpenAPI calls. Therefore, no dependency (besides the jackson modules described above) needs to be added for using Http Call task or downloading http resources.

However, for further configuration of Http functionality, users might include the Jakarta based modules, which will allow customizing `jakarta.ws.rs.client.Client` in Jakarta EE environments.

* **openworkflow-impl-http** HTTP `Call` task handler, based on JAX-RS client
* **openworkflow-impl-jackson-jwt** Optimized entity converter for Jackson model and OAuth2/OIDC helpers for Jakarta HTTP calls.
* **openworkflow-impl-http-jackson** Optimized entity converter for Jackson model

---

Expand All @@ -131,25 +132,12 @@ However, for further configuration of Http functionality, users might include th
<artifactId>openworkflow-impl-jackson</artifactId>
</dependency>

<!-- Add if you use HTTP Call tasks -->
<dependency>
<groupId>org.openworkflow.sdk</groupId>
<artifactId>openworkflow-impl-http</artifactId>
</dependency>

<!-- Add if your HTTP calls require OAuth2/OIDC -->
<dependency>
<groupId>org.openworkflow.sdk</groupId>
<artifactId>openworkflow-impl-jackson-jwt</artifactId>
</dependency>
```

### Gradle (Kotlin/Groovy)

```gradle
implementation("org.openworkflow.sdk:openworkflow-impl-jackson")
implementation("org.openworkflow.sdk:openworkflow-impl-http") // if using HTTP
implementation("org.openworkflow.sdk:openworkflow-impl-jackson-jwt") // if using OAuth2/OIDC
```

> Requires **Java 21+**.
Expand Down
15 changes: 15 additions & 0 deletions impl/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,19 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public static WorkflowValueResolver<URI> getURISupplier(
return (w, t, n) ->
application
.templateResolver()
.resolveTemplates(template.getLiteralUriTemplate(), w, t, n);
.resolveTemplates(template.getLiteralUriTemplate(), n.asMap().orElse(Map.of()));
}
throw new IllegalArgumentException("Invalid uritemplate definition " + template);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ abstract class AbstractAuthRequestBuilder<T extends OAuth2AuthenticationData>
implements AuthRequestBuilder<T> {

protected final WorkflowApplication application;
protected final HttpRequestInfoBuilder requestBuilder = new HttpRequestInfoBuilder();
protected final AuthHttpRequestInfoBuilder requestBuilder = new AuthHttpRequestInfoBuilder();

public AbstractAuthRequestBuilder(WorkflowApplication application) {
this.application = application;
}

@Override
public AuthHttpRequestInfo apply(T authenticationData) {
requestBuilder.withIssuers(authenticationData.getIssuers());
requestEncoding(authenticationData);
authenticationURI(authenticationData);
audience(authenticationData);
Expand All @@ -66,6 +67,7 @@ public AuthHttpRequestInfo apply(T authenticationData) {

@Override
public AuthHttpRequestInfo apply(Map<String, Object> secret) {
requestBuilder.withIssuers((String) secret.get("issuers"));
requestEncoding(secret);
authenticationURI(secret);
audience(secret);
Expand Down Expand Up @@ -194,10 +196,7 @@ void requestEncoding(T authenticationData) {

void requestEncoding(Map<String, Object> secret) {
Map<String, Object> request = (Map<String, Object>) secret.get(REQUEST);
String encoding = (String) request.get(ENCODING);
if (isValid(encoding)) {
requestBuilder.addHeader("Content-Type", encoding);
}
requestBuilder.withContentType((String) request.get(ENCODING));
}

protected abstract void authenticationURI(T authenticationData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,82 @@
*/
package org.openworkflow.sdk.impl.auth;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import org.openworkflow.sdk.impl.TaskContext;
import org.openworkflow.sdk.impl.WorkflowApplication;
import org.openworkflow.sdk.impl.WorkflowContext;
import org.openworkflow.sdk.impl.http.WorkflowHttpContentType;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestHelper;
import org.openworkflow.sdk.impl.http.WorkflowHttpRequestInfo;

public interface AccessTokenProvider {
CompletableFuture<JWT> validateAndGet(WorkflowContext workflow, TaskContext context);
class AccessTokenProvider {

private final WorkflowApplication app;
private final Supplier<AuthHttpRequestInfo> requestInfoSupplier;
private final JWTConverter jwtConverter;

AccessTokenProvider(
WorkflowApplication app,
Supplier<AuthHttpRequestInfo> requestInfoSupplier,
JWTConverter jwtConverter) {
this.app = app;
this.requestInfoSupplier = requestInfoSupplier;
this.jwtConverter = jwtConverter;
}

public CompletableFuture<JWT> validateAndGet(WorkflowContext workflow, TaskContext context) {
AuthHttpRequestInfo authRequestInfo = requestInfoSupplier.get();
WorkflowHttpRequestInfo httpRequestInfo =
buildHttpRequestInfo(workflow, context, authRequestInfo);
CompletableFuture<JWT> future =
WorkflowHttpRequestHelper.executeRequest(httpRequestInfo, app, workflow, context)
.thenApply(bytes -> jwtConverter.fromToken(bytes));
List<String> issuers = authRequestInfo.issuers();
if (!issuers.isEmpty()) {
future =
future.whenComplete(
(jwt, ex) -> {
if (jwt != null) {
jwt.issuer()
.ifPresent(
issuer -> {
if (!issuers.contains(issuer)) {
throw new IllegalStateException(
"Token issuer is not valid: " + issuer);
}
});
}
});
}
return future;
}

private WorkflowHttpRequestInfo buildHttpRequestInfo(
WorkflowContext workflow, TaskContext task, AuthHttpRequestInfo requestInfo) {
WorkflowHttpRequestInfo.Builder builder = WorkflowHttpRequestInfo.builder("POST");
Map<String, Object> headers = new LinkedHashMap<>();
headers.put("grant_type", requestInfo.grantType());
headers.put("User-Agent", "OAuth2-Client-Credentials/1.0");
headers.put("Cache-Control", "no-cache");
headers.put("Accept", "application/json");
for (var entry : requestInfo.headers().entrySet()) {
headers.put(entry.getKey(), entry.getValue().apply(workflow, task));
}
headers.put(WorkflowHttpContentType.HEADER_NAME, requestInfo.contentType().toString());
builder.headers(headers);
Map<String, Object> body = new HashMap<String, Object>();
body.put("grant_type", requestInfo.grantType());
requestInfo.queryParams().forEach((key, value) -> body.put(key, value.apply(workflow, task)));
requestInfo
.clientAuthParams()
.forEach((key, value) -> body.put(key, value.apply(workflow, task)));
return builder
.body(app.modelFactory().from(body))
.build(requestInfo.uri().apply(workflow, task));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
package org.openworkflow.sdk.impl.auth;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.openworkflow.sdk.impl.WorkflowValueResolver;
import org.openworkflow.sdk.impl.http.WorkflowHttpContentType;

public record AuthHttpRequestInfo(
Map<String, WorkflowValueResolver<String>> headers,
Expand All @@ -28,4 +30,5 @@ public record AuthHttpRequestInfo(
Optional<WorkflowValueResolver<URI>> revocationUri,
Optional<WorkflowValueResolver<URI>> introspectionUri,
String grantType,
String contentType) {}
WorkflowHttpContentType contentType,
List<String> issuers) {}
Loading
Loading