Skip to content

Commit

Permalink
Added Keycloak integration test
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
corneil committed Dec 12, 2024
1 parent a576e5c commit 78bf012
Show file tree
Hide file tree
Showing 28 changed files with 4,986 additions and 281 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci-it-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(() -> {
Expand All @@ -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<GrantedAuthority> 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<String> scopes = new HashSet<>();
scopes.add("dataflow.manage");
scopes.add("dataflow.view");
Expand All @@ -77,12 +78,13 @@ public void testEmptyMapConstructor() throws Exception {
Collection<? extends GrantedAuthority> 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");
Expand All @@ -93,80 +95,115 @@ public void testMapConstructorWithIncompleteRoleMappings() throws Exception {
}

@Test
public void testThat7MappedAuthoritiesAreReturned() throws Exception {
Map<String, String> 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<String, String> 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<String> 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<String> roles = Set.of("dataflow_manage", "dataflow_view", "dataflow_deploy");

DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
Collection<? extends GrantedAuthority> 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<String, String> 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<String> scopes = Set.of(
"foo-manage",
"bar-view",
"blubba-create",
"foo-modify",
"foo-deploy",
"foo-destroy",
"foo-schedule"
);

DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
Collection<? extends GrantedAuthority> 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<String> scopes = new HashSet<>();
scopes.add("dataflow.manage");
scopes.add("dataflow.view");
scopes.add("dataflow.create");
Set<String> scopes = Set.of(
"dataflow.manage",
"dataflow.view",
"dataflow.create"
);

DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
Collection<? extends GrantedAuthority> 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<String> scopes = new HashSet<>();
scopes.add("dataflow.manage");
scopes.add("dataflow.view");
scopes.add("dataflow.create");
void that7MappedAuthoritiesAreReturnedForDefaultMappingWithoutMappingScopes() throws Exception {
Set<String> scopes = Set.of(
"dataflow.manage",
"dataflow.view",
"dataflow.create"
);

DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", false);
Collection<? extends GrantedAuthority> 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<String> scopes = new HashSet<>();
scopes.add("dataflow.view");
scopes.add("dataflow.create");
void that2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception {
Set<String> scopes = Set.of(
"dataflow.view",
"dataflow.create"
);

DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true);
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa",
Expand All @@ -178,19 +215,18 @@ public void testThat2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exce
}

@Test
public void testThat7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception {
Map<String, String> 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<String> scopes = new HashSet<>();
scopes.add("foo-manage");
scopes.add("blubba-create");
void that7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception {
Map<String, String> 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<String> scopes = Set.of("foo-manage", "blubba-create");

DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true, roleMappings);
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa",
Expand All @@ -203,61 +239,64 @@ public void testThat7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerR
}

@Test
public void testThatUriStyleScopeRemovesLeadingPart() throws Exception {
Map<String, String> 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<String> scopes = new HashSet<>();
scopes.add("api://foobar/foo-manage");
scopes.add("blubba-create");
void thatUriStyleScopeRemovesLeadingPart() throws Exception {
Map<String, String> 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<String> scopes = Set.of("api://foobar/foo-manage", "blubba-create");

DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true, roleMappings);
Collection<? extends GrantedAuthority> 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<String, String> 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<String, String> 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<String> 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<String> scopes = Set.of(
"/ROLE/2000803042",
"/ROLE/2000803036",
"/ROLE/2000803039",
"/ROLE/20008030340",
"/ROLE/2000803037",
"/ROLE/2000803038",
"/ROLE/2000803041"
);

DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
Collection<? extends GrantedAuthority> 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");
}
Expand Down
6 changes: 6 additions & 0 deletions spring-cloud-dataflow-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<!-- database driver versions -->
<oracle-ojdbc8.version>21.9.0.0</oracle-ojdbc8.version>
<db2-jcc.version>11.5.9.0</db2-jcc.version>
<testcontainers-keycloak.version>3.4.0</testcontainers-keycloak.version>
<!-- questionable testing libs -->
<org-json.version>20240303</org-json.version>
<littleproxy.version>1.1.2</littleproxy.version>
Expand Down Expand Up @@ -257,6 +258,11 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.github.dasniko</groupId>
<artifactId>testcontainers-keycloak</artifactId>
<version>${testcontainers-keycloak.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 -> {
Expand Down
10 changes: 10 additions & 0 deletions spring-cloud-dataflow-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
Expand Down Expand Up @@ -104,6 +109,11 @@
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.dasniko</groupId>
<artifactId>testcontainers-keycloak</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
Expand Down
Loading

0 comments on commit 78bf012

Please sign in to comment.