Skip to content

Commit d9dcdd9

Browse files
committed
[Fix #930] Adding authorization runtime expression
Signed-off-by: fjtirado <[email protected]>
1 parent 4b79f1b commit d9dcdd9

File tree

46 files changed

+375
-114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+375
-114
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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;
17+
18+
public record AuthorizationDescriptor(String scheme, String parameter) {}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.serverlessworkflow.api.types.Workflow;
2222
import io.serverlessworkflow.impl.additional.WorkflowAdditionalObject;
2323
import io.serverlessworkflow.impl.config.ConfigManager;
24+
import io.serverlessworkflow.impl.config.ConfigSecretManager;
2425
import io.serverlessworkflow.impl.config.SecretManager;
2526
import io.serverlessworkflow.impl.config.SystemPropertyConfigManager;
2627
import io.serverlessworkflow.impl.events.EventConsumer;
@@ -316,7 +317,7 @@ public WorkflowApplication build() {
316317
secretManager =
317318
ServiceLoader.load(SecretManager.class)
318319
.findFirst()
319-
.orElseGet(() -> s -> configManager.config(s, String.class));
320+
.orElseGet(() -> new ConfigSecretManager(configManager));
320321
}
321322
return new WorkflowApplication(this);
322323
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class WorkflowContext implements WorkflowContextData {
1919
private final WorkflowDefinition definition;
2020
private final WorkflowMutableInstance instance;
2121
private WorkflowModel context;
22+
private AuthorizationDescriptor authorization;
2223

2324
WorkflowContext(WorkflowDefinition definition, WorkflowMutableInstance instance) {
2425
this.definition = definition;
@@ -48,6 +49,14 @@ public WorkflowDefinition definition() {
4849
return definition;
4950
}
5051

52+
public AuthorizationDescriptor authorization() {
53+
return authorization;
54+
}
55+
56+
public void authorization(String scheme, String parameter) {
57+
this.authorization = new AuthorizationDescriptor(scheme, parameter);
58+
}
59+
5160
@Override
5261
public String toString() {
5362
return "WorkflowContext [definition="

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
import java.util.Optional;
2020

2121
public interface ConfigManager extends ServicePriority {
22+
2223
<T> Optional<T> config(String propName, Class<T> propClass);
24+
25+
Iterable<String> names();
2326
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.config;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import java.util.concurrent.ConcurrentHashMap;
21+
22+
public class ConfigSecretManager implements SecretManager {
23+
24+
private final ConfigManager configManager;
25+
26+
private Map<String, Map<String, String>> secretMap = new ConcurrentHashMap<>();
27+
28+
public ConfigSecretManager(ConfigManager configManager) {
29+
this.configManager = configManager;
30+
}
31+
32+
@Override
33+
public Map<String, String> secret(String secretName) {
34+
return secretMap.computeIfAbsent(secretName, this::buildMap);
35+
}
36+
37+
private Map<String, String> buildMap(String secretName) {
38+
Map<String, String> map = new HashMap<String, String>();
39+
final String prefix = secretName + ".";
40+
for (String name : configManager.names()) {
41+
if (name.startsWith(prefix)) {
42+
configManager
43+
.config(name, String.class)
44+
.ifPresent(v -> map.put(name.substring(prefix.length()), v));
45+
}
46+
}
47+
return map;
48+
}
49+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
package io.serverlessworkflow.impl.config;
1717

1818
import io.serverlessworkflow.impl.ServicePriority;
19-
import java.util.Optional;
19+
import java.util.Map;
2020

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

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,9 @@ protected <T> T convertComplex(String value, Class<T> propClass) {
2727
throw new UnsupportedOperationException(
2828
"Conversion of property " + value + " to class " + propClass + " is not supported");
2929
}
30+
31+
@Override
32+
public Iterable<String> names() {
33+
return System.getProperties().keySet().stream().map(Object::toString).toList();
34+
}
3035
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.SecretBasedAuthenticationPolicy;
19+
import io.serverlessworkflow.api.types.Workflow;
20+
import io.serverlessworkflow.impl.TaskContext;
21+
import io.serverlessworkflow.impl.WorkflowContext;
22+
import io.serverlessworkflow.impl.WorkflowModel;
23+
import jakarta.ws.rs.client.Invocation.Builder;
24+
25+
public abstract class AbstractAuthProvider implements AuthProvider {
26+
27+
private static final String AUTH_HEADER_FORMAT = "%s %s";
28+
29+
@Override
30+
public Builder build(
31+
Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
32+
String scheme = authScheme();
33+
String parameter = authParameter(workflow, task, model);
34+
workflow.authorization(scheme, parameter);
35+
builder.header(
36+
AuthProviderFactory.AUTH_HEADER_NAME, String.format(AUTH_HEADER_FORMAT, scheme, parameter));
37+
return builder;
38+
}
39+
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+
53+
protected abstract String authScheme();
54+
55+
protected abstract String authParameter(
56+
WorkflowContext workflow, TaskContext task, WorkflowModel model);
57+
}

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,6 @@
2121
import jakarta.ws.rs.client.Invocation;
2222

2323
interface AuthProvider {
24-
25-
default void preRequest(
26-
Invocation.Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) {
27-
// Default implementation does nothing
28-
}
29-
30-
default void postRequest(WorkflowContext workflow, TaskContext task, WorkflowModel model) {
31-
// Default implementation does nothing
32-
}
33-
3424
Invocation.Builder build(
3525
Invocation.Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model);
3626
}

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,14 @@
2323
import io.serverlessworkflow.impl.WorkflowModel;
2424
import io.serverlessworkflow.impl.WorkflowUtils;
2525
import io.serverlessworkflow.impl.WorkflowValueResolver;
26-
import jakarta.ws.rs.client.Invocation.Builder;
2726
import java.util.Base64;
2827

29-
class BasicAuthProvider implements AuthProvider {
28+
class BasicAuthProvider extends AbstractAuthProvider {
3029

31-
private static final String BASIC_TOKEN = "Basic %s";
3230
private static final String USER_PASSWORD = "%s:%s";
3331

34-
private WorkflowValueResolver<String> userFilter;
35-
private WorkflowValueResolver<String> passwordFilter;
32+
private final WorkflowValueResolver<String> userFilter;
33+
private final WorkflowValueResolver<String> passwordFilter;
3634

3735
public BasicAuthProvider(
3836
WorkflowApplication app, Workflow workflow, BasicAuthenticationPolicy authPolicy) {
@@ -44,24 +42,29 @@ public BasicAuthProvider(
4442
WorkflowUtils.buildStringFilter(
4543
app, authPolicy.getBasic().getBasicAuthenticationProperties().getPassword());
4644
} else if (authPolicy.getBasic().getBasicAuthenticationPolicySecret() != null) {
47-
throw new UnsupportedOperationException("Secrets are still not supported");
45+
String secretName =
46+
checkSecret(workflow, authPolicy.getBasic().getBasicAuthenticationPolicySecret());
47+
userFilter = (w, t, m) -> find(w, secretName, "username");
48+
passwordFilter = (w, t, m) -> find(w, secretName, "password");
49+
} else {
50+
throw new IllegalStateException("Both secret and properties are null for authorization");
4851
}
4952
}
5053

5154
@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, model),
63-
passwordFilter.apply(workflow, task, model))
64-
.getBytes())));
65-
return builder;
55+
protected String authParameter(WorkflowContext workflow, TaskContext task, WorkflowModel model) {
56+
return new String(
57+
Base64.getEncoder()
58+
.encode(
59+
String.format(
60+
USER_PASSWORD,
61+
userFilter.apply(workflow, task, model),
62+
passwordFilter.apply(workflow, task, model))
63+
.getBytes()));
64+
}
65+
66+
@Override
67+
protected String authScheme() {
68+
return "Basic";
6669
}
6770
}

0 commit comments

Comments
 (0)