Skip to content

Commit d48e441

Browse files
committed
[Fix #1544] auth Content to be completable future
Signed-off-by: fjtirado <ftirados@ibm.com>
1 parent c748450 commit d48e441

20 files changed

Lines changed: 203 additions & 263 deletions

File tree

impl/core/src/main/java/io/serverlessworkflow/impl/auth/AccessTokenProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import io.serverlessworkflow.impl.TaskContext;
1919
import io.serverlessworkflow.impl.WorkflowContext;
2020
import io.serverlessworkflow.impl.WorkflowModel;
21+
import java.util.concurrent.CompletableFuture;
2122

2223
public interface AccessTokenProvider {
23-
JWT validateAndGet(WorkflowContext workflow, TaskContext context, WorkflowModel model);
24+
CompletableFuture<JWT> validateAndGet(
25+
WorkflowContext workflow, TaskContext context, WorkflowModel model);
2426
}

impl/core/src/main/java/io/serverlessworkflow/impl/auth/AuthProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import io.serverlessworkflow.impl.WorkflowContext;
2020
import io.serverlessworkflow.impl.WorkflowModel;
2121
import java.net.URI;
22+
import java.util.concurrent.CompletableFuture;
2223

2324
public interface AuthProvider {
2425

2526
String scheme();
2627

27-
String content(WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri);
28+
CompletableFuture<String> content(
29+
WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri);
2830
}

impl/core/src/main/java/io/serverlessworkflow/impl/auth/BasicAuthProvider.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.serverlessworkflow.impl.WorkflowValueResolver;
3131
import java.net.URI;
3232
import java.util.Base64;
33+
import java.util.concurrent.CompletableFuture;
3334

3435
class BasicAuthProvider implements AuthProvider {
3536

@@ -58,15 +59,17 @@ public BasicAuthProvider(
5859
}
5960

6061
@Override
61-
public String content(WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
62-
return new String(
63-
Base64.getEncoder()
64-
.encode(
65-
String.format(
66-
USER_PASSWORD,
67-
userFilter.apply(workflow, task, model),
68-
passwordFilter.apply(workflow, task, model))
69-
.getBytes()));
62+
public CompletableFuture<String> content(
63+
WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
64+
return CompletableFuture.completedFuture(
65+
new String(
66+
Base64.getEncoder()
67+
.encode(
68+
String.format(
69+
USER_PASSWORD,
70+
userFilter.apply(workflow, task, model),
71+
passwordFilter.apply(workflow, task, model))
72+
.getBytes())));
7073
}
7174

7275
@Override

impl/core/src/main/java/io/serverlessworkflow/impl/auth/BearerAuthProvider.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.serverlessworkflow.impl.WorkflowUtils;
3030
import io.serverlessworkflow.impl.WorkflowValueResolver;
3131
import java.net.URI;
32+
import java.util.concurrent.CompletableFuture;
3233

3334
class BearerAuthProvider implements AuthProvider {
3435

@@ -49,8 +50,9 @@ public BearerAuthProvider(
4950
}
5051

5152
@Override
52-
public String content(WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
53-
return tokenFilter.apply(workflow, task, model);
53+
public CompletableFuture<String> content(
54+
WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
55+
return CompletableFuture.completedFuture(tokenFilter.apply(workflow, task, model));
5456
}
5557

5658
@Override

impl/core/src/main/java/io/serverlessworkflow/impl/auth/CommonOAuthProvider.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
import java.net.URI;
3030
import java.util.Arrays;
3131
import java.util.Map;
32+
import java.util.concurrent.CompletableFuture;
3233

33-
abstract class CommonOAuthProvider implements AuthProvider {
34+
public abstract class CommonOAuthProvider implements AuthProvider {
3435

3536
private final WorkflowValueResolver<AccessTokenProvider> tokenProvider;
3637

@@ -47,8 +48,12 @@ protected CommonOAuthProvider(WorkflowValueResolver<AccessTokenProvider> tokenPr
4748
}
4849

4950
@Override
50-
public String content(WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
51-
return tokenProvider.apply(workflow, task, model).validateAndGet(workflow, task, model).token();
51+
public CompletableFuture<String> content(
52+
WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
53+
return tokenProvider
54+
.apply(workflow, task, model)
55+
.validateAndGet(workflow, task, model)
56+
.thenApply(JWT::token);
5257
}
5358

5459
@Override

impl/core/src/main/java/io/serverlessworkflow/impl/auth/DigestAuthProvider.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131
import io.serverlessworkflow.impl.WorkflowValueResolver;
3232
import io.serverlessworkflow.impl.utils.RandomFactory;
3333
import java.io.IOException;
34-
import java.io.UncheckedIOException;
3534
import java.net.HttpURLConnection;
3635
import java.net.URI;
3736
import java.security.MessageDigest;
3837
import java.security.NoSuchAlgorithmException;
3938
import java.util.Optional;
4039
import java.util.Random;
4140
import java.util.StringTokenizer;
41+
import java.util.concurrent.CompletableFuture;
4242
import java.util.concurrent.atomic.AtomicInteger;
4343
import java.util.regex.Matcher;
4444
import java.util.regex.Pattern;
@@ -146,7 +146,8 @@ public String scheme() {
146146
}
147147

148148
@Override
149-
public String content(WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
149+
public CompletableFuture<String> content(
150+
WorkflowContext workflow, TaskContext task, WorkflowModel model, URI uri) {
150151
try {
151152
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
152153
connection.setRequestMethod(method);
@@ -186,17 +187,19 @@ public String content(WorkflowContext workflow, TaskContext task, WorkflowModel
186187
ha2))
187188
.orElseGet(() -> calculateHash(ha1, serverInfo.nonce, ha2));
188189

189-
return buildResponseInfo(serverInfo, userName, path, clientNonce, nonceCount, response);
190+
return CompletableFuture.completedFuture(
191+
buildResponseInfo(serverInfo, userName, path, clientNonce, nonceCount, response));
190192
} else {
191-
throw new IllegalStateException(
192-
"URI "
193-
+ uri
194-
+ " is not digest protected, it returned code "
195-
+ responseCode
196-
+ " when invoked without authentication header, but it should have returned 401 as per RFC 2617");
193+
return CompletableFuture.failedFuture(
194+
new IllegalStateException(
195+
"URI "
196+
+ uri
197+
+ " is not digest protected, it returned code "
198+
+ responseCode
199+
+ " when invoked without authentication header, but it should have returned 401 as per RFC 2617"));
197200
}
198201
} catch (IOException io) {
199-
throw new UncheckedIOException(io);
202+
return CompletableFuture.failedFuture(io);
200203
}
201204
}
202205

impl/core/src/main/java/io/serverlessworkflow/impl/auth/JWT.java

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,75 @@
1616
package io.serverlessworkflow.impl.auth;
1717

1818
import java.time.Instant;
19+
import java.time.format.DateTimeParseException;
20+
import java.util.Arrays;
21+
import java.util.Collection;
1922
import java.util.List;
2023
import java.util.Map;
2124
import java.util.Optional;
2225

23-
public interface JWT {
26+
public record JWT(String token, Map<String, Object> header, Map<String, Object> claims) {
2427

25-
String token();
28+
public Optional<Instant> expiresAt() {
29+
return toInstant(claims.get("exp"));
30+
}
2631

27-
List<String> audience();
32+
public Optional<Instant> issuedAt() {
33+
return toInstant(claims.get("iat"));
34+
}
2835

29-
Map<String, Object> claims();
36+
public Collection<String> audience() {
37+
return toCollection(claims.get("aud"), String.class);
38+
}
3039

31-
<T> Optional<T> claim(String name, Class<T> type);
40+
public Optional<String> issuer() {
41+
return Optional.ofNullable((String) claims.get("iss"));
42+
}
3243

33-
Optional<Instant> expiresAt();
44+
public Optional<String> subject() {
45+
return Optional.ofNullable((String) claims.get("sub"));
46+
}
3447

35-
Map<String, Object> header();
48+
public Optional<String> type() {
49+
return header.containsKey("typ")
50+
? Optional.of((String) header.get("typ"))
51+
: Optional.ofNullable((String) claims.get("typ"));
52+
}
3653

37-
Optional<Instant> issuedAt();
54+
private static Optional<Instant> toInstant(Object v) {
55+
if (v instanceof Instant i) {
56+
return Optional.of(i);
57+
}
58+
if (v instanceof Number n) {
59+
return Optional.of(Instant.ofEpochSecond((n.longValue())));
60+
}
61+
if (v instanceof String s) {
62+
try {
63+
long sec = Long.parseLong(s.trim());
64+
return Optional.of(Instant.ofEpochSecond((sec)));
65+
} catch (NumberFormatException ignored) {
66+
try {
67+
return Optional.of(Instant.parse(s.trim()));
68+
} catch (DateTimeParseException ex) {
69+
}
70+
}
71+
}
72+
return Optional.empty();
73+
}
3874

39-
Optional<String> issuer();
40-
41-
Optional<String> subject();
42-
43-
Optional<String> type();
75+
private static <T> Collection toCollection(Object v, Class<T> clazz) {
76+
if (v == null) {
77+
return List.of();
78+
}
79+
if (clazz.isInstance(v)) {
80+
return List.of(clazz.cast(v));
81+
}
82+
if (v instanceof Collection col) {
83+
return col;
84+
}
85+
if (v.getClass().isArray() && v.getClass().getComponentType().equals(clazz)) {
86+
return Arrays.asList(v);
87+
}
88+
return List.of();
89+
}
4490
}

impl/core/src/main/java/io/serverlessworkflow/impl/auth/OAuth2AuthProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import io.serverlessworkflow.api.types.Workflow;
1919
import io.serverlessworkflow.impl.WorkflowApplication;
2020

21-
class OAuth2AuthProvider extends CommonOAuthProvider {
21+
public class OAuth2AuthProvider extends CommonOAuthProvider {
2222

2323
public OAuth2AuthProvider(
2424
WorkflowApplication application, Workflow workflow, OAuthPolicyData policyData) {

impl/core/src/main/java/io/serverlessworkflow/impl/auth/OpenIdAuthProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import io.serverlessworkflow.api.types.Workflow;
1919
import io.serverlessworkflow.impl.WorkflowApplication;
2020

21-
class OpenIdAuthProvider extends CommonOAuthProvider {
21+
public class OpenIdAuthProvider extends CommonOAuthProvider {
2222

2323
public OpenIdAuthProvider(
2424
WorkflowApplication application, Workflow workflow, OAuthPolicyData policyData) {

impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunScriptExecutor.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,31 @@ public RunScriptExecutor(
5656
@Override
5757
public CompletableFuture<WorkflowModel> apply(
5858
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) {
59-
ScriptContext scriptContext =
60-
new ScriptContext(
61-
argumentExpr.map(m -> m.apply(workflowContext, taskContext, input)).orElse(Map.of()),
62-
environmentExpr.map(m -> m.apply(workflowContext, taskContext, input)).orElse(Map.of()),
63-
codeSupplier.apply(workflowContext, taskContext, input),
64-
returnType);
6559
if (isAwait) {
6660
return CompletableFuture.supplyAsync(
67-
() -> runScript(scriptContext, workflowContext, taskContext, input),
61+
() -> runScript(workflowContext, taskContext, input),
6862
workflowContext.definition().application().executorService());
6963
} else {
7064
workflowContext
7165
.definition()
7266
.application()
7367
.executorService()
74-
.submit(() -> runScript(scriptContext, workflowContext, taskContext, input));
68+
.submit(() -> runScript(workflowContext, taskContext, input));
7569
return CompletableFuture.completedFuture(input);
7670
}
7771
}
7872

7973
private WorkflowModel runScript(
80-
ScriptContext scriptContext,
81-
WorkflowContext workflowContext,
82-
TaskContext taskContext,
83-
WorkflowModel input) {
74+
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) {
8475
try {
76+
ScriptContext scriptContext =
77+
new ScriptContext(
78+
argumentExpr.map(m -> m.apply(workflowContext, taskContext, input)).orElse(Map.of()),
79+
environmentExpr
80+
.map(m -> m.apply(workflowContext, taskContext, input))
81+
.orElse(Map.of()),
82+
codeSupplier.apply(workflowContext, taskContext, input),
83+
returnType);
8584
return taskRunner.runScript(scriptContext, workflowContext, taskContext, input);
8685
} catch (Exception ex) {
8786
throw new WorkflowException(WorkflowError.runtime(taskContext, ex).build());

0 commit comments

Comments
 (0)