Skip to content

Commit 63607ee

Browse files
Giovanni Lovatoeleftherias
authored andcommitted
Add configurable mapping function to map authorities
1 parent 2d26be9 commit 63607ee

File tree

2 files changed

+63
-14
lines changed

2 files changed

+63
-14
lines changed

ldap/src/integration-test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818

1919
import static org.assertj.core.api.Assertions.*;
2020

21+
import java.util.Collection;
22+
import java.util.HashSet;
23+
import java.util.Set;
24+
2125
import org.junit.*;
2226
import org.junit.runner.RunWith;
23-
2427
import org.springframework.beans.factory.annotation.Autowired;
2528
import org.springframework.ldap.core.ContextSource;
2629
import org.springframework.ldap.core.DirContextAdapter;
@@ -29,11 +32,10 @@
2932
import org.springframework.security.core.GrantedAuthority;
3033
import org.springframework.security.core.authority.AuthorityUtils;
3134
import org.springframework.security.ldap.ApacheDsContainerConfig;
35+
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
3236
import org.springframework.test.context.ContextConfiguration;
3337
import org.springframework.test.context.junit4.SpringRunner;
3438

35-
import java.util.*;
36-
3739
/**
3840
*
3941
* @author Luke Taylor
@@ -185,4 +187,25 @@ public void userDnWithEscapedCharacterParameterReturnsExpectedRoles() {
185187
assertThat(authorities).as("Should have 1 role").hasSize(1);
186188
assertThat(authorities.contains("ROLE_MANAGER")).isTrue();
187189
}
190+
191+
@Test
192+
public void customAuthoritiesMappingFunction() {
193+
populator.setAuthorityMapper(record -> {
194+
String dn = record.get(SpringSecurityLdapTemplate.DN_KEY).get(0);
195+
String role = record.get(populator.getGroupRoleAttribute()).get(0);
196+
return new LdapAuthority(role, dn);
197+
});
198+
199+
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName(
200+
"cn=mouse\\, jerry,ou=people,dc=springframework,dc=org"));
201+
202+
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "notused");
203+
204+
assertThat(authorities).allMatch(LdapAuthority.class::isInstance);
205+
}
206+
207+
@Test(expected = IllegalArgumentException.class)
208+
public void customAuthoritiesMappingFunctionThrowsIfNull() {
209+
populator.setAuthorityMapper(null);
210+
}
188211
}

ldap/src/main/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulator.java

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
import java.util.Collection;
2121
import java.util.HashSet;
2222
import java.util.List;
23+
import java.util.Map;
2324
import java.util.Set;
25+
import java.util.function.Function;
2426

2527
import javax.naming.directory.SearchControls;
2628

2729
import org.apache.commons.logging.Log;
2830
import org.apache.commons.logging.LogFactory;
29-
3031
import org.springframework.ldap.core.ContextSource;
3132
import org.springframework.ldap.core.DirContextOperations;
3233
import org.springframework.ldap.core.LdapTemplate;
@@ -137,15 +138,22 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
137138
* The pattern to be used for the user search. {0} is the user's DN
138139
*/
139140
private String groupSearchFilter = "(member={0})";
141+
140142
/**
141143
* The role prefix that will be prepended to each role name
142144
*/
143145
private String rolePrefix = "ROLE_";
146+
144147
/**
145148
* Should we convert the role name to uppercase
146149
*/
147150
private boolean convertToUpperCase = true;
148151

152+
/**
153+
* The mapping function to be used to populate authorities.
154+
*/
155+
private Function<Map<String, List<String>>, GrantedAuthority> authorityMapper;
156+
149157
// ~ Constructors
150158
// ===================================================================================================
151159

@@ -171,6 +179,16 @@ else if (groupSearchBase.length() == 0) {
171179
logger.info(
172180
"groupSearchBase is empty. Searches will be performed from the context source base");
173181
}
182+
183+
this.authorityMapper = record -> {
184+
String role = record.get(this.groupRoleAttribute).get(0);
185+
186+
if (this.convertToUpperCase) {
187+
role = role.toUpperCase();
188+
}
189+
190+
return new SimpleGrantedAuthority(this.rolePrefix + role);
191+
};
174192
}
175193

176194
// ~ Methods
@@ -238,21 +256,18 @@ public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String usern
238256
+ " in search base '" + getGroupSearchBase() + "'");
239257
}
240258

241-
Set<String> userRoles = getLdapTemplate().searchForSingleAttributeValues(
242-
getGroupSearchBase(), this.groupSearchFilter,
243-
new String[] { userDn, username }, this.groupRoleAttribute);
259+
Set<Map<String, List<String>>> userRoles = getLdapTemplate()
260+
.searchForMultipleAttributeValues(getGroupSearchBase(),
261+
this.groupSearchFilter,
262+
new String[] { userDn, username },
263+
new String[] { this.groupRoleAttribute });
244264

245265
if (logger.isDebugEnabled()) {
246266
logger.debug("Roles from search: " + userRoles);
247267
}
248268

249-
for (String role : userRoles) {
250-
251-
if (this.convertToUpperCase) {
252-
role = role.toUpperCase();
253-
}
254-
255-
authorities.add(new SimpleGrantedAuthority(this.rolePrefix + role));
269+
for (Map<String, List<String>> role : userRoles) {
270+
authorities.add(authorityMapper.apply(role));
256271
}
257272

258273
return authorities;
@@ -325,6 +340,17 @@ public void setIgnorePartialResultException(boolean ignore) {
325340
getLdapTemplate().setIgnorePartialResultException(ignore);
326341
}
327342

343+
/**
344+
* Sets the mapping function which will be used to create instances of {@link GrantedAuthority}
345+
* given the context record.
346+
*
347+
* @param authorityMapper the mapping function
348+
*/
349+
public void setAuthorityMapper(Function<Map<String, List<String>>, GrantedAuthority> authorityMapper) {
350+
Assert.notNull(authorityMapper, "authorityMapper must not be null");
351+
this.authorityMapper = authorityMapper;
352+
}
353+
328354
/**
329355
* Returns the current LDAP template. Method available so that classes extending this
330356
* can override the template used

0 commit comments

Comments
 (0)