diff --git a/serverless-workflow-examples/pom.xml b/serverless-workflow-examples/pom.xml index 962cbd298a..37df8bda43 100644 --- a/serverless-workflow-examples/pom.xml +++ b/serverless-workflow-examples/pom.xml @@ -67,6 +67,7 @@ serverless-workflow-loanbroker-showcase serverless-workflow-newsletter-subscription serverless-workflow-oauth2-orchestration-quarkus + serverless-workflow-oauth2-token-exchange-quarkus serverless-workflow-order-processing serverless-workflow-parallel-execution serverless-workflow-qas-service-showcase diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/README.md b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/README.md new file mode 100644 index 0000000000..2cb4fb4c3b --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/README.md @@ -0,0 +1,12 @@ +# Serverless Workflow OAuth2 Token Exchange Example + +TODO: + +- Create the financial application for two users to show distinct statement datas +- Create the workflow to ask for a loan: grab the statement info and verify if the user is able to receive the loan + +## References + +- [Running Keycloak in a container](https://www.keycloak.org/server/containers) +- [Using Keycloak Authorization Services and Policy Enforcer to Protect JAX-RS Applications](https://github.com/quarkusio/quarkus-quickstarts/tree/main/security-keycloak-authorization-quickstart) +- [Keycloak Docs - Audience Support](https://www.keycloak.org/docs/latest/server_admin/#_audience) \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/.gitignore b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/.gitignore new file mode 100644 index 0000000000..91a800a186 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/.gitignore @@ -0,0 +1,45 @@ +#Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +release.properties +.flattened-pom.xml + +# Eclipse +.project +.classpath +.settings/ +bin/ + +# IntelliJ +.idea +*.ipr +*.iml +*.iws + +# NetBeans +nb-configuration.xml + +# Visual Studio Code +.vscode +.factorypath + +# OSX +.DS_Store + +# Vim +*.swp +*.swo + +# patch +*.orig +*.rej + +# Local environment +.env + +# Plugin directory +/.quarkus/cli/plugins/ +# TLS Certificates +.certs/ diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/README.md b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/README.md new file mode 100644 index 0000000000..2213d1749c --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/README.md @@ -0,0 +1,19 @@ +# Serverless Workflow OAuth2 Token Exchange Example + +```shell +KEYCLOAK_ADDRESS=http://192.168.106.2:32769 + +curl -X POST "${KEYCLOAK_ADDRESS}/realms/quarkus/protocol/openid-connect/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "grant_type=client_credentials" \ + -d "client_id=quarkus-app" \ + -d "client_secret=secret" +``` + +## References + +- [Using OpenID Connect (OIDC) and Keycloak to centralize authorization](https://quarkus.io/guides/security-keycloak-authorization) + +## Troubleshooting + +Problems with Colima on MacOs: https://github.com/testcontainers/testcontainers-java/issues/6450 \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/pom.xml b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/pom.xml new file mode 100644 index 0000000000..e6a3cef97f --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/pom.xml @@ -0,0 +1,164 @@ + + + 4.0.0 + acme-financial-service + 1.0.0-SNAPSHOT + Kogito Example :: Serverless Workflow Oauth2 Token Exchange Example :: ACME Financial Service + + + org.acme.workflow.oauth2 + serverless-workflow-oauth2-token-exchange-quarkus + 1.0.0-SNAPSHOT + + + + 3.13.0 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.13.2 + true + 3.2.5 + + 3.22.0 + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + + org.slf4j + slf4j-api + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-oidc + + + io.quarkus + quarkus-keycloak-authorization + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + org.assertj + assertj-core + ${version.org.assertj} + test + + + io.quarkus + quarkus-test-keycloak-server + test + + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + native-image-agent + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + true + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + native + + + native + + + + false + true + + + + diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialApplication.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialApplication.java new file mode 100644 index 0000000000..a40847ad69 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialApplication.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.financial.service; + +import org.eclipse.microprofile.openapi.annotations.Components; +import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; +import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeType; +import org.eclipse.microprofile.openapi.annotations.info.Info; +import org.eclipse.microprofile.openapi.annotations.security.OAuthFlow; +import org.eclipse.microprofile.openapi.annotations.security.OAuthFlows; +import org.eclipse.microprofile.openapi.annotations.security.SecurityScheme; + +/** + * Defines OpenAPI configurations for the Quarkus application, for more information you must see + * Using OpenAPI and Swagger UI + */ +@OpenAPIDefinition( + info = @Info( + title = "Acme Financial Service API", + version = "1.0.0"), + components = @Components( + securitySchemes = { + @SecurityScheme(securitySchemeName = "acme-financial-oauth", + type = SecuritySchemeType.OAUTH2, + flows = @OAuthFlows( + clientCredentials = @OAuthFlow( + authorizationUrl = "http://localhost:9090/auth/realms/acme/protocol/openid-connect/auth", + tokenUrl = "http://localhost:9090/auth/realms/kogito/acme/openid-connect/token", + scopes = {}))) + })) +public class AcmeFinancialApplication extends jakarta.ws.rs.core.Application { +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialResource.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialResource.java new file mode 100644 index 0000000000..1bdd141ad7 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/AcmeFinancialResource.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.financial.service; + +import io.quarkus.security.identity.SecurityIdentity; +import jakarta.annotation.security.RolesAllowed; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +@Path("financial-service") +public class AcmeFinancialResource { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcmeFinancialResource.class); + + @Inject + SecurityIdentity identity; + + @Inject + StatementsDB statementsDB; + + @GET + @Path("statement") + @Produces(MediaType.APPLICATION_JSON) + @Operation(operationId = "getStatement") + @RolesAllowed("customer") + @SecurityRequirement(name = "acme-financial-oauth") + public List getStatement() { + LOGGER.info("Getting statement for user {}", identity.getPrincipal()); + return statementsDB.getStatementEntries(identity.getPrincipal().getName()); + } +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/CustomersDB.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/CustomersDB.java new file mode 100644 index 0000000000..0d6b717cbd --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/CustomersDB.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.financial.service; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@ApplicationScoped +public class CustomersDB { + + static final String ALICE = "alice"; + static final String BOB = "bob"; + + private final List userNames = new ArrayList<>(); + + @PostConstruct + void initialize(){ + userNames.add(BOB); + userNames.add(ALICE); + } + + public List getUserNames() { + return Collections.unmodifiableList(userNames); + } + +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementEntry.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementEntry.java new file mode 100644 index 0000000000..e0ea1311ac --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementEntry.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.financial.service; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; + +public class StatementEntry implements Serializable { + + private double amount; + private LocalDate date; + + public StatementEntry() {} + + public StatementEntry(double amount, String date) { + this.amount = amount; + this.date = LocalDate.parse(date); + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StatementEntry that = (StatementEntry) o; + return Double.compare(amount, that.amount) == 0 && Objects.equals(date, that.date); + } + + @Override + public int hashCode() { + return Objects.hash(amount, date); + } + + @Override + public String toString() { + return "StatementEntry{" + + "amount=" + amount + + ", date=" + date + + '}'; + } +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementsDB.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementsDB.java new file mode 100644 index 0000000000..7ab549f10a --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/java/org/acme/workflow/financial/service/StatementsDB.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.financial.service; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import java.util.*; + +@ApplicationScoped +public class StatementsDB { + + private static final Map> STATEMENT_ENTRY = new HashMap<>(); + + @Inject + CustomersDB customersDB; + + @PostConstruct + void initialize() { + + customersDB.getUserNames().forEach(c -> { + List statementEntries = new ArrayList<>(); + + if (Objects.equals(c, CustomersDB.ALICE)) { + statementEntries.add(new StatementEntry(50.00, "2024-03-17")); + statementEntries.add(new StatementEntry(11.00, "2024-03-18")); + statementEntries.add(new StatementEntry(12.00, "2024-03-19")); + statementEntries.add(new StatementEntry(13.00, "2024-03-20")); + statementEntries.add(new StatementEntry(14.00, "2024-03-21")); + } else { + statementEntries.add(new StatementEntry(1.00, "2024-03-17")); + } + + + STATEMENT_ENTRY.put(c, statementEntries); + }); + } + + public List getStatementEntries(String customerUserName) { + return Collections.unmodifiableList(STATEMENT_ENTRY.get(customerUserName)); + } +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/resources/application.properties new file mode 100644 index 0000000000..20e3be902f --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/acme-financial-service/src/main/resources/application.properties @@ -0,0 +1,35 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +quarkus.http.port=8181 + +# OIDC configuration for this service +quarkus.oidc.application-type=service +# In production, you should use Kubernetes Secrets instead +quarkus.oidc.client-id=financial-service +quarkus.oidc.credentials.secret=secret +quarkus.oidc.tls.verification=none +quarkus.oidc.token.issuer=any +# External Keycloak docker container running via ./scripts/boot-keycloak.sh +quarkus.oidc.auth-server-url=http://localhost:9090/realms/acme + +quarkus.keycloak.policy-enforcer.lazy-load-paths=false + +# Keycloak devservices disabled since we are using an external container +quarkus.keycloak.devservices.enabled=false diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/keycloak/realm-export.json b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/keycloak/realm-export.json new file mode 100644 index 0000000000..aa0c9a4caf --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/keycloak/realm-export.json @@ -0,0 +1,2783 @@ +{ + "id": "5f7076a7-b154-4915-9ea2-7a1d173a2197", + "realm": "acme", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "f277d4aa-ee9f-4d53-adf0-464c87349a3a", + "name": "customer", + "description": "", + "composite": false, + "clientRole": false, + "containerId": "5f7076a7-b154-4915-9ea2-7a1d173a2197", + "attributes": {} + }, + { + "id": "942a2cbb-b185-498d-9017-d5f91ddd396e", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "5f7076a7-b154-4915-9ea2-7a1d173a2197", + "attributes": {} + }, + { + "id": "2475b504-7b41-48b9-a826-cfa1e3e46b21", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "5f7076a7-b154-4915-9ea2-7a1d173a2197", + "attributes": {} + }, + { + "id": "f024f7c3-71a2-470f-b10c-3c8ab8ebb95d", + "name": "default-roles-acme", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "5f7076a7-b154-4915-9ea2-7a1d173a2197", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "fb674c3c-6c61-4054-adf8-9463b27d3b92", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "f416d8e8-a2f4-47b1-a000-46c3be8809b7", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "b40bc591-c2e2-46ce-9c81-36533c358a2b", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "27a678b7-2c0d-4d01-9d6f-bf75d970a161", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "e2d55a80-f885-42e2-9172-531330766ad8", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "0730f9c7-c662-4b36-8f37-6023dcae5e65", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "ac69c01e-63cc-469b-b486-32f39acb8b30", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "cf56b2e1-7817-4c4c-bc4e-adcad70b1d29", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "14ab569c-aecd-4121-bd90-4d8d3c5adde5", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "dbc4fab0-6df2-4250-adb5-2222dc9a467b", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "cc0c738c-b984-4108-8a09-d1366506f3fa", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "view-identity-providers", + "view-authorization", + "query-clients", + "query-realms", + "query-users", + "manage-users", + "create-client", + "view-users", + "manage-identity-providers", + "query-groups", + "manage-events", + "view-events", + "impersonation", + "view-clients", + "view-realm", + "manage-authorization", + "manage-realm", + "manage-clients" + ] + } + }, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "81be853a-4a76-4a12-8661-3dd8b82907ae", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "757303c9-034a-4a85-b505-89dd2247a7e7", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "cdb4a902-732b-4906-b1c9-040db4efffff", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "a139b498-1421-4987-b49e-24ff66145cce", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "a7a14669-5825-4ce2-90a7-80b9193b70c3", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "c9764434-5964-4d48-9892-02ca3ac70cf0", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "d8402b8f-6dc8-4591-a0f7-773e58d73164", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "6349ddb7-af68-4fec-929f-5ce01e264b33", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + }, + { + "id": "ed9acf9c-9214-4479-a121-4949a39a7ac9", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "attributes": {} + } + ], + "workflow-app": [], + "security-admin-console": [], + "admin-cli": [], + "financial-service": [], + "account-console": [], + "broker": [ + { + "id": "d720ea77-4cf9-4b08-ae09-3a985e08d7ff", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "371bb08f-ca30-44c9-ad71-b8f536119f6d", + "attributes": {} + } + ], + "account": [ + { + "id": "27586e74-c6e0-4729-a793-aca81b47bb57", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "723c4e97-c68c-4798-8365-e06ccb7cf7d5", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "0398539d-e686-42d6-98ad-dab4d01fcabf", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "faf7f450-3843-4100-bdd7-85ad8b0ab77f", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "da63754b-4899-4af1-8025-76756f1b01de", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "6c6c8866-90e2-4b42-8597-60cf8d6e178a", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "4ebe7af9-775c-4b1d-9137-3f20b5f9a4e9", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + }, + { + "id": "7d37ca78-5259-4c98-843a-eac2da7eb2c2", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "515d496a-7eb1-4804-972b-24e9676bf260", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "f024f7c3-71a2-470f-b10c-3c8ab8ebb95d", + "name": "default-roles-acme", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "5f7076a7-b154-4915-9ea2-7a1d173a2197" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "users": [ + { + "username": "alice", + "enabled": true, + "emailVerified": true, + "credentials": [ + { + "type": "password", + "value": "alice" + } + ], + "realmRoles": [ + "default-roles-acme", + "customer" + ] + }, + { + "username": "bob", + "enabled": true, + "emailVerified": true, + "credentials": [ + { + "type": "password", + "value": "bob" + } + ], + "realmRoles": [ + "default-roles-acme", + "customer" + ] + }, + { + "id": "a300a11f-4c0d-4d35-a490-aca2978150f8", + "username": "service-account-financial-service", + "emailVerified": false, + "createdTimestamp": 1723808925850, + "enabled": true, + "totp": false, + "serviceAccountClientId": "financial-service", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-acme" + ], + "notBefore": 0, + "groups": [] + }, + { + "id": "8710de5a-bb8b-40c0-ba68-e833ff40bda8", + "username": "service-account-realm-management", + "emailVerified": false, + "createdTimestamp": 1723757213624, + "enabled": true, + "totp": false, + "serviceAccountClientId": "realm-management", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-acme" + ], + "clientRoles": { + "realm-management": [ + "uma_protection" + ] + }, + "notBefore": 0, + "groups": [] + }, + { + "id": "19e730ea-3981-4790-bd0d-adb6c84d9b05", + "username": "service-account-workflow-app", + "emailVerified": false, + "createdTimestamp": 1723233154559, + "enabled": true, + "totp": false, + "serviceAccountClientId": "workflow-app", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-acme" + ], + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, + "clients": [ + { + "id": "515d496a-7eb1-4804-972b-24e9676bf260", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/acme/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/acme/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "b7d21691-d143-4a32-bb2e-1973a9cea983", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/acme/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/acme/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "7d13f6df-9d0e-4c8a-b879-96622ab0402d", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "09efb772-505a-40b0-bf62-c84fd2b5ce17", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "371bb08f-ca30-44c9-ad71-b8f536119f6d", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "9e7642bf-bc64-4def-bbbe-e2f6afda6bb3", + "clientId": "financial-service", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "secret", + "redirectUris": [ + "/*" + ], + "webOrigins": [ + "/*" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1723808925", + "backchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "534a38c9-2e56-44d8-9c19-edad765c0a7f", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "47f9deb3-ded8-48f7-bcf3-1ee30e0cbba4", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "6bdaab1d-30d3-45d9-9be5-614a43d7de03", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "92e05815-0bc8-4c1c-9eca-a517446d510a", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "workflow-app", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "47961cdc-e169-4794-8c2d-c54ea4988fe5", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "client.secret.creation.time": "1723757677", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "d1a7c94d-4481-4e2b-bda0-dfd8b77414b9", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "1f66a41a-8883-4767-bd42-6613022af099", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "ab2674dd-b80f-4887-b991-b9f84705282a", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ], + "authorizationSettings": { + "allowRemoteResourceManagement": false, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "Client", + "ownerManagedAccess": false, + "attributes": {}, + "uris": [], + "scopes": [ + { + "name": "view" + }, + { + "name": "map-roles-client-scope" + }, + { + "name": "configure" + }, + { + "name": "map-roles" + }, + { + "name": "manage" + }, + { + "name": "token-exchange" + }, + { + "name": "map-roles-composite" + } + ] + } + ], + "policies": [ + { + "name": "workflow-app-policy", + "description": "", + "type": "client", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "clients": "[\"workflow-app\"]" + } + }, + { + "name": "workflow2-exchange", + "description": "", + "type": "client", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "clients": "[]" + } + }, + { + "name": "manage.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"manage\"]" + } + }, + { + "name": "configure.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"configure\"]" + } + }, + { + "name": "view.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"view\"]" + } + }, + { + "name": "map-roles.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"map-roles\"]" + } + }, + { + "name": "map-roles-client-scope.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"map-roles-client-scope\"]" + } + }, + { + "name": "map-roles-composite.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"map-roles-composite\"]" + } + }, + { + "name": "token-exchange.permission.client.700132ee-a2fc-4fc6-8194-df6782aa23b7", + "description": "", + "type": "scope", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"client.resource.700132ee-a2fc-4fc6-8194-df6782aa23b7\"]", + "scopes": "[\"token-exchange\"]", + "applyPolicies": "[\"workflow-app-policy\"]" + } + } + ], + "scopes": [ + { + "name": "manage" + }, + { + "name": "view" + }, + { + "name": "map-roles" + }, + { + "name": "map-roles-client-scope" + }, + { + "name": "map-roles-composite" + }, + { + "name": "configure" + }, + { + "name": "token-exchange" + } + ], + "decisionStrategy": "UNANIMOUS" + } + }, + { + "id": "e4dac26b-92ea-40a1-bda0-70a984b37b1b", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/acme/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/acme/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "465d69e9-664c-4a43-bf39-e92a24c6f1d4", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "700132ee-a2fc-4fc6-8194-df6782aa23b7", + "clientId": "workflow-app", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "secret", + "redirectUris": [ + "/*" + ], + "webOrigins": [ + "/*" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1723757733", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "d0769785-1e48-4e06-bf41-1b115cf7d5a8", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "0f46501b-628f-4a49-a847-918d8a21d631", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "c3bc52e4-c6b8-49fb-a7c1-714c97c26c21", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "75381980-7a81-4ec1-9ad2-460a0827b1b3", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "5202a7c6-cc7c-44e8-8c87-6d739e321868", + "name": "workflow-app", + "description": "Scope for the Workflow Application Audience", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false", + "gui.order": "", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "5ec19709-1519-43b8-b924-73fe817b427f", + "name": "workflow-app", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.client.audience": "workflow-app", + "id.token.claim": "false", + "lightweight.claim": "false", + "access.token.claim": "true", + "introspection.token.claim": "true" + } + } + ] + }, + { + "id": "c50188de-867b-496a-b7ba-89abcf4e491d", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6d5cddac-f5b3-4ba6-bc50-390e7a007be7", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "9fdd2c08-1176-4317-b864-687fe57a66e2", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "5212f083-20ea-4bab-90db-2221eb66e329", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "e1dc8eb1-ea9c-4ed2-8a7f-03c50d9ed3ac", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + }, + { + "id": "06318d41-2045-4984-87d2-c842f0059f81", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "5233c149-d966-4af4-9e20-a91696730a4e", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "6e21b645-d17d-4f76-81d1-4b3854523de1", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "ccc9f61b-f2a3-44f3-89c9-db872c8059b6", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "d9294395-1b20-4959-9359-015c6ecf3a70", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e2ed1d59-976a-41ea-be65-1616a1d25465", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "d333ae22-9dba-4573-b348-b1efb1ebd208", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "290505cb-e5a4-472a-bdae-2f170132eef3", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e1a63680-5729-4813-a252-c9795ea20518", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "bf422afd-dff3-4ba3-9754-c8fe45993a42", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "39c6c363-211e-42d0-a4f4-8659f277f0d9", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "53dc781a-39e4-4b95-b854-76e87484c128", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "ad06389c-80be-4344-afb4-7835cbf73b6e", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "25e70c0d-ee2b-4c08-a914-3d69e7cc4721", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "5b650bbb-73e7-4e16-a3b5-fa389275913c", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "eb7c4a36-94fa-41d1-9196-2d619530e6ff", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "e8383c1d-95b5-44d1-8a23-e74977aa0f59", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "dababf01-c1a8-42af-8f0f-a375711435a9", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "b5ebe645-ca59-47e7-bcdf-5b06231e8948", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "00b6be51-aa65-4116-946c-d6f33fdf076c", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "abb9c9d4-17c4-45ef-9fe0-889097db0547", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "3ec07ce5-c38c-42e0-a15c-23197552c185", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "e40b32ba-5755-450e-ae6b-51039af5e2db", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "542b446d-b95b-4492-82c2-2249ff99fc12", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + } + ] + }, + { + "id": "be9061df-44cd-4703-a7ba-114794094a3b", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "896eba18-fe8b-4dd5-bb6a-ae8103b958eb", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "281787d6-716b-434c-9db8-b5435492c3e9", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "feb02166-5e5b-4d2b-a84d-243b3ad9aad3", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "4ae95d03-b421-41d3-a611-fca0db575a5c", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "7341dbcb-b207-4860-9cdd-fb469f8f61b9", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "5a41073c-0a80-4e7b-a397-9bd0da669d08", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "3b2eb35b-54ea-4ca2-b707-bb010aefe2b9", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "4481fd4b-1c22-45c0-babc-52f5d199c389", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "2b5dd39b-4099-4e6a-8b37-2c9668a20040", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + }, + { + "id": "424a6e95-824f-4ed7-b98f-1c6c52c6507b", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins", + "acr", + "basic", + "workflow-app" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "5f64958a-2f28-4521-8116-7eb5d919c710", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "72a76754-15fd-4704-a804-89d09095c8ea", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "8db359e2-1877-4d1c-8e95-fed9e029395b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "ec75647f-adbd-491e-ac98-da4bb1ee90bb", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "00ddef35-16f1-4860-8b67-7b48ee7f6c79", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-usermodel-property-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper" + ] + } + }, + { + "id": "4e67e444-554f-41e8-aef4-6056bd7b0372", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "4246fddd-073d-4450-9615-4d06d687fc8c", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "bb80bd95-77f8-4b93-b217-81c4a998228d", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper", + "saml-role-list-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "08072e73-6ef2-4aaa-b998-75bc912b01a1", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "71ee3a07-fceb-45f3-b65a-fb27b80f3b5e", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + }, + { + "id": "946b2828-e958-458d-a1c4-16fdcefdf4f5", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "f3e3b1bf-61b3-4748-b2a0-4cd49e3b9f1c", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "fefe2bc0-d9df-42db-8961-6974d6298483", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "e72b2e68-4e7e-460b-9393-93a9fbac8fa1", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "60aa840b-8ba0-4968-a45e-2fe104282633", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "91e6d753-0230-4f79-ac40-15b46f2701f3", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8cfb2a8b-75c3-4d06-9d65-54fc2932b849", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "b6985d26-2bff-4f33-8538-1cd63e2196c0", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "c15d8ec7-6cae-4d7d-b920-36fecf592152", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "fe2ea76c-bb68-40b0-9017-417a7fe9cfbc", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "b2f72af1-7f5f-48fb-adbb-7b237db779cc", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "e758e76f-25c0-4db8-b3da-ecf20b0a9c57", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "9eb5331d-dc19-4f31-9bcd-d19dec2c31b9", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "b0b5d76f-e67b-4eef-b5df-ba2023a7f060", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "582a48a2-8fa8-4dda-9b63-758b32ba4ac8", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "ed4d909d-7aea-4710-b08e-e03177a4ca75", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "119c4260-74cd-4a60-91cf-c8d91f1112f6", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "3450fa36-da36-4f06-be15-c68bb5f358de", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f847a9e5-bcbc-4b06-a818-d62755bcb86d", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "5b0ec71c-a9f1-4609-9377-2fbd7b3cdffe", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "4819e841-dfdc-4db8-a6f4-0af222e95418", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "f297ddde-2005-43d2-860b-7e466c62b22d", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": false, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": false, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": false, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": false, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": false, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": false, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": false, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaAuthRequestedUserHint": "login_hint", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false", + "cibaExpiresIn": "120", + "oauth2DeviceCodeLifespan": "600", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "organizationsEnabled": "false" + }, + "keycloakVersion": "25.0.2", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/pom.xml b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/pom.xml new file mode 100644 index 0000000000..abd416504d --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/pom.xml @@ -0,0 +1,186 @@ + + + 4.0.0 + 1.0.0-SNAPSHOT + Kogito Example :: Serverless Workflow Oauth2 Token Exchange Example :: Acme Loan Workflow + loan-workflow + + + org.acme.workflow.oauth2 + serverless-workflow-oauth2-token-exchange-quarkus + 1.0.0-SNAPSHOT + + + + 3.8.4 + quarkus-bom + io.quarkus + 3.8.4 + org.kie.kogito + kogito-bom + 999-SNAPSHOT + 3.8.1 + 17 + + 3.2.5 + 3.8.1 + 17 + 3.0.0-M7 + 3.22.0 + + true + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + ${kogito.bom.group-id} + ${kogito.bom.artifact-id} + ${kogito.bom.version} + pom + import + + + + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-oidc-client-filter + + + io.quarkus + quarkus-oidc-token-propagation + + + io.quarkus + quarkus-cache + + + io.quarkus + quarkus-smallrye-jwt + + + org.apache.kie.sonataflow + sonataflow-quarkus + + + org.kie + kie-addons-quarkus-source-files + + + io.quarkus + quarkus-junit5 + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus-plugin.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${version.compiler.plugin} + + ${maven.compiler.release} + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + container + + + container + + + + container + + + + io.quarkus + quarkus-container-image-jib + + + + + native + + + native + + + + native + + + + \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/JWTParserHelper.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/JWTParserHelper.java new file mode 100644 index 0000000000..1b3595ed75 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/JWTParserHelper.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.auth; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.smallrye.jwt.auth.principal.JWTParser; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.jose4j.jwt.JwtClaims; +import org.jose4j.jwt.consumer.InvalidJwtException; + +import java.util.Base64; + +/** + * Used in the workflow to parse the JWT Token and retrieve user's info from the custom header. + * + * @see Parse and Verify JsonWebToken with JWTParser + * @see Decode JWT Token and Verify in Plain Java + */ +@ApplicationScoped +public class JWTParserHelper { + + @Inject + JWTParser jwtParser; + + ObjectMapper objectMapper = new ObjectMapper(); + + public JsonNode extractUser(String token) throws InvalidJwtException, JsonProcessingException { + final String[] tokenParts = token.split("\\."); + if (tokenParts.length != 3) { + throw new IllegalArgumentException("Invalid JWT token"); + } + + return objectMapper.readTree( + JwtClaims.parse( + new String(Base64.getUrlDecoder().decode(tokenParts[1]))).getRawJson()); + } + +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/WorkflowTokenRequestFilter.java b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/WorkflowTokenRequestFilter.java new file mode 100644 index 0000000000..ba6f3951d0 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/java/org/acme/workflow/auth/WorkflowTokenRequestFilter.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.acme.workflow.auth; + +import io.quarkus.arc.Arc; +import io.quarkus.cache.Cache; +import io.quarkus.cache.CacheName; +import io.quarkus.cache.CaffeineCache; +import io.quarkus.oidc.client.*; +import io.quarkus.oidc.token.propagation.AccessTokenRequestFilter; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.security.credential.TokenCredential; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.core.MultivaluedMap; +import org.eclipse.microprofile.config.ConfigProvider; +import org.jboss.resteasy.microprofile.client.impl.MpClientInvocation; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class WorkflowTokenRequestFilter extends AccessTokenRequestFilter { + + @Inject + Instance accessToken; + + @CacheName("my-cache") + Cache refreshTokensCache; + + OidcClient exchangeTokenClient; + String exchangeTokenProperty; + + @PostConstruct + public void initExchangeTokenClient() { + if (isExchangeToken()) { + OidcClients clients = Arc.container().instance(OidcClients.class).get(); + String clientName = getClientName(); + exchangeTokenClient = clientName != null ? clients.getClient(clientName) : clients.getClient(); + OidcClientConfig.Grant.Type exchangeTokenGrantType = ConfigProvider.getConfig().getValue("quarkus.oidc-client." + (clientName != null ? clientName + "." : "") + "grant.type", OidcClientConfig.Grant.Type.class); + if (exchangeTokenGrantType == OidcClientConfig.Grant.Type.EXCHANGE) { + exchangeTokenProperty = "subject_token"; + } else if (exchangeTokenGrantType == OidcClientConfig.Grant.Type.JWT) { + exchangeTokenProperty = "assertion"; + } else { + throw new ConfigurationException("Token exchange is required but OIDC client is configured " + "to use the " + exchangeTokenGrantType.getGrantType() + " grantType"); + } + } + } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + final String authTokenFromCtx = acquireTokenCredentialFromCtx(requestContext); + if (authTokenFromCtx.isEmpty()) { + if (verifyTokenInstance(requestContext, accessToken)) { + propagateToken(requestContext, exchangeTokenIfNeeded(accessToken.get().getToken())); + } + } else { + propagateToken(requestContext, exchangeTokenIfNeeded(authTokenFromCtx)); + } + } + + private String exchangeTokenIfNeeded(String token) { + if (exchangeTokenClient != null) { + Tokens tokens; + try { + // more dynamic parameters can be configured if required + // cache exchangedTokens to avoid roundtrips, for this to work we have to introspect the token and verify if it's valid or expired + // see https://quarkus.io/guides/security-oidc-bearer-token-authentication#accessing-jwt-claims + tokens = exchangeTokenClient.getTokens(Collections.singletonMap(exchangeTokenProperty, token)).await().indefinitely(); + // Lame implementation + refreshTokensCache.as(CaffeineCache.class).put(token, CompletableFuture.completedFuture(tokens.getRefreshToken())); + return tokens.getAccessToken(); + } catch (OidcClientException e) { + // no refresh tokens, nothing to do. + if (refreshTokensCache.get(token, k -> null).await().indefinitely() == null) { + throw e; + } + // catch, if invalid token try refreshing + final String refreshToken = (String) refreshTokensCache.get(token, k -> null).await().indefinitely(); + tokens = exchangeTokenClient.refreshTokens(refreshToken).await().indefinitely(); + // Lame implementation + refreshTokensCache.as(CaffeineCache.class).put(token, CompletableFuture.completedFuture(tokens.getRefreshToken())); + return tokens.getAccessToken(); + } + } + return token; + } + + private String acquireTokenCredentialFromCtx(ClientRequestContext requestContext) { + MultivaluedMap containerHeaders = (MultivaluedMap) requestContext.getProperty(MpClientInvocation.CONTAINER_HEADERS); + if (containerHeaders != null) { + final List authorizationHeader = containerHeaders.get("X-Authorization-acme_financial_auth"); + if (authorizationHeader != null && !authorizationHeader.isEmpty()) { + return authorizationHeader.get(0).replace("Bearer ", "").trim(); + } + } + return ""; + } + +} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/application.properties new file mode 100644 index 0000000000..c0da81729c --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/application.properties @@ -0,0 +1,57 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +quarkus.log.category."org.acme".level=DEBUG +quarkus.swagger-ui.always-include=true + +quarkus.kogito.devservices.enabled=false + +# Service we will call is in the module acme-financial-service generated by the OpenAPI Generator +# It's based on the openapi file in the specs dir +# acme_financial_service_yaml is the name of the openapi file used here as the key to configure the service connection +quarkus.rest-client.acme_financial_service_yaml.url=http://localhost:8181 + +quarkus.openapi-generator.codegen.spec.acme_financial_service_yml.base-package=com.acme +# We disabled the security codegen because it's not supporting token exchange at the moment +quarkus.openapi-generator.codegen.spec.acme_financial_service_yaml.enable-security-generation=false +# This is a custom register provider that does the token exchange based on our custom header X-Authentication- +quarkus.openapi-generator.codegen.spec.acme_financial_service_yaml.additional-api-type-annotations=@org.eclipse.microprofile.rest.client.annotation.RegisterProvider(org.acme.workflow.auth.WorkflowTokenRequestFilter.class) + +# The token propagation from the OpenAPI Generator is also disabled since we don't have the generated security beans +//quarkus.openapi-generator.acme_financial_service_yaml.auth.acme_financial_oauth.token-propagation=true + +# Information about this Keycloak instance can be found at ./scripts/boot-keycloak.sh and ./keycloak/realm-export.json +# acme_financial_oauth is the sanitized name of the SecurityScheme in the openapi spec file + +quarkus.oidc-client.acme_financial_oauth.discovery-enabled=false +# Here's the openid discovery endpoint: http://localhost:9090/realms/acme/.well-known/openid-configuration +quarkus.oidc-client.acme_financial_oauth.auth-server-url=http://localhost:9090/realms/acme/protocol/openid-connect/auth +quarkus.oidc-client.acme_financial_oauth.token-path=http://localhost:9090/realms/acme/protocol/openid-connect/token +quarkus.oidc-client.acme_financial_oauth.client-id=workflow-app +quarkus.oidc-client.acme_financial_oauth.credentials.secret=secret +quarkus.oidc-client.acme_financial_oauth.grant.type=exchange +quarkus.oidc-client.acme_financial_oauth.credentials.client-secret.method=basic +quarkus.oidc-client.acme_financial_oauth.grant-options.exchange.subject_token_type=urn:ietf:params:oauth:token-type:access_token + +quarkus.oidc-token-propagation.client-name=acme_financial_oauth +quarkus.oidc-token-propagation.exchange-token=true +quarkus.oidc-token-propagation.enabled=true + +# Debug +quarkus.log.category."io.quarkus.oidc.client.runtime".level=TRACE diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/loan-workflow.sw.yaml b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/loan-workflow.sw.yaml new file mode 100644 index 0000000000..c462a179cf --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/loan-workflow.sw.yaml @@ -0,0 +1,84 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +id: loan-workflow +version: "1.0" +name: Acme Loan Workflow +start: extractUserName +functions: + - name: extractUser + type: custom + operation: "service:org.acme.workflow.auth.JWTParserHelper::extractUser" + - name: getStatement + type: rest + operation: specs/acme-financial-service.yaml#getStatement + - name: calcBalance + type: expression + operation: "${ .statements | map(.amount) | add }" +states: + - name: extractUserName + type: operation + actions: + - name: extractUserAction + functionRef: + # we use a custom java function to extract the token from the custom auth header propagated to the target service + refName: extractUser + arguments: + token: "${ $WORKFLOW.headers.\"X-Authorization-acme_financial_auth\" }" + stateDataFilter: + output: "${ { user: .preferred_username } }" + transition: checkBalance + - name: checkBalance + type: operation + actions: + - name: getStatementAction + functionRef: + # The input for this function is the access token that contains info about the authenticated user in the financial service + refName: getStatement + actionDataFilter: + results: "${ { statements: . } }" + - name: calcBalanceAction + functionRef: + refName: calcBalance + actionDataFilter: + results: "${ { balance: . } }" + transition: checkLoan + - name: checkLoan + type: switch + dataConditions: + - condition: "${ .balance >= 30.00 }" + transition: + nextState: loanApproved + - condition: "${ .balance < 30.00 }" + transition: + nextState: loanDenied + - name: loanApproved + type: inject + data: + loanApproved: true + stateDataFilter: + output: "${ { message: \"Congrats \\(.user)! Your loan has been approved!\", loanApproved } }" + end: true + - name: loanDenied + type: inject + data: + loanApproved: false + stateDataFilter: + output: "${ { message: \"Sorry \\(.user). Your loan has been denied.\", loanApproved } }" + end: true diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/specs/acme-financial-service.yaml b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/specs/acme-financial-service.yaml new file mode 100644 index 0000000000..1a35c5c799 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/loan-workflow/src/main/resources/specs/acme-financial-service.yaml @@ -0,0 +1,45 @@ +--- +openapi: 3.0.3 +info: + title: Acme Financial Service API + version: 1.0.0 +paths: + /financial-service/statement: + get: + tags: + - Acme Financial Resource + operationId: getStatement + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/StatementEntry" + security: + - acme-financial-oauth: + - customer +components: + schemas: + LocalDate: + format: date + type: string + example: 2022-03-10 + StatementEntry: + type: object + properties: + amount: + format: double + type: number + date: + $ref: "#/components/schemas/LocalDate" + securitySchemes: + acme-financial-oauth: + type: oauth2 + flows: + clientCredentials: + authorizationUrl: http://localhost:9090/auth/realms/acme/protocol/openid-connect/auth + tokenUrl: http://localhost:9090/auth/realms/kogito/acme/openid-connect/token + scopes: {} diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/pom.xml b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/pom.xml new file mode 100644 index 0000000000..24bf57ec95 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + + org.kie.kogito.examples + serverless-workflow-examples-parent + 999-SNAPSHOT + ../serverless-workflow-examples-parent/pom.xml + + + org.acme.workflow.oauth2 + serverless-workflow-oauth2-token-exchange-quarkus + 1.0.0-SNAPSHOT + pom + Kogito Example :: Serverless Workflow Oauth2 Token Exchange (RFC 8693) Example + + + acme-financial-service + loan-workflow + + diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/postman/Token Exchange.postman_collection.json b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/postman/Token Exchange.postman_collection.json new file mode 100644 index 0000000000..8c1f7dfd65 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/postman/Token Exchange.postman_collection.json @@ -0,0 +1,281 @@ +{ + "info": { + "_postman_id": "345054ed-fe34-4117-9435-466b21d97bfd", + "name": "Token Exchange", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "1268158" + }, + "item": [ + { + "name": "Acme Financial Service", + "item": [ + { + "name": "Request Access Token Acme Financial Service", + "request": { + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "secret", + "type": "string" + }, + { + "key": "username", + "value": "financial-service", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "username", + "value": "bob", + "type": "text" + }, + { + "key": "password", + "value": "bob", + "type": "text" + }, + { + "key": "grant_type", + "value": "password", + "type": "text" + }, + { + "key": "scope", + "value": "workflow-app", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "{{keycloak_url}}/realms/acme/protocol/openid-connect/token", + "host": [ + "{{keycloak_url}}" + ], + "path": [ + "realms", + "acme", + "protocol", + "openid-connect", + "token" + ] + } + }, + "response": [] + }, + { + "name": "Get Statement", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEWjZlaWwwME12MTE1eDNwQ0hfTy1lQWpKQVIxTW5mRE1pN3YybkdrRjI0In0.eyJleHAiOjE3MjQzMzczMjgsImlhdCI6MTcyNDMzNzAyOCwianRpIjoiMmE0ZDRiNWEtMzBmZi00NTQ1LWJmYzktNWY2N2QxMThhZWE4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MDkwL3JlYWxtcy9hY21lIiwiYXVkIjpbIndvcmtmbG93LWFwcCIsImFjY291bnQiXSwic3ViIjoiMDdhN2E5MGQtOGQ2Mi00NmYxLWE5ZDItMzJmYTEzM2RhYzBiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZmluYW5jaWFsLXNlcnZpY2UiLCJzaWQiOiIxMDkxNGQ2Ni02MDI0LTQ1ZjItODIxMy00Yzc1MDZiMTExOGMiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIi8qIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWFjbWUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiY3VzdG9tZXIiXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IndvcmtmbG93LWFwcCBlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6ImFsaWNlIn0.iV-lHdl_RyLZPFAGyJ0zxVFq_IVTf9Ct-hGKvB507S73md2npTfZ-4KMcEYUfWQg_CcE0lGUghpV_9BFrzAWO-TWvLPEc_RJ6GpQqPhgJGM3LUges1WeubevFqEAmj91DR8RjGiZ3OitLmbtdALonbjvZXMjuGoteJbQFVwL7l1NqShkSM8cyy4XUpsyvBh8G0b2nY_bjp08r1ZH0g-awhpWTfyj61CYPcuB1ImMXLvhckooSOoEUmutUcEvnEZ8r_kZaP9tKTvpIDV9-IIH9DSBUPIdHpOaWkLEkUshK8xO6uqYVR34-39azssbfJ38HNMzewPV15IP7EZRsdwXoQ", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{financial_service_url}}/financial-service/statement", + "host": [ + "{{financial_service_url}}" + ], + "path": [ + "financial-service", + "statement" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Keycloak", + "item": [ + { + "name": "Workflow App Get Access Token", + "request": { + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "secret", + "type": "string" + }, + { + "key": "username", + "value": "workflow-app", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "grant_type", + "value": "urn:ietf:params:oauth:grant-type:token-exchange", + "type": "text" + } + ] + }, + "url": { + "raw": "{{keycloak_url}}/realms/acme/protocol/openid-connect/token", + "host": [ + "{{keycloak_url}}" + ], + "path": [ + "realms", + "acme", + "protocol", + "openid-connect", + "token" + ] + } + }, + "response": [] + }, + { + "name": "Workflow App Token Exchange Request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "grant_type", + "value": "urn:ietf:params:oauth:grant-type:token-exchange", + "type": "text" + }, + { + "key": "client_id", + "value": "workflow-app", + "type": "text" + }, + { + "key": "client_secret", + "value": "secret", + "type": "text" + }, + { + "key": "subject_token", + "value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEWjZlaWwwME12MTE1eDNwQ0hfTy1lQWpKQVIxTW5mRE1pN3YybkdrRjI0In0.eyJleHAiOjE3MjQyNTgyMjMsImlhdCI6MTcyNDI1NzkyMywianRpIjoiODg0ZGIyZDMtMDQwYy00YTE3LWJkZTYtYWE1NjU3ODBiYjU1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MDkwL3JlYWxtcy9hY21lIiwiYXVkIjpbIndvcmtmbG93LWFwcCIsImFjY291bnQiXSwic3ViIjoiZmI5NWNlYTctYzcwYy00MTlmLWEyMzktNjg1OWI5NWZlNzA2IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZmluYW5jaWFsLXNlcnZpY2UiLCJzaWQiOiJhNjNjOGI4MC0wMTQyLTRlMzUtOThmMS0wZDg0YTk1NDg4MjgiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIi8qIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWFjbWUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiY3VzdG9tZXIiXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IndvcmtmbG93LWFwcCBlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6ImJvYiJ9.LYPYXDjkpx2S8aPUQriC8JC344yHh9AJr3wSfWIfJnN0fx4cjDbr8Uhq45gWopUJ6URQqy0fa3u-Bu1V8EwIgCF5-om9rbDbeBgicHwfgogjrpbQL6YN5ScwOgk5wcNkOTJsr9O_UeFGqDvd-3cVQtBquAs1a5I-65a3lRJGeu06N51sFh87fs_E6XCWNrz6UMrQwPpTiN80omz04w0scPCIKQpp27fy495ZyHgZaNUJWKw40iNLMyNFHBRrlCREbYeVHeqPALO1c2cdW4BkXFCSgXbBPLV6VFI-D4p-rdrqCYZmaDP4c4DxWT_kenQvHPaqzDIWXdbbWZC73Z54WA", + "type": "text" + }, + { + "key": "subject_token_type", + "value": "urn:ietf:params:oauth:token-type:access_token", + "type": "text" + } + ] + }, + "url": { + "raw": "{{keycloak_url}}/realms/acme/protocol/openid-connect/token", + "host": [ + "{{keycloak_url}}" + ], + "path": [ + "realms", + "acme", + "protocol", + "openid-connect", + "token" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Start Workflow", + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "X-Authorization-acme_financial_auth", + "value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJEWjZlaWwwME12MTE1eDNwQ0hfTy1lQWpKQVIxTW5mRE1pN3YybkdrRjI0In0.eyJleHAiOjE3MjQzNDEzODIsImlhdCI6MTcyNDM0MTA4MiwianRpIjoiMDE2MGVhMDEtNTFhMi00NDJjLWEyNTAtYTVmZmY1N2IyOTI2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MDkwL3JlYWxtcy9hY21lIiwiYXVkIjpbIndvcmtmbG93LWFwcCIsImFjY291bnQiXSwic3ViIjoiZmI5NWNlYTctYzcwYy00MTlmLWEyMzktNjg1OWI5NWZlNzA2IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZmluYW5jaWFsLXNlcnZpY2UiLCJzaWQiOiIxNmFmYTRjZC1iMTEyLTQyNTktYWE3Yi01OTQzODBiZWU3MzUiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIi8qIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWFjbWUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiY3VzdG9tZXIiXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IndvcmtmbG93LWFwcCBlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6ImJvYiJ9.p0pb9S1X8d4nfgscXgaG2R6BpR6LG9YXC07j2__HApFN7Wx3qqDoQ2gBJRjrhdWQiqp6bVeouy3DPZM4E5cn2UQI5eww4orE3lg9Dy9rbpDcYXwTxLlwNoibfpIBCEDkwIqNeJ9NNxNBpTnBaipYM-t4BXs9bFPgRAZK6ql5KF3qmWGoXD31ZWp8UJ_nnFzvg7DWlsqxH2-FHTj-VuZ7iMNJ0PuxGgKdZR1HHajYzbs2WGKYlQ4jIRdJax1BqpJAHKjEF4U1FKY3XCF-GZqmwq4exUuxYz-K4WW2iOdPeO8IlDzGVsxB9pBKth7eBqLCPvryuBxx9dZK9H1nijXPUQ", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{workflow_url}}/loan-workflow", + "host": [ + "{{workflow_url}}" + ], + "path": [ + "loan-workflow" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "keycloak_url", + "value": "http://localhost:9090/", + "type": "string" + }, + { + "key": "financial_service_url", + "value": "http://localhost:8181/", + "type": "string" + }, + { + "key": "workflow_url", + "value": "http://localhost:8080/", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/scripts/boot-keycloak.sh b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/scripts/boot-keycloak.sh new file mode 100755 index 0000000000..ab392bfab6 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-oauth2-token-exchange-quarkus/scripts/boot-keycloak.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +user="admin" +password="admin" +java_opts="-Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.profile.feature.admin_fine_grained_authz=enabled -Dkeycloak.profile.feature.impersonation=enabled" +realm_path="$(pwd)/keycloak" + +if ! test "${realm_path}"; then + echo "--> Realm import file '${realm_path}' does not exist. Check your path and try again." + exit 1 +fi + +# Start Keycloak in devmode, see: https://www.keycloak.org/server/containers +docker run -p 9090:8080 -e KEYCLOAK_ADMIN="${user}" -e KEYCLOAK_ADMIN_PASSWORD="${password}" -e JAVA_OPTS_APPEND="${java_opts}" \ + -v "${realm_path}":/opt/keycloak/data/import \ + quay.io/keycloak/keycloak:latest \ + start-dev --import-realm