Skip to content

Commit 78bf012

Browse files
author
Corneil du Plessis
committed
Added Keycloak integration test
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 a576e5c commit 78bf012

File tree

28 files changed

+4986
-281
lines changed

28 files changed

+4986
-281
lines changed

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

-1
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

+126-87
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

+6
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

+1
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

+10
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)