KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > security > ldap > LDAPSecurityService


1 package org.apache.turbine.services.security.ldap;
2
3 /*
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License")
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.util.Hashtable JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.Vector JavaDoc;
22 import javax.naming.NameAlreadyBoundException JavaDoc;
23 import javax.naming.NamingEnumeration JavaDoc;
24 import javax.naming.NamingException JavaDoc;
25 import javax.naming.directory.Attribute JavaDoc;
26 import javax.naming.directory.Attributes JavaDoc;
27 import javax.naming.directory.BasicAttribute JavaDoc;
28 import javax.naming.directory.BasicAttributes JavaDoc;
29 import javax.naming.directory.DirContext JavaDoc;
30 import javax.naming.directory.SearchControls JavaDoc;
31 import javax.naming.directory.SearchResult JavaDoc;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.torque.util.Criteria;
36 import org.apache.turbine.om.security.Group;
37 import org.apache.turbine.om.security.Permission;
38 import org.apache.turbine.om.security.Role;
39 import org.apache.turbine.om.security.TurbineGroup;
40 import org.apache.turbine.om.security.TurbinePermission;
41 import org.apache.turbine.om.security.TurbineRole;
42 import org.apache.turbine.om.security.User;
43 import org.apache.turbine.services.security.BaseSecurityService;
44 import org.apache.turbine.services.security.TurbineSecurity;
45 import org.apache.turbine.util.security.AccessControlList;
46 import org.apache.turbine.util.security.DataBackendException;
47 import org.apache.turbine.util.security.EntityExistsException;
48 import org.apache.turbine.util.security.GroupSet;
49 import org.apache.turbine.util.security.PermissionSet;
50 import org.apache.turbine.util.security.RoleSet;
51 import org.apache.turbine.util.security.UnknownEntityException;
52
53 /**
54  * An implementation of SecurityService that uses LDAP as a backend.
55  *
56  * @author <a HREF="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
57  * @author <a HREF="mailto:tadewunmi@gluecode.com">Tracy M. Adewunmi </a>
58  * @author <a HREF="mailto:lflournoy@gluecode.com">Leonard J. Flournoy </a>
59  * @author <a HREF="mailto:jvanzyl@apache.org">Jason van Zyl</a>
60  * @author <a HREF="mailto:marco@intermeta.de">Marco Kn&uuml;ttel</a>
61  * @author <a HREF="mailto:hhernandez@itweb.com.mx">Humberto Hernandez</a>
62  * @version $Id: LDAPSecurityService.java,v 1.16.2.2 2004/05/20 03:06:48 seade Exp $
63  */

64 public class LDAPSecurityService extends BaseSecurityService
65 {
66
67     /** Logging */
68     private static Log log = LogFactory.getLog(LDAPSecurityService.class);
69
70     /*
71      * -----------------------------------------------------------------------
72      * C R E A T I O N O F A C C E S S C O N T R O L L I S T
73      * -----------------------------------------------------------------------
74      */

75
76     /**
77      * Constructs an AccessControlList for a specific user.
78      *
79      * This method creates a snapshot of the state of security information
80      * concerning this user, at the moment of invocation and stores it
81      * into an AccessControlList object.
82      *
83      * @param user the user for whom the AccessControlList are to be retrieved
84      * @throws DataBackendException if there was an error accessing the backend.
85      * @throws UnknownEntityException if user account is not present.
86      * @return an AccessControlList for a specific user.
87      */

88     public AccessControlList getACL(User user)
89             throws DataBackendException, UnknownEntityException
90     {
91         if (!TurbineSecurity.accountExists(user))
92         {
93             throw new UnknownEntityException("The account '"
94                     + user.getName() + "' does not exist");
95         }
96         try
97         {
98             Hashtable JavaDoc roles = new Hashtable JavaDoc();
99             Hashtable JavaDoc permissions = new Hashtable JavaDoc();
100
101             // notify the state modifiers (writers) that we want to create
102
// the snapshot.
103
lockShared();
104
105             // construct the snapshot:
106
// foreach group in the system
107
Iterator JavaDoc groupsIterator = getAllGroups().iterator();
108
109             while (groupsIterator.hasNext())
110             {
111                 Group group = (Group) groupsIterator.next();
112
113                 // get roles of user in the group
114
RoleSet groupRoles = getRoles(user, group);
115
116                 // put the Set into roles(group)
117
roles.put(group, groupRoles);
118                 // collect all permissoins in this group
119
PermissionSet groupPermissions = new PermissionSet();
120                 // foreach role in Set
121
Iterator JavaDoc rolesIterator = groupRoles.iterator();
122
123                 while (rolesIterator.hasNext())
124                 {
125                     Role role = (Role) rolesIterator.next();
126                     // get permissions of the role
127
PermissionSet rolePermissions = getPermissions(role);
128
129                     groupPermissions.add(rolePermissions);
130                 }
131                 // put the Set into permissions(group)
132
permissions.put(group, groupPermissions);
133             }
134             return getAclInstance(roles, permissions);
135         }
136         catch (Exception JavaDoc e)
137         {
138             throw new DataBackendException("Failed to build ACL for user '"
139                     + user.getName() + "'", e);
140         }
141         finally
142         {
143             // notify the state modifiers that we are done creating
144
// the snapshot.
145
unlockShared();
146         }
147     }
148
149     /*
150      * -----------------------------------------------------------------------
151      * S E C U R I T Y M A N A G E M E N T
152      * -----------------------------------------------------------------------
153      */

154
155     /**
156      * Grant an User a Role in a Group.
157      *
158      * @param user the user.
159      * @param group the group.
160      * @param role the role.
161      * @throws DataBackendException if there was an error accessing the backend.
162      * @throws UnknownEntityException if user account, group or role
163      * is not present.
164      */

165     public synchronized void grant(User user, Group group, Role role)
166             throws DataBackendException, UnknownEntityException
167     {
168         try
169         {
170             lockExclusive();
171
172             String JavaDoc userName = user.getName();
173             String JavaDoc roleName = role.getName();
174             String JavaDoc groupName = group.getName();
175
176             if (!accountExists(user))
177             {
178                 throw new UnknownEntityException(
179                         "User '" + userName + "' does not exist");
180             }
181
182             if (!checkExists(role))
183             {
184                 throw new UnknownEntityException(
185                         "Role '" + roleName + "' does not exist");
186             }
187
188             if (!checkExists(group))
189             {
190                 throw new UnknownEntityException(
191                         "Group '" + groupName + "' does not exist");
192             }
193
194             // Make the distinguished name.
195
String JavaDoc dn = "turbineGroupName=" + groupName + ","
196                     + LDAPSecurityConstants.getNameAttribute()
197                     + "=" + userName + ","
198                     + LDAPSecurityConstants.getBaseSearch();
199
200
201             // Connect to LDAP.
202
DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
203
204             // Make the attributes.
205
Attributes JavaDoc attrs = new BasicAttributes JavaDoc();
206
207             attrs.put(new BasicAttribute JavaDoc("turbineRoleName", roleName));
208             attrs.put(new BasicAttribute JavaDoc("objectClass", "turbineUserGroup"));
209             attrs.put(new BasicAttribute JavaDoc("turbineUserUniqueId", userName));
210             try
211             {
212                 // Add the turbineUserGroup.
213
ctx.bind(dn, null, attrs);
214             }
215             catch (NameAlreadyBoundException JavaDoc ex)
216             {
217                 // Since turbineUserGroup had already been created
218
// then just add the role name attribute.
219
attrs = new BasicAttributes JavaDoc();
220                 attrs.put(new BasicAttribute JavaDoc("turbineRoleName", roleName));
221                 ctx.modifyAttributes(dn, DirContext.ADD_ATTRIBUTE, attrs);
222             }
223
224         }
225         catch (NamingException JavaDoc ex)
226         {
227             throw new DataBackendException("NamingException caught", ex);
228         }
229         finally
230         {
231             unlockExclusive();
232         }
233     }
234
235     /**
236      * Revoke a Role in a Group from an User.
237      *
238      * @param user the user.
239      * @param group the group.
240      * @param role the role.
241      * @throws DataBackendException if there was an error accessing the backend.
242      * @throws UnknownEntityException if user account, group or role is
243      * not present.
244      */

245     public synchronized void revoke(User user, Group group, Role role)
246             throws DataBackendException, UnknownEntityException
247     {
248         try
249         {
250             lockExclusive();
251
252             String JavaDoc userName = user.getName();
253             String JavaDoc roleName = role.getName();
254             String JavaDoc groupName = group.getName();
255
256             if (!accountExists(user))
257             {
258                 throw new UnknownEntityException(
259                         "User '" + userName + "' does not exist");
260             }
261
262             if (!checkExists(role))
263             {
264                 throw new UnknownEntityException(
265                         "Role '" + roleName + "' does not exist");
266             }
267
268             if (!checkExists(group))
269             {
270                 throw new UnknownEntityException(
271                         "Group '" + groupName + "' does not exist");
272             }
273
274             // Make the distinguished name.
275
String JavaDoc dn = "turbineGroupName=" + groupName + ","
276                     + LDAPSecurityConstants.getNameAttribute()
277                     + "=" + userName + ","
278                     + LDAPSecurityConstants.getBaseSearch();
279
280             // Make the attributes.
281
Attributes JavaDoc attrs = new BasicAttributes JavaDoc();
282
283             attrs.put(new BasicAttribute JavaDoc("turbineRoleName", roleName));
284
285             // Connect to LDAP.
286
DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
287
288             // Remove the role.
289
ctx.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, attrs);
290
291         }
292         catch (NamingException JavaDoc ex)
293         {
294             throw new DataBackendException("NamingException caught", ex);
295         }
296         finally
297         {
298             unlockExclusive();
299         }
300     }
301
302     /**
303      * Grants a Role a Permission
304      *
305      * @param role the Role.
306      * @param permission the Permission.
307      * @throws DataBackendException if there was an error accessing the backend.
308      * @throws UnknownEntityException if role or permission is not present.
309      */

310     public synchronized void grant(Role role, Permission permission)
311             throws DataBackendException, UnknownEntityException
312     {
313         try
314         {
315             lockExclusive();
316
317             String JavaDoc roleName = role.getName();
318             String JavaDoc permName = permission.getName();
319
320             if (!checkExists(role))
321             {
322                 throw new UnknownEntityException(
323                         "Role '" + roleName + "' does not exist");
324             }
325
326             if (!checkExists(permission))
327             {
328                 throw new UnknownEntityException(
329                         "Permission '" + permName + "' does not exist");
330             }
331
332             // Make the distinguished name.
333
String JavaDoc dn = "turbineRoleName=" + roleName + ","
334                     + LDAPSecurityConstants.getBaseSearch();
335
336             // Make the attributes.
337
Attributes JavaDoc attrs = new BasicAttributes JavaDoc();
338
339             attrs.put(new BasicAttribute JavaDoc("turbinePermissionName", permName));
340
341             // Connect to LDAP.
342
DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
343
344             // Add the permission.
345
ctx.modifyAttributes(dn, DirContext.ADD_ATTRIBUTE, attrs);
346
347         }
348         catch (NamingException JavaDoc ex)
349         {
350             throw new DataBackendException("NamingException caught", ex);
351         }
352         finally
353         {
354             unlockExclusive();
355         }
356     }
357
358     /**
359      * Revokes a Permission from a Role.
360      *
361      * @param role the Role.
362      * @param permission the Permission.
363      * @throws DataBackendException if there was an error accessing the backend.
364      * @throws UnknownEntityException if role or permission is not present.
365      */

366     public synchronized void revoke(Role role, Permission permission)
367             throws DataBackendException, UnknownEntityException
368     {
369         try
370         {
371             lockExclusive();
372
373             String JavaDoc roleName = role.getName();
374             String JavaDoc permName = permission.getName();
375
376             if (!checkExists(role))
377             {
378                 throw new UnknownEntityException(
379                         "Role '" + roleName + "' does not exist");
380             }
381
382             if (!checkExists(permission))
383             {
384                 throw new UnknownEntityException(
385                         "Permission '" + permName + "' does not exist");
386             }
387
388             // Make the distinguished name.
389
String JavaDoc dn = "turbineRoleName=" + roleName + ","
390                     + LDAPSecurityConstants.getBaseSearch();
391
392             // Make the attributes.
393
Attributes JavaDoc attrs = new BasicAttributes JavaDoc();
394
395             attrs.put(new BasicAttribute JavaDoc("turbinePermissionName", permName));
396
397             // Connect to LDAP.
398
DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
399
400             // Remove the permission.
401
ctx.modifyAttributes(dn, DirContext.REMOVE_ATTRIBUTE, attrs);
402
403         }
404         catch (NamingException JavaDoc ex)
405         {
406             throw new DataBackendException("NamingException caught", ex);
407         }
408         finally
409         {
410             unlockExclusive();
411         }
412     }
413
414     /*
415      * -----------------------------------------------------------------------
416      * G R O U P / R O L E / P E R M I S S I O N M A N A G E M E N T
417      * -----------------------------------------------------------------------
418      */

419
420     /**
421      * Retrieves a new Group. It creates
422      * a new Group based on the Services Group implementation. It does not
423      * create a new Group in the system though. Use addGroup for that.
424      * <strong>Not implemented</strong>
425      *
426      * @param groupName The name of the Group to be retrieved.
427      * @return a Group.
428      */

429     public Group getNewGroup(String JavaDoc groupName)
430     {
431         return (Group) new TurbineGroup(groupName);
432     }
433
434     /**
435      * Retrieves a new Role. It creates
436      * a new Role based on the Services Role implementation. It does not
437      * create a new Role in the system though. Use addRole for that.
438      * <strong>Not implemented</strong>
439      *
440      * @param roleName The name of the Group to be retrieved.
441      * @return a Role.
442      */

443     public Role getNewRole(String JavaDoc roleName)
444     {
445         return (Role) new TurbineRole(roleName);
446     }
447
448     /**
449      * Retrieves a new Permission. It creates
450      * a new Permission based on the Services Permission implementation. It
451      * does not create a new Permission in the system though. Use create for
452      * that.
453      * <strong>Not implemented</strong>
454      *
455      * @param permissionName The name of the Permission to be retrieved.
456      * @return a Permission
457      */

458     public Permission getNewPermission(String JavaDoc permissionName)
459     {
460         return (Permission) new TurbinePermission(permissionName);
461     }
462
463     /**
464      * Retrieve a set of Groups that meet the specified Criteria.
465      *
466      * @param criteria Criteria of Group selection.
467      * @return a set of Groups that meet the specified Criteria.
468      * @throws DataBackendException if there is problem with the Backend.
469      */

470     public GroupSet getGroups(Criteria criteria)
471             throws DataBackendException
472     {
473         Vector JavaDoc groups = new Vector JavaDoc();
474
475         try
476         {
477             DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
478
479             String JavaDoc baseSearch = LDAPSecurityConstants.getBaseSearch();
480             String JavaDoc filter = "(objectclass=turbineGroup)";
481
482             /*
483              * Create the default search controls.
484              */

485             SearchControls JavaDoc ctls = new SearchControls JavaDoc();
486
487             NamingEnumeration JavaDoc answer = ctx.search(baseSearch, filter, ctls);
488
489             while (answer.hasMore())
490             {
491                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
492                 Attributes JavaDoc attribs = sr.getAttributes();
493                 Attribute JavaDoc attr = attribs.get("turbineGroupName");
494
495                 if (attr != null && attr.get() != null)
496                 {
497                     Group group = getNewGroup(attr.get().toString());
498
499                     groups.add(group);
500                 }
501             }
502         }
503         catch (NamingException JavaDoc ex)
504         {
505             throw new DataBackendException("NamingException caught", ex);
506         }
507         return new GroupSet(groups);
508     }
509
510     /** Get the Roles that a user belongs in a specific group.
511      * @param user The user.
512      * @param group The group
513      * @throws DataBackendException if there is a problem with
514      * the LDAP service.
515      * @return a RoleSet.
516      */

517     private RoleSet getRoles(User user, Group group)
518             throws DataBackendException
519     {
520         Vector JavaDoc roles = new Vector JavaDoc(0);
521
522         try
523         {
524             DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
525
526             String JavaDoc baseSearch = LDAPSecurityConstants.getBaseSearch();
527             String JavaDoc filter = "(& ";
528
529             filter += "(objectclass=turbineUserGroup)";
530             filter += "(turbineUserUniqueId=" + user.getName() + ")";
531             filter += "(turbineGroupName=" + group.getName() + ")";
532             filter += ")";
533
534             /*
535              * Create the default search controls.
536              */

537             SearchControls JavaDoc ctls = new SearchControls JavaDoc();
538
539             ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
540
541             NamingEnumeration JavaDoc answer = ctx.search(baseSearch, filter, ctls);
542
543             while (answer.hasMore())
544             {
545                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
546                 Attributes JavaDoc attribs = sr.getAttributes();
547                 Attribute JavaDoc attr = attribs.get("turbineRoleName");
548
549                 if (attr != null)
550                 {
551                     NamingEnumeration JavaDoc values = attr.getAll();
552
553                     while (values.hasMore())
554                     {
555                         Role role = getNewRole(values.next().toString());
556
557                         roles.add(role);
558                     }
559                 }
560                 else
561                 {
562                     log.error("Role doesn't have a name");
563                 }
564             }
565         }
566         catch (NamingException JavaDoc ex)
567         {
568             throw new DataBackendException(
569                     "NamingException caught:", ex);
570         }
571
572         return new RoleSet(roles);
573     }
574
575     /**
576      * Retrieve a set of Roles that meet the specified Criteria.
577      *
578      * @param criteria Criteria of Roles selection.
579      * @return a set of Roles that meet the specified Criteria.
580      * @throws DataBackendException if there is a problem with the Backend.
581      */

582     public RoleSet getRoles(Criteria criteria) throws DataBackendException
583     {
584         Vector JavaDoc roles = new Vector JavaDoc(0);
585
586         try
587         {
588             DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
589
590             String JavaDoc baseSearch = LDAPSecurityConstants.getBaseSearch();
591             String JavaDoc filter = "(objectclass=turbineRole)";
592
593             /*
594              * Create the default search controls.
595              */

596             SearchControls JavaDoc ctls = new SearchControls JavaDoc();
597
598             NamingEnumeration JavaDoc answer = ctx.search(baseSearch, filter, ctls);
599
600             while (answer.hasMore())
601             {
602                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
603                 Attributes JavaDoc attribs = sr.getAttributes();
604                 Attribute JavaDoc attr = attribs.get("turbineRoleName");
605
606                 if (attr != null && attr.get() != null)
607                 {
608                     Role role = getNewRole(attr.get().toString());
609
610                     roles.add(role);
611                 }
612                 else
613                 {
614                     log.error("Role doesn't have a name");
615                 }
616             }
617         }
618         catch (NamingException JavaDoc ex)
619         {
620             throw new DataBackendException("NamingException caught", ex);
621         }
622
623         return new RoleSet(roles);
624     }
625
626     /**
627      * Retrieve a set of Permissions that meet the specified Criteria.
628      *
629      * @param criteria Criteria of Permissions selection.
630      * @return a set of Permissions that meet the specified Criteria.
631      * @throws DataBackendException if there is a problem with the Backend.
632      */

633     public PermissionSet getPermissions(Criteria criteria)
634             throws DataBackendException
635     {
636         Vector JavaDoc permissions = new Vector JavaDoc();
637
638         try
639         {
640             DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
641
642             String JavaDoc baseSearch = LDAPSecurityConstants.getBaseSearch();
643             String JavaDoc filter = "(objectClass=turbinePermission)";
644
645             /*
646              * Create the default search controls.
647              */

648             SearchControls JavaDoc ctls = new SearchControls JavaDoc();
649
650             NamingEnumeration JavaDoc answer = ctx.search(baseSearch, filter, ctls);
651
652             while (answer.hasMore())
653             {
654                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
655                 Attributes JavaDoc attribs = sr.getAttributes();
656                 Attribute JavaDoc attr = attribs.get("turbinePermissionName");
657
658                 if (attr != null && attr.get() != null)
659                 {
660                     Permission perm = getNewPermission(attr.get().toString());
661
662                     permissions.add(perm);
663                 }
664                 else
665                 {
666                     log.error("Permission doesn't have a name");
667                 }
668             }
669         }
670         catch (NamingException JavaDoc ex)
671         {
672             throw new DataBackendException(
673                     "The LDAP server specified is unavailable", ex);
674         }
675         return new PermissionSet(permissions);
676     }
677
678     /**
679      * Retrieves all permissions associated with a role.
680      *
681      * @param role the role name, for which the permissions are to be retrieved.
682      * @throws DataBackendException if there was an error accessing the backend.
683      * @throws UnknownEntityException if the role is not present.
684      * @return a PermissionSet.
685      */

686     public PermissionSet getPermissions(Role role)
687             throws DataBackendException, UnknownEntityException
688     {
689         Hashtable JavaDoc permissions = new Hashtable JavaDoc();
690
691         try
692         {
693             DirContext JavaDoc ctx = LDAPUserManager.bindAsAdmin();
694
695             String JavaDoc baseSearch = LDAPSecurityConstants.getBaseSearch();
696             String JavaDoc filter = "(& ";
697
698             filter += "(objectClass=turbineRole)";
699             filter += "(turbineRoleName=" + role.getName() + ")";
700             filter += ")";
701
702             /*
703              * Create the default search controls.
704              */

705             SearchControls JavaDoc ctls = new SearchControls JavaDoc();
706
707             NamingEnumeration JavaDoc answer = ctx.search(baseSearch, filter, ctls);
708
709             while (answer.hasMore())
710             {
711                 SearchResult JavaDoc sr = (SearchResult JavaDoc) answer.next();
712                 Attributes JavaDoc attribs = sr.getAttributes();
713                 Attribute JavaDoc attr = attribs.get("turbinePermissionName");
714
715                 if (attr != null)
716                 {
717                     NamingEnumeration JavaDoc values = attr.getAll();
718
719                     while (values.hasMore())
720                     {
721                         String JavaDoc permName = values.next().toString();
722                         Permission perm = getNewPermission(permName);
723
724                         permissions.put(perm.getName(), perm);
725                     }
726                 }
727             }
728         }
729         catch (NamingException