Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 34f2e73

Browse files
ghillertjvalkeal
authored andcommitted
Add support for mapping of LDAP groups to ROLES
- Pump to spring-cloud-common-security-config 1.0.1 snapshots. - Add tests - Add documentation - Fixes #2084
1 parent 7b09e35 commit 34f2e73

File tree

6 files changed

+292
-3
lines changed

6 files changed

+292
-3
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<!-- Note: Change ./spring-cloud-dataflow-server-local/pom.xml to match the spring-cloud.version -->
4040
<spring-cloud.version>Edgware.SR2</spring-cloud.version>
4141

42-
<spring-cloud-common-security-config.version>1.0.0.RELEASE</spring-cloud-common-security-config.version>
42+
<spring-cloud-common-security-config.version>1.0.1.BUILD-SNAPSHOT</spring-cloud-common-security-config.version>
4343

4444
<spring-analytics.version>1.1.3.RELEASE</spring-analytics.version>
4545
<spring-batch-admin-manager.version>1.3.1.RELEASE</spring-batch-admin-manager.version>

spring-cloud-dataflow-docs/src/main/asciidoc/configuration.adoc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,39 @@ TIP: For more information, please also see the
584584
http://docs.spring.io/spring-security/site/docs/current/reference/html/ldap.html[LDAP Authentication]
585585
chapter of the Spring Security reference guide.
586586

587+
===== LDAP Role Mapping
588+
589+
By default, the role name retrieved from Ldap needs to match the name of the
590+
role in Spring Cloud Data Flow. However, it is also possible to explicitly
591+
provide a mapping between LDAP roles and Spring Cloud Data Flow roles.
592+
[source,yaml]
593+
----
594+
security:
595+
basic:
596+
enabled: true
597+
realm: Spring Cloud Data Flow
598+
spring:
599+
cloud:
600+
dataflow:
601+
security:
602+
authentication:
603+
ldap:
604+
enabled: true
605+
url: ldap://localhost:10389
606+
managerDn: uid=admin,ou=system
607+
managerPassword: secret
608+
userSearchBase: ou=otherpeople,dc=example,dc=com
609+
userSearchFilter: uid={0}
610+
roleMappings: # <1>
611+
ROLE_MANAGE: foo-manage # <2>
612+
ROLE_VIEW: bar-view
613+
ROLE_CREATE: foo-manage
614+
----
615+
616+
<1> Enables explicit role mapping support
617+
<2> When role mapping support is enabled, you must provide a mapping for
618+
all 3 Spring Cloud Data Flow roles *ROLE_MANAGE*, *ROLE_VIEW*, *ROLE_CREATE*.
619+
587620
===== LDAP Transport Security
588621

589622
When connecting to an LDAP server, you typically (in the LDAP world) have two options

spring-cloud-starter-dataflow-server-local/src/test/java/org/springframework/cloud/dataflow/server/local/security/LdapServerResource.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,21 @@ public class LdapServerResource extends ExternalResource {
5555

5656
private boolean enabledSsl = false;
5757

58+
private final String ldapFileName;
59+
5860
public LdapServerResource() {
5961
super();
62+
this.ldapFileName = "testUsers.ldif";
63+
}
64+
65+
public LdapServerResource(String ldapFileName) {
66+
super();
67+
this.ldapFileName = ldapFileName;
6068
}
6169

6270
public LdapServerResource(boolean enabledSsl) {
6371
this.enabledSsl = true;
72+
this.ldapFileName = "testUsers.ldif";
6473
}
6574

6675
@Override
@@ -70,9 +79,8 @@ protected void before() throws Throwable {
7079

7180
temporaryFolder.create();
7281
apacheDSContainer = new ApacheDSContainerWithSecurity("dc=springframework,dc=org",
73-
"classpath:org/springframework/cloud/dataflow/server/local/security/testUsers.ldif");
82+
"classpath:org/springframework/cloud/dataflow/server/local/security/" + this.ldapFileName);
7483
int ldapPort = SocketUtils.findAvailableTcpPort();
75-
7684
if (enabledSsl) {
7785

7886
apacheDSContainer.setEnabledLdapOverSsl(true);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.cloud.dataflow.server.local.security;
17+
18+
import org.junit.ClassRule;
19+
import org.junit.Test;
20+
import org.junit.rules.RuleChain;
21+
import org.junit.rules.TestRule;
22+
23+
import org.springframework.cloud.dataflow.server.local.LocalDataflowResource;
24+
25+
import static org.springframework.cloud.dataflow.server.local.security.SecurityTestUtils.basicAuthorizationHeader;
26+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
27+
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
28+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
29+
30+
/**
31+
* @author Gunnar Hillert
32+
*/
33+
public class LocalServerSecurityWithLdapSimpleBindGroupMappingTests {
34+
35+
private final static LocalDataflowResource localDataflowResource = new LocalDataflowResource(
36+
"classpath:org/springframework/cloud/dataflow/server/local/security/ldapSimpleBindGroupMapping.yml");
37+
38+
@ClassRule
39+
public static TestRule springDataflowAndLdapServer = RuleChain.outerRule(
40+
new LdapServerResource("testUsersWithCustomRoles.ldif")).around(localDataflowResource);
41+
42+
@Test
43+
public void testWrongUsernameFails() throws Exception {
44+
localDataflowResource.getMockMvc()
45+
.perform(get("/apps").header("Authorization", basicAuthorizationHeader("joe", "wrongspassword")))
46+
.andDo(print()).andExpect(status().isUnauthorized());
47+
}
48+
49+
@Test
50+
public void testDefaultSpringBootConfigurationFails() throws Exception {
51+
localDataflowResource.getMockMvc()
52+
.perform(get("/apps").header("Authorization", basicAuthorizationHeader("admin", "whosThere")))
53+
.andDo(print()).andExpect(status().isUnauthorized());
54+
}
55+
56+
@Test
57+
public void testWrongPasswordFails() throws Exception {
58+
localDataflowResource.getMockMvc()
59+
.perform(get("/apps").header("Authorization", basicAuthorizationHeader("bob", "bobpassword999")))
60+
.andDo(print()).andExpect(status().isUnauthorized());
61+
}
62+
63+
@Test
64+
public void testUnauthenticatedAccessToAppsEndpointFails() throws Exception {
65+
localDataflowResource.getMockMvc().perform(get("/apps")).andExpect(status().isUnauthorized());
66+
}
67+
68+
@Test
69+
public void testUnauthenticatedAccessToManagementEndpointFails() throws Exception {
70+
localDataflowResource.getMockMvc().perform(get("/management/metrics")).andExpect(status().isUnauthorized());
71+
}
72+
73+
@Test
74+
public void testAuthenticatedAccessToAppsEndpointSucceeds() throws Exception {
75+
localDataflowResource.getMockMvc()
76+
.perform(get("/apps").header("Authorization", basicAuthorizationHeader("joe", "joespassword")))
77+
.andDo(print()).andExpect(status().isOk());
78+
}
79+
80+
@Test
81+
public void testAuthenticatedAccessToManagementEndpointSucceeds() throws Exception {
82+
localDataflowResource.getMockMvc().perform(
83+
get("/management/metrics").header("Authorization", basicAuthorizationHeader("joe", "joespassword")))
84+
.andDo(print()).andExpect(status().isOk());
85+
}
86+
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
management:
2+
security:
3+
enabled: true
4+
security:
5+
basic:
6+
enabled: true
7+
realm: Spring Cloud Data Flow
8+
spring:
9+
cloud:
10+
dataflow:
11+
security:
12+
authentication:
13+
ldap:
14+
enabled: true
15+
url: ldap://localhost:${ldap.port}
16+
userDnPattern: uid={0},ou=otherpeople,dc=springframework,dc=org
17+
groupSearchFilter: member={0}
18+
groupRoleAttribute: cn
19+
groupSearchBase: ou=groups,dc=springframework,dc=org
20+
roleMappings:
21+
ROLE_MANAGE: foo-manage
22+
ROLE_VIEW: bar-view
23+
ROLE_CREATE: foo-manage
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
dn: ou=groups,dc=springframework,dc=org
2+
objectclass: top
3+
objectclass: organizationalUnit
4+
ou: groups
5+
6+
dn: ou=subgroups,ou=groups,dc=springframework,dc=org
7+
objectclass: top
8+
objectclass: organizationalUnit
9+
ou: subgroups
10+
11+
dn: ou=people,dc=springframework,dc=org
12+
objectclass: top
13+
objectclass: organizationalUnit
14+
ou: people
15+
16+
dn: ou=space cadets,dc=springframework,dc=org
17+
objectclass: top
18+
objectclass: organizationalUnit
19+
ou: space cadets
20+
21+
dn: ou=\"quoted people\",dc=springframework,dc=org
22+
objectclass: top
23+
objectclass: organizationalUnit
24+
ou: "quoted people"
25+
26+
dn: ou=otherpeople,dc=springframework,dc=org
27+
objectclass: top
28+
objectclass: organizationalUnit
29+
ou: otherpeople
30+
31+
dn: uid=ben,ou=people,dc=springframework,dc=org
32+
objectclass: top
33+
objectclass: person
34+
objectclass: organizationalPerson
35+
objectclass: inetOrgPerson
36+
cn: Ben Alex
37+
sn: Alex
38+
uid: ben
39+
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
40+
41+
dn: uid=bob,ou=people,dc=springframework,dc=org
42+
objectclass: top
43+
objectclass: person
44+
objectclass: organizationalPerson
45+
objectclass: inetOrgPerson
46+
cn: Bob Hamilton
47+
sn: Hamilton
48+
uid: bob
49+
userPassword: bobspassword
50+
51+
dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
52+
objectclass: top
53+
objectclass: person
54+
objectclass: organizationalPerson
55+
objectclass: inetOrgPerson
56+
cn: Joe Smeth
57+
sn: Smeth
58+
uid: joe
59+
userPassword: joespassword
60+
61+
dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
62+
objectclass: top
63+
objectclass: person
64+
objectclass: organizationalPerson
65+
objectclass: inetOrgPerson
66+
cn: Mouse, Jerry
67+
sn: Mouse
68+
uid: jerry
69+
userPassword: jerryspassword
70+
71+
dn: cn=slash/guy,ou=people,dc=springframework,dc=org
72+
objectclass: top
73+
objectclass: person
74+
objectclass: organizationalPerson
75+
objectclass: inetOrgPerson
76+
cn: slash/guy
77+
sn: Slash
78+
uid: slashguy
79+
userPassword: slashguyspassword
80+
81+
dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org
82+
objectclass: top
83+
objectclass: person
84+
objectclass: organizationalPerson
85+
objectclass: inetOrgPerson
86+
cn: quote\"guy
87+
sn: Quote
88+
uid: quoteguy
89+
userPassword: quoteguyspassword
90+
91+
dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org
92+
objectclass: top
93+
objectclass: person
94+
objectclass: organizationalPerson
95+
objectclass: inetOrgPerson
96+
cn: Space Cadet
97+
sn: Cadet
98+
uid: space cadet
99+
userPassword: spacecadetspassword
100+
101+
102+
103+
dn: cn=developers,ou=groups,dc=springframework,dc=org
104+
objectclass: top
105+
objectclass: groupOfNames
106+
cn: developers
107+
ou: developer
108+
member: uid=ben,ou=people,dc=springframework,dc=org
109+
member: uid=bob,ou=people,dc=springframework,dc=org
110+
111+
dn: cn=bar-view,ou=groups,dc=springframework,dc=org
112+
objectclass: top
113+
objectclass: groupOfNames
114+
cn: bar-view
115+
ou: bar-view
116+
member: uid=joe,ou=otherpeople,dc=springframework,dc=org
117+
118+
dn: cn=foo-manage,ou=groups,dc=springframework,dc=org
119+
objectclass: top
120+
objectclass: groupOfNames
121+
cn: foo-manage
122+
ou: foo-manage
123+
member: uid=joe,ou=otherpeople,dc=springframework,dc=org
124+
125+
dn: cn=managers,ou=groups,dc=springframework,dc=org
126+
objectclass: top
127+
objectclass: groupOfNames
128+
cn: manager
129+
ou: manager
130+
member: uid=ben,ou=people,dc=springframework,dc=org
131+
member: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
132+
133+
dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
134+
objectclass: top
135+
objectclass: groupOfNames
136+
cn: submanagers
137+
ou: submanager
138+
member: uid=ben,ou=people,dc=springframework,dc=org

0 commit comments

Comments
 (0)