This project has retired. For details please refer to its
Attic page.
DefaultLdapRoleMapper xref
1 package org.apache.archiva.redback.common.ldap.role;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import com.google.common.collect.ArrayListMultimap;
22 import com.google.common.collect.Multimap;
23 import org.apache.archiva.redback.common.ldap.MappingException;
24 import org.apache.archiva.redback.common.ldap.connection.LdapConnectionFactory;
25 import org.apache.archiva.redback.common.ldap.connection.LdapException;
26 import org.apache.archiva.redback.configuration.UserConfiguration;
27 import org.apache.archiva.redback.configuration.UserConfigurationKeys;
28 import org.apache.commons.lang.StringUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.stereotype.Service;
32
33 import javax.annotation.PostConstruct;
34 import javax.inject.Inject;
35 import javax.inject.Named;
36 import javax.naming.NameAlreadyBoundException;
37 import javax.naming.NameNotFoundException;
38 import javax.naming.NamingEnumeration;
39 import javax.naming.NamingException;
40 import javax.naming.directory.Attribute;
41 import javax.naming.directory.Attributes;
42 import javax.naming.directory.BasicAttribute;
43 import javax.naming.directory.BasicAttributes;
44 import javax.naming.directory.DirContext;
45 import javax.naming.directory.ModificationItem;
46 import javax.naming.directory.SearchControls;
47 import javax.naming.directory.SearchResult;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Collections;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Set;
55
56
57
58
59
60 @Service( "ldapRoleMapper#default" )
61 public class DefaultLdapRoleMapper
62 implements LdapRoleMapper
63 {
64
65 private Logger log = LoggerFactory.getLogger( getClass() );
66
67 @Inject
68 @Named( value = "ldapConnectionFactory#configurable" )
69 private LdapConnectionFactory ldapConnectionFactory;
70
71 @Inject
72 @Named( value = "userConfiguration#default" )
73 private UserConfiguration userConf;
74
75 @Inject
76 @Named( value = "ldapRoleMapperConfiguration#default" )
77 private LdapRoleMapperConfiguration ldapRoleMapperConfiguration;
78
79
80
81
82
83 private String ldapGroupClass = "groupOfUniqueNames";
84
85 private String groupsDn;
86
87 private String baseDn;
88
89 private boolean useDefaultRoleName = false;
90
91
92
93
94
95 private String userIdAttribute = "uid";
96
97 @PostConstruct
98 public void initialize()
99 {
100 this.ldapGroupClass = userConf.getString( UserConfigurationKeys.LDAP_GROUPS_CLASS, this.ldapGroupClass );
101
102 this.baseDn = userConf.getConcatenatedList( UserConfigurationKeys.LDAP_BASEDN, this.baseDn );
103
104 this.groupsDn = userConf.getConcatenatedList( UserConfigurationKeys.LDAP_GROUPS_BASEDN, this.groupsDn );
105
106 if ( StringUtils.isEmpty( this.groupsDn ) )
107 {
108 this.groupsDn = this.baseDn;
109 }
110
111 this.useDefaultRoleName =
112 userConf.getBoolean( UserConfigurationKeys.LDAP_GROUPS_USE_ROLENAME, this.useDefaultRoleName );
113
114 this.userIdAttribute = userConf.getString( UserConfigurationKeys.LDAP_USER_ID_ATTRIBUTE, this.userIdAttribute );
115 }
116
117 public List<String> getAllGroups( DirContext context )
118 throws MappingException
119 {
120
121 NamingEnumeration<SearchResult> namingEnumeration = null;
122 try
123 {
124
125 SearchControls searchControls = new SearchControls();
126
127 searchControls.setDerefLinkFlag( true );
128 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
129
130 String filter = "objectClass=" + getLdapGroupClass();
131
132 namingEnumeration = context.search( getGroupsDn(), filter, searchControls );
133
134 List<String> allGroups = new ArrayList<String>();
135
136 while ( namingEnumeration.hasMore() )
137 {
138 SearchResult searchResult = namingEnumeration.next();
139
140 String groupName = searchResult.getName();
141
142 groupName = StringUtils.substringAfter( groupName, "=" );
143
144 log.debug( "found groupName: '{}", groupName );
145
146 allGroups.add( groupName );
147
148 }
149
150 return allGroups;
151 }
152 catch ( LdapException e )
153 {
154 throw new MappingException( e.getMessage(), e );
155 }
156 catch ( NamingException e )
157 {
158 throw new MappingException( e.getMessage(), e );
159 }
160
161 finally
162 {
163 close( namingEnumeration );
164 }
165 }
166
167 protected void closeNamingEnumeration( NamingEnumeration namingEnumeration )
168 {
169 if ( namingEnumeration != null )
170 {
171 try
172 {
173 namingEnumeration.close();
174 }
175 catch ( NamingException e )
176 {
177 log.warn( "failed to close NamingEnumeration", e );
178 }
179 }
180 }
181
182 public boolean hasRole( DirContext context, String roleName )
183 throws MappingException
184 {
185 String groupName = findGroupName( roleName );
186
187 if ( groupName == null )
188 {
189 if ( this.useDefaultRoleName )
190 {
191 groupName = roleName;
192 }
193 else
194 {
195 log.warn( "skip group creation as no mapping for roleName:'{}'", roleName );
196 return false;
197 }
198 }
199 NamingEnumeration<SearchResult> namingEnumeration = null;
200 try
201 {
202
203 SearchControls searchControls = new SearchControls();
204
205 searchControls.setDerefLinkFlag( true );
206 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
207
208 String filter = "objectClass=" + getLdapGroupClass();
209
210 namingEnumeration = context.search( "cn=" + groupName + "," + getGroupsDn(), filter, searchControls );
211
212 return namingEnumeration.hasMore();
213 }
214 catch ( NameNotFoundException e )
215 {
216 log.debug( "group {} for role {} not found", groupName, roleName );
217 return false;
218 }
219 catch ( LdapException e )
220 {
221 throw new MappingException( e.getMessage(), e );
222 }
223 catch ( NamingException e )
224 {
225 throw new MappingException( e.getMessage(), e );
226 }
227
228 finally
229 {
230 close( namingEnumeration );
231 }
232 }
233
234 public List<String> getAllRoles( DirContext context )
235 throws MappingException
236 {
237 List<String> groups = getAllGroups( context );
238
239 if ( groups.isEmpty() )
240 {
241 return Collections.emptyList();
242 }
243
244 Set<String> roles = new HashSet<String>( groups.size() );
245
246 Map<String, Collection<String>> mapping = ldapRoleMapperConfiguration.getLdapGroupMappings();
247
248 for ( String group : groups )
249 {
250 Collection<String> rolesPerGroup = mapping.get( group );
251 if ( rolesPerGroup != null )
252 {
253 for ( String role : rolesPerGroup )
254 {
255 roles.add( role );
256 }
257 }
258 }
259
260 return new ArrayList<String>( roles );
261 }
262
263 public List<String> getGroupsMember( String group, DirContext context )
264 throws MappingException
265 {
266
267 NamingEnumeration<SearchResult> namingEnumeration = null;
268 try
269 {
270
271 SearchControls searchControls = new SearchControls();
272
273 searchControls.setDerefLinkFlag( true );
274 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
275
276 String filter = "objectClass=" + getLdapGroupClass();
277
278 namingEnumeration = context.search( "cn=" + group + "," + getGroupsDn(), filter, searchControls );
279
280 List<String> allMembers = new ArrayList<String>();
281
282 while ( namingEnumeration.hasMore() )
283 {
284 SearchResult searchResult = namingEnumeration.next();
285
286 Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" );
287
288 if ( uniqueMemberAttr != null )
289 {
290 NamingEnumeration<String> allMembersEnum = (NamingEnumeration<String>) uniqueMemberAttr.getAll();
291 while ( allMembersEnum.hasMore() )
292 {
293 String userName = allMembersEnum.next();
294
295 userName = StringUtils.substringAfter( userName, "=" );
296 userName = StringUtils.substringBefore( userName, "," );
297 log.debug( "found userName for group {}: '{}", group, userName );
298
299 allMembers.add( userName );
300 }
301 close( allMembersEnum );
302 }
303
304
305 }
306
307 return allMembers;
308 }
309 catch ( LdapException e )
310 {
311 throw new MappingException( e.getMessage(), e );
312 }
313 catch ( NamingException e )
314 {
315 throw new MappingException( e.getMessage(), e );
316 }
317
318 finally
319 {
320 close( namingEnumeration );
321 }
322 }
323
324 public List<String> getGroups( String username, DirContext context )
325 throws MappingException
326 {
327
328 List<String> userGroups = new ArrayList<String>();
329
330 NamingEnumeration<SearchResult> namingEnumeration = null;
331 try
332 {
333
334 SearchControls searchControls = new SearchControls();
335
336 searchControls.setDerefLinkFlag( true );
337 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
338
339 String filter =
340 new StringBuilder().append( "(&" ).append( "(objectClass=" + getLdapGroupClass() + ")" ).append(
341 "(uniquemember=" ).append( this.userIdAttribute + "=" + username + "," + this.getBaseDn() ).append(
342 ")" ).append( ")" ).toString();
343
344 log.debug( "filter: {}", filter );
345
346 namingEnumeration = context.search( getGroupsDn(), filter, searchControls );
347
348 while ( namingEnumeration.hasMore() )
349 {
350 SearchResult searchResult = namingEnumeration.next();
351
352 List<String> allMembers = new ArrayList<String>();
353
354 Attribute uniqueMemberAttr = searchResult.getAttributes().get( "uniquemember" );
355
356 if ( uniqueMemberAttr != null )
357 {
358 NamingEnumeration<String> allMembersEnum = (NamingEnumeration<String>) uniqueMemberAttr.getAll();
359 while ( allMembersEnum.hasMore() )
360 {
361 String userName = allMembersEnum.next();
362
363 userName = StringUtils.substringAfter( userName, "=" );
364 userName = StringUtils.substringBefore( userName, "," );
365 allMembers.add( userName );
366 }
367 close( allMembersEnum );
368 }
369
370 if ( allMembers.contains( username ) )
371 {
372 String groupName = searchResult.getName();
373
374 groupName = StringUtils.substringAfter( groupName, "=" );
375 userGroups.add( groupName );
376
377 }
378
379
380 }
381
382 return userGroups;
383 }
384 catch ( LdapException e )
385 {
386 throw new MappingException( e.getMessage(), e );
387 }
388 catch ( NamingException e )
389 {
390 throw new MappingException( e.getMessage(), e );
391 }
392 finally
393 {
394 close( namingEnumeration );
395 }
396 }
397
398 public List<String> getRoles( String username, DirContext context, Collection<String> realRoles )
399 throws MappingException
400 {
401 List<String> groups = getGroups( username, context );
402
403 Map<String, Collection<String>> rolesMapping = ldapRoleMapperConfiguration.getLdapGroupMappings();
404
405 Set<String> roles = new HashSet<String>( groups.size() );
406
407 for ( String group : groups )
408 {
409 Collection<String> rolesPerGroup = rolesMapping.get( group );
410 if ( rolesPerGroup != null )
411 {
412 roles.addAll( rolesPerGroup );
413 }
414 else
415 {
416 if ( this.useDefaultRoleName && realRoles != null && realRoles.contains( group ) )
417 {
418 roles.add( group );
419 }
420 }
421 }
422
423 return new ArrayList<String>( roles );
424 }
425
426 private void close( NamingEnumeration namingEnumeration )
427 {
428 if ( namingEnumeration != null )
429 {
430 try
431 {
432 namingEnumeration.close();
433 }
434 catch ( NamingException e )
435 {
436 log.warn( "fail to close namingEnumeration: {}", e.getMessage() );
437 }
438 }
439 }
440
441 public String getGroupsDn()
442 {
443 return this.groupsDn;
444 }
445
446 public String getLdapGroupClass()
447 {
448 return this.ldapGroupClass;
449 }
450
451
452 public boolean saveRole( String roleName, DirContext context )
453 throws MappingException
454 {
455
456 if ( hasRole( context, roleName ) )
457 {
458 return true;
459 }
460
461 String groupName = findGroupName( roleName );
462
463 if ( groupName == null )
464 {
465 if ( this.useDefaultRoleName )
466 {
467 groupName = roleName;
468 }
469 else
470 {
471 log.warn( "skip group creation as no mapping for roleName:'{}'", roleName );
472 return false;
473 }
474 }
475
476 List<String> allGroups = getAllGroups( context );
477 if ( allGroups.contains( groupName ) )
478 {
479 log.info( "group {} already exists for role.", groupName, roleName );
480 return false;
481 }
482
483 Attributes attributes = new BasicAttributes( true );
484 BasicAttribute objectClass = new BasicAttribute( "objectClass" );
485 objectClass.add( "top" );
486 objectClass.add( "groupOfUniqueNames" );
487 attributes.put( objectClass );
488 attributes.put( "cn", groupName );
489
490
491
492 BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" );
493 basicAttribute.add( this.userIdAttribute + "=admin," + getBaseDn() );
494 attributes.put( basicAttribute );
495
496 try
497 {
498 String dn = "cn=" + groupName + "," + this.groupsDn;
499
500 context.createSubcontext( dn, attributes );
501
502 log.info( "created group with dn:'{}", dn );
503
504 return true;
505 }
506 catch ( NameAlreadyBoundException e )
507 {
508 log.info( "skip group '{}' creation as already exists", groupName );
509 return true;
510 }
511 catch ( LdapException e )
512 {
513 throw new MappingException( e.getMessage(), e );
514
515 }
516 catch ( NamingException e )
517 {
518 throw new MappingException( e.getMessage(), e );
519 }
520 }
521
522 public boolean saveUserRole( String roleName, String username, DirContext context )
523 throws MappingException
524 {
525
526 String groupName = findGroupName( roleName );
527
528 if ( groupName == null )
529 {
530 log.warn( "no group found for role '{}", roleName );
531 groupName = roleName;
532 }
533
534 NamingEnumeration<SearchResult> namingEnumeration = null;
535 try
536 {
537 SearchControls searchControls = new SearchControls();
538
539 searchControls.setDerefLinkFlag( true );
540 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
541
542 String filter = "objectClass=" + getLdapGroupClass();
543
544 namingEnumeration = context.search( "cn=" + groupName + "," + getGroupsDn(), filter, searchControls );
545
546 while ( namingEnumeration.hasMore() )
547 {
548 SearchResult searchResult = namingEnumeration.next();
549 Attribute attribute = searchResult.getAttributes().get( "uniquemember" );
550 if ( attribute == null )
551 {
552 BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" );
553 basicAttribute.add( this.userIdAttribute + "=" + username + "," + getBaseDn() );
554 context.modifyAttributes( "cn=" + groupName + "," + getGroupsDn(), new ModificationItem[]{
555 new ModificationItem( DirContext.ADD_ATTRIBUTE, basicAttribute ) } );
556 }
557 else
558 {
559 attribute.add( this.userIdAttribute + "=" + username + "," + getBaseDn() );
560 context.modifyAttributes( "cn=" + groupName + "," + getGroupsDn(), new ModificationItem[]{
561 new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attribute ) } );
562 }
563 return true;
564 }
565
566 return false;
567 }
568 catch ( LdapException e )
569 {
570 throw new MappingException( e.getMessage(), e );
571 }
572 catch ( NamingException e )
573 {
574 throw new MappingException( e.getMessage(), e );
575 }
576
577 finally
578 {
579 if ( namingEnumeration != null )
580 {
581 try
582 {
583 namingEnumeration.close();
584 }
585 catch ( NamingException e )
586 {
587 log.warn( "failed to close search results", e );
588 }
589 }
590 }
591 }
592
593 public boolean removeUserRole( String roleName, String username, DirContext context )
594 throws MappingException
595 {
596 String groupName = findGroupName( roleName );
597
598 if ( groupName == null )
599 {
600 log.warn( "no group found for role '{}", roleName );
601 return false;
602 }
603
604 NamingEnumeration<SearchResult> namingEnumeration = null;
605 try
606 {
607
608 SearchControls searchControls = new SearchControls();
609
610 searchControls.setDerefLinkFlag( true );
611 searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
612
613 String filter = "objectClass=" + getLdapGroupClass();
614
615 namingEnumeration = context.search( "cn=" + groupName + "," + getGroupsDn(), filter, searchControls );
616
617 while ( namingEnumeration.hasMore() )
618 {
619 SearchResult searchResult = namingEnumeration.next();
620 Attribute attribute = searchResult.getAttributes().get( "uniquemember" );
621 if ( attribute != null )
622 {
623 BasicAttribute basicAttribute = new BasicAttribute( "uniquemember" );
624 basicAttribute.add( this.userIdAttribute + "=" + username + "," + getGroupsDn() );
625 context.modifyAttributes( "cn=" + groupName + "," + getGroupsDn(), new ModificationItem[]{
626 new ModificationItem( DirContext.REMOVE_ATTRIBUTE, basicAttribute ) } );
627 }
628 return true;
629 }
630
631 return false;
632 }
633 catch ( LdapException e )
634 {
635 throw new MappingException( e.getMessage(), e );
636 }
637 catch ( NamingException e )
638 {
639 throw new MappingException( e.getMessage(), e );
640 }
641
642 finally
643 {
644 if ( namingEnumeration != null )
645 {
646 try
647 {
648 namingEnumeration.close();
649 }
650 catch ( NamingException e )
651 {
652 log.warn( "failed to close search results", e );
653 }
654 }
655 }
656 }
657
658 public void removeAllRoles( DirContext context )
659 throws MappingException
660 {
661
662 Collection<String> groups = ldapRoleMapperConfiguration.getLdapGroupMappings().keySet();
663
664 try
665 {
666 for ( String groupName : groups )
667 {
668
669 String dn = "cn=" + groupName + "," + this.groupsDn;
670
671 context.unbind( dn );
672
673 log.debug( "deleted group with dn:'{}", dn );
674 }
675
676 }
677 catch ( LdapException e )
678 {
679 throw new MappingException( e.getMessage(), e );
680
681 }
682 catch ( NamingException e )
683 {
684 throw new MappingException( e.getMessage(), e );
685 }
686 }
687
688 public void removeRole( String roleName, DirContext context )
689 throws MappingException
690 {
691
692 String groupName = findGroupName( roleName );
693
694 try
695 {
696
697 String dn = "cn=" + groupName + "," + this.groupsDn;
698
699 context.unbind( dn );
700
701 log.info( "deleted group with dn:'{}", dn );
702
703 }
704 catch ( LdapException e )
705 {
706 throw new MappingException( e.getMessage(), e );
707
708 }
709 catch ( NamingException e )
710 {
711 throw new MappingException( e.getMessage(), e );
712 }
713 }
714
715
716
717
718
719
720
721
722
723
724 public void setGroupsDn( String groupsDn )
725 {
726 this.groupsDn = groupsDn;
727 }
728
729 public void setLdapGroupClass( String ldapGroupClass )
730 {
731 this.ldapGroupClass = ldapGroupClass;
732 }
733
734 public void setUserConf( UserConfiguration userConf )
735 {
736 this.userConf = userConf;
737 }
738
739 public void setLdapConnectionFactory( LdapConnectionFactory ldapConnectionFactory )
740 {
741 this.ldapConnectionFactory = ldapConnectionFactory;
742 }
743
744 public String getBaseDn()
745 {
746 return baseDn;
747 }
748
749 public void setBaseDn( String baseDn )
750 {
751 this.baseDn = baseDn;
752 }
753
754
755
756
757
758 protected String findGroupName( String role )
759 throws MappingException
760 {
761 Map<String, Collection<String>> mapping = ldapRoleMapperConfiguration.getLdapGroupMappings();
762
763 for ( Map.Entry<String, Collection<String>> entry : mapping.entrySet() )
764 {
765 if ( entry.getValue().contains( role ) )
766 {
767 return entry.getKey();
768 }
769 }
770 return null;
771 }
772
773
774 public String getUserIdAttribute()
775 {
776 return userIdAttribute;
777 }
778
779 public void setUserIdAttribute( String userIdAttribute )
780 {
781 this.userIdAttribute = userIdAttribute;
782 }
783
784 public boolean isUseDefaultRoleName()
785 {
786 return useDefaultRoleName;
787 }
788
789 public void setUseDefaultRoleName( boolean useDefaultRoleName )
790 {
791 this.useDefaultRoleName = useDefaultRoleName;
792 }
793 }