diff --git a/experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallExecutor.java b/experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallExecutor.java index 7e448f77..10f10008 100644 --- a/experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallExecutor.java +++ b/experimental/lambda/src/main/java/io/serverlessworkflow/impl/executors/func/JavaCallExecutor.java @@ -18,19 +18,14 @@ import io.serverlessworkflow.api.types.TaskBase; import io.serverlessworkflow.api.types.func.CallJava; import io.serverlessworkflow.impl.TaskContext; -import io.serverlessworkflow.impl.WorkflowApplication; import io.serverlessworkflow.impl.WorkflowContext; import io.serverlessworkflow.impl.WorkflowModel; import io.serverlessworkflow.impl.WorkflowModelFactory; import io.serverlessworkflow.impl.executors.CallableTask; -import io.serverlessworkflow.impl.resources.ResourceLoader; import java.util.concurrent.CompletableFuture; public class JavaCallExecutor implements CallableTask { - @Override - public void init(CallJava task, WorkflowApplication application, ResourceLoader loader) {} - @Override public CompletableFuture apply( WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) { diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallTaskExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallTaskExecutor.java index 56545b68..1dc07645 100644 --- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallTaskExecutor.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallTaskExecutor.java @@ -42,7 +42,7 @@ protected CallTaskExecutorBuilder( CallableTask callable) { super(position, task, workflow, application, resourceLoader); this.callable = callable; - callable.init(task, application, resourceLoader); + callable.init(task, workflow, application, resourceLoader); } @Override diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallableTask.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallableTask.java index e391dae6..6cc52922 100644 --- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallableTask.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/CallableTask.java @@ -16,6 +16,7 @@ package io.serverlessworkflow.impl.executors; import io.serverlessworkflow.api.types.TaskBase; +import io.serverlessworkflow.api.types.Workflow; import io.serverlessworkflow.impl.TaskContext; import io.serverlessworkflow.impl.WorkflowApplication; import io.serverlessworkflow.impl.WorkflowContext; @@ -24,7 +25,8 @@ import java.util.concurrent.CompletableFuture; public interface CallableTask { - void init(T task, WorkflowApplication application, ResourceLoader loader); + default void init( + T task, Workflow workflow, WorkflowApplication application, ResourceLoader loader) {} CompletableFuture apply( WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input); diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProvider.java new file mode 100644 index 00000000..7a902435 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import jakarta.ws.rs.client.Invocation; + +@FunctionalInterface +interface AuthProvider { + Invocation.Builder build( + Invocation.Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model); +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProviderFactory.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProviderFactory.java new file mode 100644 index 00000000..86322e1a --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/AuthProviderFactory.java @@ -0,0 +1,82 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.AuthenticationPolicyUnion; +import io.serverlessworkflow.api.types.EndpointConfiguration; +import io.serverlessworkflow.api.types.ReferenceableAuthenticationPolicy; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.WorkflowApplication; +import java.util.Optional; + +class AuthProviderFactory { + + private AuthProviderFactory() {} + + static final String AUTH_HEADER_NAME = "Authorization"; + + public static Optional getAuth( + WorkflowApplication app, Workflow workflow, EndpointConfiguration endpointConfiguration) { + if (endpointConfiguration == null) { + return Optional.empty(); + } + ReferenceableAuthenticationPolicy auth = endpointConfiguration.getAuthentication(); + if (auth == null) { + return Optional.empty(); + } + if (auth.getAuthenticationPolicyReference() != null) { + return buildFromReference(app, workflow, auth.getAuthenticationPolicyReference().getUse()); + } else if (auth.getAuthenticationPolicy() != null) { + return buildFromPolicy(app, workflow, auth.getAuthenticationPolicy()); + } + return Optional.empty(); + } + + private static Optional buildFromReference( + WorkflowApplication app, Workflow workflow, String use) { + return workflow.getUse().getAuthentications().getAdditionalProperties().entrySet().stream() + .filter(s -> s.getKey().equals(use)) + .findAny() + .flatMap(e -> buildFromPolicy(app, workflow, e.getValue())); + } + + private static Optional buildFromPolicy( + WorkflowApplication app, Workflow workflow, AuthenticationPolicyUnion authenticationPolicy) { + if (authenticationPolicy.getBasicAuthenticationPolicy() != null) { + return Optional.of( + new BasicAuthProvider( + app, workflow, authenticationPolicy.getBasicAuthenticationPolicy())); + } else if (authenticationPolicy.getBearerAuthenticationPolicy() != null) { + return Optional.of( + new BearerAuthProvider( + app, workflow, authenticationPolicy.getBearerAuthenticationPolicy())); + } else if (authenticationPolicy.getDigestAuthenticationPolicy() != null) { + return Optional.of( + new DigestAuthProvider( + app, workflow, authenticationPolicy.getDigestAuthenticationPolicy())); + } else if (authenticationPolicy.getOAuth2AuthenticationPolicy() != null) { + return Optional.of( + new OAuth2AuthProvider( + app, workflow, authenticationPolicy.getOAuth2AuthenticationPolicy())); + } else if (authenticationPolicy.getOpenIdConnectAuthenticationPolicy() != null) { + return Optional.of( + new OpenIdAuthProvider( + app, workflow, authenticationPolicy.getOpenIdConnectAuthenticationPolicy())); + } + + return Optional.empty(); + } +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BasicAuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BasicAuthProvider.java new file mode 100644 index 00000000..a8bcfead --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BasicAuthProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.BasicAuthenticationPolicy; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.StringFilter; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.WorkflowUtils; +import jakarta.ws.rs.client.Invocation.Builder; +import java.util.Base64; + +class BasicAuthProvider implements AuthProvider { + + private static final String BASIC_TOKEN = "Basic %s"; + private static final String USER_PASSWORD = "%s:%s"; + + private StringFilter userFilter; + private StringFilter passwordFilter; + + public BasicAuthProvider( + WorkflowApplication app, Workflow workflow, BasicAuthenticationPolicy authPolicy) { + if (authPolicy.getBasic().getBasicAuthenticationProperties() != null) { + userFilter = + WorkflowUtils.buildStringFilter( + app, authPolicy.getBasic().getBasicAuthenticationProperties().getUsername()); + passwordFilter = + WorkflowUtils.buildStringFilter( + app, authPolicy.getBasic().getBasicAuthenticationProperties().getPassword()); + } else if (authPolicy.getBasic().getBasicAuthenticationPolicySecret() != null) { + throw new UnsupportedOperationException("Secrets are still not supported"); + } + } + + @Override + public Builder build( + Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) { + builder.header( + AuthProviderFactory.AUTH_HEADER_NAME, + String.format( + BASIC_TOKEN, + Base64.getEncoder() + .encode( + String.format( + USER_PASSWORD, + userFilter.apply(workflow, task), + passwordFilter.apply(workflow, task)) + .getBytes()))); + return builder; + } +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BearerAuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BearerAuthProvider.java new file mode 100644 index 00000000..a0df5b61 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/BearerAuthProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.BearerAuthenticationPolicy; +import io.serverlessworkflow.api.types.BearerAuthenticationPolicyConfiguration; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.StringFilter; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import io.serverlessworkflow.impl.WorkflowUtils; +import jakarta.ws.rs.client.Invocation.Builder; + +class BearerAuthProvider implements AuthProvider { + + private static final String BEARER_TOKEN = "Bearer %s"; + + private StringFilter tokenFilter; + + public BearerAuthProvider( + WorkflowApplication app, + Workflow workflow, + BearerAuthenticationPolicy basicAuthenticationPolicy) { + BearerAuthenticationPolicyConfiguration config = basicAuthenticationPolicy.getBearer(); + if (config.getBearerAuthenticationProperties() != null) { + String token = config.getBearerAuthenticationProperties().getToken(); + tokenFilter = WorkflowUtils.buildStringFilter(app, token); + } else if (config.getBearerAuthenticationPolicySecret() != null) { + throw new UnsupportedOperationException("Secrets are still not supported"); + } + } + + @Override + public Builder build( + Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) { + builder.header( + AuthProviderFactory.AUTH_HEADER_NAME, + String.format(BEARER_TOKEN, tokenFilter.apply(workflow, task))); + return builder; + } +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/DigestAuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/DigestAuthProvider.java new file mode 100644 index 00000000..27a961b9 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/DigestAuthProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.DigestAuthenticationPolicy; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import jakarta.ws.rs.client.Invocation.Builder; + +public class DigestAuthProvider implements AuthProvider { + + public DigestAuthProvider( + WorkflowApplication app, Workflow workflow, DigestAuthenticationPolicy authPolicy) { + throw new UnsupportedOperationException("Digest auth not supported yet"); + } + + @Override + public Builder build( + Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) { + // TODO Auto-generated method stub + return builder; + } +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java index fe2fe971..b66a9319 100644 --- a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/HttpExecutor.java @@ -21,6 +21,7 @@ import io.serverlessworkflow.api.types.HTTPArguments; import io.serverlessworkflow.api.types.TaskBase; import io.serverlessworkflow.api.types.UriTemplate; +import io.serverlessworkflow.api.types.Workflow; import io.serverlessworkflow.impl.TaskContext; import io.serverlessworkflow.impl.WorkflowApplication; import io.serverlessworkflow.impl.WorkflowContext; @@ -50,8 +51,9 @@ public class HttpExecutor implements CallableTask { private TargetSupplier targetSupplier; private Optional headersMap; private Optional queryMap; + private Optional authProvider; private RequestSupplier requestFunction; - private static HttpModelConverter converter = new HttpModelConverter() {}; + private HttpModelConverter converter = new HttpModelConverter() {}; @FunctionalInterface private interface TargetSupplier { @@ -65,8 +67,17 @@ WorkflowModel apply( } @Override - public void init(CallHTTP task, WorkflowApplication application, ResourceLoader resourceLoader) { + public void init( + CallHTTP task, + Workflow workflow, + WorkflowApplication application, + ResourceLoader resourceLoader) { HTTPArguments httpArgs = task.getWith(); + + this.authProvider = + AuthProviderFactory.getAuth( + application, workflow, task.getWith().getEndpoint().getEndpointConfiguration()); + this.targetSupplier = getTargetSupplier(httpArgs.getEndpoint(), application.expressionFactory()); this.headersMap = @@ -94,11 +105,11 @@ public void init(CallHTTP task, WorkflowApplication application, ResourceLoader WorkflowFilter bodyFilter = WorkflowUtils.buildWorkflowFilter(application, null, httpArgs.getBody()); this.requestFunction = - (request, workflow, context, node) -> + (request, w, context, node) -> converter.toModel( application.modelFactory(), request.post( - converter.toEntity(bodyFilter.apply(workflow, context, node)), + converter.toEntity(bodyFilter.apply(w, context, node)), node.objectClass())); break; case HttpMethod.GET: @@ -136,6 +147,7 @@ public CompletableFuture apply( q.apply(workflow, taskContext, input) .forEach((k, v) -> supplier.addQuery(k, v.asJavaObject()))); Builder request = supplier.get().request(); + authProvider.ifPresent(auth -> auth.build(request, workflow, taskContext, input)); headersMap.ifPresent( h -> h.apply(workflow, taskContext, input) diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OAuth2AuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OAuth2AuthProvider.java new file mode 100644 index 00000000..9a558be2 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OAuth2AuthProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.OAuth2AuthenticationPolicy; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import jakarta.ws.rs.client.Invocation.Builder; + +public class OAuth2AuthProvider implements AuthProvider { + + public OAuth2AuthProvider( + WorkflowApplication app, Workflow workflow, OAuth2AuthenticationPolicy authPolicy) { + throw new UnsupportedOperationException("Oauth2 auth not supported yet"); + } + + @Override + public Builder build( + Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) { + // TODO Auto-generated method stub + return builder; + } +} diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OpenIdAuthProvider.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OpenIdAuthProvider.java new file mode 100644 index 00000000..fcbc7273 --- /dev/null +++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/http/OpenIdAuthProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.impl.executors.http; + +import io.serverlessworkflow.api.types.OpenIdConnectAuthenticationPolicy; +import io.serverlessworkflow.api.types.Workflow; +import io.serverlessworkflow.impl.TaskContext; +import io.serverlessworkflow.impl.WorkflowApplication; +import io.serverlessworkflow.impl.WorkflowContext; +import io.serverlessworkflow.impl.WorkflowModel; +import jakarta.ws.rs.client.Invocation.Builder; + +public class OpenIdAuthProvider implements AuthProvider { + + public OpenIdAuthProvider( + WorkflowApplication app, Workflow workflow, OpenIdConnectAuthenticationPolicy authPolicy) { + throw new UnsupportedOperationException("OpenId auth not supported yet"); + } + + @Override + public Builder build( + Builder builder, WorkflowContext workflow, TaskContext task, WorkflowModel model) { + // TODO Auto-generated method stub + return builder; + } +}