Skip to content

Commit 359c9c3

Browse files
committed
[Fix #952] More refactor
Signed-off-by: fjtirado <ftirados@redhat.com>
1 parent 35fdccf commit 359c9c3

17 files changed

+361
-395
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
1919
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;
2022

2123
import io.serverlessworkflow.api.types.BasicAuthenticationPolicy;
2224
import io.serverlessworkflow.api.types.Workflow;
@@ -47,8 +49,8 @@ public BasicAuthProvider(
4749
} else if (authPolicy.getBasic().getBasicAuthenticationPolicySecret() != null) {
4850
String secretName =
4951
checkSecret(workflow, authPolicy.getBasic().getBasicAuthenticationPolicySecret());
50-
userFilter = (w, t, m) -> secretProp(w, secretName, "username");
51-
passwordFilter = (w, t, m) -> secretProp(w, secretName, "password");
52+
userFilter = (w, t, m) -> secretProp(w, secretName, USER);
53+
passwordFilter = (w, t, m) -> secretProp(w, secretName, PASSWORD);
5254
} else {
5355
throw new IllegalStateException("Both secret and properties are null for authorization");
5456
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static io.serverlessworkflow.impl.WorkflowUtils.checkSecret;
1919
import static io.serverlessworkflow.impl.WorkflowUtils.secretProp;
20+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.TOKEN;
2021

2122
import io.serverlessworkflow.api.types.BearerAuthenticationPolicy;
2223
import io.serverlessworkflow.api.types.BearerAuthenticationPolicyConfiguration;
@@ -42,7 +43,7 @@ public BearerAuthProvider(
4243
tokenFilter = WorkflowUtils.buildStringFilter(app, token);
4344
} else if (config.getBearerAuthenticationPolicySecret() != null) {
4445
String secretName = checkSecret(workflow, config.getBearerAuthenticationPolicySecret());
45-
tokenFilter = (w, t, m) -> secretProp(w, secretName, "token");
46+
tokenFilter = (w, t, m) -> secretProp(w, secretName, TOKEN);
4647
}
4748
}
4849

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
public class SecretKeys {
19+
20+
private SecretKeys() {}
21+
22+
public static final String GRANT = "grant";
23+
public static final String USER = "username";
24+
public static final String CLIENT = "client";
25+
public static final String PASSWORD = "password";
26+
public static final String ID = "id";
27+
public static final String SECRET = "secret";
28+
public static final String ISSUERS = "issuers";
29+
public static final String AUDIENCES = "audiences";
30+
public static final String ENDPOINTS = "endpoints";
31+
public static final String TOKEN = "token";
32+
public static final String AUTHORITY = "authority";
33+
public static final String SCOPES = "scopes";
34+
public static final String REQUEST = "request";
35+
public static final String ENCODING = "encoding";
36+
public static final String AUTHENTICATION = "authentication";
37+
}

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/auth/requestbuilder/AbstractAuthRequestBuilder.java

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717

1818
import static io.serverlessworkflow.api.types.OAuth2AuthenticationDataClient.ClientAuthentication.CLIENT_SECRET_POST;
1919
import static io.serverlessworkflow.impl.WorkflowUtils.isValid;
20-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.AUDIENCES;
21-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.AUTHENTICATION;
22-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.CLIENT;
23-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.ENCODING;
24-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.REQUEST;
25-
import static io.serverlessworkflow.impl.executors.http.auth.requestbuilder.SecretKeys.SCOPES;
20+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.AUDIENCES;
21+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.AUTHENTICATION;
22+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.CLIENT;
23+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.ENCODING;
24+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.REQUEST;
25+
import static io.serverlessworkflow.impl.executors.http.SecretKeys.SCOPES;
2626

2727
import io.serverlessworkflow.api.types.OAuth2AuthenticationData;
2828
import io.serverlessworkflow.api.types.OAuth2AuthenticationDataClient;
@@ -37,84 +37,85 @@
3737
abstract class AbstractAuthRequestBuilder<T extends OAuth2AuthenticationData>
3838
implements AuthRequestBuilder<T> {
3939

40-
private static final String DEFAULT_ENCODING = "application/x-www-form-urlencoded; charset=UTF-8";
41-
4240
protected final WorkflowApplication application;
41+
protected final HttpRequestInfoBuilder requestBuilder = new HttpRequestInfoBuilder();
4342

4443
public AbstractAuthRequestBuilder(WorkflowApplication application) {
4544
this.application = application;
4645
}
4746

48-
public void accept(HttpRequestBuilder requestBuilder, T authenticationData) {
49-
requestEncoding(requestBuilder, authenticationData);
50-
authenticationURI(requestBuilder, authenticationData);
51-
audience(requestBuilder, authenticationData);
52-
scope(requestBuilder, authenticationData);
53-
authenticationMethod(requestBuilder, authenticationData);
47+
@Override
48+
public HttpRequestInfo apply(T authenticationData) {
49+
requestEncoding(authenticationData);
50+
authenticationURI(authenticationData);
51+
audience(authenticationData);
52+
scope(authenticationData);
53+
authenticationMethod(authenticationData);
54+
return requestBuilder.build();
5455
}
5556

5657
@Override
57-
public void accept(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
58-
requestEncoding(requestBuilder, secret);
59-
authenticationURI(requestBuilder, secret);
60-
audience(requestBuilder, secret);
61-
scope(requestBuilder, secret);
62-
authenticationMethod(requestBuilder, secret);
58+
public HttpRequestInfo apply(Map<String, Object> secret) {
59+
requestEncoding(secret);
60+
authenticationURI(secret);
61+
audience(secret);
62+
scope(secret);
63+
authenticationMethod(secret);
64+
return requestBuilder.build();
6365
}
6466

65-
protected void audience(HttpRequestBuilder requestBuilder, T authenticationData) {
67+
protected void audience(T authenticationData) {
6668
if (authenticationData.getAudiences() != null && !authenticationData.getAudiences().isEmpty()) {
6769
String audiences = String.join(" ", authenticationData.getAudiences());
6870
requestBuilder.addQueryParam(
6971
"audience", WorkflowUtils.buildStringFilter(application, audiences));
7072
}
7173
}
7274

73-
protected void audience(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
75+
protected void audience(Map<String, Object> secret) {
7476
String audiences = (String) secret.get(AUDIENCES);
7577
if (isValid(audiences)) {
76-
requestBuilder.addQueryParam("audience", (w, t, m) -> audiences);
78+
requestBuilder.addQueryParam("audience", audiences);
7779
}
7880
}
7981

80-
protected void authenticationMethod(HttpRequestBuilder requestBuilder, T authenticationData) {
82+
protected void authenticationMethod(T authenticationData) {
8183
ClientSecretHandler secretHandler;
8284
switch (getClientAuthentication(authenticationData)) {
8385
case CLIENT_SECRET_BASIC:
84-
secretHandler = new ClientSecretBasic(application);
86+
secretHandler = new ClientSecretBasic(application, requestBuilder);
8587
case CLIENT_SECRET_JWT:
8688
throw new UnsupportedOperationException("Client Secret JWT is not supported yet");
8789
case PRIVATE_KEY_JWT:
8890
throw new UnsupportedOperationException("Private Key JWT is not supported yet");
8991
default:
90-
secretHandler = new ClientSecretPost(application);
92+
secretHandler = new ClientSecretPost(application, requestBuilder);
9193
}
92-
secretHandler.accept(requestBuilder, authenticationData);
94+
secretHandler.accept(authenticationData);
9395
}
9496

95-
protected void authenticationMethod(
96-
HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
97+
protected void authenticationMethod(Map<String, Object> secret) {
9798
Map<String, Object> client = (Map<String, Object>) secret.get(CLIENT);
9899
ClientSecretHandler secretHandler;
99100
String auth = (String) client.get(AUTHENTICATION);
100101
if (auth == null) {
101-
secretHandler = new ClientSecretPost(application);
102+
secretHandler = new ClientSecretPost(application, requestBuilder);
102103
} else {
103104
switch (auth) {
104105
case "client_secret_basic":
105-
secretHandler = new ClientSecretBasic(application);
106+
secretHandler = new ClientSecretBasic(application, requestBuilder);
106107
break;
107108
default:
108109
case "client_secret_post":
109-
secretHandler = new ClientSecretPost(application);
110+
secretHandler = new ClientSecretPost(application, requestBuilder);
110111
break;
111112
case "private_key_jwt":
112113
throw new UnsupportedOperationException("Private Key JWT is not supported yet");
113114
case "client_secret_jwt":
114115
throw new UnsupportedOperationException("Client Secret JWT is not supported yet");
115116
}
116117
}
117-
secretHandler.accept(requestBuilder, secret);
118+
secretHandler.accept(secret);
118119
}
119120

120121
private OAuth2AuthenticationDataClient.ClientAuthentication getClientAuthentication(
@@ -125,11 +126,11 @@ private OAuth2AuthenticationDataClient.ClientAuthentication getClientAuthenticat
125126
: authenticationData.getClient().getAuthentication();
126127
}
127128

128-
protected void scope(HttpRequestBuilder requestBuilder, T authenticationData) {
129-
scope(requestBuilder, authenticationData.getScopes());
129+
protected void scope(T authenticationData) {
130+
scope(authenticationData.getScopes());
130131
}
131132

132-
protected void scope(HttpRequestBuilder requestBuilder, List<String> scopesList) {
133+
protected void scope(List<String> scopesList) {
133134
if (scopesList == null || scopesList.isEmpty()) {
134135
return;
135136
}
@@ -147,28 +148,26 @@ protected void scope(HttpRequestBuilder requestBuilder, List<String> scopesList)
147148
}
148149
}
149150

150-
protected void scope(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
151+
protected void scope(Map<String, Object> secret) {
151152
String scopes = (String) secret.get(SCOPES);
152153
if (isValid(scopes)) {
153-
requestBuilder.addQueryParam("scope", (w, t, m) -> scopes);
154+
requestBuilder.addQueryParam("scope", scopes);
154155
}
155156
}
156157

157-
void requestEncoding(HttpRequestBuilder requestBuilder, T authenticationData) {
158-
requestBuilder.withRequestContentType(authenticationData.getRequest());
158+
void requestEncoding(T authenticationData) {
159+
requestBuilder.withContentType(authenticationData.getRequest());
159160
}
160161

161-
void requestEncoding(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
162+
void requestEncoding(Map<String, Object> secret) {
162163
Map<String, Object> request = (Map<String, Object>) secret.get(REQUEST);
163164
String encoding = (String) request.get(ENCODING);
164165
if (isValid(encoding)) {
165-
requestBuilder.addHeader("Content-Type", (w, t, m) -> encoding);
166+
requestBuilder.addHeader("Content-Type", encoding);
166167
}
167168
}
168169

169-
protected abstract void authenticationURI(
170-
HttpRequestBuilder requestBuilder, T authenticationData);
170+
protected abstract void authenticationURI(T authenticationData);
171171

172-
protected abstract void authenticationURI(
173-
HttpRequestBuilder requestBuilder, Map<String, Object> secret);
172+
protected abstract void authenticationURI(Map<String, Object> secret);
174173
}

impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/auth/requestbuilder/AccessTokenProvider.java

Lines changed: 94 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,44 @@
1515
*/
1616
package io.serverlessworkflow.impl.executors.http.auth.requestbuilder;
1717

18+
import static io.serverlessworkflow.api.types.OAuth2TokenRequest.Oauth2TokenRequestEncoding.APPLICATION_X_WWW_FORM_URLENCODED;
19+
1820
import io.serverlessworkflow.impl.TaskContext;
1921
import io.serverlessworkflow.impl.WorkflowContext;
22+
import io.serverlessworkflow.impl.WorkflowError;
23+
import io.serverlessworkflow.impl.WorkflowException;
2024
import io.serverlessworkflow.impl.WorkflowModel;
25+
import io.serverlessworkflow.impl.executors.http.HttpClientResolver;
2126
import io.serverlessworkflow.impl.executors.http.auth.jwt.JWT;
2227
import io.serverlessworkflow.impl.executors.http.auth.jwt.JWTConverter;
28+
import jakarta.ws.rs.ProcessingException;
29+
import jakarta.ws.rs.client.Client;
30+
import jakarta.ws.rs.client.Entity;
31+
import jakarta.ws.rs.client.Invocation;
32+
import jakarta.ws.rs.client.ResponseProcessingException;
33+
import jakarta.ws.rs.client.WebTarget;
34+
import jakarta.ws.rs.core.Form;
35+
import jakarta.ws.rs.core.GenericType;
36+
import jakarta.ws.rs.core.MediaType;
37+
import jakarta.ws.rs.core.Response;
38+
import java.util.HashMap;
2339
import java.util.List;
2440
import java.util.Map;
25-
import java.util.ServiceLoader;
2641

2742
public class AccessTokenProvider {
2843

29-
private final TokenResponseHandler tokenResponseHandler = new TokenResponseHandler();
30-
3144
private final List<String> issuers;
32-
private final HttpRequestBuilder requestBuilder;
33-
45+
private final HttpRequestInfo requestInfo;
3446
private final JWTConverter jwtConverter;
3547

36-
AccessTokenProvider(HttpRequestBuilder requestBuilder, List<String> issuers) {
37-
this.requestBuilder = requestBuilder;
48+
AccessTokenProvider(HttpRequestInfo requestInfo, List<String> issuers, JWTConverter converter) {
49+
this.requestInfo = requestInfo;
3850
this.issuers = issuers;
39-
this.jwtConverter =
40-
ServiceLoader.load(JWTConverter.class)
41-
.findFirst()
42-
.orElseThrow(() -> new IllegalStateException("No JWTConverter implementation found"));
51+
this.jwtConverter = converter;
4352
}
4453

4554
public JWT validateAndGet(WorkflowContext workflow, TaskContext context, WorkflowModel model) {
46-
Map<String, Object> token =
47-
tokenResponseHandler.apply(requestBuilder.build(workflow, context, model), context);
55+
Map<String, Object> token = invoke(workflow, context, model);
4856
JWT jwt = jwtConverter.fromToken((String) token.get("access_token"));
4957
if (issuers != null && !issuers.isEmpty()) {
5058
jwt.issuer()
@@ -57,4 +65,77 @@ public JWT validateAndGet(WorkflowContext workflow, TaskContext context, Workflo
5765
}
5866
return jwt;
5967
}
68+
69+
private Map<String, Object> invoke(
70+
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel model) {
71+
try {
72+
Response response = executeRequest(workflowContext, taskContext, model);
73+
74+
if (response.getStatus() < 200 || response.getStatus() >= 300) {
75+
throw new WorkflowException(
76+
WorkflowError.communication(
77+
response.getStatus(),
78+
taskContext,
79+
"Failed to obtain token: HTTP "
80+
+ response.getStatus()
81+
+ " — "
82+
+ response.getEntity())
83+
.build());
84+
}
85+
return response.readEntity(new GenericType<>() {});
86+
} catch (ResponseProcessingException e) {
87+
throw new WorkflowException(
88+
WorkflowError.communication(
89+
e.getResponse().getStatus(),
90+
taskContext,
91+
"Failed to process response: " + e.getMessage())
92+
.build(),
93+
e);
94+
} catch (ProcessingException e) {
95+
throw new WorkflowException(
96+
WorkflowError.communication(
97+
-1, taskContext, "Failed to connect or process request: " + e.getMessage())
98+
.build(),
99+
e);
100+
}
101+
}
102+
103+
private Response executeRequest(WorkflowContext workflow, TaskContext task, WorkflowModel model) {
104+
105+
Client client = HttpClientResolver.client(workflow, task);
106+
WebTarget target = client.target(requestInfo.uri().apply(workflow, task, model));
107+
108+
Invocation.Builder builder = target.request(MediaType.APPLICATION_JSON);
109+
110+
builder.header("grant_type", requestInfo.grantType());
111+
builder.header("User-Agent", "OAuth2-Client-Credentials/1.0");
112+
builder.header("Accept", MediaType.APPLICATION_JSON);
113+
builder.header("Cache-Control", "no-cache");
114+
115+
for (var entry : requestInfo.headers().entrySet()) {
116+
String headerValue = entry.getValue().apply(workflow, task, model);
117+
if (headerValue != null) {
118+
builder.header(entry.getKey(), headerValue);
119+
}
120+
}
121+
122+
Entity<?> entity;
123+
if (requestInfo.contentType().equals(APPLICATION_X_WWW_FORM_URLENCODED.value())) {
124+
Form form = new Form();
125+
form.param("grant_type", requestInfo.grantType());
126+
requestInfo
127+
.queryParams()
128+
.forEach((key, value) -> form.param(key, value.apply(workflow, task, model)));
129+
entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED);
130+
} else {
131+
Map<String, Object> jsonData = new HashMap<>();
132+
jsonData.put("grant_type", requestInfo.grantType());
133+
requestInfo
134+
.queryParams()
135+
.forEach((key, value) -> jsonData.put(key, value.apply(workflow, task, model)));
136+
entity = Entity.entity(jsonData, MediaType.APPLICATION_JSON);
137+
}
138+
139+
return builder.post(entity);
140+
}
60141
}

0 commit comments

Comments
 (0)