Skip to content

Commit a980cd7

Browse files
authored
Merge pull request #674 from fjtirado/Fix_#673
[Fix #673] Adding basic and bearer auth support
2 parents bd81ad6 + cc4191d commit a980cd7

File tree

11 files changed

+369
-11
lines changed

11 files changed

+369
-11
lines changed

experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallExecutor.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,14 @@
1818
import io.serverlessworkflow.api.types.TaskBase;
1919
import io.serverlessworkflow.api.types.func.CallJava;
2020
import io.serverlessworkflow.impl.TaskContext;
21-
import io.serverlessworkflow.impl.WorkflowApplication;
2221
import io.serverlessworkflow.impl.WorkflowContext;
2322
import io.serverlessworkflow.impl.WorkflowModel;
2423
import io.serverlessworkflow.impl.WorkflowModelFactory;
2524
import io.serverlessworkflow.impl.executors.CallableTask;
26-
import io.serverlessworkflow.impl.resources.ResourceLoader;
2725
import java.util.concurrent.CompletableFuture;
2826

2927
public class JavaCallExecutor implements CallableTask<CallJava> {
3028

31-
@Override
32-
public void init(CallJava task, WorkflowApplication application, ResourceLoader loader) {}
33-
3429
@Override
3530
public CompletableFuture<WorkflowModel> apply(
3631
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected CallTaskExecutorBuilder(
4242
CallableTask<T> callable) {
4343
super(position, task, workflow, application, resourceLoader);
4444
this.callable = callable;
45-
callable.init(task, application, resourceLoader);
45+
callable.init(task, workflow, application, resourceLoader);
4646
}
4747

4848
@Override

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.serverlessworkflow.impl.executors;
1717

1818
import io.serverlessworkflow.api.types.TaskBase;
19+
import io.serverlessworkflow.api.types.Workflow;
1920
import io.serverlessworkflow.impl.TaskContext;
2021
import io.serverlessworkflow.impl.WorkflowApplication;
2122
import io.serverlessworkflow.impl.WorkflowContext;
@@ -24,7 +25,8 @@
2425
import java.util.concurrent.CompletableFuture;
2526

2627
public interface CallableTask<T extends TaskBase> {
27-
void init(T task, WorkflowApplication application, ResourceLoader loader);
28+
default void init(
29+
T task, Workflow workflow, WorkflowApplication application, ResourceLoader loader) {}
2830

2931
CompletableFuture<WorkflowModel> apply(
3032
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 io.serverlessworkflow.impl.TaskContext;
19+
import io.serverlessworkflow.impl.WorkflowContext;
20+
import io.serverlessworkflow.impl.WorkflowModel;
21+
import jakarta.ws.rs.client.Invocation;
22+
23+
@FunctionalInterface
24+
interface AuthProvider {
25+
Invocation.Builder build(
26+
Invocation.Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model);
27+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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 io.serverlessworkflow.api.types.AuthenticationPolicyUnion;
19+
import io.serverlessworkflow.api.types.EndpointConfiguration;
20+
import io.serverlessworkflow.api.types.ReferenceableAuthenticationPolicy;
21+
import io.serverlessworkflow.api.types.Workflow;
22+
import io.serverlessworkflow.impl.WorkflowApplication;
23+
import java.util.Optional;
24+
25+
class AuthProviderFactory {
26+
27+
private AuthProviderFactory() {}
28+
29+
static final String AUTH_HEADER_NAME = "Authorization";
30+
31+
public static Optional<AuthProvider> getAuth(
32+
WorkflowApplication app, Workflow workflow, EndpointConfiguration endpointConfiguration) {
33+
if (endpointConfiguration == null) {
34+
return Optional.empty();
35+
}
36+
ReferenceableAuthenticationPolicy auth = endpointConfiguration.getAuthentication();
37+
if (auth == null) {
38+
return Optional.empty();
39+
}
40+
if (auth.getAuthenticationPolicyReference() != null) {
41+
return buildFromReference(app, workflow, auth.getAuthenticationPolicyReference().getUse());
42+
} else if (auth.getAuthenticationPolicy() != null) {
43+
return buildFromPolicy(app, workflow, auth.getAuthenticationPolicy());
44+
}
45+
return Optional.empty();
46+
}
47+
48+
private static Optional<AuthProvider> buildFromReference(
49+
WorkflowApplication app, Workflow workflow, String use) {
50+
return workflow.getUse().getAuthentications().getAdditionalProperties().entrySet().stream()
51+
.filter(s -> s.getKey().equals(use))
52+
.findAny()
53+
.flatMap(e -> buildFromPolicy(app, workflow, e.getValue()));
54+
}
55+
56+
private static Optional<AuthProvider> buildFromPolicy(
57+
WorkflowApplication app, Workflow workflow, AuthenticationPolicyUnion authenticationPolicy) {
58+
if (authenticationPolicy.getBasicAuthenticationPolicy() != null) {
59+
return Optional.of(
60+
new BasicAuthProvider(
61+
app, workflow, authenticationPolicy.getBasicAuthenticationPolicy()));
62+
} else if (authenticationPolicy.getBearerAuthenticationPolicy() != null) {
63+
return Optional.of(
64+
new BearerAuthProvider(
65+
app, workflow, authenticationPolicy.getBearerAuthenticationPolicy()));
66+
} else if (authenticationPolicy.getDigestAuthenticationPolicy() != null) {
67+
return Optional.of(
68+
new DigestAuthProvider(
69+
app, workflow, authenticationPolicy.getDigestAuthenticationPolicy()));
70+
} else if (authenticationPolicy.getOAuth2AuthenticationPolicy() != null) {
71+
return Optional.of(
72+
new OAuth2AuthProvider(
73+
app, workflow, authenticationPolicy.getOAuth2AuthenticationPolicy()));
74+
} else if (authenticationPolicy.getOpenIdConnectAuthenticationPolicy() != null) {
75+
return Optional.of(
76+
new OpenIdAuthProvider(
77+
app, workflow, authenticationPolicy.getOpenIdConnectAuthenticationPolicy()));
78+
}
79+
80+
return Optional.empty();
81+
}
82+
}
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 io.serverlessworkflow.api.types.BasicAuthenticationPolicy;
19+
import io.serverlessworkflow.api.types.Workflow;
20+
import io.serverlessworkflow.impl.StringFilter;
21+
import io.serverlessworkflow.impl.TaskContext;
22+
import io.serverlessworkflow.impl.WorkflowApplication;
23+
import io.serverlessworkflow.impl.WorkflowContext;
24+
import io.serverlessworkflow.impl.WorkflowModel;
25+
import io.serverlessworkflow.impl.WorkflowUtils;
26+
import jakarta.ws.rs.client.Invocation.Builder;
27+
import java.util.Base64;
28+
29+
class BasicAuthProvider implements AuthProvider {
30+
31+
private static final String BASIC_TOKEN = "Basic %s";
32+
private static final String USER_PASSWORD = "%s:%s";
33+
34+
private StringFilter userFilter;
35+
private StringFilter passwordFilter;
36+
37+
public BasicAuthProvider(
38+
WorkflowApplication app, Workflow workflow, BasicAuthenticationPolicy authPolicy) {
39+
if (authPolicy.getBasic().getBasicAuthenticationProperties() != null) {
40+
userFilter =
41+
WorkflowUtils.buildStringFilter(
42+
app, authPolicy.getBasic().getBasicAuthenticationProperties().getUsername());
43+
passwordFilter =
44+
WorkflowUtils.buildStringFilter(
45+
app, authPolicy.getBasic().getBasicAuthenticationProperties().getPassword());
46+
} else if (authPolicy.getBasic().getBasicAuthenticationPolicySecret() != null) {
47+
throw new UnsupportedOperationException("Secrets are still not supported");
48+
}
49+
}
50+
51+
@Override
52+
public Builder build(
53+
Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
54+
builder.header(
55+
AuthProviderFactory.AUTH_HEADER_NAME,
56+
String.format(
57+
BASIC_TOKEN,
58+
Base64.getEncoder()
59+
.encode(
60+
String.format(
61+
USER_PASSWORD,
62+
userFilter.apply(workflow, task),
63+
passwordFilter.apply(workflow, task))
64+
.getBytes())));
65+
return builder;
66+
}
67+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 io.serverlessworkflow.api.types.BearerAuthenticationPolicy;
19+
import io.serverlessworkflow.api.types.BearerAuthenticationPolicyConfiguration;
20+
import io.serverlessworkflow.api.types.Workflow;
21+
import io.serverlessworkflow.impl.StringFilter;
22+
import io.serverlessworkflow.impl.TaskContext;
23+
import io.serverlessworkflow.impl.WorkflowApplication;
24+
import io.serverlessworkflow.impl.WorkflowContext;
25+
import io.serverlessworkflow.impl.WorkflowModel;
26+
import io.serverlessworkflow.impl.WorkflowUtils;
27+
import jakarta.ws.rs.client.Invocation.Builder;
28+
29+
class BearerAuthProvider implements AuthProvider {
30+
31+
private static final String BEARER_TOKEN = "Bearer %s";
32+
33+
private StringFilter tokenFilter;
34+
35+
public BearerAuthProvider(
36+
WorkflowApplication app,
37+
Workflow workflow,
38+
BearerAuthenticationPolicy basicAuthenticationPolicy) {
39+
BearerAuthenticationPolicyConfiguration config = basicAuthenticationPolicy.getBearer();
40+
if (config.getBearerAuthenticationProperties() != null) {
41+
String token = config.getBearerAuthenticationProperties().getToken();
42+
tokenFilter = WorkflowUtils.buildStringFilter(app, token);
43+
} else if (config.getBearerAuthenticationPolicySecret() != null) {
44+
throw new UnsupportedOperationException("Secrets are still not supported");
45+
}
46+
}
47+
48+
@Override
49+
public Builder build(
50+
Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
51+
builder.header(
52+
AuthProviderFactory.AUTH_HEADER_NAME,
53+
String.format(BEARER_TOKEN, tokenFilter.apply(workflow, task)));
54+
return builder;
55+
}
56+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 io.serverlessworkflow.api.types.DigestAuthenticationPolicy;
19+
import io.serverlessworkflow.api.types.Workflow;
20+
import io.serverlessworkflow.impl.TaskContext;
21+
import io.serverlessworkflow.impl.WorkflowApplication;
22+
import io.serverlessworkflow.impl.WorkflowContext;
23+
import io.serverlessworkflow.impl.WorkflowModel;
24+
import jakarta.ws.rs.client.Invocation.Builder;
25+
26+
public class DigestAuthProvider implements AuthProvider {
27+
28+
public DigestAuthProvider(
29+
WorkflowApplication app, Workflow workflow, DigestAuthenticationPolicy authPolicy) {
30+
throw new UnsupportedOperationException("Digest auth not supported yet");
31+
}
32+
33+
@Override
34+
public Builder build(
35+
Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
36+
// TODO Auto-generated method stub
37+
return builder;
38+
}
39+
}

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.serverlessworkflow.api.types.HTTPArguments;
2222
import io.serverlessworkflow.api.types.TaskBase;
2323
import io.serverlessworkflow.api.types.UriTemplate;
24+
import io.serverlessworkflow.api.types.Workflow;
2425
import io.serverlessworkflow.impl.TaskContext;
2526
import io.serverlessworkflow.impl.WorkflowApplication;
2627
import io.serverlessworkflow.impl.WorkflowContext;
@@ -50,8 +51,9 @@ public class HttpExecutor implements CallableTask<CallHTTP> {
5051
private TargetSupplier targetSupplier;
5152
private Optional<WorkflowFilter> headersMap;
5253
private Optional<WorkflowFilter> queryMap;
54+
private Optional<AuthProvider> authProvider;
5355
private RequestSupplier requestFunction;
54-
private static HttpModelConverter converter = new HttpModelConverter() {};
56+
private HttpModelConverter converter = new HttpModelConverter() {};
5557

5658
@FunctionalInterface
5759
private interface TargetSupplier {
@@ -65,8 +67,17 @@ WorkflowModel apply(
6567
}
6668

6769
@Override
68-
public void init(CallHTTP task, WorkflowApplication application, ResourceLoader resourceLoader) {
70+
public void init(
71+
CallHTTP task,
72+
Workflow workflow,
73+
WorkflowApplication application,
74+
ResourceLoader resourceLoader) {
6975
HTTPArguments httpArgs = task.getWith();
76+
77+
this.authProvider =
78+
AuthProviderFactory.getAuth(
79+
application, workflow, task.getWith().getEndpoint().getEndpointConfiguration());
80+
7081
this.targetSupplier =
7182
getTargetSupplier(httpArgs.getEndpoint(), application.expressionFactory());
7283
this.headersMap =
@@ -94,11 +105,11 @@ public void init(CallHTTP task, WorkflowApplication application, ResourceLoader
94105
WorkflowFilter bodyFilter =
95106
WorkflowUtils.buildWorkflowFilter(application, null, httpArgs.getBody());
96107
this.requestFunction =
97-
(request, workflow, context, node) ->
108+
(request, w, context, node) ->
98109
converter.toModel(
99110
application.modelFactory(),
100111
request.post(
101-
converter.toEntity(bodyFilter.apply(workflow, context, node)),
112+
converter.toEntity(bodyFilter.apply(w, context, node)),
102113
node.objectClass()));
103114
break;
104115
case HttpMethod.GET:
@@ -136,6 +147,7 @@ public CompletableFuture<WorkflowModel> apply(
136147
q.apply(workflow, taskContext, input)
137148
.forEach((k, v) -> supplier.addQuery(k, v.asJavaObject())));
138149
Builder request = supplier.get().request();
150+
authProvider.ifPresent(auth -> auth.build(request, workflow, taskContext, input));
139151
headersMap.ifPresent(
140152
h ->
141153
h.apply(workflow, taskContext, input)

0 commit comments

Comments
 (0)