Skip to content

Commit f7fa2fe

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

13 files changed

+288
-329
lines changed

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

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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)) {
7678
requestBuilder.addQueryParam("audience", (w, t, m) -> 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)) {
153154
requestBuilder.addQueryParam("scope", (w, t, m) -> 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)) {
165166
requestBuilder.addHeader("Content-Type", (w, t, m) -> 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 & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,39 @@
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;
2541
import java.util.ServiceLoader;
2642

2743
public class AccessTokenProvider {
2844

29-
private final TokenResponseHandler tokenResponseHandler = new TokenResponseHandler();
30-
3145
private final List<String> issuers;
32-
private final HttpRequestBuilder requestBuilder;
33-
46+
private final HttpRequestInfo requestInfo;
3447
private final JWTConverter jwtConverter;
3548

36-
AccessTokenProvider(HttpRequestBuilder requestBuilder, List<String> issuers) {
37-
this.requestBuilder = requestBuilder;
49+
AccessTokenProvider(HttpRequestInfo requestInfo, List<String> issuers) {
50+
this.requestInfo = requestInfo;
3851
this.issuers = issuers;
3952
this.jwtConverter =
4053
ServiceLoader.load(JWTConverter.class)
@@ -43,8 +56,7 @@ public class AccessTokenProvider {
4356
}
4457

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

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@ private AccessTokenProviderFactory() {}
2828

2929
public static WorkflowValueResolver<AccessTokenProvider> build(
3030
OAuth2AuthenticationData authenticationData, AuthRequestBuilder authBuilder) {
31-
HttpRequestBuilder httpBuilder = new HttpRequestBuilder();
32-
authBuilder.accept(httpBuilder, authenticationData);
3331
AccessTokenProvider tokenProvider =
34-
new AccessTokenProvider(httpBuilder, authenticationData.getIssuers());
32+
new AccessTokenProvider(
33+
authBuilder.apply(authenticationData), authenticationData.getIssuers());
3534
return (w, t, m) -> tokenProvider;
3635
}
3736

3837
public static WorkflowValueResolver<AccessTokenProvider> build(
3938
String secretName, AuthRequestBuilder authBuilder) {
40-
HttpRequestBuilder httpBuilder = new HttpRequestBuilder();
4139
return (w, t, m) -> {
4240
Map<String, Object> secret = secret(w, secretName);
43-
authBuilder.accept(httpBuilder, secret);
4441
String issuers = (String) secret.get("issuers");
4542
return new AccessTokenProvider(
46-
httpBuilder, issuers != null ? Arrays.asList(issuers.split(",")) : null);
43+
authBuilder.apply(secret), issuers != null ? Arrays.asList(issuers.split(",")) : null);
4744
};
4845
}
4946
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
public interface AuthRequestBuilder<T extends OAuth2AuthenticationData> {
2222

23-
void accept(HttpRequestBuilder requestBuilder, T authenticationData);
23+
HttpRequestInfo apply(T authenticationData);
2424

25-
void accept(HttpRequestBuilder requestBuilder, Map<String, Object> authenticationData);
25+
HttpRequestInfo apply(Map<String, Object> authenticationData);
2626
}

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,21 @@
3030

3131
class ClientSecretBasic extends ClientSecretHandler {
3232

33-
protected ClientSecretBasic(WorkflowApplication application) {
34-
super(application);
33+
protected ClientSecretBasic(
34+
WorkflowApplication application, HttpRequestInfoBuilder requestBuilder) {
35+
super(application, requestBuilder);
3536
}
3637

3738
@Override
38-
protected void clientCredentials(
39-
HttpRequestBuilder requestBuilder, OAuth2AuthenticationData authenticationData) {
39+
protected void clientCredentials(OAuth2AuthenticationData authenticationData) {
4040
requestBuilder
4141
.addHeader("Authorization", "Basic " + encodedAuth(authenticationData))
4242
.withGrantType(authenticationData.getGrant().value());
4343
}
4444

4545
@Override
46-
protected void password(
47-
HttpRequestBuilder requestBuilder, OAuth2AuthenticationData authenticationData) {
48-
clientCredentials(requestBuilder, authenticationData);
46+
protected void password(OAuth2AuthenticationData authenticationData) {
47+
clientCredentials(authenticationData);
4948
requestBuilder
5049
.addQueryParam(
5150
"username",
@@ -56,15 +55,15 @@ protected void password(
5655
}
5756

5857
@Override
59-
protected void clientCredentials(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
58+
protected void clientCredentials(Map<String, Object> secret) {
6059
requestBuilder
6160
.withGrantType((String) secret.get(GRANT))
6261
.addHeader("Authorization", "Basic " + encodedAuth(secret));
6362
}
6463

6564
@Override
66-
protected void password(HttpRequestBuilder requestBuilder, Map<String, Object> secret) {
67-
clientCredentials(requestBuilder, secret);
65+
protected void password(Map<String, Object> secret) {
66+
clientCredentials(secret);
6867
requestBuilder
6968
.addQueryParam("username", (String) secret.get(USER))
7069
.addQueryParam("password", (String) secret.get(PASSWORD));

0 commit comments

Comments
 (0)