Skip to content

Commit 5e5edc5

Browse files
author
Corneil du Plessis
authored
Added Keycloak integration test (spring-attic#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.
1 parent 3eb2b80 commit 5e5edc5

File tree

28 files changed

+4986
-281
lines changed

28 files changed

+4986
-281
lines changed

.github/workflows/ci-it-security.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ jobs:
3333
- name: Run Security IT
3434
shell: bash
3535
run: |
36-
./mvnw clean install -DskipTests -T 1C -s .settings.xml -pl spring-cloud-dataflow-server -am -B --no-transfer-progress
3736
./mvnw -s .settings.xml \
3837
-pl spring-cloud-dataflow-server \
3938
-Dgroups=oauth \

spring-cloud-common-security-config/spring-cloud-common-security-config-web/src/test/java/org/springframework/cloud/common/security/support/DefaultAuthoritiesMapperTests.java

Lines changed: 126 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@
3434
/**
3535
* @author Gunnar Hillert
3636
*/
37-
public class DefaultAuthoritiesMapperTests {
37+
class DefaultAuthoritiesMapperTests {
3838

3939
@Test
40-
public void testNullConstructor() throws Exception {
40+
void nullConstructor() throws Exception {
4141
assertThatThrownBy(() -> {
4242
new DefaultAuthoritiesMapper(null, "");
4343
}).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("providerRoleMappings must not be null.");
4444
}
4545

4646
@Test
47-
public void testMapScopesToAuthoritiesWithNullParameters() throws Exception {
47+
void mapScopesToAuthoritiesWithNullParameters() throws Exception {
4848
DefaultAuthoritiesMapper authoritiesMapper = new DefaultAuthoritiesMapper(Collections.emptyMap(), "");
4949

5050
assertThatThrownBy(() -> {
@@ -56,18 +56,19 @@ public void testMapScopesToAuthoritiesWithNullParameters() throws Exception {
5656
}
5757

5858
@Test
59-
public void testThat7AuthoritiesAreReturned() throws Exception {
59+
void that7AuthoritiesAreReturned() throws Exception {
6060
DefaultAuthoritiesMapper authoritiesMapper = new DefaultAuthoritiesMapper("uaa", false);
6161
Set<GrantedAuthority> authorities = authoritiesMapper.mapScopesToAuthorities("uaa", Collections.emptySet(), null);
6262

6363
assertThat(authorities).hasSize(7);
64-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
64+
assertThat(authorities)
65+
.extracting(GrantedAuthority::getAuthority)
6566
.containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW", "ROLE_DEPLOY", "ROLE_MODIFY",
6667
"ROLE_SCHEDULE", "ROLE_DESTROY");
6768
}
6869

6970
@Test
70-
public void testEmptyMapConstructor() throws Exception {
71+
void emptyMapConstructor() throws Exception {
7172
Set<String> scopes = new HashSet<>();
7273
scopes.add("dataflow.manage");
7374
scopes.add("dataflow.view");
@@ -77,12 +78,13 @@ public void testEmptyMapConstructor() throws Exception {
7778
Collection<? extends GrantedAuthority> authorities = authoritiesMapper.mapScopesToAuthorities("uaa", scopes, null);
7879

7980
assertThat(authorities).hasSize(3);
80-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
81+
assertThat(authorities)
82+
.extracting(GrantedAuthority::getAuthority)
8183
.containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW");
8284
}
8385

8486
@Test
85-
public void testMapConstructorWithIncompleteRoleMappings() throws Exception {
87+
void mapConstructorWithIncompleteRoleMappings() throws Exception {
8688
ProviderRoleMapping roleMapping = new ProviderRoleMapping();
8789
roleMapping.setMapOauthScopes(true);
8890
roleMapping.addRoleMapping("ROLE_MANAGE", "foo-scope-in-oauth");
@@ -93,80 +95,115 @@ public void testMapConstructorWithIncompleteRoleMappings() throws Exception {
9395
}
9496

9597
@Test
96-
public void testThat7MappedAuthoritiesAreReturned() throws Exception {
97-
Map<String, String> roleMappings = new HashMap<>();
98-
roleMappings.put("ROLE_MANAGE", "foo-manage");
99-
roleMappings.put("ROLE_VIEW", "bar-view");
100-
roleMappings.put("ROLE_CREATE", "blubba-create");
101-
roleMappings.put("ROLE_MODIFY", "foo-modify");
102-
roleMappings.put("ROLE_DEPLOY", "foo-deploy");
103-
roleMappings.put("ROLE_DESTROY", "foo-destroy");
104-
roleMappings.put("ROLE_SCHEDULE", "foo-schedule");
98+
void that3MappedAuthoritiesAreReturned() throws Exception {
99+
Map<String, String> roleMappings = Map.of(
100+
"ROLE_MANAGE", "dataflow_manage",
101+
"ROLE_VIEW", "dataflow_view",
102+
"ROLE_CREATE", "dataflow_create",
103+
"ROLE_MODIFY", "dataflow_modify",
104+
"ROLE_DEPLOY", "dataflow_deploy",
105+
"ROLE_DESTROY", "dataflow_destroy",
106+
"ROLE_SCHEDULE", "dataflow_schedule"
107+
);
105108

106109
ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping();
107110
providerRoleMapping.setMapOauthScopes(true);
108111
providerRoleMapping.getRoleMappings().putAll(roleMappings);
109112

110-
Set<String> scopes = new HashSet<>();
111-
scopes.add("foo-manage");
112-
scopes.add("bar-view");
113-
scopes.add("blubba-create");
114-
scopes.add("foo-modify");
115-
scopes.add("foo-deploy");
116-
scopes.add("foo-destroy");
117-
scopes.add("foo-schedule");
113+
Set<String> roles = Set.of("dataflow_manage", "dataflow_view", "dataflow_deploy");
114+
115+
DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
116+
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa",
117+
roles, null);
118+
119+
assertThat(authorities).hasSize(3);
120+
assertThat(authorities)
121+
.extracting(GrantedAuthority::getAuthority)
122+
.containsExactlyInAnyOrder("ROLE_DEPLOY", "ROLE_MANAGE", "ROLE_VIEW");
123+
}
124+
@Test
125+
void that7MappedAuthoritiesAreReturned() throws Exception {
126+
Map<String, String> roleMappings = Map.of(
127+
"ROLE_MANAGE", "foo-manage",
128+
"ROLE_VIEW", "bar-view",
129+
"ROLE_CREATE", "blubba-create",
130+
"ROLE_MODIFY", "foo-modify",
131+
"ROLE_DEPLOY", "foo-deploy",
132+
"ROLE_DESTROY", "foo-destroy",
133+
"ROLE_SCHEDULE", "foo-schedule"
134+
);
135+
136+
ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping();
137+
providerRoleMapping.setMapOauthScopes(true);
138+
providerRoleMapping.getRoleMappings().putAll(roleMappings);
139+
140+
Set<String> scopes = Set.of(
141+
"foo-manage",
142+
"bar-view",
143+
"blubba-create",
144+
"foo-modify",
145+
"foo-deploy",
146+
"foo-destroy",
147+
"foo-schedule"
148+
);
118149

119150
DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
120151
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa",
121152
scopes, null);
122153

123154
assertThat(authorities).hasSize(7);
124-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
155+
assertThat(authorities)
156+
.extracting(GrantedAuthority::getAuthority)
125157
.containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY",
126158
"ROLE_SCHEDULE", "ROLE_VIEW");
127159
}
128160

129161
@Test
130-
public void testThat3MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception {
162+
void that3MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception {
131163
ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping();
132164
providerRoleMapping.setMapOauthScopes(true);
133165

134-
Set<String> scopes = new HashSet<>();
135-
scopes.add("dataflow.manage");
136-
scopes.add("dataflow.view");
137-
scopes.add("dataflow.create");
166+
Set<String> scopes = Set.of(
167+
"dataflow.manage",
168+
"dataflow.view",
169+
"dataflow.create"
170+
);
138171

139172
DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
140173
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa",
141174
scopes, null);
142175

143176
assertThat(authorities).hasSize(3);
144-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
177+
assertThat(authorities)
178+
.extracting(GrantedAuthority::getAuthority)
145179
.containsExactlyInAnyOrder("ROLE_MANAGE", "ROLE_CREATE", "ROLE_VIEW");
146180
}
147181

148182
@Test
149-
public void testThat7MappedAuthoritiesAreReturnedForDefaultMappingWithoutMappingScopes() throws Exception {
150-
Set<String> scopes = new HashSet<>();
151-
scopes.add("dataflow.manage");
152-
scopes.add("dataflow.view");
153-
scopes.add("dataflow.create");
183+
void that7MappedAuthoritiesAreReturnedForDefaultMappingWithoutMappingScopes() throws Exception {
184+
Set<String> scopes = Set.of(
185+
"dataflow.manage",
186+
"dataflow.view",
187+
"dataflow.create"
188+
);
154189

155190
DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", false);
156191
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa",
157192
scopes, null);
158193

159194
assertThat(authorities).hasSize(7);
160-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
195+
assertThat(authorities)
196+
.extracting(GrantedAuthority::getAuthority)
161197
.containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY",
162198
"ROLE_SCHEDULE", "ROLE_VIEW");
163199
}
164200

165201
@Test
166-
public void testThat2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception {
167-
Set<String> scopes = new HashSet<>();
168-
scopes.add("dataflow.view");
169-
scopes.add("dataflow.create");
202+
void that2MappedAuthoritiesAreReturnedForDefaultMapping() throws Exception {
203+
Set<String> scopes = Set.of(
204+
"dataflow.view",
205+
"dataflow.create"
206+
);
170207

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

180217
@Test
181-
public void testThat7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception {
182-
Map<String, String> roleMappings = new HashMap<>();
183-
roleMappings.put("ROLE_MANAGE", "foo-manage");
184-
roleMappings.put("ROLE_VIEW", "foo-manage");
185-
roleMappings.put("ROLE_DEPLOY", "foo-manage");
186-
roleMappings.put("ROLE_DESTROY", "foo-manage");
187-
roleMappings.put("ROLE_MODIFY", "foo-manage");
188-
roleMappings.put("ROLE_SCHEDULE", "foo-manage");
189-
roleMappings.put("ROLE_CREATE", "blubba-create");
190-
191-
Set<String> scopes = new HashSet<>();
192-
scopes.add("foo-manage");
193-
scopes.add("blubba-create");
218+
void that7AuthoritiesAreReturnedAndOneOAuthScopeCoversMultipleServerRoles() throws Exception {
219+
Map<String, String> roleMappings = Map.of(
220+
"ROLE_MANAGE", "foo-manage",
221+
"ROLE_VIEW", "foo-manage",
222+
"ROLE_DEPLOY", "foo-manage",
223+
"ROLE_DESTROY", "foo-manage",
224+
"ROLE_MODIFY", "foo-manage",
225+
"ROLE_SCHEDULE", "foo-manage",
226+
"ROLE_CREATE", "blubba-create"
227+
);
228+
229+
Set<String> scopes = Set.of("foo-manage", "blubba-create");
194230

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

205241
@Test
206-
public void testThatUriStyleScopeRemovesLeadingPart() throws Exception {
207-
Map<String, String> roleMappings = new HashMap<>();
208-
roleMappings.put("ROLE_MANAGE", "foo-manage");
209-
roleMappings.put("ROLE_VIEW", "foo-manage");
210-
roleMappings.put("ROLE_DEPLOY", "foo-manage");
211-
roleMappings.put("ROLE_DESTROY", "foo-manage");
212-
roleMappings.put("ROLE_MODIFY", "foo-manage");
213-
roleMappings.put("ROLE_SCHEDULE", "foo-manage");
214-
roleMappings.put("ROLE_CREATE", "blubba-create");
215-
216-
Set<String> scopes = new HashSet<>();
217-
scopes.add("api://foobar/foo-manage");
218-
scopes.add("blubba-create");
242+
void thatUriStyleScopeRemovesLeadingPart() throws Exception {
243+
Map<String, String> roleMappings = Map.of(
244+
"ROLE_MANAGE", "foo-manage",
245+
"ROLE_VIEW", "foo-manage",
246+
"ROLE_DEPLOY", "foo-manage",
247+
"ROLE_DESTROY", "foo-manage",
248+
"ROLE_MODIFY", "foo-manage",
249+
"ROLE_SCHEDULE", "foo-manage",
250+
"ROLE_CREATE", "blubba-create"
251+
);
252+
253+
Set<String> scopes = Set.of("api://foobar/foo-manage", "blubba-create");
219254

220255
DefaultAuthoritiesMapper defaultAuthoritiesExtractor = new DefaultAuthoritiesMapper("uaa", true, roleMappings);
221256
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesExtractor.mapScopesToAuthorities("uaa",
222257
scopes, null);
223258

224259
assertThat(authorities).hasSize(7);
225-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
260+
assertThat(authorities)
261+
.extracting(GrantedAuthority::getAuthority)
226262
.containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY",
227263
"ROLE_SCHEDULE", "ROLE_VIEW");
228264
}
229265

230266
@Test
231-
public void testThatUriStyleScopeParsingCanBeDisabled() throws Exception {
232-
Map<String, String> roleMappings = new HashMap<>();
233-
roleMappings.put("ROLE_MANAGE", "/ROLE/2000803042");
234-
roleMappings.put("ROLE_VIEW", "/ROLE/2000803036");
235-
roleMappings.put("ROLE_DEPLOY", "/ROLE/2000803039");
236-
roleMappings.put("ROLE_DESTROY", "/ROLE/20008030340");
237-
roleMappings.put("ROLE_MODIFY", "/ROLE/2000803037");
238-
roleMappings.put("ROLE_SCHEDULE", "/ROLE/2000803038");
239-
roleMappings.put("ROLE_CREATE", "/ROLE/2000803041");
267+
void thatUriStyleScopeParsingCanBeDisabled() throws Exception {
268+
Map<String, String> roleMappings = Map.of(
269+
"ROLE_MANAGE", "/ROLE/2000803042",
270+
"ROLE_VIEW", "/ROLE/2000803036",
271+
"ROLE_DEPLOY", "/ROLE/2000803039",
272+
"ROLE_DESTROY", "/ROLE/20008030340",
273+
"ROLE_MODIFY", "/ROLE/2000803037",
274+
"ROLE_SCHEDULE", "/ROLE/2000803038",
275+
"ROLE_CREATE", "/ROLE/2000803041"
276+
);
240277

241278
ProviderRoleMapping providerRoleMapping = new ProviderRoleMapping();
242279
providerRoleMapping.setMapOauthScopes(true);
243280
providerRoleMapping.setParseOauthScopePathParts(false);
244281
providerRoleMapping.getRoleMappings().putAll(roleMappings);
245282

246-
Set<String> scopes = new HashSet<>();
247-
scopes.add("/ROLE/2000803042");
248-
scopes.add("/ROLE/2000803036");
249-
scopes.add("/ROLE/2000803039");
250-
scopes.add("/ROLE/20008030340");
251-
scopes.add("/ROLE/2000803037");
252-
scopes.add("/ROLE/2000803038");
253-
scopes.add("/ROLE/2000803041");
283+
Set<String> scopes = Set.of(
284+
"/ROLE/2000803042",
285+
"/ROLE/2000803036",
286+
"/ROLE/2000803039",
287+
"/ROLE/20008030340",
288+
"/ROLE/2000803037",
289+
"/ROLE/2000803038",
290+
"/ROLE/2000803041"
291+
);
254292

255293
DefaultAuthoritiesMapper defaultAuthoritiesMapper = new DefaultAuthoritiesMapper("uaa", providerRoleMapping);
256294
Collection<? extends GrantedAuthority> authorities = defaultAuthoritiesMapper.mapScopesToAuthorities("uaa",
257295
scopes, null);
258296

259297
assertThat(authorities).hasSize(7);
260-
assertThat(authorities.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
298+
assertThat(authorities)
299+
.extracting(GrantedAuthority::getAuthority)
261300
.containsExactlyInAnyOrder("ROLE_CREATE", "ROLE_DEPLOY", "ROLE_DESTROY", "ROLE_MANAGE", "ROLE_MODIFY",
262301
"ROLE_SCHEDULE", "ROLE_VIEW");
263302
}

spring-cloud-dataflow-parent/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<!-- database driver versions -->
6363
<oracle-ojdbc8.version>21.9.0.0</oracle-ojdbc8.version>
6464
<db2-jcc.version>11.5.9.0</db2-jcc.version>
65+
<testcontainers-keycloak.version>3.4.0</testcontainers-keycloak.version>
6566
<!-- questionable testing libs -->
6667
<org-json.version>20240303</org-json.version>
6768
<littleproxy.version>1.1.2</littleproxy.version>
@@ -257,6 +258,11 @@
257258
<type>pom</type>
258259
<scope>import</scope>
259260
</dependency>
261+
<dependency>
262+
<groupId>com.github.dasniko</groupId>
263+
<artifactId>testcontainers-keycloak</artifactId>
264+
<version>${testcontainers-keycloak.version}</version>
265+
</dependency>
260266
</dependencies>
261267
</dependencyManagement>
262268
<dependencies>

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataflowOAuthSecurityConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
164164
auth.userInfoEndpoint(customizer -> {
165165
customizer.userService(plainOauth2UserService).oidcUserService(oidcUserService);
166166
});
167+
auth.defaultSuccessUrl(authorizationProperties.getDashboardUrl());
167168
});
168169

169170
http.oauth2ResourceServer(resourceserver -> {

spring-cloud-dataflow-server/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272
<artifactId>spring-boot-starter-test</artifactId>
7373
<scope>test</scope>
7474
</dependency>
75+
<dependency>
76+
<groupId>org.springframework.security</groupId>
77+
<artifactId>spring-security-test</artifactId>
78+
<scope>test</scope>
79+
</dependency>
7580
<dependency>
7681
<groupId>org.springframework.boot</groupId>
7782
<artifactId>spring-boot-devtools</artifactId>
@@ -104,6 +109,11 @@
104109
<artifactId>junit-jupiter</artifactId>
105110
<scope>test</scope>
106111
</dependency>
112+
<dependency>
113+
<groupId>com.github.dasniko</groupId>
114+
<artifactId>testcontainers-keycloak</artifactId>
115+
<scope>test</scope>
116+
</dependency>
107117
<dependency>
108118
<groupId>org.testcontainers</groupId>
109119
<artifactId>postgresql</artifactId>

0 commit comments

Comments
 (0)