Skip to content

Commit 9a16384

Browse files
authored
[Fix #952] Refactoring auth code (#975)
* [Fix #952] Refactoring auth code Signed-off-by: fjtirado <ftirados@redhat.com> * [Fix #952] More refactor Signed-off-by: fjtirado <ftirados@redhat.com> --------- Signed-off-by: fjtirado <ftirados@redhat.com>
1 parent 3c8f4ff commit 9a16384

28 files changed

+794
-549
lines changed

impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowApplication.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import io.serverlessworkflow.impl.resources.DefaultResourceLoaderFactory;
3636
import io.serverlessworkflow.impl.resources.ExternalResourceHandler;
3737
import io.serverlessworkflow.impl.resources.ResourceLoaderFactory;
38+
import io.serverlessworkflow.impl.resources.URITemplateResolver;
3839
import io.serverlessworkflow.impl.scheduler.DefaultWorkflowScheduler;
3940
import io.serverlessworkflow.impl.scheduler.WorkflowScheduler;
4041
import io.serverlessworkflow.impl.schema.SchemaValidator;
@@ -73,6 +74,7 @@ public class WorkflowApplication implements AutoCloseable {
7374
private final ConfigManager configManager;
7475
private final SecretManager secretManager;
7576
private final SchedulerListener schedulerListener;
77+
private final Optional<URITemplateResolver> templateResolver;
7678

7779
private WorkflowApplication(Builder builder) {
7880
this.taskFactory = builder.taskFactory;
@@ -94,6 +96,7 @@ private WorkflowApplication(Builder builder) {
9496
this.additionalObjects = builder.additionalObjects;
9597
this.configManager = builder.configManager;
9698
this.secretManager = builder.secretManager;
99+
this.templateResolver = builder.templateResolver;
97100
}
98101

99102
public TaskExecutorFactory taskFactory() {
@@ -173,6 +176,7 @@ public SchemaValidator getValidator(SchemaInline inline) {
173176
private SecretManager secretManager;
174177
private ConfigManager configManager;
175178
private SchedulerListener schedulerListener;
179+
private Optional<URITemplateResolver> templateResolver;
176180

177181
private Builder() {}
178182

@@ -325,6 +329,7 @@ public WorkflowApplication build() {
325329
.findFirst()
326330
.orElseGet(() -> new ConfigSecretManager(configManager));
327331
}
332+
templateResolver = ServiceLoader.load(URITemplateResolver.class).findFirst();
328333
return new WorkflowApplication(this);
329334
}
330335
}
@@ -398,6 +403,10 @@ SchedulerListener schedulerListener() {
398403
return schedulerListener;
399404
}
400405

406+
public Optional<URITemplateResolver> templateResolver() {
407+
return templateResolver;
408+
}
409+
401410
public <T> Optional<T> additionalObject(
402411
String name, WorkflowContext workflowContext, TaskContext taskContext) {
403412
return Optional.ofNullable(additionalObjects.get(name))

impl/core/src/main/java/io/serverlessworkflow/impl/WorkflowUtils.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import io.serverlessworkflow.api.types.InputFrom;
2121
import io.serverlessworkflow.api.types.OutputAs;
2222
import io.serverlessworkflow.api.types.SchemaUnion;
23+
import io.serverlessworkflow.api.types.SecretBasedAuthenticationPolicy;
2324
import io.serverlessworkflow.api.types.TimeoutAfter;
2425
import io.serverlessworkflow.api.types.UriTemplate;
26+
import io.serverlessworkflow.api.types.Workflow;
2527
import io.serverlessworkflow.impl.expressions.ExpressionDescriptor;
2628
import io.serverlessworkflow.impl.expressions.ExpressionUtils;
2729
import io.serverlessworkflow.impl.resources.ResourceLoader;
@@ -200,4 +202,45 @@ public static WorkflowValueResolver<Duration> fromTimeoutAfter(
200202
return (w, t, f) -> Duration.ZERO;
201203
}
202204
}
205+
206+
public static final String secretProp(WorkflowContext context, String secretName, String prop) {
207+
return (String) secret(context, secretName).get(prop);
208+
}
209+
210+
public static final Map<String, Object> secret(WorkflowContext context, String secretName) {
211+
return context.definition().application().secretManager().secret(secretName);
212+
}
213+
214+
public static final String checkSecret(
215+
Workflow workflow, SecretBasedAuthenticationPolicy secretPolicy) {
216+
String secretName = secretPolicy.getUse();
217+
return workflow.getUse().getSecrets().stream()
218+
.filter(s -> s.equals(secretName))
219+
.findAny()
220+
.orElseThrow(() -> new IllegalStateException("Secret " + secretName + " does not exist"));
221+
}
222+
223+
public static URI concatURI(URI uri, String pathToAppend) {
224+
return uri.getPath().endsWith("/")
225+
? uri.resolve(pathToAppend)
226+
: URI.create(
227+
uri.toString() + (pathToAppend.startsWith("/") ? pathToAppend : "/" + pathToAppend));
228+
}
229+
230+
public static WorkflowValueResolver<URI> getURISupplier(
231+
WorkflowApplication application, UriTemplate template) {
232+
if (template.getLiteralUri() != null) {
233+
return (w, t, n) -> template.getLiteralUri();
234+
} else if (template.getLiteralUriTemplate() != null) {
235+
return (w, t, n) ->
236+
application
237+
.templateResolver()
238+
.orElseThrow(
239+
() ->
240+
new IllegalStateException(
241+
"Need an uri template resolver to resolve uri template"))
242+
.resolveTemplates(template.getLiteralUriTemplate(), w, t, n);
243+
}
244+
throw new IllegalArgumentException("Invalid uritemplate definition " + template);
245+
}
203246
}

impl/core/src/main/java/io/serverlessworkflow/impl/config/ConfigSecretManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ public class ConfigSecretManager implements SecretManager {
2323

2424
private final ConfigManager configManager;
2525

26-
private Map<String, Map<String, String>> secretMap = new ConcurrentHashMap<>();
26+
private Map<String, Map<String, Object>> secretMap = new ConcurrentHashMap<>();
2727

2828
public ConfigSecretManager(ConfigManager configManager) {
2929
this.configManager = configManager;
3030
}
3131

3232
@Override
33-
public Map<String, String> secret(String secretName) {
33+
public Map<String, Object> secret(String secretName) {
3434
return secretMap.computeIfAbsent(secretName, this::buildMap);
3535
}
3636

37-
private Map<String, String> buildMap(String secretName) {
38-
Map<String, String> map = new HashMap<String, String>();
37+
private Map<String, Object> buildMap(String secretName) {
38+
Map<String, Object> map = new HashMap<>();
3939
final String prefix = secretName + ".";
4040
for (String name : configManager.names()) {
4141
if (name.startsWith(prefix)) {

impl/core/src/main/java/io/serverlessworkflow/impl/config/SecretManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020

2121
@FunctionalInterface
2222
public interface SecretManager extends ServicePriority {
23-
Map<String, String> secret(String secretName);
23+
Map<String, Object> secret(String secretName);
2424
}

impl/core/src/main/java/io/serverlessworkflow/impl/resources/DefaultResourceLoader.java

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
*/
1616
package io.serverlessworkflow.impl.resources;
1717

18+
import static io.serverlessworkflow.impl.WorkflowUtils.getURISupplier;
19+
1820
import io.serverlessworkflow.api.types.Endpoint;
1921
import io.serverlessworkflow.api.types.EndpointUri;
2022
import io.serverlessworkflow.api.types.ExternalResource;
21-
import io.serverlessworkflow.api.types.UriTemplate;
2223
import io.serverlessworkflow.impl.TaskContext;
2324
import io.serverlessworkflow.impl.WorkflowApplication;
2425
import io.serverlessworkflow.impl.WorkflowContext;
@@ -31,41 +32,21 @@
3132
import java.time.Instant;
3233
import java.util.Map;
3334
import java.util.Optional;
34-
import java.util.ServiceLoader;
3535
import java.util.concurrent.ConcurrentHashMap;
36-
import java.util.concurrent.atomic.AtomicReference;
3736
import java.util.function.Function;
3837

3938
public class DefaultResourceLoader implements ResourceLoader {
4039

4140
private final Optional<Path> workflowPath;
4241
private final WorkflowApplication application;
4342

44-
private final AtomicReference<URITemplateResolver> templateResolver =
45-
new AtomicReference<URITemplateResolver>();
46-
4743
private Map<ExternalResourceHandler, CachedResource> resourceCache = new ConcurrentHashMap<>();
4844

4945
protected DefaultResourceLoader(WorkflowApplication application, Path workflowPath) {
5046
this.application = application;
5147
this.workflowPath = Optional.ofNullable(workflowPath);
5248
}
5349

54-
private URITemplateResolver templateResolver() {
55-
URITemplateResolver result = templateResolver.get();
56-
if (result == null) {
57-
result =
58-
ServiceLoader.load(URITemplateResolver.class)
59-
.findFirst()
60-
.orElseThrow(
61-
() ->
62-
new IllegalStateException(
63-
"Need an uri template resolver to resolve uri template"));
64-
templateResolver.set(result);
65-
}
66-
return result;
67-
}
68-
6950
private ExternalResourceHandler fileResource(String pathStr) {
7051
Path path = Path.of(pathStr);
7152
if (path.isAbsolute()) {
@@ -122,7 +103,7 @@ public WorkflowValueResolver<URI> uriSupplier(Endpoint endpoint) {
122103
if (endpoint.getEndpointConfiguration() != null) {
123104
EndpointUri uri = endpoint.getEndpointConfiguration().getUri();
124105
if (uri.getLiteralEndpointURI() != null) {
125-
return getURISupplier(uri.getLiteralEndpointURI());
106+
return getURISupplier(application, uri.getLiteralEndpointURI());
126107
} else if (uri.getExpressionEndpointURI() != null) {
127108
return new ExpressionURISupplier(
128109
application
@@ -135,21 +116,11 @@ public WorkflowValueResolver<URI> uriSupplier(Endpoint endpoint) {
135116
.expressionFactory()
136117
.resolveString(ExpressionDescriptor.from(endpoint.getRuntimeExpression())));
137118
} else if (endpoint.getUriTemplate() != null) {
138-
return getURISupplier(endpoint.getUriTemplate());
119+
return getURISupplier(application, endpoint.getUriTemplate());
139120
}
140121
throw new IllegalArgumentException("Invalid endpoint definition " + endpoint);
141122
}
142123

143-
private WorkflowValueResolver<URI> getURISupplier(UriTemplate template) {
144-
if (template.getLiteralUri() != null) {
145-
return (w, t, n) -> template.getLiteralUri();
146-
} else if (template.getLiteralUriTemplate() != null) {
147-
return (w, t, n) ->
148-
templateResolver().resolveTemplates(template.getLiteralUriTemplate(), w, t, n);
149-
}
150-
throw new IllegalArgumentException("Invalid uritemplate definition " + template);
151-
}
152-
153124
private class ExpressionURISupplier implements WorkflowValueResolver<URI> {
154125
private WorkflowValueResolver<String> expr;
155126

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AbstractAuthProvider.java

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@
1515
*/
1616
package io.serverlessworkflow.impl.executors.http;
1717

18-
import io.serverlessworkflow.api.types.SecretBasedAuthenticationPolicy;
19-
import io.serverlessworkflow.api.types.Workflow;
2018
import io.serverlessworkflow.impl.TaskContext;
2119
import io.serverlessworkflow.impl.WorkflowContext;
2220
import io.serverlessworkflow.impl.WorkflowModel;
2321
import jakarta.ws.rs.client.Invocation.Builder;
2422

25-
public abstract class AbstractAuthProvider implements AuthProvider {
23+
abstract class AbstractAuthProvider implements AuthProvider {
2624

2725
private static final String AUTH_HEADER_FORMAT = "%s %s";
2826

@@ -37,19 +35,6 @@ public Builder build(
3735
return builder;
3836
}
3937

40-
protected final String checkSecret(
41-
Workflow workflow, SecretBasedAuthenticationPolicy secretPolicy) {
42-
String secretName = secretPolicy.getUse();
43-
return workflow.getUse().getSecrets().stream()
44-
.filter(s -> s.equals(secretName))
45-
.findAny()
46-
.orElseThrow(() -> new IllegalStateException("Secret " + secretName + " does not exist"));
47-
}
48-
49-
protected final String find(WorkflowContext context, String secretName, String prop) {
50-
return context.definition().application().secretManager().secret(secretName).get(prop);
51-
}
52-
5338
protected abstract String authScheme();
5439

5540
protected abstract String authParameter(

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BasicAuthProvider.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
*/
1616
package io.serverlessworkflow.impl.executors.http;
1717

18+
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
19+
import static io.serverlessworkflow.impl.WorkflowUtils.secretProp;
20+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.PASSWORD;
21+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.USER;
22+
1823
import io.serverlessworkflow.api.types.BasicAuthenticationPolicy;
1924
import io.serverlessworkflow.api.types.Workflow;
2025
import io.serverlessworkflow.impl.TaskContext;
@@ -44,8 +49,8 @@ public BasicAuthProvider(
4449
} else if (authPolicy.getBasic().getBasicAuthenticationPolicySecret() != null) {
4550
String secretName =
4651
checkSecret(workflow, authPolicy.getBasic().getBasicAuthenticationPolicySecret());
47-
userFilter = (w, t, m) -> find(w, secretName, "username");
48-
passwordFilter = (w, t, m) -> find(w, secretName, "password");
52+
userFilter = (w, t, m) -> secretProp(w, secretName, USER);
53+
passwordFilter = (w, t, m) -> secretProp(w, secretName, PASSWORD);
4954
} else {
5055
throw new IllegalStateException("Both secret and properties are null for authorization");
5156
}

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BearerAuthProvider.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package io.serverlessworkflow.impl.executors.http;
1717

18+
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
19+
import static io.serverlessworkflow.impl.WorkflowUtils.secretProp;
20+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.TOKEN;
21+
1822
import io.serverlessworkflow.api.types.BearerAuthenticationPolicy;
1923
import io.serverlessworkflow.api.types.BearerAuthenticationPolicyConfiguration;
2024
import io.serverlessworkflow.api.types.Workflow;
@@ -39,7 +43,7 @@ public BearerAuthProvider(
3943
tokenFilter = WorkflowUtils.buildStringFilter(app, token);
4044
} else if (config.getBearerAuthenticationPolicySecret() != null) {
4145
String secretName = checkSecret(workflow, config.getBearerAuthenticationPolicySecret());
42-
tokenFilter = (w, t, m) -> find(w, secretName, "bearer");
46+
tokenFilter = (w, t, m) -> secretProp(w, secretName, TOKEN);
4347
}
4448
}
4549

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.executors.http;
17+
18+
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
19+
20+
import io.serverlessworkflow.api.types.OAuth2AuthenticationData;
21+
import io.serverlessworkflow.api.types.SecretBasedAuthenticationPolicy;
22+
import io.serverlessworkflow.api.types.Workflow;
23+
import io.serverlessworkflow.impl.TaskContext;
24+
import io.serverlessworkflow.impl.WorkflowContext;
25+
import io.serverlessworkflow.impl.WorkflowModel;
26+
import io.serverlessworkflow.impl.WorkflowValueResolver;
27+
import io.serverlessworkflow.impl.executors.http.auth.requestbuilder.AccessTokenProvider;
28+
import io.serverlessworkflow.impl.executors.http.auth.requestbuilder.AccessTokenProviderFactory;
29+
import io.serverlessworkflow.impl.executors.http.auth.requestbuilder.AuthRequestBuilder;
30+
import java.util.Map;
31+
32+
abstract class CommonOAuthProvider extends AbstractAuthProvider {
33+
34+
private final WorkflowValueResolver<AccessTokenProvider> tokenProvider;
35+
36+
protected CommonOAuthProvider(WorkflowValueResolver<AccessTokenProvider> tokenProvider) {
37+
this.tokenProvider = tokenProvider;
38+
}
39+
40+
@Override
41+
protected String authParameter(WorkflowContext workflow, TaskContext task, WorkflowModel model) {
42+
return tokenProvider.apply(workflow, task, model).validateAndGet(workflow, task, model).token();
43+
}
44+
45+
@Override
46+
protected String authScheme() {
47+
return "Bearer";
48+
}
49+
50+
protected static OAuth2AuthenticationData fillFromMap(
51+
OAuth2AuthenticationData data, Map<String, Object> secretMap) {
52+
return data;
53+
}
54+
55+
protected static WorkflowValueResolver<AccessTokenProvider> accessToken(
56+
Workflow workflow,
57+
OAuth2AuthenticationData authenticationData,
58+
SecretBasedAuthenticationPolicy secret,
59+
AuthRequestBuilder<?> builder) {
60+
if (authenticationData != null) {
61+
return AccessTokenProviderFactory.build(authenticationData, builder);
62+
} else if (secret != null) {
63+
return AccessTokenProviderFactory.build(checkSecret(workflow, secret), builder);
64+
}
65+
throw new IllegalStateException("Both policy and secret are null");
66+
}
67+
}

0 commit comments

Comments
 (0)