From 5e5edc5744fb9772c73025070287b4115387ec61 Mon Sep 17 00:00:00 2001 From: Corneil du Plessis Date: Thu, 12 Dec 2024 15:39:51 +0200 Subject: [PATCH] Added Keycloak integration test (#6085) Adds Keycloak integration test to DataflowOAuthIT Adds Authorities mapping test similar to keycloak role usage. Added scripts to src/local for testing keycloak locally with preconfigured roles / group and user. Fix duplicate output for skipper and dataflow and some output frames. Refactor DefaultAuthoritiesMapperTests for JUnit 5 conventions. Rename DataflowOAuthIT methods for JUnit 5 conventions. Add testcontainers-keycloak to dependency management in spring-cloud-dataflow-parent. Updates src/local/README.md with information on the scripts. Removes create-containers.sh that used jib Adds comment to application-dataflow-keycloak.yaml on client-secret. --- .github/workflows/ci-it-security.yml | 1 - .../DefaultAuthoritiesMapperTests.java | 213 +- spring-cloud-dataflow-parent/pom.xml | 6 + .../DataflowOAuthSecurityConfiguration.java | 1 + spring-cloud-dataflow-server/pom.xml | 10 + .../test/db/AbstractDataflowTests.java | 13 +- .../test/db/container/ContainerUtils.java | 10 +- .../test/db/container/DataflowCluster.java | 196 +- .../test/oauth/DataflowOAuthIT.java | 98 +- .../integration/test/tags/TagNames.java | 4 + .../application-keycloak-client.yaml | 62 + .../test/resources/application-keycloak.yaml | 65 + .../src/test/resources/dataflow-realm.json | 2057 +++++++++++++++++ .../src/test/resources/dataflow-users-0.json | 44 + src/local/README.md | 39 +- src/local/application-dataflow-keycloak.yaml | 51 + src/local/application-skipper-keycloak.yaml | 46 + src/local/container-id.sh | 7 + src/local/create-containers.sh | 64 - src/local/data/dataflow-realm.json | 2057 +++++++++++++++++ src/local/data/dataflow-users-0.json | 44 + src/local/docker-compose-keycloak.yml | 21 + src/local/docker-compose.yml | 20 - src/local/launch-dataflow.sh | 6 +- src/local/launch-keycloak.sh | 9 + src/local/launch-with-keycloak.sh | 92 + src/local/stop-dataflow.sh | 26 +- src/local/tail-container-log.sh | 5 + 28 files changed, 4986 insertions(+), 281 deletions(-) create mode 100644 spring-cloud-dataflow-server/src/test/resources/application-keycloak-client.yaml create mode 100644 spring-cloud-dataflow-server/src/test/resources/application-keycloak.yaml create mode 100644 spring-cloud-dataflow-server/src/test/resources/dataflow-realm.json create mode 100644 spring-cloud-dataflow-server/src/test/resources/dataflow-users-0.json create mode 100644 src/local/application-dataflow-keycloak.yaml create mode 100644 src/local/application-skipper-keycloak.yaml create mode 100755 src/local/container-id.sh delete mode 100755 src/local/create-containers.sh create mode 100644 src/local/data/dataflow-realm.json create mode 100644 src/local/data/dataflow-users-0.json create mode 100644 src/local/docker-compose-keycloak.yml create mode 100755 src/local/launch-keycloak.sh create mode 100755 src/local/launch-with-keycloak.sh create mode 100755 src/local/tail-container-log.sh diff --git a/.github/workflows/ci-it-security.yml b/.github/workflows/ci-it-security.yml index 61a86936d3..074e4507a8 100644 --- a/.github/workflows/ci-it-security.yml +++ b/.github/workflows/ci-it-security.yml @@ -33,7 +33,6 @@ jobs: - name: Run Security IT shell: bash run: | - ./mvnw clean install -DskipTests -T 1C -s .settings.xml -pl spring-cloud-dataflow-server -am -B --no-transfer-progress ./mvnw -s .settings.xml \ -pl spring-cloud-dataflow-server \ -Dgroups=oauth \ diff --git a/spring-cloud-common-security-config/spring-cloud-common-security-config-web/src/test/java/org/springframework/cloud/common/security/support/DefaultAuthoritiesMapperTests.java b/spring-cloud-common-security-config/spring-cloud-common-security-config-web/src/test/java/org/springframework/cloud/common/security/support/DefaultAuthoritiesMapperTests.java index fde46cb93f..3332ae70f3 100644 --- a/spring-cloud-common-security-config/spring-cloud-common-security-config-web/src/test/java/org/springframework/cloud/common/security/support/DefaultAuthoritiesMapperTests.java +++ b/spring-cloud-common-security-config/spring-cloud-common-security-config-web/src/test/java/org/springframework/cloud/common/security/support/DefaultAuthoritiesMapperTests.java @@ -34,17 +34,17 @@ /** * @author Gunnar Hillert */ -public class DefaultAuthoritiesMapperTests { +class DefaultAuthoritiesMapperTests { @Test - public void testNullConstructor() throws Exception { + void nullConstructor() throws Exception { assertThatThrownBy(() -> { new DefaultAuthoritiesMapper(null, ""); }).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("providerRoleMappings must not be null."); } @Test - public void testMapScopesToAuthoritiesWithNullParameters() throws Exception { + void mapScopesToAuthoritiesWithNullParameters() throws Exception { DefaultAuthoritiesMapper authoritiesMapper = new DefaultAuthoritiesMapper(Collections.emptyMap(), ""); assertThatThrownBy(() -> { @@ -56,18 +56,19 @@ public void testMapScopesToAuthoritiesWithNullParameters() throws Exception { } @Test - public void testThat7AuthoritiesAreReturned() throws Exception { + void that7AuthoritiesAreReturned() throws Exception { DefaultAuthoritiesMapper authoritiesMapper = new DefaultAuthoritiesMapper("uaa", false); Set authorities = authoritiesMapper.mapScopesToAuthorities("uaa", Collections.emptySet(), null); assertThat(authorities).hasSize(7); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW", "ROLE_DEPLOY", "ROLE_MODIFY", "ROLE_SCHEDULE", "ROLE_DESTROY"); } @Test - public void testEmptyMapConstructor() throws Exception { + void emptyMapConstructor() throws Exception { Set scopes = new HashSet<>(); scopes.add("dataflow.manage"); scopes.add("dataflow.view"); @@ -77,12 +78,13 @@ public void testEmptyMapConstructor() throws Exception { Collection authorities = authoritiesMapper.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(3); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW"); } @Test - public void testMapConstructorWithIncompleteRoleMappings() throws Exception { + void mapConstructorWithIncompleteRoleMappings() throws Exception { ProviderRoleMapping roleMapping = new ProviderRoleMapping(); roleMapping.setMapOauthScopes(true); roleMapping.addRoleMapping("ROLE_MANAGE", "foo-scope-in-oauth"); @@ -93,80 +95,115 @@ public void testMapConstructorWithIncompleteRoleMappings() throws Exception { } @Test - public void testThat7MappedAuthoritiesAreReturned() throws Exception { - Map roleMappings = new HashMap<>(); - roleMappings.put("ROLE_MANAGE", "foo-manage"); - roleMappings.put("ROLE_VIEW", "bar-view"); - roleMappings.put("ROLE_CREATE", "blubba-create"); - roleMappings.put("ROLE_MODIFY", "foo-modify"); - roleMappings.put("ROLE_DEPLOY", "foo-deploy"); - roleMappings.put("ROLE_DESTROY", "foo-destroy"); - roleMappings.put("ROLE_SCHEDULE", "foo-schedule"); + void that3MappedAuthoritiesAreReturned() throws Exception { + Map roleMappings = Map.of( + "ROLE_MANAGE", "dataflow_manage", + "ROLE_VIEW", "dataflow_view", + "ROLE_CREATE", "dataflow_create", + "ROLE_MODIFY", "dataflow_modify", + "ROLE_DEPLOY", "dataflow_deploy", + "ROLE_DESTROY", "dataflow_destroy", + "ROLE_SCHEDULE", "dataflow_schedule" + ); ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping(); providerRoleMapping.setMapOauthScopes(true); providerRoleMapping.getRoleMappings().putAll(roleMappings); - Set scopes = new HashSet<>(); - scopes.add("foo-manage"); - scopes.add("bar-view"); - scopes.add("blubba-create"); - scopes.add("foo-modify"); - scopes.add("foo-deploy"); - scopes.add("foo-destroy"); - scopes.add("foo-schedule"); + Set roles = Set.of("dataflow_manage", "dataflow_view", "dataflow_deploy"); + + DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping); + Collection authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa", + roles, null); + + assertThat(authorities).hasSize(3); + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) + .containsExactlyInAnyOrder("ROLE_DEPLOY", "ROLE_MANAGE", "ROLE_VIEW"); + } + @Test + void that7MappedAuthoritiesAreReturned() throws Exception { + Map roleMappings = Map.of( + "ROLE_MANAGE", "foo-manage", + "ROLE_VIEW", "bar-view", + "ROLE_CREATE", "blubba-create", + "ROLE_MODIFY", "foo-modify", + "ROLE_DEPLOY", "foo-deploy", + "ROLE_DESTROY", "foo-destroy", + "ROLE_SCHEDULE", "foo-schedule" + ); + + ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping(); + providerRoleMapping.setMapOauthScopes(true); + providerRoleMapping.getRoleMappings().putAll(roleMappings); + + Set scopes = Set.of( + "foo-manage", + "bar-view", + "blubba-create", + "foo-modify", + "foo-deploy", + "foo-destroy", + "foo-schedule" + ); DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping); Collection authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(7); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY", "ROLE_SCHEDULE", "ROLE_VIEW"); } @Test - public void testThat3MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception { + void that3MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception { ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping(); providerRoleMapping.setMapOauthScopes(true); - Set scopes = new HashSet<>(); - scopes.add("dataflow.manage"); - scopes.add("dataflow.view"); - scopes.add("dataflow.create"); + Set scopes = Set.of( + "dataflow.manage", + "dataflow.view", + "dataflow.create" + ); DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", providerRoleMapping); Collection authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(3); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW"); } @Test - public void testThat7MappedAuthoritiesAreReturnedForDefaultMappingWithoutMappingScopes() throws Exception { - Set scopes = new HashSet<>(); - scopes.add("dataflow.manage"); - scopes.add("dataflow.view"); - scopes.add("dataflow.create"); + void that7MappedAuthoritiesAreReturnedForDefaultMappingWithoutMappingScopes() throws Exception { + Set scopes = Set.of( + "dataflow.manage", + "dataflow.view", + "dataflow.create" + ); DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", false); Collection authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(7); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY", "ROLE_SCHEDULE", "ROLE_VIEW"); } @Test - public void testThat2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception { - Set scopes = new HashSet<>(); - scopes.add("dataflow.view"); - scopes.add("dataflow.create"); + void that2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception { + Set scopes = Set.of( + "dataflow.view", + "dataflow.create" + ); DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true); Collection authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa", @@ -178,19 +215,18 @@ public void testThat2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exce } @Test - public void testThat7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception { - Map roleMappings = new HashMap<>(); - roleMappings.put("ROLE_MANAGE", "foo-manage"); - roleMappings.put("ROLE_VIEW", "foo-manage"); - roleMappings.put("ROLE_DEPLOY", "foo-manage"); - roleMappings.put("ROLE_DESTROY", "foo-manage"); - roleMappings.put("ROLE_MODIFY", "foo-manage"); - roleMappings.put("ROLE_SCHEDULE", "foo-manage"); - roleMappings.put("ROLE_CREATE", "blubba-create"); - - Set scopes = new HashSet<>(); - scopes.add("foo-manage"); - scopes.add("blubba-create"); + void that7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception { + Map roleMappings = Map.of( + "ROLE_MANAGE", "foo-manage", + "ROLE_VIEW", "foo-manage", + "ROLE_DEPLOY", "foo-manage", + "ROLE_DESTROY", "foo-manage", + "ROLE_MODIFY", "foo-manage", + "ROLE_SCHEDULE", "foo-manage", + "ROLE_CREATE", "blubba-create" + ); + + Set scopes = Set.of("foo-manage", "blubba-create"); DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true, roleMappings); Collection authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa", @@ -203,61 +239,64 @@ public void testThat7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerR } @Test - public void testThatUriStyleScopeRemovesLeadingPart() throws Exception { - Map roleMappings = new HashMap<>(); - roleMappings.put("ROLE_MANAGE", "foo-manage"); - roleMappings.put("ROLE_VIEW", "foo-manage"); - roleMappings.put("ROLE_DEPLOY", "foo-manage"); - roleMappings.put("ROLE_DESTROY", "foo-manage"); - roleMappings.put("ROLE_MODIFY", "foo-manage"); - roleMappings.put("ROLE_SCHEDULE", "foo-manage"); - roleMappings.put("ROLE_CREATE", "blubba-create"); - - Set scopes = new HashSet<>(); - scopes.add("api://foobar/foo-manage"); - scopes.add("blubba-create"); + void thatUriStyleScopeRemovesLeadingPart() throws Exception { + Map roleMappings = Map.of( + "ROLE_MANAGE", "foo-manage", + "ROLE_VIEW", "foo-manage", + "ROLE_DEPLOY", "foo-manage", + "ROLE_DESTROY", "foo-manage", + "ROLE_MODIFY", "foo-manage", + "ROLE_SCHEDULE", "foo-manage", + "ROLE_CREATE", "blubba-create" + ); + + Set scopes = Set.of("api://foobar/foo-manage", "blubba-create"); DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true, roleMappings); Collection authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(7); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY", "ROLE_SCHEDULE", "ROLE_VIEW"); } @Test - public void testThatUriStyleScopeParsingCanBeDisabled() throws Exception { - Map roleMappings = new HashMap<>(); - roleMappings.put("ROLE_MANAGE", "/ROLE/2000803042"); - roleMappings.put("ROLE_VIEW", "/ROLE/2000803036"); - roleMappings.put("ROLE_DEPLOY", "/ROLE/2000803039"); - roleMappings.put("ROLE_DESTROY", "/ROLE/20008030340"); - roleMappings.put("ROLE_MODIFY", "/ROLE/2000803037"); - roleMappings.put("ROLE_SCHEDULE", "/ROLE/2000803038"); - roleMappings.put("ROLE_CREATE", "/ROLE/2000803041"); + void thatUriStyleScopeParsingCanBeDisabled() throws Exception { + Map roleMappings = Map.of( + "ROLE_MANAGE", "/ROLE/2000803042", + "ROLE_VIEW", "/ROLE/2000803036", + "ROLE_DEPLOY", "/ROLE/2000803039", + "ROLE_DESTROY", "/ROLE/20008030340", + "ROLE_MODIFY", "/ROLE/2000803037", + "ROLE_SCHEDULE", "/ROLE/2000803038", + "ROLE_CREATE", "/ROLE/2000803041" + ); ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping(); providerRoleMapping.setMapOauthScopes(true); providerRoleMapping.setParseOauthScopePathParts(false); providerRoleMapping.getRoleMappings().putAll(roleMappings); - Set scopes = new HashSet<>(); - scopes.add("/ROLE/2000803042"); - scopes.add("/ROLE/2000803036"); - scopes.add("/ROLE/2000803039"); - scopes.add("/ROLE/20008030340"); - scopes.add("/ROLE/2000803037"); - scopes.add("/ROLE/2000803038"); - scopes.add("/ROLE/2000803041"); + Set scopes = Set.of( + "/ROLE/2000803042", + "/ROLE/2000803036", + "/ROLE/2000803039", + "/ROLE/20008030340", + "/ROLE/2000803037", + "/ROLE/2000803038", + "/ROLE/2000803041" + ); DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping); Collection authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa", scopes, null); assertThat(authorities).hasSize(7); - assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + assertThat(authorities) + .extracting(GrantedAuthority::getAuthority) .containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY", "ROLE_SCHEDULE", "ROLE_VIEW"); } diff --git a/spring-cloud-dataflow-parent/pom.xml b/spring-cloud-dataflow-parent/pom.xml index a573ebf0a7..0fdbd5b1ac 100644 --- a/spring-cloud-dataflow-parent/pom.xml +++ b/spring-cloud-dataflow-parent/pom.xml @@ -62,6 +62,7 @@ 21.9.0.0 11.5.9.0 + 3.4.0 20240303 1.1.2 @@ -257,6 +258,11 @@ pom import + + com.github.dasniko + testcontainers-keycloak + ${testcontainers-keycloak.version} + diff --git a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataflowOAuthSecurityConfiguration.java b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataflowOAuthSecurityConfiguration.java index 8038459f8e..d27ab9533f 100644 --- a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataflowOAuthSecurityConfiguration.java +++ b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataflowOAuthSecurityConfiguration.java @@ -164,6 +164,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { auth.userInfoEndpoint(customizer -> { customizer.userService(plainOauth2UserService).oidcUserService(oidcUserService); }); + auth.defaultSuccessUrl(authorizationProperties.getDashboardUrl()); }); http.oauth2ResourceServer(resourceserver -> { diff --git a/spring-cloud-dataflow-server/pom.xml b/spring-cloud-dataflow-server/pom.xml index 9d3f723b1c..7931b9c049 100644 --- a/spring-cloud-dataflow-server/pom.xml +++ b/spring-cloud-dataflow-server/pom.xml @@ -72,6 +72,11 @@ spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + org.springframework.boot spring-boot-devtools @@ -104,6 +109,11 @@ junit-jupiter test + + com.github.dasniko + testcontainers-keycloak + test + org.testcontainers postgresql diff --git a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/AbstractDataflowTests.java b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/AbstractDataflowTests.java index 501f437b89..0d37bec796 100644 --- a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/AbstractDataflowTests.java +++ b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/AbstractDataflowTests.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -59,7 +58,7 @@ protected static class EmptyConfig { public final static String SKIPPER_IMAGE_PREFIX = "springcloud/spring-cloud-skipper-server:"; - public final static List DATAFLOW_CONTAINERS = Arrays.asList( + public final static List DATAFLOW_CONTAINERS = List.of( ClusterContainer.from(TagNames.DATAFLOW_2_7, DATAFLOW_IMAGE_PREFIX + "2.7.2"), ClusterContainer.from(TagNames.DATAFLOW_2_8, DATAFLOW_IMAGE_PREFIX + "2.8.4"), ClusterContainer.from(TagNames.DATAFLOW_2_9, DATAFLOW_IMAGE_PREFIX + "2.9.6"), @@ -68,7 +67,7 @@ protected static class EmptyConfig { ClusterContainer.from(TagNames.DATAFLOW_3_0, DATAFLOW_IMAGE_PREFIX + "3.0.0") ); - public final static List SKIPPER_CONTAINERS = Arrays.asList( + public final static List SKIPPER_CONTAINERS = List.of( ClusterContainer.from(TagNames.SKIPPER_2_6, SKIPPER_IMAGE_PREFIX + "2.6.2"), ClusterContainer.from(TagNames.SKIPPER_2_7, SKIPPER_IMAGE_PREFIX + "2.7.4"), ClusterContainer.from(TagNames.SKIPPER_2_8, SKIPPER_IMAGE_PREFIX + "2.8.6"), @@ -77,7 +76,7 @@ protected static class EmptyConfig { ClusterContainer.from(TagNames.SKIPPER_3_0, SKIPPER_IMAGE_PREFIX + "3.0.0") ); - public final static List DATABASE_CONTAINERS = Arrays.asList( + public final static List DATABASE_CONTAINERS = List.of( ClusterContainer.from(TagNames.POSTGRES_10, "postgres:10", TagNames.POSTGRES), ClusterContainer.from(TagNames.POSTGRES_14, "postgres:14", TagNames.POSTGRES_14), ClusterContainer.from(TagNames.MARIADB_10_4, "mariadb:10.4", TagNames.MARIADB), @@ -91,8 +90,10 @@ protected static class EmptyConfig { ClusterContainer.from(TagNames.DB2_11_5_8_0, "icr.io/db2_community/db2:11.5.8.0", TagNames.DB2) ); - public final static List OAUTH_CONTAINERS = Collections.singletonList( - ClusterContainer.from(TagNames.UAA_4_32, "springcloud/scdf-uaa-test:4.32", TagNames.UAA) + public final static List OAUTH_CONTAINERS = List.of( + ClusterContainer.from(TagNames.UAA_4_32, "springcloud/scdf-uaa-test:4.32", TagNames.UAA), + ClusterContainer.from(TagNames.KEYCLOAK_25, "quay.io/keycloak/keycloak:25.0", TagNames.KEYCLOAK), + ClusterContainer.from(TagNames.KEYCLOAK_26, "quay.io/keycloak/keycloak:26.0", TagNames.KEYCLOAK) ); @Autowired diff --git a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/ContainerUtils.java b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/ContainerUtils.java index 0bd52338a9..4e0b3f4e51 100644 --- a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/ContainerUtils.java +++ b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/ContainerUtils.java @@ -33,11 +33,15 @@ public class ContainerUtils { public static void output(String container, OutputFrame outputFrame) { switch (outputFrame.getType()) { case STDOUT: - logger.info("{}:{}", container, outputFrame.getUtf8String()); + logger.info("{}:{}", container, outputFrame.getUtf8StringWithoutLineEnding()); + break; case STDERR: - logger.error("{}:{}", container, outputFrame.getUtf8String()); + logger.error("{}:{}", container, outputFrame.getUtf8StringWithoutLineEnding()); + break; case END: - logger.info("{}:END:{}", container, outputFrame.getUtf8String()); + // don't log logger.info("{}:END:{}", container, outputFrame.getUtf8StringWithoutLineEnding()); + break; + } } diff --git a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/DataflowCluster.java b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/DataflowCluster.java index 9bc832a24b..c63343922c 100644 --- a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/DataflowCluster.java +++ b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/db/container/DataflowCluster.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.stream.Collectors; +import dasniko.testcontainers.keycloak.KeycloakContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.Db2Container; @@ -30,7 +31,6 @@ import org.testcontainers.containers.Network; import org.testcontainers.containers.OracleContainer; import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.containers.output.Slf4jLogConsumer; import org.testcontainers.lifecycle.Startable; import org.springframework.cloud.dataflow.integration.test.tags.TagNames; @@ -57,6 +57,8 @@ public class DataflowCluster implements Startable { private final int UAA_PORT = 8099; + private final int KEYCLOAK_PORT = 8080; + private final Map dataflowImages; private final Map skipperImages; @@ -190,11 +192,26 @@ public void startIdentityProvider(String id) { ClusterContainer clusterContainer = this.oauthImages.get(id); Assert.notNull(clusterContainer, String.format("Unknown oauth %s", id)); - GenericContainer oauthContainer = new GenericContainer<>(clusterContainer.image); + GenericContainer oauthContainer; + if (id.startsWith(TagNames.KEYCLOAK)) { + KeycloakContainer keycloakContainer = new KeycloakContainer(clusterContainer.image) + .withRealmImportFiles("/dataflow-realm.json", "/dataflow-users-0.json") + .withAdminUsername("admin") + .withAdminPassword("admin") + .withExposedPorts(KEYCLOAK_PORT, 9000); + oauthContainer = keycloakContainer; + } else { + oauthContainer = new GenericContainer<>(clusterContainer.image); + oauthContainer.withExposedPorts(UAA_PORT); + } oauthContainer.withNetworkAliases("oauth"); oauthContainer.withNetwork(network); - oauthContainer.withExposedPorts(UAA_PORT); + oauthContainer.withLogConsumer(outputFrame -> ContainerUtils.output("oauth", outputFrame)); oauthContainer.start(); + if(id.startsWith(TagNames.KEYCLOAK)) { + String authServerUrl = ((KeycloakContainer) oauthContainer).getAuthServerUrl(); + logger.info("keycloak using authServerUrl=" + authServerUrl); + } runningOauth = oauthContainer; } @@ -396,37 +413,73 @@ private SkipperContainer buildSkipperContainer( } if (oauthContainer != null) { - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.map-oauth-scopes", "true"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_CREATE", "dataflow.create"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DEPLOY", "dataflow.deploy"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DESTROY", "dataflow.destroy"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MANAGE", "dataflow.manage"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MODIFY", "dataflow.modify"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_SCHEDULE", "dataflow.schedule"); - skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_VIEW", "dataflow.view"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_REDIRECT_URI", "{baseUrl}/login/oauth2/code/{registrationId}"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_AUTHORIZATION_GRANT_TYPE", "authorization_code"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_ID", "dataflow"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_SECRET", "secret"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_SCOPE", - "openid,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_JWK_SET_URI", "http://oauth:8099/uaa/token_keys"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_TOKEN_URI", "http://oauth:8099/uaa/oauth/token"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_INFO_URI", "http://oauth:8099/uaa/userinfo"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_NAME_ATTRIBUTE", "user_name"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_AUTHORIZATION_URI", "http://oauth:8099/uaa/oauth/authorize"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTION_URI", "http://oauth:8099/uaa/introspect"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_ID", "dataflow"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET", "secret"); - skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECK_TOKEN_ACCESS", "isAuthenticated()"); + if(oauthContainer.getDockerImageName().contains(TagNames.KEYCLOAK)) { + configureSkipperForKeycloak(skipperContainer); + } else { + configureSkipperForUAA(skipperContainer); + } } - skipperContainer.withLogConsumer(new Slf4jLogConsumer(logger)); skipperContainer.withNetworkAliases("skipper"); skipperContainer.withNetwork(network); return skipperContainer; } + private static void configureSkipperForUAA(SkipperContainer skipperContainer) { + String oauthUrlPrefix = "http://oauth:8099/uaa"; + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.map-oauth-scopes", "true"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_CREATE", "dataflow.create"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DEPLOY", "dataflow.deploy"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DESTROY", "dataflow.destroy"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MANAGE", "dataflow.manage"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MODIFY", "dataflow.modify"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_SCHEDULE", "dataflow.schedule"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_VIEW", "dataflow.view"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_REDIRECT_URI", "{baseUrl}/login/oauth2/code/{registrationId}"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_AUTHORIZATION_GRANT_TYPE", "authorization_code"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_ID", "dataflow"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_SECRET", "secret"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_SCOPE", "openid,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_JWK_SET_URI", oauthUrlPrefix + "/token_keys"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_TOKEN_URI", oauthUrlPrefix + "/oauth/token"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_INFO_URI", oauthUrlPrefix + "/userinfo"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_NAME_ATTRIBUTE", "user_name"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_AUTHORIZATION_URI", oauthUrlPrefix + "/oauth/authorize"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTION_URI", oauthUrlPrefix + "/introspect"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_ID", "dataflow"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET", "secret"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECK_TOKEN_ACCESS", "isAuthenticated()"); + } + + private static void configureSkipperForKeycloak(SkipperContainer skipperContainer) { + String oauthUrlPrefix = "http://oauth:8080"; + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.map-oauth-scopes", "false"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.map-group-claims", "false"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_CREATE", "dataflow_create"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_DEPLOY", "dataflow_deploy"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_DESTROY", "dataflow_destroy"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_MANAGE", "dataflow_manage"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_MODIFY", "dataflow_modify"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_SCHEDULE", "dataflow_schedule"); + skipperContainer.withEnv("spring.cloud.skipper.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_VIEW", "dataflow_view"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_REDIRECTURI", "{baseUrl}/login/oauth2/code/{registrationId}"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_AUTHORIZATIONGRANTTYPE", "authorization_code"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENTID", "dataflow"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENTSECRET", "secret"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENTAUTHENTICATIONMETHOD", "post"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_SCOPE", "openid, roles"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_ISSUERURI", oauthUrlPrefix + "/realms/dataflow"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_JWKSETURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/certs"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_TOKENURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/token"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_USERINFOURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/userinfo"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_AUTHORIZATIONURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/auth"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_USER_NAME_ATTRIBUTE", "user_name"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTIONURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/token/introspect"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENTID", "dataflow"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENTSECRET", "090RucamvekrMLyGHMr4lkHX9xhAlsqK"); + skipperContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECKTOKENACCESS", "isAuthenticated()"); + } + private DataflowContainer buildDataflowContainer( ClusterContainer clusterContainer, JdbcDatabaseContainer databaseContainer, GenericContainer oauthContainer, @@ -460,42 +513,77 @@ private DataflowContainer buildDataflowContainer( dataflowContainer.withEnv("SPRING_DATASOURCE_URL", databaseContainer.getJdbcUrl()); } } - dataflowContainer.withEnv("SPRING_CLOUD_SKIPPER_CLIENT_SERVER_URI", - String.format("http://%s:%s/api", "skipper", SKIPPER_PORT)); + dataflowContainer.withEnv("SPRING_CLOUD_SKIPPER_CLIENT_SERVER_URI", String.format("http://skipper:%s/api", SKIPPER_PORT)); if (oauthContainer != null) { - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.map-oauth-scopes", "true"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_CREATE", "dataflow.create"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DEPLOY", "dataflow.deploy"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DESTROY", "dataflow.destroy"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MANAGE", "dataflow.manage"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MODIFY", "dataflow.modify"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_SCHEDULE", - "dataflow.schedule"); - dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_VIEW", "dataflow.view"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_REDIRECT_URI", "{baseUrl}/login/oauth2/code/{registrationId}"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_AUTHORIZATION_GRANT_TYPE", "authorization_code"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_ID", "dataflow"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_SECRET", "secret"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_SCOPE", - "openid,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_JWK_SET_URI", "http://oauth:8099/uaa/token_keys"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_TOKEN_URI", "http://oauth:8099/uaa/oauth/token"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_INFO_URI", "http://oauth:8099/uaa/userinfo"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_NAME_ATTRIBUTE", "user_name"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_AUTHORIZATION_URI", "http://oauth:8099/uaa/oauth/authorize"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTION_URI", "http://oauth:8099/uaa/introspect"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_ID", "dataflow"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET", "secret"); - dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECK_TOKEN_ACCESS", "isAuthenticated()"); + if(oauthContainer.getDockerImageName().contains(TagNames.KEYCLOAK)) { + configureDataflowForKeycloak(dataflowContainer); + } else { + configureDataflowForUAA(dataflowContainer); + } } - dataflowContainer.withLogConsumer(new Slf4jLogConsumer(logger)); dataflowContainer.withNetworkAliases("dataflow"); dataflowContainer.withNetwork(network); return dataflowContainer; } + private void configureDataflowForKeycloak(DataflowContainer dataflowContainer) { + String oauthUrlPrefix = "http://oauth:" + KEYCLOAK_PORT; + dataflowContainer.withEnv("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY", "DEBUG"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.map-oauth-scopes", "false"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.map-group-claims", "false"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_CREATE", "dataflow_create"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_DEPLOY", "dataflow_deploy"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_DESTROY", "dataflow_destroy"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_MANAGE", "dataflow_manage"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_MODIFY", "dataflow_modify"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_SCHEDULE", "dataflow_schedule"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.keycloak.role-mappings.ROLE_VIEW", "dataflow_view"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_REDIRECTURI", "{baseUrl}/login/oauth2/code/{registrationId}"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_AUTHORIZATIONGRANTTYPE", "authorization_code"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENTID", "dataflow"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_CLIENTSECRET", "090RucamvekrMLyGHMr4lkHX9xhAlsqK"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_KEYCLOAK_SCOPE", "openid,roles"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_ISSUERURI", oauthUrlPrefix + "/realms/dataflow"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_JWKSETURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/certs"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_TOKENURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/token"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_USERINFOURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/userinfo"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_AUTHORIZATIONURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/auth"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_KEYCLOAK_USERNAMEATTRIBUTE", "user_name"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTIONURI", oauthUrlPrefix + "/realms/dataflow/protocol/openid-connect/token/introspect"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENTID", "dataflow"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENTSECRET", "090RucamvekrMLyGHMr4lkHX9xhAlsqK"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECKTOKENACCESS", "isAuthenticated()"); + } + + private void configureDataflowForUAA(DataflowContainer dataflowContainer) { + String oauthUrlPrefix = "http://oauth:" + UAA_PORT + "/uaa"; + dataflowContainer.withEnv("LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_SECURITY", "DEBUG"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.map-oauth-scopes", "true"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_CREATE", "dataflow.create"); + dataflowContainer.withEnv( "spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DEPLOY", "dataflow.deploy"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_DESTROY", "dataflow.destroy"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MANAGE", "dataflow.manage"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_MODIFY", "dataflow.modify"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_SCHEDULE", "dataflow.schedule"); + dataflowContainer.withEnv("spring.cloud.dataflow.security.authorization.provider-role-mappings.uaa.role-mappings.ROLE_VIEW", "dataflow.view"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_REDIRECT_URI", "{baseUrl}/login/oauth2/code/{registrationId}"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_AUTHORIZATION_GRANT_TYPE", "authorization_code"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_ID", "dataflow"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_CLIENT_SECRET", "secret"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_UAA_SCOPE", "openid,dataflow.create,dataflow.deploy,dataflow.destroy,dataflow.manage,dataflow.modify,dataflow.schedule,dataflow.view"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_JWK_SET_URI", oauthUrlPrefix + "/token_keys"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_TOKEN_URI", oauthUrlPrefix + "/oauth/token"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_INFO_URI", oauthUrlPrefix + "/userinfo"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_USER_NAME_ATTRIBUTE", "user_name"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_UAA_AUTHORIZATION_URI", oauthUrlPrefix + "/oauth/authorize"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_INTROSPECTION_URI", oauthUrlPrefix + "/introspect"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_ID", "dataflow"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET", "secret"); + dataflowContainer.withEnv("SPRING_SECURITY_OAUTH2_AUTHORIZATION_CHECK_TOKEN_ACCESS", "isAuthenticated()"); + } + public static class ClusterContainer { String id; diff --git a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/oauth/DataflowOAuthIT.java b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/oauth/DataflowOAuthIT.java index 9535274284..ce51091ec7 100644 --- a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/oauth/DataflowOAuthIT.java +++ b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/oauth/DataflowOAuthIT.java @@ -16,6 +16,7 @@ package org.springframework.cloud.dataflow.integration.test.oauth; +import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -34,14 +35,14 @@ import static org.assertj.core.api.Assertions.assertThat; @Oauth -@ActiveProfiles({TagNames.PROFILE_OAUTH}) +@ActiveProfiles(TagNames.PROFILE_OAUTH) class DataflowOAuthIT extends AbstractDataflowTests { private final Logger log = LoggerFactory.getLogger(DataflowOAuthIT.class); @Test - void securedSetup() throws Exception { - log.info("Running testSecuredSetup()"); + void runningUAASecuredSetup() throws Exception { + log.info("Running UAASecuredSetup"); this.dataflowCluster.startIdentityProvider(TagNames.UAA_4_32); this.dataflowCluster.startSkipper(TagNames.SKIPPER_main); this.dataflowCluster.startDataflow(TagNames.DATAFLOW_main); @@ -60,30 +61,10 @@ void securedSetup() throws Exception { .ignoreExceptions() .atMost(90, TimeUnit.SECONDS) .untilAsserted(() -> { - log.info("Checking auth using curl"); - ExecResult cmdResult = execInToolsContainer("curl", "-v", "-u", "janne:janne", "http://dataflow:9393/about"); - String response = cmdResult.getStdout(); - if (StringUtils.hasText(response)) { - log.info("Response is {}", response); - } - stderr.set(cmdResult.getStderr()); - assertThat(response).contains("\"authenticated\":true"); - assertThat(response).contains("\"username\":\"janne\""); - stderr.set(""); + assertGetAboutWithUser("janne", "janne", stderr); }); - log.info("Checking without credentials using curl"); - ExecResult cmdResult = execInToolsContainer("curl", "-v", "-f", "http://dataflow:9393/about"); - String response = cmdResult.getStdout(); - if (StringUtils.hasText(response)) { - log.info("Response is {}", response); - } - response = cmdResult.getStderr(); - if(StringUtils.hasText(response)) { - log.warn("Error is {}", response); - } - stderr.set(cmdResult.getStderr()); - assertThat(cmdResult.getExitCode()).isNotZero(); - stderr.set(""); + log.info("Checking without credentials using curl"); + assertAboutWithoutUser(stderr); } finally { String msg = stderr.get(); @@ -92,4 +73,69 @@ void securedSetup() throws Exception { } } } + + @Test + void runningKeycloakSecuredSetup() throws Exception { + log.info("Running KeycloakSecuredSetup"); + this.dataflowCluster.startIdentityProvider(TagNames.KEYCLOAK_26); + this.dataflowCluster.startSkipper(TagNames.SKIPPER_main); + this.dataflowCluster.startDataflow(TagNames.DATAFLOW_main); + + // we can't do oauth flow from host due to how oauth works as we + // need proper networking, so use separate tools container to run + // curl command as we support basic auth and if we get good response + // oauth is working with dataflow and skipper. + + AtomicReference stderr = new AtomicReference<>(); + try { + with() + .pollInterval(5, TimeUnit.SECONDS) + .and() + .await() + .ignoreExceptions() + .atMost(90, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertGetAboutWithUser("joe", "password", stderr); + }); + log.info("Checking without credentials using curl"); + assertAboutWithoutUser(stderr); + } + finally { + String msg = stderr.get(); + if (StringUtils.hasText(msg)) { + log.error("curl error: {}", msg); + } + } + } + + private void assertGetAboutWithUser(String username, String password, AtomicReference stderr) throws IOException, InterruptedException { + log.info("Checking auth using curl"); + ExecResult cmdResult = execInToolsContainer("curl", "-v", "-u", username + ":" + password, "http://dataflow:9393/about"); + String response = cmdResult.getStdout(); + if (StringUtils.hasText(response)) { + log.info("Response is {}", response); + } + if(StringUtils.hasText(cmdResult.getStderr())) { + log.error(cmdResult.getStderr()); + } + stderr.set(cmdResult.getStderr()); + assertThat(response).contains("\"authenticated\":true"); + assertThat(response).contains("\"username\":\"" + username + "\""); + stderr.set(""); + } + + private void assertAboutWithoutUser(AtomicReference stderr) throws IOException, InterruptedException { + ExecResult cmdResult = execInToolsContainer("curl", "-v", "-f", "http://dataflow:9393/about"); + String response = cmdResult.getStdout(); + if (StringUtils.hasText(response)) { + log.info("Response is {}", response); + } + response = cmdResult.getStderr(); + if(StringUtils.hasText(response)) { + log.warn("Error is {}", response); + } + stderr.set(cmdResult.getStderr()); + assertThat(cmdResult.getExitCode()).isNotZero(); + stderr.set(""); + } } diff --git a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/tags/TagNames.java b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/tags/TagNames.java index 25da881e23..0094f37bc3 100644 --- a/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/tags/TagNames.java +++ b/spring-cloud-dataflow-server/src/test/java/org/springframework/cloud/dataflow/integration/test/tags/TagNames.java @@ -63,6 +63,10 @@ public abstract class TagNames { public static final String OAUTH = "oauth"; public static final String PERFORMANCE = "performance"; public static final String UAA = "uaa"; + public static final String KEYCLOAK = "keycloak"; + public static final String KEYCLOAK_25 = "keycloak_25"; + public static final String KEYCLOAK_26 = "keycloak_26"; + public static final String UAA_4_32 = "uaa_4_32"; public static final String SKIPPER = "skipper"; diff --git a/spring-cloud-dataflow-server/src/test/resources/application-keycloak-client.yaml b/spring-cloud-dataflow-server/src/test/resources/application-keycloak-client.yaml new file mode 100644 index 0000000000..f8b7c9c868 --- /dev/null +++ b/spring-cloud-dataflow-server/src/test/resources/application-keycloak-client.yaml @@ -0,0 +1,62 @@ +spring: + cloud: + dataflow: + security: + authorization: + provider-role-mappings: + keycloak: + map-group-claims: true + role-mappings: + ROLE_VIEW: dataflow_view + ROLE_CREATE: dataflow_create + ROLE_MANAGE: dataflow_manage + ROLE_DEPLOY: dataflow_deploy + ROLE_DESTROY: dataflow_destroy + ROLE_MODIFY: dataflow_modify + ROLE_SCHEDULE: dataflow_schedule + client: + authentication: + client-id: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + oauth2: + client-registration-id: keycloak + scope: openid, roles + security: + oauth2: + client: + provider: + keycloak: + issuer-uri: '${keycloak.url}/realms/dataflow' + jwk-set-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/certs' + token-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/token' + user-info-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/userinfo' + user-name-attribute: 'user_name' + authorization-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/auth' + registration: + keycloak: + redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' + client-id: 'dataflow' + client-name: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + provider: 'keycloak' + authorization-grant-type: 'authorization_code' + scope: + - openid + - roles + resourceserver: + opaquetoken: + introspection-uri: ${keycloak.url}/realms/dataflow/protocol/openid-connect/token/introspect + client-id: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + authorization: + check-token-access: isAuthenticated() +logging: + level: + org.springframework.security: debug + org.springframework.web: debug + org.springframework.cloud.dataflow: debug + org.springframework.cloud.common: debug + org.apache.hc: debug + org.apache.http: debug + threshold: + console: debug \ No newline at end of file diff --git a/spring-cloud-dataflow-server/src/test/resources/application-keycloak.yaml b/spring-cloud-dataflow-server/src/test/resources/application-keycloak.yaml new file mode 100644 index 0000000000..08d2cfb63a --- /dev/null +++ b/spring-cloud-dataflow-server/src/test/resources/application-keycloak.yaml @@ -0,0 +1,65 @@ +spring: + cloud: + dataflow: + features: + schedules-enabled: false + streams-enabled: false + security: + authorization: + provider-role-mappings: + keycloak: + map-group-claims: true + role-mappings: + ROLE_VIEW: dataflow_view + ROLE_CREATE: dataflow_create + ROLE_MANAGE: dataflow_manage + ROLE_DEPLOY: dataflow_deploy + ROLE_DESTROY: dataflow_destroy + ROLE_MODIFY: dataflow_modify + ROLE_SCHEDULE: dataflow_schedule + client: + authentication: + client-id: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + oauth2: + client-registration-id: keycloak + scope: openid, roles + security: + oauth2: + client: + provider: + keycloak: + issuer-uri: '${keycloak.url}/realms/dataflow' + jwk-set-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/certs' + token-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/token' + user-info-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/userinfo' + user-name-attribute: 'user_name' + authorization-uri: '${keycloak.url}/realms/dataflow/protocol/openid-connect/auth' + registration: + keycloak: + redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' + client-id: 'dataflow' + client-name: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + provider: 'keycloak' + authorization-grant-type: 'authorization_code' + scope: + - openid + - roles + resourceserver: + opaquetoken: + introspection-uri: ${keycloak.url}/realms/dataflow/protocol/openid-connect/token/introspect + client-id: 'dataflow' + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + authorization: + check-token-access: isAuthenticated() +logging: + level: + org.springframework.security: debug + org.springframework.web: debug + org.springframework.cloud.dataflow: debug + org.springframework.cloud.common: debug + org.apache.hc: debug + org.apache.http: debug + threshold: + console: debug \ No newline at end of file diff --git a/spring-cloud-dataflow-server/src/test/resources/dataflow-realm.json b/spring-cloud-dataflow-server/src/test/resources/dataflow-realm.json new file mode 100644 index 0000000000..551580a2f2 --- /dev/null +++ b/spring-cloud-dataflow-server/src/test/resources/dataflow-realm.json @@ -0,0 +1,2057 @@ +{ + "id" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "realm" : "dataflow", + "displayName" : "", + "displayNameHtml" : "", + "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" : "none", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : false, + "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" : "d58ec37e-955b-4dd1-88b6-749cc2eac653", + "name" : "ADMIN", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "73317621-0f5c-4c10-a7bb-907e789a966e", + "name" : "dataflow_deploy", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "d239b6bf-1426-41a6-bea0-cb27f65ee56f", + "name" : "dataflow_schedule", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "ca1016ba-3ffc-45a6-8b9d-c00c1ebafb56", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "90d84348-835c-413f-a815-fc8a444a8d9e", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "c92d02b3-a184-44ce-bb2f-10aecf82a04c", + "name" : "dataflow_create", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "bc22a2ea-b505-4fa4-a9ac-8a7610fb4400", + "name" : "dataflow_view", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "c13395f0-4a1d-4be5-af25-6202cfc75428", + "name" : "dataflow_modify", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "276259e7-d971-4972-8656-102b2575846e", + "name" : "dataflow_manage", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "ed54ea38-493d-4def-a9a7-57fa56813c61", + "name" : "default-roles-dataflow", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "view-profile", "manage-account" ] + } + }, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "fe469ec1-eb24-422b-9492-f9e2ffa47f85", + "name" : "dataflow_destroy", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "3d3d4b18-bd9d-4c23-a830-eed83709335f", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "ea4a2541-7fd3-4c6a-8aa7-aa87631d1ca3", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "ca17f224-727c-42dc-a4da-c1c01f6a872a", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "0ecf1006-86e7-48f1-87c3-9bd931e1aae2", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "11e3cd98-f893-47fd-8310-d7a3aa4c65dd", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "f5470f88-bed6-4044-a0d0-e8c665efee65", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "manage-users", "view-identity-providers", "view-events", "query-users", "manage-authorization", "view-realm", "view-users", "query-clients", "view-authorization", "manage-events", "manage-realm", "query-realms", "create-client", "query-groups", "manage-clients", "manage-identity-providers", "view-clients", "impersonation" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "c24ba356-b344-405e-93b0-a2b2c9dc38a7", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "3ab018c0-85cf-4169-8478-86d433c37d07", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-users", "query-groups" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "9cd5b2aa-307c-4b72-adc5-7bb023e11a44", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "fbc0d3d9-ec05-4b69-93c1-92fc01ede9b1", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "68b7dd08-272b-459d-bcef-df971e671e1b", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "0f0229ba-080b-4c23-a389-e14b0c6a9613", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "e2144b8e-b4f3-49d6-8602-a994f8f181e9", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "2798859b-3fcb-432e-8123-4c99b7dc999e", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "93d898fd-b702-4dc5-bfcd-dff76fec9ec6", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "eeb68873-9bd5-4905-828b-0c160295add7", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "d9cc3611-31f8-426e-bee7-988a256ed043", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "efd69870-1ae3-4b0a-acc3-a8b6d5d4c0c8", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "449263f4-9e69-47c4-a94a-6733952f6d75", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + } ], + "dataflow" : [ { + "id" : "90a8c46b-c91d-467f-9af1-1d7c13b60122", + "name" : "ADMIN", + "description" : "", + "composite" : false, + "clientRole" : true, + "containerId" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "attributes" : { } + }, { + "id" : "2d6698f6-1260-47cc-9836-85d86d1536d3", + "name" : "uma_protection", + "composite" : false, + "clientRole" : true, + "containerId" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "3053579b-49cd-4311-96ff-70db3facd0cb", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "41f5e232-c5fd-40c2-ac0a-15df0ef36bdf", + "attributes" : { } + } ], + "account" : [ { + "id" : "0f3f48f0-7396-4296-93cf-55e509137f95", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "cc9b7a19-9a0b-47ae-b5eb-ed440c6753cf", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "da16948e-6eb8-4441-9076-1231a09a6e55", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "babf7894-3c07-445c-b9b9-ab5587c1902e", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "3ccbb748-9087-475e-87d5-b46ca6f0d771", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "1af0d267-dd3e-47a1-8347-d1b88ab69729", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "23b3fa11-a18e-4eff-9d20-e51a1b0ccae9", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "6d3be4d5-a6d6-4d48-b9e3-26b7a7e994f4", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + } ] + } + }, + "groups" : [ { + "id" : "60ccd51e-1b2d-4510-9afb-da23ebe165d6", + "name" : "dataflow-admin", + "path" : "/dataflow-admin", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "dataflow_deploy", "dataflow_schedule", "dataflow_view", "dataflow_create", "dataflow_modify", "dataflow_manage", "dataflow_destroy" ], + "clientRoles" : { + "dataflow" : [ "uma_protection" ] + } + } ], + "defaultRole" : { + "id" : "ed54ea38-493d-4def-a9a7-57fa56813c61", + "name" : "default-roles-dataflow", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce" + }, + "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" : [ ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dataflow/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dataflow/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" : "72dabab7-ef11-4392-8064-bab95d3e660b", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dataflow/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dataflow/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" : "e4bd267e-1d8c-485a-8365-bb6bcf203a10", + "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" : "0a29e3d0-b8d7-4899-a8dc-ab4911f1fb10", + "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" : "41f5e232-c5fd-40c2-ac0a-15df0ef36bdf", + "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" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "clientId" : "dataflow", + "name" : "${client_account}", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : true, + "clientAuthenticatorType" : "client-secret", + "secret" : "090RucamvekrMLyGHMr4lkHX9xhAlsqK", + "redirectUris" : [ "http://localhost:9393/*" ], + "webOrigins" : [ "" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled" : true, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1731500243", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "+", + "display.on.consent.screen" : "false", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "f4847976-7ee7-4f91-86dd-3cfad2a017a5", + "name" : "Username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "lightweight.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "user_name", + "jsonType.label" : "String" + } + }, { + "id" : "b461e8d8-84da-4ae9-b927-a03944f499a0", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "userinfo.token.claim" : "false", + "user.attribute" : "foo", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String" + } + }, { + "id" : "8f3ea527-380a-40ca-ad03-4a3cfbf720e0", + "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" + } + }, { + "id" : "67467aa3-49a2-499d-841a-ebeff48bc24e", + "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" : "30a46803-933c-4938-8528-f2bee2991463", + "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" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings" : { + "allowRemoteResourceManagement" : true, + "policyEnforcementMode" : "ENFORCING", + "resources" : [ { + "name" : "Default Resource", + "type" : "urn:dataflow:resources:default", + "ownerManagedAccess" : false, + "attributes" : { }, + "uris" : [ "/*" ] + } ], + "policies" : [ ], + "scopes" : [ ], + "decisionStrategy" : "UNANIMOUS" + } + }, { + "id" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "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" : "61c009a1-8183-49d8-b680-100e4329d804", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/dataflow/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/dataflow/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" : "df4e00b7-2665-4adc-8062-ed8c4f6c4845", + "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" ] + } ], + "clientScopes" : [ { + "id" : "dd7788e5-74ff-41c4-bd4d-3802b712b285", + "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" : "e2bb61c5-b64c-446a-8e4d-3579931786f1", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + } ] + }, { + "id" : "15127dc5-a81f-438a-93f9-046b33a5e4bb", + "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" : "9bd80e49-8798-4ebe-bfab-a61e34c2177a", + "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" : "bc758953-016a-4564-b77a-5e80234504af", + "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" : "066f78cc-5f57-4a9b-b859-613af59ce403", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "4c9653de-13bf-4ccb-883e-d8cd8a5b071f", + "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" : "0b6564ce-607e-4f75-83d4-257ccbf0565e", + "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" : "c44f05ff-959e-425c-8bc5-c55fdabba209", + "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" : "08df5e8d-1bc7-48eb-9171-f9d9701ba9ae", + "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" : "703981fc-3beb-4db1-b3f6-572d55758f87", + "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" : "b4740fe4-ba83-445e-ad33-225c2a6d6251", + "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" : "ddffeac0-c4d5-4f46-bd2c-621b7c58601f", + "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" : "cdb889ec-3a18-4da7-a87e-79e4e3c4d06a", + "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" : "890daab1-52a9-492f-899d-0e139f89924e", + "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" : "47520142-2275-4d24-ad1f-885caf3fb386", + "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" : "62b31d2e-282c-421b-b3a4-a34abcaaa578", + "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" : "30081984-75d5-4593-adda-eb350f463d0c", + "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" : "3ac14257-edd7-4cda-95c5-33c3ffaaa732", + "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" : "4af4aee0-ae10-4e55-94c6-36d65327466d", + "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" : "6aa38d97-94b9-4578-8cf9-44f1c0483ed7", + "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" : "c024d9ce-10ac-4965-8eb4-750f6e4ad489", + "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" : "737a228d-e448-4a65-a1cc-dfdbf314f81b", + "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" : "1478fd20-c2e1-4e49-9679-d139fa7b087d", + "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" : "95f90de9-7071-4eb0-bb6c-a6178b8236d0", + "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" : "105c0a33-ba95-43c9-b66a-11d91fb4ea25", + "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" : "68aa3586-e241-4401-a206-54f6f708459d", + "name" : "sub", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-sub-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + } ] + }, { + "id" : "0d59f7b0-287d-4144-890f-606cd4c2f8ff", + "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" : "5e85384a-cb15-421f-8227-9a7834b399ac", + "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" : "6fc655fe-ecaf-429b-8196-3194ddf003d9", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + }, { + "id" : "9b42d818-be9e-4d57-bf58-510162ee65b0", + "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" : "188181b2-6767-4ae4-af70-5710007f6419", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "d5e22c70-c9b9-42d4-a574-06ae98103138", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "3f2d3d67-696b-45a2-bfd0-078b0f884846", + "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" : "05b3a9ae-ab8f-456e-b52b-e3b9f35485d7", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + }, { + "id" : "9fcb562a-dc02-47b6-acfc-0649715394af", + "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" : "6d7492ec-e6a7-491f-a295-0a2185a04345", + "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" : "cce1f2e3-54dc-4395-b936-367512edef2f", + "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" : "a98b3a04-9e59-406b-84ea-38fd547ff99b", + "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" : "2187bd2c-f2aa-4980-b7bd-3dc249d64997", + "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" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "roles", "profile", "role_list", "acr", "email", "basic", "web-origins" ], + "defaultOptionalClientScopes" : [ "offline_access", "phone", "microprofile-jwt", "address" ], + "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" : "b5c7aa4b-20b2-4d8f-a37c-94aca4210907", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "58eac984-08c6-44eb-aca7-908bb2d605c5", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "1378f56e-5fc6-4a9b-a186-635379a76a47", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper" ] + } + }, { + "id" : "62d0ec0d-e35e-47e8-8970-886919cb883a", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "2108fb8f-44db-4ce1-b0c9-28ef3c68c429", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ], + "allowed-client-scopes" : [ "email", "roles", "role_list", "profile" ] + } + }, { + "id" : "4336c077-e19a-4f01-b6d6-f2a143ac80b6", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper" ] + } + }, { + "id" : "00b141c9-3fef-4e1d-91c6-45278333e7c7", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "8c1796b5-42e3-4d4f-9f80-5db3c278c8e7", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "f8d38b52-292b-43b7-8aa4-dcd5bba266c8", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEoQIBAAKCAQEA1DBCq/0XlOCki1yQHsFd3Pzr25QkqKxYJRQypp0OcolHqeR5l8WQQmtTOpj72ssw3QBxcdQ0mOj27JvylVse7RNBDs69FQm+sELZflvGGi3pg356ioAjZs0wMaryLvcg0pv2cuOJJdx66JwgnE2/NwFFfNTiu56fGmGql75C4j/+zK4UC5tWFIwfEipZxbAE5TM0XlkQWxycRYjkNTK8EsdssFK7kY0EwTX4y2neDa/A7jEsDpOAHLFl/sajkPppeO42TVxGH5QKU4F/rOmHIfvZhxNzL3m5w4+UUQZSvFZGhfTwBTT1qV/ld/NLE+8cU9cjeoN+mVcs543O0OgLzQIDAQABAoIBABDQ5vpuEJLeFMbt+zFSHh1ii/yhv8qq/JdVA53xtNCTRvMqELrcT45RUXjDjAjZxpG/3xMS1WedkDLN5HU9Z0o0QZkp/ZEvwwWBXsQ6rgyqwSazJ4SsxWF4dyPQij36Rtx6EMIn0dmGy39+HsApvIg1mRYHYcAAa60xuqJ+U8WjVfqMQ0Lx1ciXCcFXfURQ4d8MRqMEZ61oTpbKbB767VN2RCW0YJvoub5tOe7ZCPfayEpqfRF65rMoZfCYoLytuB8Ke5tKy2xisvO/5lATCDYop6Yrb4VniHWV0rk+o4g/kEFxN1gKZx5nS/rn1Lecj6w01IR+po5yjhdNtIEayPECgYEA/hhXQ9A9HB0bHpuBx4G/gE5Gy0cJOyuKHO8rJNUaZQ1BYy3w7C/DK8meCJXvS63Fs8+N2GTMk3bySsQyxmN/FFze5oyHYYQ9zffuF90Ii4YTiCdZgwpRlq0IB7386dxGy5B0EjL+A3QXd64PdAZPADJo18Swlk7UhKxN9uy0vZUCgYEA1cd+FOf9l4VthKNzSMsAReWn33o/6087rs5o14xe8JqipwGYqWgt+JY/r0Zg3C64MCNbIqNtr4SHabbGXnbw+JbRVM7qsV62mqzYN+mTCuEXbFXnxp5fa/Cam9vgZ2CiiNVoxkwrLLDt2WbT9n6O1iBvy9aG9VkNrO3ZyHTy11kCf0KAHFajKVsyQua/zDdqvbPWyLBq5v+VZZAtCB2bqEzKK1LJs0QdO/c5zSJyGy6zTArDR1xbBS+S8dafgqppX9j0dWHhZY0gDwzY1ndoYdQiQvpfUg35pWDJ6FAeaRLLk7uzEq2wqso8l+e6plC3VfW3O7k8wPqVpwkSD1WQnb0CgYAJ2eOJexdIgDGHxzBszk346phNyAhiA4iwiXpzVFibpcSRBZXPWKmlpubQYOHdw5lhPn/YnMdVKzpCONXzTG/WRLzot5BBFCg+AHEGQpEwEydNKrg/gtTK2I+HVx6EJQPYYl0tphznNk//kKl71mEmpOAB+KTHcY8bxOogPqNiIQKBgQCZ6q653cgA8x3H9ka2bAOejHhUUlEPm7vFh1svi3HWku03iSAvW80Pjh3HxARuVC9xdbFfh5WJue6SC39dHoxAeoBfjQAuYrFuhha719ra7umnuEAe5J8H6ZCVngkWbdLzw/lGwMS3+jzFLbuBO9+v0S+jy9EJXWfW2CcXqsxsxA==" ], + "certificate" : [ "MIICnzCCAYcCBgGTUz4GtDANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhkYXRhZmxvdzAeFw0yNDExMjIwOTM4MTRaFw0zNDExMjIwOTM5NTRaMBMxETAPBgNVBAMMCGRhdGFmbG93MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1DBCq/0XlOCki1yQHsFd3Pzr25QkqKxYJRQypp0OcolHqeR5l8WQQmtTOpj72ssw3QBxcdQ0mOj27JvylVse7RNBDs69FQm+sELZflvGGi3pg356ioAjZs0wMaryLvcg0pv2cuOJJdx66JwgnE2/NwFFfNTiu56fGmGql75C4j/+zK4UC5tWFIwfEipZxbAE5TM0XlkQWxycRYjkNTK8EsdssFK7kY0EwTX4y2neDa/A7jEsDpOAHLFl/sajkPppeO42TVxGH5QKU4F/rOmHIfvZhxNzL3m5w4+UUQZSvFZGhfTwBTT1qV/ld/NLE+8cU9cjeoN+mVcs543O0OgLzQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDQTeMN/RP+6O5YkUTAcjClcO+IBYIMuNW3Muqm8j4X2T9QJ9Fi17cDt6uqmcgFuRxoBnvxI/zd9ct47MQi5c+XeBMiv5Pb+/Pe2CWZA3N5dUsw9ieqnOkcK/o6UdqiRL3u89fZBPFgFVFO7NLZGqphndWKoIB3a359GKORDkBUc7W1O2u1KJQ9tbn7nsqudr/Twv4OkNfqPcq/qSCLMLYwB0uuspoADC5daZdyNucTkCXJuBOu/A3ejd0CYBPlFuX8o2kBbjeV5Md4h/OVcRVvTsYW5N4b/0D6arp+PSVSZpX39PqgasQF7LAOZgf8ryYDxrPuqui5IsVMeR0dtAMP" ], + "priority" : [ "100" ] + } + }, { + "id" : "9c91c645-71be-4605-ae55-d5e8f33d0021", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a8058942-eced-4429-92ba-1b840eb8038f" ], + "secret" : [ "yKmq3CM-DxvipKeoHzS2wg" ], + "priority" : [ "100" ] + } + }, { + "id" : "eaffb764-adc5-4954-a1ff-9cb4b745e7ad", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAuH9aHqE59BqnpFp21vMCDkvFhr0t9bpsCpswJ7cHX+e9rtzgyTInKAiurqvWex1vkH1BmMhmU6dm7USDpYF/ktOfiNht8S4pKL5dJcejr3I/onPKw71X0JK2i/vPDqY4FLjP+u2k4z6VbJo1NFsxP9381/9oY4nVaajHkMS3H3OBgvaPGj+O1V4zCt8asqjNuDZJhHlYnKiXKLekPmoFyQwRPNit2n7Mr34krATRk+KXGfjwPZPCYDz6iMedL+S+QqtKLIEV6xUgTbRu/e6ol4gXuL4b5rMq5hsaRiAKCjErXls2B9Xo6iuax6zGIeBSGwc5VY0JM9lD/GMGY5DRGwIDAQABAoIBAAIcRX33iX/W/4yWvaiZy6/kLVSW52avL5CI0+qFt8o2Dr+9pmicGpc6T4fko/sb4Wx9XPm6w8jjL6nj0GmyldtVG7cSBWKZN5P6vCVe0kAt22J9VpgZ8LOMahV8gj2AU0CRbfed2Pasfu2+GdZee1gSrv4S3YZ99iNTm0Ihre090lhEDvYeV4usBLrYxcubBWlWTYhKxfMtbwuH4IhmrSnsGdIocgTcaSztdjZ7Y8fKg2BOfdHtdFtBQg/ZnZK1XMj82ynKru9rOZ7T1q/+beaahJpJGE40WYRNVHCPZ5lfug4/+A1swjqS1jJ1pwP6P7LSFHnViKTEwJByokwvQsECgYEA7ieGwcOLTW5LCx9LOqEsCKYC0RuOdkr/yn37b9NV0P91zTan89fIP/4QCd0WwgXOaVfe9rHC8ugkhCtkZ5MAi8WcRiBTUl+klO7eIQB+KvzlkDrmaYxV5ItlWGXHRQrbSNnk5lThfFgseEcRzsRnw1g/iD27v3LOks1leUVbxaECgYEAxlKIxEkrNP2XSYutJ08+uj+3VAJeHAv6rg8ojDLj3SmufCrAi5Ps1VBYM6RhR38uTVmm9wM93/WqgoHsOmWXw4AG4efOWubKAAbODAbY6D//kgfn4tr+jQv+PYgRr6xbbfcUM602yl1/1tGz2KTdaAkWeTuOa+nFXu5hzqGaJTsCgYAKPJa1Q3N8a448NycjqQPch049sMKJ4SVnjcy9/MaGikSFAqFrgM3xujj0Q5WT124M5yMFVZS8ni/booXZUd9HIsJZ3U/XjZbkc/QGVSAXNvGjJnT6+nZCsZ80koNjO1k7o2oMYH+kuaGHtf5U9epD4kowz/5+9y9b7go7kTiloQKBgQCFFRll7luqIYoF9k7plAnZ3aveGgCg/YDokI97FSNHZBMMi3vNriQ9OL8XWHVXDwc5LLIYC/rXcPlMvnaQ8V+X9y+nJHCbG0fuIKLf+zBPGbMcgWWgG6i5aZTgIZEMu7JW5niN/OxJe9ivhOUUuf1BNOf5zndR/vtNKtZDXLodxQKBgDVUYjpFaNGoYuDTT8ra/Q5HFMiH9IsVpDuF+ignuwmUtOTBXau3NeiamVM+CxKCmko7Wq1tPW2V9qKaBBJf4WKcCGUhP+zs8+4C4Ii3Wu/xVRvd5HAxFdnJe6Cn1nk4stfOI1n11S1s+Gv40kNo//mOqAGqApqs0CaRUp+z6RGK" ], + "certificate" : [ "MIICnzCCAYcCBgGTUz4IBjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhkYXRhZmxvdzAeFw0yNDExMjIwOTM4MTRaFw0zNDExMjIwOTM5NTRaMBMxETAPBgNVBAMMCGRhdGFmbG93MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuH9aHqE59BqnpFp21vMCDkvFhr0t9bpsCpswJ7cHX+e9rtzgyTInKAiurqvWex1vkH1BmMhmU6dm7USDpYF/ktOfiNht8S4pKL5dJcejr3I/onPKw71X0JK2i/vPDqY4FLjP+u2k4z6VbJo1NFsxP9381/9oY4nVaajHkMS3H3OBgvaPGj+O1V4zCt8asqjNuDZJhHlYnKiXKLekPmoFyQwRPNit2n7Mr34krATRk+KXGfjwPZPCYDz6iMedL+S+QqtKLIEV6xUgTbRu/e6ol4gXuL4b5rMq5hsaRiAKCjErXls2B9Xo6iuax6zGIeBSGwc5VY0JM9lD/GMGY5DRGwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBh9l7vDQKCFsSGYExe5RfJ+dXcE8SP5Wksi85yY3MlGxHHSsG9iMF9mTbDYk0AVoZOUnpGf31aXgG4plOPmsWE+BurgL8LcE+kkLWcY7nQzNmxgpMXinaHNUbpk3omUaUlivElFK3kQjBauUIJecF1m6gDoE/LpBCkTy7JS4+kclk/VCLU+uHqMmpcumQezq0Sx/yHFz56dtIs/1/u3dkIiUaSFDEHNR6UgCuvYB4lVnO2XkTL4HP3S8jX3R5qbwvvrqC2SYO2Hp+XeP7GtmQdfbP7m9cCrnrw3Mt6Us4P7HeCjETR3sNr2SUrPBT5aX8VMrd40v1OT1loEtVIq1v2" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "663c3543-ad2a-4939-a3ea-d981c54df909", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "1044cd20-88b3-46c0-b0f7-8fb3ccce7b56" ], + "secret" : [ "LS2x8GZfakJOpWc2QzhzQR-E0XBFwh5UMER8SZTMMfCNZkgOCW60ND3JoH3yYn0wtof0WzTjrb5KJaYuUuum0Z0wImtvNVVtZKfmGl1G1z5s6MJO6sGXBeB5ULDWJK6YjvYGVSGu4pVyMgUMTbzPWU2lBb-_KLPjsaiK_Q_gOu4" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "3d4dc820-3aa6-49ce-9efa-825bcd63b14d", + "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" : "bb88ed4f-b322-4fd4-9ff0-507333118ce0", + "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" : "554f9696-3f2e-4f7a-b4a3-287205e175cc", + "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" : "32093cc9-f4ca-46fa-984c-feed52b50d0f", + "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" : "e1fbbe8e-d213-4ac5-be6f-ef0f1c14de41", + "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" : "943f2420-c69c-43aa-8a70-cf0cd45c533f", + "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" : "f8441c8e-500d-49ce-a953-94b43b6b4c34", + "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" : "46104f48-7396-4049-8213-05f64f672635", + "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" : "3da19f36-7857-4a85-8c1d-f463ed60b38a", + "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" : "63121b48-1a7b-4911-857b-4fa2963c3b4c", + "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" : "5c401bdd-c533-4be9-822c-79a5e611ea8b", + "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" : "718cd7d0-df1c-434f-b14a-f65eb10d4256", + "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" : "aabce211-5f39-4be4-82d0-7da7028e8a74", + "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" : "eea842a0-b4ba-4483-933b-46bd1872036f", + "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" : "07caeb32-26b5-4f7e-a316-b88f1a7396d0", + "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" : "c7b0bb0c-b239-478b-85e1-112b30921207", + "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" : "3eac1851-ae12-44b4-8300-f7fdb93e43ce", + "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" : "8be91df7-d95d-4bd3-a261-6d1a017cffc5", + "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" : "11dadb43-4fb5-49a1-b3a0-a907168482b9", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "76b7b055-a4ee-4094-b7d7-1f4fb9e4dbd5", + "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" : false, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : false, + "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", + "frontendUrl" : "", + "organizationsEnabled" : "false", + "acr.loa.map" : "{}" + }, + "keycloakVersion" : "25.0.6", + "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} \ No newline at end of file diff --git a/spring-cloud-dataflow-server/src/test/resources/dataflow-users-0.json b/spring-cloud-dataflow-server/src/test/resources/dataflow-users-0.json new file mode 100644 index 0000000000..497df10112 --- /dev/null +++ b/spring-cloud-dataflow-server/src/test/resources/dataflow-users-0.json @@ -0,0 +1,44 @@ +{ + "realm" : "dataflow", + "users" : [ { + "id" : "5156de66-37dc-4908-9108-c62ce8701f1f", + "username" : "joe", + "firstName" : "Joe", + "lastName" : "Soap", + "email" : "joe@soap.com", + "emailVerified" : true, + "createdTimestamp" : 1732268525809, + "enabled" : true, + "totp" : false, + "credentials" : [ { + "id" : "2b602938-1888-4923-9b95-28e18bd2d263", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1732268542192, + "secretData" : "{\"value\":\"qjtNPC4a52Yn8TZRlE5C79RsXAEteqFaQ1WSw/UMJFU=\",\"salt\":\"TV+2gSVHE/7D4pH3BvDL5A==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-dataflow" ], + "notBefore" : 0, + "groups" : [ "/dataflow-admin" ] + }, { + "id" : "2c0dd201-5e86-4e0f-97b6-f82604d215e8", + "username" : "service-account-dataflow", + "emailVerified" : false, + "createdTimestamp" : 1731498869096, + "enabled" : true, + "totp" : false, + "serviceAccountClientId" : "dataflow", + "credentials" : [ ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-dataflow" ], + "clientRoles" : { + "dataflow" : [ "uma_protection" ] + }, + "notBefore" : 0, + "groups" : [ ] + } ] +} \ No newline at end of file diff --git a/src/local/README.md b/src/local/README.md index db8a30f1fd..34b646c8d4 100644 --- a/src/local/README.md +++ b/src/local/README.md @@ -12,11 +12,38 @@ Downloads all applications needed by `create-containers.sh` from Maven repositor Usage: `download-apps.sh [version]` * `version` is the dataflow-server version like `2.10.3`. Default is `2.11.3-SNAPSHOT` -## `create-containers.sh` -Creates all containers and pushes to local docker registry. +## `launch-dataflow.sh` +Uses docker compose to launch a database, broker, skipper and dataflow server. -This script requires [jib-cli](https://github.com/GoogleContainerTools/jib/tree/master/jib-cli) +## `launch-with-keycloak.sh` +Uses docker compose to launch a database, broker, skipper and dataflow server and a Keycloak server that loads the `dataflow` realm from `./src/local/data` which define a single user named `joe` with password `password` -Usage: `create-containers.sh [version] [jre-version]` -* `version` is the dataflow-server version like `2.9.6`. Default is `2.11.3-SNAPSHOT` -* `jre-version` should be one of 11, 17. Default is 11 +## `stop-dataflow.sh` +Stops docker-compose and all running Java instances based on the pid files. + +## `launch-keycloak.sh` +Launches standalone Keycloak and loads the dataflow realm from `./src/local/data` which define a single user named `joe` with password `password` + +## `tail-container-log.sh` +Finds a container with provided name and tails the stdout of the container. + +## Testing with Keycloak +### Build with Java 17 +```shell +./mvnw clean install -am -pl :spring-cloud-dataflow-server -DskipTests -Dmaven.javadoc.skip=true -T 1C +``` +### Execute: +```shell +./src/local/launch-keycloak.sh +``` + +### Debug +Module: `spring-cloud-dataflow-server` +Class: `org.springframework.cloud.dataflow.server.single.DataFlowServerApplication` +Arguments: `--spring.cloud.dataflow.features.streams-enabled=false --spring.cloud.dataflow.features.tasks-enabled=true --spring.cloud.dataflow.features.schedules-enabled=false --spring.config.additional-location="$ProjectFileDir$/src/local/application-dataflow-keycloak.yaml"` + +### Run + +```shell +java -jar spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-3.0.0-SNAPSHOT.jar --spring.cloud.dataflow.features.streams-enabled=false --spring.cloud.dataflow.features.tasks-enabled=true --spring.cloud.dataflow.features.schedules-enabled=false --spring.config.additional-location="src/local/application-dataflow-keycloak.yaml" +``` \ No newline at end of file diff --git a/src/local/application-dataflow-keycloak.yaml b/src/local/application-dataflow-keycloak.yaml new file mode 100644 index 0000000000..c0e265fbdd --- /dev/null +++ b/src/local/application-dataflow-keycloak.yaml @@ -0,0 +1,51 @@ +spring: + cloud: + dataflow: + security: + authorization: + provider-role-mappings: + keycloak: + map-group-claims: false + map-oauth-scopes: false + role-mappings: + ROLE_VIEW: dataflow_view + ROLE_CREATE: dataflow_create + ROLE_MANAGE: dataflow_manage + ROLE_DEPLOY: dataflow_deploy + ROLE_DESTROY: dataflow_destroy + ROLE_MODIFY: dataflow_modify + ROLE_SCHEDULE: dataflow_schedule + security: + oauth2: + client: + provider: + keycloak: + issuer-uri: 'http://localhost:8080/realms/dataflow' + jwk-set-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/certs' + token-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/token' + user-info-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/userinfo' + user-name-attribute: 'user_name' + authorization-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/auth' + registration: + keycloak: + redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' + client-id: 'dataflow' + client-name: 'dataflow' + # aligns with the realm imported from the data directory + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + provider: 'keycloak' + authorization-grant-type: 'authorization_code' + scope: + - openid + - roles + resourceserver: + opaquetoken: + introspection-uri: http://localhost:8080/realms/dataflow/protocol/openid-connect/token/introspect + client-id: 'dataflow' + # aligns with the realm imported from the data directory + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + +logging: + level: + org.springframework.security: DEBUG + \ No newline at end of file diff --git a/src/local/application-skipper-keycloak.yaml b/src/local/application-skipper-keycloak.yaml new file mode 100644 index 0000000000..93a5f96e54 --- /dev/null +++ b/src/local/application-skipper-keycloak.yaml @@ -0,0 +1,46 @@ +spring: + cloud: + skipper: + security: + authorization: + provider-role-mappings: + keycloak: + map-group-claims: false + map-oauth-scopes: false + role-mappings: + ROLE_VIEW: dataflow_view + ROLE_CREATE: dataflow_create + ROLE_MANAGE: dataflow_manage + ROLE_DEPLOY: dataflow_deploy + ROLE_DESTROY: dataflow_destroy + ROLE_MODIFY: dataflow_modify + ROLE_SCHEDULE: dataflow_schedule + security: + oauth2: + client: + provider: + keycloak: + issuer-uri: 'http://localhost:8080/realms/dataflow' + jwk-set-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/certs' + token-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/token' + user-info-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/userinfo' + user-name-attribute: 'user_name' + authorization-uri: 'http://localhost:8080/realms/dataflow/protocol/openid-connect/auth' + registration: + keycloak: + redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}' + client-id: 'dataflow' + client-name: 'dataflow' + # aligns with the realm imported from the data directory + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' + provider: 'keycloak' + authorization-grant-type: 'authorization_code' + scope: + - openid + - roles + resourceserver: + opaquetoken: + introspection-uri: http://localhost:8080/realms/dataflow/protocol/openid-connect/token/introspect + client-id: 'dataflow' + # aligns with the realm imported from the data directory + client-secret: '090RucamvekrMLyGHMr4lkHX9xhAlsqK' diff --git a/src/local/container-id.sh b/src/local/container-id.sh new file mode 100755 index 0000000000..7c265abe0e --- /dev/null +++ b/src/local/container-id.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if [ "$1" == "" ]; then + echo "Usage " + exit 1 +fi +ID=$(docker ps --filter "name=$1" --format "{{.ID}}") +echo "$ID" \ No newline at end of file diff --git a/src/local/create-containers.sh b/src/local/create-containers.sh deleted file mode 100755 index 79b3d4460a..0000000000 --- a/src/local/create-containers.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash -if [ -z "$BASH_VERSION" ]; then - echo "This script requires Bash. Use: bash $0 $*" - exit 0 -fi -SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") -SCDIR=$(realpath $SCDIR) -ROOT_DIR=$(realpath $SCDIR/../..) - -# set to specific version -if [ "$1" != "" ]; then - TAG=$1 -else - TAG=2.11.3-SNAPSHOT -fi -if [ "$2" != "" ]; then - v=$2 -else - v=17 -fi -PROCESSOR=$(uname -p) -# export ARCH=arm64v8 for ARM64 image -if [ "$ARCH" == "" ]; then - case $PROCESSOR in - "x86_64") - ARCH=amd64 - ;; - *) - if [[ "$PROCESSOR" == *"arm"* ]]; then - ARCH=arm64v8 - fi - ;; - esac -fi -CRED= -if [ "$DOCKER_USERNAME" != "" ]; then - echo "Using $DOCKER_USERNAME for docker.io" - CRED="--from-username=$DOCKER_USERNAME --from-password=$DOCKER_PASSWORD" -fi -# set with extra option for buildpacks. BP_OPTIONS= -IMAGE="$ARCH/eclipse-temurin:$v-jdk-jammy" -APPS=("spring-cloud-dataflow-server" "spring-cloud-dataflow-composed-task-runner" "spring-cloud-dataflow-single-step-batch-job") -for app in ${APPS[@]}; do - APP_PATH="$ROOT_DIR/$app/target" - if [ ! -f "$APP_PATH/$app-$TAG.jar" ]; then - echo "Cannot find $APP_PATH/$app-$TAG.jar download using download-apps.sh or build using ./mvnw install" - exit 1 - fi - jib jar --from=$IMAGE $CRED --target=docker://springcloud/$app:$TAG $APP_PATH/$app-$TAG.jar - # docker tag springcloud/$app:$TAG springcloud/$app:$ARCH -done -TS_APPS=("spring-cloud-dataflow-tasklauncher-sink-kafka" "spring-cloud-dataflow-tasklauncher-sink-rabbit") -for app in ${TS_APPS[@]}; do - APP_PATH="$ROOT_DIR/spring-cloud-dataflow-tasklauncher/$app/target" - if [ ! -f "$APP_PATH/$app-$TAG.jar" ]; then - echo "Cannot find $APP_PATH/$app-$TAG.jar download using download-apps.sh or build using ./mvnw install" - exit 1 - fi - jib jar --from=$IMAGE $CRED --target=docker://springcloud/$app:$TAG $APP_PATH/$app-$TAG.jar -done - -pushd $ROOT_DIR >/dev/null -docker build -t springcloud/spring-cloud-dataflow-prometheus-local:$TAG src/grafana/prometheus/docker/prometheus-local -popd >/dev/null diff --git a/src/local/data/dataflow-realm.json b/src/local/data/dataflow-realm.json new file mode 100644 index 0000000000..551580a2f2 --- /dev/null +++ b/src/local/data/dataflow-realm.json @@ -0,0 +1,2057 @@ +{ + "id" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "realm" : "dataflow", + "displayName" : "", + "displayNameHtml" : "", + "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" : "none", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : false, + "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" : "d58ec37e-955b-4dd1-88b6-749cc2eac653", + "name" : "ADMIN", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "73317621-0f5c-4c10-a7bb-907e789a966e", + "name" : "dataflow_deploy", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "d239b6bf-1426-41a6-bea0-cb27f65ee56f", + "name" : "dataflow_schedule", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "ca1016ba-3ffc-45a6-8b9d-c00c1ebafb56", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "90d84348-835c-413f-a815-fc8a444a8d9e", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "c92d02b3-a184-44ce-bb2f-10aecf82a04c", + "name" : "dataflow_create", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "bc22a2ea-b505-4fa4-a9ac-8a7610fb4400", + "name" : "dataflow_view", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "c13395f0-4a1d-4be5-af25-6202cfc75428", + "name" : "dataflow_modify", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "276259e7-d971-4972-8656-102b2575846e", + "name" : "dataflow_manage", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "ed54ea38-493d-4def-a9a7-57fa56813c61", + "name" : "default-roles-dataflow", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "view-profile", "manage-account" ] + } + }, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + }, { + "id" : "fe469ec1-eb24-422b-9492-f9e2ffa47f85", + "name" : "dataflow_destroy", + "description" : "", + "composite" : false, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "3d3d4b18-bd9d-4c23-a830-eed83709335f", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "ea4a2541-7fd3-4c6a-8aa7-aa87631d1ca3", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "ca17f224-727c-42dc-a4da-c1c01f6a872a", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "0ecf1006-86e7-48f1-87c3-9bd931e1aae2", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "11e3cd98-f893-47fd-8310-d7a3aa4c65dd", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "f5470f88-bed6-4044-a0d0-e8c665efee65", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "manage-users", "view-identity-providers", "view-events", "query-users", "manage-authorization", "view-realm", "view-users", "query-clients", "view-authorization", "manage-events", "manage-realm", "query-realms", "create-client", "query-groups", "manage-clients", "manage-identity-providers", "view-clients", "impersonation" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "c24ba356-b344-405e-93b0-a2b2c9dc38a7", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "3ab018c0-85cf-4169-8478-86d433c37d07", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-users", "query-groups" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "9cd5b2aa-307c-4b72-adc5-7bb023e11a44", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "fbc0d3d9-ec05-4b69-93c1-92fc01ede9b1", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "68b7dd08-272b-459d-bcef-df971e671e1b", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "0f0229ba-080b-4c23-a389-e14b0c6a9613", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "e2144b8e-b4f3-49d6-8602-a994f8f181e9", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "2798859b-3fcb-432e-8123-4c99b7dc999e", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "93d898fd-b702-4dc5-bfcd-dff76fec9ec6", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "eeb68873-9bd5-4905-828b-0c160295add7", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "d9cc3611-31f8-426e-bee7-988a256ed043", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "efd69870-1ae3-4b0a-acc3-a8b6d5d4c0c8", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + }, { + "id" : "449263f4-9e69-47c4-a94a-6733952f6d75", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "attributes" : { } + } ], + "dataflow" : [ { + "id" : "90a8c46b-c91d-467f-9af1-1d7c13b60122", + "name" : "ADMIN", + "description" : "", + "composite" : false, + "clientRole" : true, + "containerId" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "attributes" : { } + }, { + "id" : "2d6698f6-1260-47cc-9836-85d86d1536d3", + "name" : "uma_protection", + "composite" : false, + "clientRole" : true, + "containerId" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "3053579b-49cd-4311-96ff-70db3facd0cb", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "41f5e232-c5fd-40c2-ac0a-15df0ef36bdf", + "attributes" : { } + } ], + "account" : [ { + "id" : "0f3f48f0-7396-4296-93cf-55e509137f95", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "cc9b7a19-9a0b-47ae-b5eb-ed440c6753cf", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "da16948e-6eb8-4441-9076-1231a09a6e55", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "babf7894-3c07-445c-b9b9-ab5587c1902e", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "3ccbb748-9087-475e-87d5-b46ca6f0d771", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "1af0d267-dd3e-47a1-8347-d1b88ab69729", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "23b3fa11-a18e-4eff-9d20-e51a1b0ccae9", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + }, { + "id" : "6d3be4d5-a6d6-4d48-b9e3-26b7a7e994f4", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "attributes" : { } + } ] + } + }, + "groups" : [ { + "id" : "60ccd51e-1b2d-4510-9afb-da23ebe165d6", + "name" : "dataflow-admin", + "path" : "/dataflow-admin", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "dataflow_deploy", "dataflow_schedule", "dataflow_view", "dataflow_create", "dataflow_modify", "dataflow_manage", "dataflow_destroy" ], + "clientRoles" : { + "dataflow" : [ "uma_protection" ] + } + } ], + "defaultRole" : { + "id" : "ed54ea38-493d-4def-a9a7-57fa56813c61", + "name" : "default-roles-dataflow", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "533d19e2-6dc2-465d-a390-367d6c2221ce" + }, + "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" : [ ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "793e6cf2-6397-4d26-bac9-02c76974ca5b", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dataflow/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dataflow/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" : "72dabab7-ef11-4392-8064-bab95d3e660b", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dataflow/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dataflow/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" : "e4bd267e-1d8c-485a-8365-bb6bcf203a10", + "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" : "0a29e3d0-b8d7-4899-a8dc-ab4911f1fb10", + "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" : "41f5e232-c5fd-40c2-ac0a-15df0ef36bdf", + "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" : "0b880d31-1c5c-4fe4-9b57-7b2f0c98b30f", + "clientId" : "dataflow", + "name" : "${client_account}", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : true, + "clientAuthenticatorType" : "client-secret", + "secret" : "090RucamvekrMLyGHMr4lkHX9xhAlsqK", + "redirectUris" : [ "http://localhost:9393/*" ], + "webOrigins" : [ "" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled" : true, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1731500243", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "+", + "display.on.consent.screen" : "false", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "f4847976-7ee7-4f91-86dd-3cfad2a017a5", + "name" : "Username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "lightweight.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "user_name", + "jsonType.label" : "String" + } + }, { + "id" : "b461e8d8-84da-4ae9-b927-a03944f499a0", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "multivalued" : "true", + "userinfo.token.claim" : "false", + "user.attribute" : "foo", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String" + } + }, { + "id" : "8f3ea527-380a-40ca-ad03-4a3cfbf720e0", + "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" + } + }, { + "id" : "67467aa3-49a2-499d-841a-ebeff48bc24e", + "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" : "30a46803-933c-4938-8528-f2bee2991463", + "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" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "roles", "profile", "basic", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings" : { + "allowRemoteResourceManagement" : true, + "policyEnforcementMode" : "ENFORCING", + "resources" : [ { + "name" : "Default Resource", + "type" : "urn:dataflow:resources:default", + "ownerManagedAccess" : false, + "attributes" : { }, + "uris" : [ "/*" ] + } ], + "policies" : [ ], + "scopes" : [ ], + "decisionStrategy" : "UNANIMOUS" + } + }, { + "id" : "64ed9392-6a67-4c00-bdba-1ae059b1151b", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "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" : "61c009a1-8183-49d8-b680-100e4329d804", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/dataflow/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/dataflow/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" : "df4e00b7-2665-4adc-8062-ed8c4f6c4845", + "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" ] + } ], + "clientScopes" : [ { + "id" : "dd7788e5-74ff-41c4-bd4d-3802b712b285", + "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" : "e2bb61c5-b64c-446a-8e4d-3579931786f1", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + } ] + }, { + "id" : "15127dc5-a81f-438a-93f9-046b33a5e4bb", + "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" : "9bd80e49-8798-4ebe-bfab-a61e34c2177a", + "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" : "bc758953-016a-4564-b77a-5e80234504af", + "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" : "066f78cc-5f57-4a9b-b859-613af59ce403", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "4c9653de-13bf-4ccb-883e-d8cd8a5b071f", + "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" : "0b6564ce-607e-4f75-83d4-257ccbf0565e", + "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" : "c44f05ff-959e-425c-8bc5-c55fdabba209", + "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" : "08df5e8d-1bc7-48eb-9171-f9d9701ba9ae", + "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" : "703981fc-3beb-4db1-b3f6-572d55758f87", + "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" : "b4740fe4-ba83-445e-ad33-225c2a6d6251", + "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" : "ddffeac0-c4d5-4f46-bd2c-621b7c58601f", + "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" : "cdb889ec-3a18-4da7-a87e-79e4e3c4d06a", + "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" : "890daab1-52a9-492f-899d-0e139f89924e", + "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" : "47520142-2275-4d24-ad1f-885caf3fb386", + "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" : "62b31d2e-282c-421b-b3a4-a34abcaaa578", + "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" : "30081984-75d5-4593-adda-eb350f463d0c", + "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" : "3ac14257-edd7-4cda-95c5-33c3ffaaa732", + "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" : "4af4aee0-ae10-4e55-94c6-36d65327466d", + "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" : "6aa38d97-94b9-4578-8cf9-44f1c0483ed7", + "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" : "c024d9ce-10ac-4965-8eb4-750f6e4ad489", + "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" : "737a228d-e448-4a65-a1cc-dfdbf314f81b", + "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" : "1478fd20-c2e1-4e49-9679-d139fa7b087d", + "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" : "95f90de9-7071-4eb0-bb6c-a6178b8236d0", + "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" : "105c0a33-ba95-43c9-b66a-11d91fb4ea25", + "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" : "68aa3586-e241-4401-a206-54f6f708459d", + "name" : "sub", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-sub-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + } ] + }, { + "id" : "0d59f7b0-287d-4144-890f-606cd4c2f8ff", + "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" : "5e85384a-cb15-421f-8227-9a7834b399ac", + "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" : "6fc655fe-ecaf-429b-8196-3194ddf003d9", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { + "access.token.claim" : "true", + "introspection.token.claim" : "true" + } + }, { + "id" : "9b42d818-be9e-4d57-bf58-510162ee65b0", + "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" : "188181b2-6767-4ae4-af70-5710007f6419", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "d5e22c70-c9b9-42d4-a574-06ae98103138", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "3f2d3d67-696b-45a2-bfd0-078b0f884846", + "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" : "05b3a9ae-ab8f-456e-b52b-e3b9f35485d7", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + }, { + "id" : "9fcb562a-dc02-47b6-acfc-0649715394af", + "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" : "6d7492ec-e6a7-491f-a295-0a2185a04345", + "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" : "cce1f2e3-54dc-4395-b936-367512edef2f", + "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" : "a98b3a04-9e59-406b-84ea-38fd547ff99b", + "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" : "2187bd2c-f2aa-4980-b7bd-3dc249d64997", + "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" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "roles", "profile", "role_list", "acr", "email", "basic", "web-origins" ], + "defaultOptionalClientScopes" : [ "offline_access", "phone", "microprofile-jwt", "address" ], + "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" : "b5c7aa4b-20b2-4d8f-a37c-94aca4210907", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "58eac984-08c6-44eb-aca7-908bb2d605c5", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "1378f56e-5fc6-4a9b-a186-635379a76a47", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper" ] + } + }, { + "id" : "62d0ec0d-e35e-47e8-8970-886919cb883a", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "2108fb8f-44db-4ce1-b0c9-28ef3c68c429", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ], + "allowed-client-scopes" : [ "email", "roles", "role_list", "profile" ] + } + }, { + "id" : "4336c077-e19a-4f01-b6d6-f2a143ac80b6", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper" ] + } + }, { + "id" : "00b141c9-3fef-4e1d-91c6-45278333e7c7", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "8c1796b5-42e3-4d4f-9f80-5db3c278c8e7", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "f8d38b52-292b-43b7-8aa4-dcd5bba266c8", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEoQIBAAKCAQEA1DBCq/0XlOCki1yQHsFd3Pzr25QkqKxYJRQypp0OcolHqeR5l8WQQmtTOpj72ssw3QBxcdQ0mOj27JvylVse7RNBDs69FQm+sELZflvGGi3pg356ioAjZs0wMaryLvcg0pv2cuOJJdx66JwgnE2/NwFFfNTiu56fGmGql75C4j/+zK4UC5tWFIwfEipZxbAE5TM0XlkQWxycRYjkNTK8EsdssFK7kY0EwTX4y2neDa/A7jEsDpOAHLFl/sajkPppeO42TVxGH5QKU4F/rOmHIfvZhxNzL3m5w4+UUQZSvFZGhfTwBTT1qV/ld/NLE+8cU9cjeoN+mVcs543O0OgLzQIDAQABAoIBABDQ5vpuEJLeFMbt+zFSHh1ii/yhv8qq/JdVA53xtNCTRvMqELrcT45RUXjDjAjZxpG/3xMS1WedkDLN5HU9Z0o0QZkp/ZEvwwWBXsQ6rgyqwSazJ4SsxWF4dyPQij36Rtx6EMIn0dmGy39+HsApvIg1mRYHYcAAa60xuqJ+U8WjVfqMQ0Lx1ciXCcFXfURQ4d8MRqMEZ61oTpbKbB767VN2RCW0YJvoub5tOe7ZCPfayEpqfRF65rMoZfCYoLytuB8Ke5tKy2xisvO/5lATCDYop6Yrb4VniHWV0rk+o4g/kEFxN1gKZx5nS/rn1Lecj6w01IR+po5yjhdNtIEayPECgYEA/hhXQ9A9HB0bHpuBx4G/gE5Gy0cJOyuKHO8rJNUaZQ1BYy3w7C/DK8meCJXvS63Fs8+N2GTMk3bySsQyxmN/FFze5oyHYYQ9zffuF90Ii4YTiCdZgwpRlq0IB7386dxGy5B0EjL+A3QXd64PdAZPADJo18Swlk7UhKxN9uy0vZUCgYEA1cd+FOf9l4VthKNzSMsAReWn33o/6087rs5o14xe8JqipwGYqWgt+JY/r0Zg3C64MCNbIqNtr4SHabbGXnbw+JbRVM7qsV62mqzYN+mTCuEXbFXnxp5fa/Cam9vgZ2CiiNVoxkwrLLDt2WbT9n6O1iBvy9aG9VkNrO3ZyHTy11kCf0KAHFajKVsyQua/zDdqvbPWyLBq5v+VZZAtCB2bqEzKK1LJs0QdO/c5zSJyGy6zTArDR1xbBS+S8dafgqppX9j0dWHhZY0gDwzY1ndoYdQiQvpfUg35pWDJ6FAeaRLLk7uzEq2wqso8l+e6plC3VfW3O7k8wPqVpwkSD1WQnb0CgYAJ2eOJexdIgDGHxzBszk346phNyAhiA4iwiXpzVFibpcSRBZXPWKmlpubQYOHdw5lhPn/YnMdVKzpCONXzTG/WRLzot5BBFCg+AHEGQpEwEydNKrg/gtTK2I+HVx6EJQPYYl0tphznNk//kKl71mEmpOAB+KTHcY8bxOogPqNiIQKBgQCZ6q653cgA8x3H9ka2bAOejHhUUlEPm7vFh1svi3HWku03iSAvW80Pjh3HxARuVC9xdbFfh5WJue6SC39dHoxAeoBfjQAuYrFuhha719ra7umnuEAe5J8H6ZCVngkWbdLzw/lGwMS3+jzFLbuBO9+v0S+jy9EJXWfW2CcXqsxsxA==" ], + "certificate" : [ "MIICnzCCAYcCBgGTUz4GtDANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhkYXRhZmxvdzAeFw0yNDExMjIwOTM4MTRaFw0zNDExMjIwOTM5NTRaMBMxETAPBgNVBAMMCGRhdGFmbG93MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1DBCq/0XlOCki1yQHsFd3Pzr25QkqKxYJRQypp0OcolHqeR5l8WQQmtTOpj72ssw3QBxcdQ0mOj27JvylVse7RNBDs69FQm+sELZflvGGi3pg356ioAjZs0wMaryLvcg0pv2cuOJJdx66JwgnE2/NwFFfNTiu56fGmGql75C4j/+zK4UC5tWFIwfEipZxbAE5TM0XlkQWxycRYjkNTK8EsdssFK7kY0EwTX4y2neDa/A7jEsDpOAHLFl/sajkPppeO42TVxGH5QKU4F/rOmHIfvZhxNzL3m5w4+UUQZSvFZGhfTwBTT1qV/ld/NLE+8cU9cjeoN+mVcs543O0OgLzQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDQTeMN/RP+6O5YkUTAcjClcO+IBYIMuNW3Muqm8j4X2T9QJ9Fi17cDt6uqmcgFuRxoBnvxI/zd9ct47MQi5c+XeBMiv5Pb+/Pe2CWZA3N5dUsw9ieqnOkcK/o6UdqiRL3u89fZBPFgFVFO7NLZGqphndWKoIB3a359GKORDkBUc7W1O2u1KJQ9tbn7nsqudr/Twv4OkNfqPcq/qSCLMLYwB0uuspoADC5daZdyNucTkCXJuBOu/A3ejd0CYBPlFuX8o2kBbjeV5Md4h/OVcRVvTsYW5N4b/0D6arp+PSVSZpX39PqgasQF7LAOZgf8ryYDxrPuqui5IsVMeR0dtAMP" ], + "priority" : [ "100" ] + } + }, { + "id" : "9c91c645-71be-4605-ae55-d5e8f33d0021", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a8058942-eced-4429-92ba-1b840eb8038f" ], + "secret" : [ "yKmq3CM-DxvipKeoHzS2wg" ], + "priority" : [ "100" ] + } + }, { + "id" : "eaffb764-adc5-4954-a1ff-9cb4b745e7ad", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAuH9aHqE59BqnpFp21vMCDkvFhr0t9bpsCpswJ7cHX+e9rtzgyTInKAiurqvWex1vkH1BmMhmU6dm7USDpYF/ktOfiNht8S4pKL5dJcejr3I/onPKw71X0JK2i/vPDqY4FLjP+u2k4z6VbJo1NFsxP9381/9oY4nVaajHkMS3H3OBgvaPGj+O1V4zCt8asqjNuDZJhHlYnKiXKLekPmoFyQwRPNit2n7Mr34krATRk+KXGfjwPZPCYDz6iMedL+S+QqtKLIEV6xUgTbRu/e6ol4gXuL4b5rMq5hsaRiAKCjErXls2B9Xo6iuax6zGIeBSGwc5VY0JM9lD/GMGY5DRGwIDAQABAoIBAAIcRX33iX/W/4yWvaiZy6/kLVSW52avL5CI0+qFt8o2Dr+9pmicGpc6T4fko/sb4Wx9XPm6w8jjL6nj0GmyldtVG7cSBWKZN5P6vCVe0kAt22J9VpgZ8LOMahV8gj2AU0CRbfed2Pasfu2+GdZee1gSrv4S3YZ99iNTm0Ihre090lhEDvYeV4usBLrYxcubBWlWTYhKxfMtbwuH4IhmrSnsGdIocgTcaSztdjZ7Y8fKg2BOfdHtdFtBQg/ZnZK1XMj82ynKru9rOZ7T1q/+beaahJpJGE40WYRNVHCPZ5lfug4/+A1swjqS1jJ1pwP6P7LSFHnViKTEwJByokwvQsECgYEA7ieGwcOLTW5LCx9LOqEsCKYC0RuOdkr/yn37b9NV0P91zTan89fIP/4QCd0WwgXOaVfe9rHC8ugkhCtkZ5MAi8WcRiBTUl+klO7eIQB+KvzlkDrmaYxV5ItlWGXHRQrbSNnk5lThfFgseEcRzsRnw1g/iD27v3LOks1leUVbxaECgYEAxlKIxEkrNP2XSYutJ08+uj+3VAJeHAv6rg8ojDLj3SmufCrAi5Ps1VBYM6RhR38uTVmm9wM93/WqgoHsOmWXw4AG4efOWubKAAbODAbY6D//kgfn4tr+jQv+PYgRr6xbbfcUM602yl1/1tGz2KTdaAkWeTuOa+nFXu5hzqGaJTsCgYAKPJa1Q3N8a448NycjqQPch049sMKJ4SVnjcy9/MaGikSFAqFrgM3xujj0Q5WT124M5yMFVZS8ni/booXZUd9HIsJZ3U/XjZbkc/QGVSAXNvGjJnT6+nZCsZ80koNjO1k7o2oMYH+kuaGHtf5U9epD4kowz/5+9y9b7go7kTiloQKBgQCFFRll7luqIYoF9k7plAnZ3aveGgCg/YDokI97FSNHZBMMi3vNriQ9OL8XWHVXDwc5LLIYC/rXcPlMvnaQ8V+X9y+nJHCbG0fuIKLf+zBPGbMcgWWgG6i5aZTgIZEMu7JW5niN/OxJe9ivhOUUuf1BNOf5zndR/vtNKtZDXLodxQKBgDVUYjpFaNGoYuDTT8ra/Q5HFMiH9IsVpDuF+ignuwmUtOTBXau3NeiamVM+CxKCmko7Wq1tPW2V9qKaBBJf4WKcCGUhP+zs8+4C4Ii3Wu/xVRvd5HAxFdnJe6Cn1nk4stfOI1n11S1s+Gv40kNo//mOqAGqApqs0CaRUp+z6RGK" ], + "certificate" : [ "MIICnzCCAYcCBgGTUz4IBjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhkYXRhZmxvdzAeFw0yNDExMjIwOTM4MTRaFw0zNDExMjIwOTM5NTRaMBMxETAPBgNVBAMMCGRhdGFmbG93MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuH9aHqE59BqnpFp21vMCDkvFhr0t9bpsCpswJ7cHX+e9rtzgyTInKAiurqvWex1vkH1BmMhmU6dm7USDpYF/ktOfiNht8S4pKL5dJcejr3I/onPKw71X0JK2i/vPDqY4FLjP+u2k4z6VbJo1NFsxP9381/9oY4nVaajHkMS3H3OBgvaPGj+O1V4zCt8asqjNuDZJhHlYnKiXKLekPmoFyQwRPNit2n7Mr34krATRk+KXGfjwPZPCYDz6iMedL+S+QqtKLIEV6xUgTbRu/e6ol4gXuL4b5rMq5hsaRiAKCjErXls2B9Xo6iuax6zGIeBSGwc5VY0JM9lD/GMGY5DRGwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBh9l7vDQKCFsSGYExe5RfJ+dXcE8SP5Wksi85yY3MlGxHHSsG9iMF9mTbDYk0AVoZOUnpGf31aXgG4plOPmsWE+BurgL8LcE+kkLWcY7nQzNmxgpMXinaHNUbpk3omUaUlivElFK3kQjBauUIJecF1m6gDoE/LpBCkTy7JS4+kclk/VCLU+uHqMmpcumQezq0Sx/yHFz56dtIs/1/u3dkIiUaSFDEHNR6UgCuvYB4lVnO2XkTL4HP3S8jX3R5qbwvvrqC2SYO2Hp+XeP7GtmQdfbP7m9cCrnrw3Mt6Us4P7HeCjETR3sNr2SUrPBT5aX8VMrd40v1OT1loEtVIq1v2" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "663c3543-ad2a-4939-a3ea-d981c54df909", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "1044cd20-88b3-46c0-b0f7-8fb3ccce7b56" ], + "secret" : [ "LS2x8GZfakJOpWc2QzhzQR-E0XBFwh5UMER8SZTMMfCNZkgOCW60ND3JoH3yYn0wtof0WzTjrb5KJaYuUuum0Z0wImtvNVVtZKfmGl1G1z5s6MJO6sGXBeB5ULDWJK6YjvYGVSGu4pVyMgUMTbzPWU2lBb-_KLPjsaiK_Q_gOu4" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "3d4dc820-3aa6-49ce-9efa-825bcd63b14d", + "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" : "bb88ed4f-b322-4fd4-9ff0-507333118ce0", + "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" : "554f9696-3f2e-4f7a-b4a3-287205e175cc", + "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" : "32093cc9-f4ca-46fa-984c-feed52b50d0f", + "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" : "e1fbbe8e-d213-4ac5-be6f-ef0f1c14de41", + "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" : "943f2420-c69c-43aa-8a70-cf0cd45c533f", + "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" : "f8441c8e-500d-49ce-a953-94b43b6b4c34", + "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" : "46104f48-7396-4049-8213-05f64f672635", + "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" : "3da19f36-7857-4a85-8c1d-f463ed60b38a", + "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" : "63121b48-1a7b-4911-857b-4fa2963c3b4c", + "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" : "5c401bdd-c533-4be9-822c-79a5e611ea8b", + "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" : "718cd7d0-df1c-434f-b14a-f65eb10d4256", + "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" : "aabce211-5f39-4be4-82d0-7da7028e8a74", + "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" : "eea842a0-b4ba-4483-933b-46bd1872036f", + "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" : "07caeb32-26b5-4f7e-a316-b88f1a7396d0", + "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" : "c7b0bb0c-b239-478b-85e1-112b30921207", + "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" : "3eac1851-ae12-44b4-8300-f7fdb93e43ce", + "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" : "8be91df7-d95d-4bd3-a261-6d1a017cffc5", + "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" : "11dadb43-4fb5-49a1-b3a0-a907168482b9", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "76b7b055-a4ee-4094-b7d7-1f4fb9e4dbd5", + "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" : false, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : false, + "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", + "frontendUrl" : "", + "organizationsEnabled" : "false", + "acr.loa.map" : "{}" + }, + "keycloakVersion" : "25.0.6", + "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} \ No newline at end of file diff --git a/src/local/data/dataflow-users-0.json b/src/local/data/dataflow-users-0.json new file mode 100644 index 0000000000..497df10112 --- /dev/null +++ b/src/local/data/dataflow-users-0.json @@ -0,0 +1,44 @@ +{ + "realm" : "dataflow", + "users" : [ { + "id" : "5156de66-37dc-4908-9108-c62ce8701f1f", + "username" : "joe", + "firstName" : "Joe", + "lastName" : "Soap", + "email" : "joe@soap.com", + "emailVerified" : true, + "createdTimestamp" : 1732268525809, + "enabled" : true, + "totp" : false, + "credentials" : [ { + "id" : "2b602938-1888-4923-9b95-28e18bd2d263", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1732268542192, + "secretData" : "{\"value\":\"qjtNPC4a52Yn8TZRlE5C79RsXAEteqFaQ1WSw/UMJFU=\",\"salt\":\"TV+2gSVHE/7D4pH3BvDL5A==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-dataflow" ], + "notBefore" : 0, + "groups" : [ "/dataflow-admin" ] + }, { + "id" : "2c0dd201-5e86-4e0f-97b6-f82604d215e8", + "username" : "service-account-dataflow", + "emailVerified" : false, + "createdTimestamp" : 1731498869096, + "enabled" : true, + "totp" : false, + "serviceAccountClientId" : "dataflow", + "credentials" : [ ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-dataflow" ], + "clientRoles" : { + "dataflow" : [ "uma_protection" ] + }, + "notBefore" : 0, + "groups" : [ ] + } ] +} \ No newline at end of file diff --git a/src/local/docker-compose-keycloak.yml b/src/local/docker-compose-keycloak.yml new file mode 100644 index 0000000000..33958647f3 --- /dev/null +++ b/src/local/docker-compose-keycloak.yml @@ -0,0 +1,21 @@ +services: + + keycloak: + profiles: + - keycloak + image: keycloak/keycloak:25.0 + container_name: oauth + command: start-dev --import-realm --verbose + environment: + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + KC_DB: mariadb + KC_DB_URL: 'jdbc:mariadb://mariadb:3306/dataflow' + KC_DB_USERNAME: 'root' + KC_DB_PASSWORD: 'yourpassword' + KC_HOSTNAME: 'localhost' + ports: + - 8080:8080 + - 9000:9000 + volumes: + - ${SCDIR}/data:/opt/keycloak/data/import \ No newline at end of file diff --git a/src/local/docker-compose.yml b/src/local/docker-compose.yml index 5233d6fc9a..b60506c63c 100644 --- a/src/local/docker-compose.yml +++ b/src/local/docker-compose.yml @@ -1,23 +1,3 @@ -version: '3' -## This compose file only starts database and messaging so that dataflow can be executed locally. -# Configuration environment variables: -# - SKIPPER_VERSION specify what Skipper image versions to use. -# - STREAM_APPS_URI and TASK_APPS_URI are used to specify what Stream and Task applications to pre-register. -# - HOST_MOUNT_PATH and DOCKER_MOUNT_PATH are used to set the host and docker mount folders. -# If not set HOST_MOUNT_PATH defaults to the local host folder where the docker compose is being started. -# If not set DOCKER_MOUNT_PATH defaults to /home/cnb/scdf on dataflow-server and skipper containers. -# Example to mount the local Maven repository: HOST_MOUNT_PATH=~/.m2 DOCKER_MOUNT_PATH=/home/cnb/.m2 docker-compose up -# - APPS_PORT_RANGE allows you to override the port range exported by the Skipper server. By default the APPS_PORT_RANGE -# must supersede the local deployer's PORTRANGE_LOW and PORTRANGE_HIGH - the ports assigned to the stream apps run inside the Skipper container. -# The stream apps tha run in their own docker containers must set [DOCKER_PORTRANGE_LOW, DOCKER_PORTRANGE_HIGH] range that -# doesn't overlap with the APPS_PORT_RANGE. -# -# Exposed container ports: -# - 7577:7577 - Skipper server port (http://localhost:7577/api) -# - 20000-20105:20000-20105 - Port range for all deployed stream applications that run inside the Skipper container (e.g. maven:// registered apps). -# That means you can reach the application's actuator endpoints from your host machine. -# The deployed stream applications that run in their own docker containers (e.g. docker:// registered apps), -# can be reached on the ports they expose. services: mariadb: image: mariadb:10.6 diff --git a/src/local/launch-dataflow.sh b/src/local/launch-dataflow.sh index 78edc79a01..b21e4a25ee 100755 --- a/src/local/launch-dataflow.sh +++ b/src/local/launch-dataflow.sh @@ -16,7 +16,7 @@ SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") SCDIR=$(realpath $SCDIR) PROJECT_DIR=$(realpath "$SCDIR/../..") if [ "$DATAFLOW_VERSION" = "" ]; then - DATAFLOW_VERSION=2.11.3-SNAPSHOT + DATAFLOW_VERSION=3.0.0-SNAPSHOT fi export PLATFORM_TYPE=local COMPOSE_PROFILE= @@ -63,7 +63,7 @@ if [ "$SKIPPER_CLI" = "true" ]; then --spring.datasource.username=spring \ --spring.datasource.password=spring \ --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver \ - --spring.jpa.database.platform=org.hibernate.dialect.MariaDB106Dialect & + --spring.jpa.database.platform=org.hibernate.dialect.MariaDB106Dialect | tee skipper.log & echo "$!" > skipper.pid fi if [ "$COMPOSE_PROFILE" == "skipper" ] || [ "$SKIPPER_CLI" == "true" ]; then @@ -97,7 +97,7 @@ fi if [ "$START_DATAFLOW" == "true" ]; then echo "launching $SCDF_JAR with $DATAFLOW_ARGS" read -p "Press any key to launch Spring Cloud Data Flow..." - java -jar "$SCDF_JAR" $DATAFLOW_ARGS & + java -jar "$SCDF_JAR" $DATAFLOW_ARGS | tee server.log & echo "$!" > dataflow.pid else echo "You may execute: java -jar $SCDF_JAR $DATAFLOW_ARGS" diff --git a/src/local/launch-keycloak.sh b/src/local/launch-keycloak.sh new file mode 100755 index 0000000000..8a8c31b9c9 --- /dev/null +++ b/src/local/launch-keycloak.sh @@ -0,0 +1,9 @@ +#!/bin/bash +SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +SCDIR=$(realpath $SCDIR) + +docker run --name keycloak -p 8080:8080 -p 9000:9000 \ + -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \ + -v $SCDIR/data:/opt/keycloak/data/import \ + keycloak/keycloak:25.0 \ + start-dev --import-realm --verbose diff --git a/src/local/launch-with-keycloak.sh b/src/local/launch-with-keycloak.sh new file mode 100755 index 0000000000..2a9a1052b0 --- /dev/null +++ b/src/local/launch-with-keycloak.sh @@ -0,0 +1,92 @@ +#!/bin/bash +SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +SCDIR=$(realpath $SCDIR) +PROJECT_DIR=$(realpath "$SCDIR/../..") + +function usage_msg() { + echo "Arguments: [--pro]" + echo "where:" + echo " --pro: Launches SCDF Pro instead of OSS" +} +if [ -z "$BASH_VERSION" ]; then + echo "This script requires Bash. Use: bash $0 $*" + exit 0 +fi +SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +SCDIR=$(realpath $SCDIR) +export SCDIR +PROJECT_DIR=$(realpath "$SCDIR/../..") +if [ "$DATAFLOW_VERSION" = "" ]; then + DATAFLOW_VERSION=3.0.0-SNAPSHOT +fi +export PLATFORM_TYPE=local +USE_PRO=false +RUN_SKIPPER=false +while [ "$1" != "" ]; do + case $1 in + "--pro") + USE_PRO=true + ;; + "--skipper") + RUN_SKIPPER=true + ;; + *) + usage_msg + exit 1 + ;; + esac + shift +done +DC_OPT="-f "$SCDIR/docker-compose.yml" -f "$SCDIR/docker-compose-keycloak.yml" --profile keycloak" +echo "docker compose $DC_OPT create" +docker compose $DC_OPT create +echo "docker compose $DC_OPT start" +docker compose $DC_OPT start +echo "Waiting for RabbitMQ" +wget --retry-connrefused --read-timeout=20 --timeout=15 --tries=10 --continue -q http://localhost:5672 +echo "Waiting for MariaDB" +wget --retry-connrefused --read-timeout=20 --timeout=15 --tries=10 --continue -q http://localhost:3306 +echo "Waiting for Keycloak" +wget --retry-connrefused --read-timeout=20 --timeout=15 --tries=10 --continue -q http://localhost:8080 + +if [ "$RUN_SKIPPER" == "true" ]; then +echo "java -jar skipper" +java -jar $PROJECT_DIR/spring-cloud-skipper/spring-cloud-skipper-server/target/spring-cloud-skipper-server-$DATAFLOW_VERSION.jar \ + --spring.datasource.url='jdbc:mariadb://localhost:3306/dataflow' \ + --spring.datasource.username=spring \ + --spring.datasource.password=spring \ + --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver \ + --spring.jpa.database.platform=org.hibernate.dialect.MariaDB106Dialect \ + --spring.config.additional-location="file://$SCDIR/application-skipper-keycloak.yaml" | tee skipper.log & +echo "$!" > skipper.pid +echo "Waiting for Skipper" +wget --retry-connrefused --read-timeout=20 --timeout=15 --tries=10 --continue -q http://localhost:7577 +echo "Skipper running" +fi + +if [ "$USE_PRO" == "true" ]; then + if [ "$DATAFLOW_PRO_VERSION" = "" ]; then + DATAFLOW_PRO_VERSION=3.0.0-SNAPSHOT + fi + SCDF_JAR="$(realpath $PROJECT_DIR/../scdf-pro/scdf-pro-server/target/scdf-pro-server-$DATAFLOW_PRO_VERSION.jar)" + +else + SCDF_JAR="$(realpath $PROJECT_DIR/spring-cloud-dataflow-server/target/spring-cloud-dataflow-server-$DATAFLOW_VERSION.jar)" +fi + +SCDF_ARGS="--spring.cloud.dataflow.features.streams-enabled=${RUN_SKIPPER} --spring.cloud.dataflow.features.tasks-enabled=true --spring.cloud.dataflow.features.schedules-enabled=false" +if [ "$RUN_DATAFLOW" == "true" ]; then +echo "launching $SCDF_JAR" +java -jar "$SCDF_JAR" \ + --spring.datasource.url=jdbc:mariadb://localhost:3306/dataflow \ + --spring.datasource.username=spring \ + --spring.datasource.password=spring \ + --spring.datasource.driver-class-name=org.mariadb.jdbc.Driver \ + --spring.jpa.database.platform=org.hibernate.dialect.MariaDB106Dialect \ + --spring.config.additional-location="file://$SCDIR/application-dataflow-keycloak.yaml" $SCDF_ARGS | tee server.log & + +echo "$!" > dataflow.pid +echo "Waiting for Data Flow Server" +wget --retry-connrefused --read-timeout=20 --timeout=15 --tries=10 --continue -q http://localhost:9393 +echo "Data flow running" +fi \ No newline at end of file diff --git a/src/local/stop-dataflow.sh b/src/local/stop-dataflow.sh index 7b8e61edaf..96b582b804 100755 --- a/src/local/stop-dataflow.sh +++ b/src/local/stop-dataflow.sh @@ -5,23 +5,27 @@ if [ -z "$BASH_VERSION" ]; then fi SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") SCDIR=$(realpath $SCDIR) - +export SCDIR PLATFORM_TYPE=local - +DC_ARGS="-f $SCDIR/docker-compose.yml" +if [ "$1" == "keycloak" ] || [ "$1" == "oauth" ]; then + DC_ARGS="$DC_ARGS -f $SCDIR/docker-compose-keycloak.yml --profile keycloak" +fi +set +e echo "Stopping Dataflow Server" +curl -X POST http://localhost:9393/actuator/shutdown if [ -f dataflow.pid ]; then - kill "$(cat dataflow.pid)" + kill -9 "$(cat dataflow.pid)" rm -f dataflow.pid fi -set +e -curl -X POST http://localhost:9393/actuator/shutdown +ps -ef | grep java | grep dataflow echo "Stopping Skipper" +curl -X POST http://localhost:7577/actuator/shutdown if [ -f skipper.pid ]; then - kill "$(cat skipper.pid)" + kill -9 "$(cat skipper.pid)" rm -f skipper.pid fi -curl -X POST http://localhost:7577/actuator/shutdown - -echo "Stopping RabbitMQ and MariaDB in docker compose" -docker-compose -f "$SCDIR/docker-compose.yml" stop -docker-compose -f "$SCDIR/docker-compose.yml" rm --force +ps -ef | grep java | grep skipper +echo "Stopping $DC_ARGS" +docker compose $DC_ARGS down +docker compose $DC_ARGS rm --force diff --git a/src/local/tail-container-log.sh b/src/local/tail-container-log.sh new file mode 100755 index 0000000000..13ebb8b374 --- /dev/null +++ b/src/local/tail-container-log.sh @@ -0,0 +1,5 @@ +#!/bin/bash +SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") +SCDIR=$(realpath $SCDIR) +ID=$($SCDIR/container-id.sh $1) +docker logs -f -n all $ID