0
# Authorities Population
1
2
Authority and role mapping from LDAP groups and attributes with customizable population strategies for complex authorization scenarios.
3
4
## Capabilities
5
6
### LdapAuthoritiesPopulator
7
8
Strategy interface for populating user authorities from LDAP directory information.
9
10
```java { .api }
11
/**
12
* Strategy interface for retrieving user authorities from LDAP directory entries
13
*/
14
public interface LdapAuthoritiesPopulator {
15
/**
16
* Retrieves the granted authorities for a user based on their LDAP entry
17
* @param userData the LDAP context operations containing user information
18
* @param username the username of the authenticated user
19
* @return collection of granted authorities for the user
20
*/
21
Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
22
}
23
```
24
25
### DefaultLdapAuthoritiesPopulator
26
27
Default implementation that populates authorities from LDAP group memberships and user attributes.
28
29
```java { .api }
30
/**
31
* Default LDAP authorities populator that retrieves user authorities from LDAP group memberships
32
* and optionally from user attributes
33
*/
34
public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator, InitializingBean, MessageSourceAware {
35
/**
36
* Creates an authorities populator with context source and group search base
37
* @param contextSource the LDAP context source
38
* @param groupSearchBase the base DN for searching groups (e.g., "ou=groups")
39
*/
40
public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase);
41
42
/**
43
* Retrieves granted authorities from LDAP groups and user attributes
44
* @param userData the user's LDAP context operations
45
* @param username the username
46
* @return collection of granted authorities
47
*/
48
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
49
50
/**
51
* Sets the LDAP filter for searching groups that contain the user
52
* @param groupSearchFilter filter with {0} placeholder for user DN (default: "member={0}")
53
*/
54
public void setGroupSearchFilter(String groupSearchFilter);
55
56
/**
57
* Sets the attribute name that contains the role/authority name in group entries
58
* @param groupRoleAttribute attribute name (default: "cn")
59
*/
60
public void setGroupRoleAttribute(String groupRoleAttribute);
61
62
/**
63
* Sets the prefix to add to role names extracted from groups
64
* @param rolePrefix prefix to add (default: "ROLE_")
65
*/
66
public void setRolePrefix(String rolePrefix);
67
68
/**
69
* Sets whether to convert role names to uppercase
70
* @param convertToUpperCase true to convert to uppercase (default: true)
71
*/
72
public void setConvertToUpperCase(boolean convertToUpperCase);
73
74
/**
75
* Sets the scope for group searches
76
* @param groupSearchSubtree true to search subtree, false for one level (default: false)
77
*/
78
public void setSearchSubtree(boolean groupSearchSubtree);
79
80
/**
81
* Sets a user attribute that should be used as an additional authority
82
* @param attributeName the name of the user attribute containing role information
83
*/
84
public void setGroupRoleAttribute(String attributeName);
85
86
/**
87
* Sets the default role to assign to all users
88
* @param defaultRole the default role name
89
*/
90
public void setDefaultRole(String defaultRole);
91
92
/**
93
* Sets whether to ignore partial result exceptions during group searches
94
* @param ignore true to ignore partial result exceptions
95
*/
96
public void setIgnorePartialResultException(boolean ignore);
97
}
98
```
99
100
**Usage Examples:**
101
102
```java
103
// Basic authorities populator
104
DefaultLdapAuthoritiesPopulator authoritiesPopulator =
105
new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups");
106
107
// Customized group search
108
authoritiesPopulator.setGroupSearchFilter("member={0}");
109
authoritiesPopulator.setGroupRoleAttribute("cn");
110
authoritiesPopulator.setRolePrefix("ROLE_");
111
authoritiesPopulator.setConvertToUpperCase(true);
112
113
// Search configuration
114
authoritiesPopulator.setSearchSubtree(true);
115
authoritiesPopulator.setIgnorePartialResultException(true);
116
117
// Default role for all users
118
authoritiesPopulator.setDefaultRole("USER");
119
```
120
121
### UserDetailsServiceLdapAuthoritiesPopulator
122
123
Authorities populator that delegates to a UserDetailsService for authority retrieval.
124
125
```java { .api }
126
/**
127
* LdapAuthoritiesPopulator that obtains authorities from a UserDetailsService
128
*/
129
public class UserDetailsServiceLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
130
/**
131
* Creates a populator with the specified UserDetailsService
132
* @param userService the UserDetailsService to delegate to
133
*/
134
public UserDetailsServiceLdapAuthoritiesPopulator(UserDetailsService userService);
135
136
/**
137
* Gets authorities by loading UserDetails for the username
138
* @param userData the LDAP context operations (ignored)
139
* @param username the username to look up
140
* @return collection of authorities from UserDetailsService
141
*/
142
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
143
}
144
```
145
146
### NestedLdapAuthoritiesPopulator
147
148
Authorities populator that can recursively search nested LDAP groups.
149
150
```java { .api }
151
/**
152
* LDAP authorities populator that can recursively search static nested groups
153
*/
154
public class NestedLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {
155
/**
156
* Creates a nested authorities populator
157
* @param contextSource the LDAP context source
158
* @param groupSearchBase the base DN for group searches
159
*/
160
public NestedLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase);
161
162
/**
163
* Sets the maximum search depth for nested groups
164
* @param maxSearchDepth maximum depth (default: 10)
165
*/
166
public void setMaxSearchDepth(int maxSearchDepth);
167
168
/**
169
* Sets additional search filters for nested group searches
170
* @param additionalFilters map of filter names to filter expressions
171
*/
172
public void setAdditionalFilters(Map<String, String> additionalFilters);
173
174
/**
175
* Retrieves authorities including nested group memberships
176
* @param userData the user's LDAP context
177
* @param username the username
178
* @return collection of authorities from direct and nested groups
179
*/
180
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
181
}
182
```
183
184
### NullLdapAuthoritiesPopulator
185
186
No-operation authorities populator that returns empty authorities collection.
187
188
```java { .api }
189
/**
190
* Implementation of LdapAuthoritiesPopulator that returns an empty collection of authorities
191
* Useful when authorities are managed outside of LDAP or when no role-based authorization is needed
192
*/
193
public class NullLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
194
/**
195
* Returns an empty collection of granted authorities
196
* @param userData LDAP context operations for the user (ignored)
197
* @param username the username (ignored)
198
* @return empty collection of authorities
199
*/
200
public Collection<GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username);
201
}
202
```
203
204
## Custom Authority Population Strategies
205
206
### User Attribute-Based Authorities
207
208
```java { .api }
209
/**
210
* Example custom authorities populator that extracts roles from user attributes
211
*/
212
public class UserAttributeAuthoritiesPopulator implements LdapAuthoritiesPopulator {
213
private String roleAttributeName = "employeeType";
214
private String rolePrefix = "ROLE_";
215
216
/**
217
* Sets the user attribute name containing role information
218
* @param roleAttributeName the attribute name
219
*/
220
public void setRoleAttributeName(String roleAttributeName);
221
222
/**
223
* Sets the prefix for role names
224
* @param rolePrefix the role prefix
225
*/
226
public void setRolePrefix(String rolePrefix);
227
228
@Override
229
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
230
DirContextOperations userData, String username) {
231
232
Set<GrantedAuthority> authorities = new HashSet<>();
233
234
// Extract roles from user attributes
235
String[] roles = userData.getStringAttributes(roleAttributeName);
236
if (roles != null) {
237
for (String role : roles) {
238
authorities.add(new SimpleGrantedAuthority(rolePrefix + role.toUpperCase()));
239
}
240
}
241
242
return authorities;
243
}
244
}
245
```
246
247
### Composite Authorities Populator
248
249
```java { .api }
250
/**
251
* Composite authorities populator that combines multiple population strategies
252
*/
253
public class CompositeAuthoritiesPopulator implements LdapAuthoritiesPopulator {
254
private List<LdapAuthoritiesPopulator> populators;
255
256
/**
257
* Creates a composite populator with the specified delegate populators
258
* @param populators list of authorities populators to delegate to
259
*/
260
public CompositeAuthoritiesPopulator(List<LdapAuthoritiesPopulator> populators);
261
262
@Override
263
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
264
DirContextOperations userData, String username) {
265
266
Set<GrantedAuthority> allAuthorities = new HashSet<>();
267
268
// Collect authorities from all populators
269
for (LdapAuthoritiesPopulator populator : populators) {
270
Collection<? extends GrantedAuthority> authorities =
271
populator.getGrantedAuthorities(userData, username);
272
allAuthorities.addAll(authorities);
273
}
274
275
return allAuthorities;
276
}
277
}
278
```
279
280
## Configuration Examples
281
282
### Standard Group-Based Authorization
283
284
```java
285
@Configuration
286
public class LdapAuthoritiesConfig {
287
288
@Bean
289
public DefaultLdapAuthoritiesPopulator authoritiesPopulator() {
290
DefaultLdapAuthoritiesPopulator populator =
291
new DefaultLdapAuthoritiesPopulator(contextSource(), "ou=groups");
292
293
// Configure group search
294
populator.setGroupSearchFilter("member={0}");
295
populator.setGroupRoleAttribute("cn");
296
297
// Role configuration
298
populator.setRolePrefix("ROLE_");
299
populator.setConvertToUpperCase(true);
300
populator.setDefaultRole("USER");
301
302
// Search configuration
303
populator.setSearchSubtree(true);
304
populator.setIgnorePartialResultException(true);
305
306
return populator;
307
}
308
}
309
```
310
311
### Active Directory Group Membership
312
313
```java
314
@Bean
315
public DefaultLdapAuthoritiesPopulator activeDirectoryAuthorities() {
316
DefaultLdapAuthoritiesPopulator populator =
317
new DefaultLdapAuthoritiesPopulator(contextSource(), "");
318
319
// Active Directory uses memberOf attribute
320
populator.setGroupSearchFilter("(&(objectClass=group)(member={0}))");
321
populator.setGroupRoleAttribute("cn");
322
populator.setSearchSubtree(true);
323
324
// Active Directory specific settings
325
populator.setRolePrefix("ROLE_");
326
populator.setConvertToUpperCase(true);
327
328
return populator;
329
}
330
```
331
332
### Multi-Level Group Hierarchy
333
334
```java
335
@Component
336
public class HierarchicalGroupsPopulator implements LdapAuthoritiesPopulator {
337
338
private final SpringSecurityLdapTemplate ldapTemplate;
339
private final String groupSearchBase;
340
341
public HierarchicalGroupsPopulator(SpringSecurityLdapTemplate ldapTemplate) {
342
this.ldapTemplate = ldapTemplate;
343
this.groupSearchBase = "ou=groups";
344
}
345
346
@Override
347
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
348
DirContextOperations userData, String username) {
349
350
Set<GrantedAuthority> authorities = new HashSet<>();
351
Set<String> processedGroups = new HashSet<>();
352
353
// Find direct group memberships
354
Set<String> directGroups = findDirectGroups(userData.getDn().toString());
355
356
// Recursively find parent groups
357
for (String groupDn : directGroups) {
358
collectGroupHierarchy(groupDn, authorities, processedGroups);
359
}
360
361
return authorities;
362
}
363
364
private Set<String> findDirectGroups(String userDn) {
365
return ldapTemplate.searchForSingleAttributeValues(
366
groupSearchBase,
367
"member={0}",
368
new Object[]{userDn},
369
"distinguishedName"
370
);
371
}
372
373
private void collectGroupHierarchy(String groupDn, Set<GrantedAuthority> authorities,
374
Set<String> processedGroups) {
375
376
if (processedGroups.contains(groupDn)) {
377
return; // Avoid circular references
378
}
379
processedGroups.add(groupDn);
380
381
try {
382
// Get group information
383
DirContextOperations group = ldapTemplate.searchForContext("",
384
"distinguishedName={0}", new Object[]{groupDn});
385
386
String roleName = group.getStringAttribute("cn");
387
authorities.add(new SimpleGrantedAuthority("ROLE_" + roleName.toUpperCase()));
388
389
// Find parent groups
390
String[] memberOf = group.getStringAttributes("memberOf");
391
if (memberOf != null) {
392
for (String parentGroupDn : memberOf) {
393
collectGroupHierarchy(parentGroupDn, authorities, processedGroups);
394
}
395
}
396
397
} catch (Exception e) {
398
// Log and continue with other groups
399
logger.warn("Failed to process group: " + groupDn, e);
400
}
401
}
402
}
403
```
404
405
### Role Mapping Configuration
406
407
```java
408
@Component
409
public class MappedRoleAuthoritiesPopulator implements LdapAuthoritiesPopulator {
410
411
private final DefaultLdapAuthoritiesPopulator delegate;
412
private final Map<String, String> roleMapping;
413
414
public MappedRoleAuthoritiesPopulator(ContextSource contextSource) {
415
this.delegate = new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups");
416
this.roleMapping = initializeRoleMapping();
417
}
418
419
private Map<String, String> initializeRoleMapping() {
420
Map<String, String> mapping = new HashMap<>();
421
mapping.put("LDAP_ADMINS", "ADMIN");
422
mapping.put("LDAP_USERS", "USER");
423
mapping.put("LDAP_MANAGERS", "MANAGER");
424
mapping.put("LDAP_DEVELOPERS", "DEVELOPER");
425
return mapping;
426
}
427
428
@Override
429
public Collection<? extends GrantedAuthority> getGrantedAuthorities(
430
DirContextOperations userData, String username) {
431
432
// Get authorities from delegate
433
Collection<? extends GrantedAuthority> delegateAuthorities =
434
delegate.getGrantedAuthorities(userData, username);
435
436
// Map to application-specific roles
437
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
438
for (GrantedAuthority authority : delegateAuthorities) {
439
String role = authority.getAuthority().replace("ROLE_", "");
440
String mappedRole = roleMapping.getOrDefault(role, role);
441
mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + mappedRole));
442
}
443
444
return mappedAuthorities;
445
}
446
}
447
```
448
449
### Integration with Authentication Provider
450
451
```java
452
@Configuration
453
public class CompleteAuthenticationConfig {
454
455
@Bean
456
public LdapAuthenticationProvider ldapAuthenticationProvider() {
457
// Configure authenticator
458
BindAuthenticator authenticator = new BindAuthenticator(contextSource());
459
authenticator.setUserSearch(userSearch());
460
461
// Configure authorities populator
462
DefaultLdapAuthoritiesPopulator authoritiesPopulator =
463
new DefaultLdapAuthoritiesPopulator(contextSource(), "ou=groups");
464
authoritiesPopulator.setGroupSearchFilter("member={0}");
465
authoritiesPopulator.setGroupRoleAttribute("cn");
466
authoritiesPopulator.setRolePrefix("ROLE_");
467
authoritiesPopulator.setDefaultRole("USER");
468
469
// Create authentication provider
470
LdapAuthenticationProvider provider =
471
new LdapAuthenticationProvider(authenticator, authoritiesPopulator);
472
473
// Custom user details mapping
474
provider.setUserDetailsContextMapper(customUserDetailsMapper());
475
476
return provider;
477
}
478
479
@Bean
480
public UserDetailsContextMapper customUserDetailsMapper() {
481
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
482
mapper.setRolePrefix("ROLE_");
483
return mapper;
484
}
485
}
486
```