View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
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  
17  package org.apache.jetspeed.services.security.ldap;
18  
19  import java.util.Enumeration;
20  import java.util.Iterator;
21  import java.util.StringTokenizer;
22  import java.util.Vector;
23  import java.util.HashMap;
24  import javax.naming.directory.BasicAttributes;
25  import javax.servlet.ServletConfig;
26  import org.apache.jetspeed.om.profile.Profile;
27  import org.apache.jetspeed.om.profile.ProfileException;
28  import org.apache.jetspeed.om.security.Group;
29  import org.apache.jetspeed.om.security.UserNamePrincipal;
30  import org.apache.jetspeed.om.security.ldap.LDAPGroup;
31  import org.apache.jetspeed.om.security.ldap.LDAPRole;
32  import org.apache.jetspeed.om.security.ldap.LDAPUser;
33  import org.apache.jetspeed.services.JetspeedLDAP;
34  import org.apache.jetspeed.services.JetspeedSecurity;
35  import org.apache.jetspeed.services.Profiler;
36  import org.apache.jetspeed.services.PsmlManager;
37  import org.apache.jetspeed.services.ldap.LDAPURL;
38  import org.apache.jetspeed.services.rundata.JetspeedRunData;
39  import org.apache.jetspeed.services.rundata.JetspeedRunDataService;
40  import org.apache.jetspeed.services.security.GroupException;
41  import org.apache.jetspeed.services.security.GroupManagement;
42  import org.apache.jetspeed.services.security.JetspeedSecurityException;
43  import org.apache.jetspeed.services.security.JetspeedSecurityService;
44  import org.apache.jetspeed.services.security.UnknownUserException;
45  import org.apache.turbine.services.InitializationException;
46  import org.apache.turbine.services.TurbineBaseService;
47  import org.apache.turbine.services.TurbineServices;
48  import org.apache.turbine.services.resources.ResourceService;
49  import org.apache.turbine.services.rundata.RunDataService;
50  
51  /***
52   *
53   * @author <a href="mailto:ender@kilicoglu.nom.tr">Ender KILICOGLU</a>
54   * @author <a href="mailto:sami.leino@netorek.fi">Sami Leino</a>
55   *
56   * @version $Id: LDAPGroupManagement.java,v 1.8 2004/02/23 03:52:33 jford Exp $
57   *
58   */
59  public class LDAPGroupManagement extends TurbineBaseService
60                                     implements GroupManagement
61  {
62  	// Constants
63      private final static String CONFIG_DEFAULT_ROLE     = "role.default";
64      private final static String CASCADE_DELETE          = "programmatic.cascade.delete";
65      private final static String DEFAULT_DEFAULT_ROLE   = "user";
66      private final static boolean DEFAULT_CASCADE_DELETE = true;
67      private final static String[] ATTRS                 = { "ou", "uid", "groupname" };
68  
69  	// Instance variables
70      private JetspeedRunDataService runDataService       = null;
71      private boolean cascadeDelete                       = false;
72      private String defaultRole                          = null;
73  
74      ///////////////////////////////////////////////////////////////////////////
75      // Group Management Interfaces
76      ///////////////////////////////////////////////////////////////////////////
77  
78      /***
79       * Retrieves all <code>Group</code>s for a given username principal.
80       *
81       * The security service may optionally check the current user context
82       * to determine if the requestor has permission to perform this action.
83       *
84       * @param username a user principal identity to be retrieved.
85       * @return Iterator over all groups associated to the user principal.
86       * @exception GroupException when the security provider has a general failure.
87       * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
88       */
89      public Iterator getGroups(String username)
90          throws JetspeedSecurityException
91      {
92          Vector groups = new Vector();
93          StringTokenizer st;
94          LDAPUser user;
95  
96          try
97          {
98              user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
99          }
100         catch(JetspeedSecurityException e)
101         {
102             throw new GroupException("Failed to Retrieve User: ", e);
103         }
104 
105         try
106         {
107             for (Enumeration enum = user.getGroupRoles().elements() ;enum.hasMoreElements() ;)
108             {
109                 st = new StringTokenizer((String)enum.nextElement(),",");
110                 groups.add(new LDAPGroup(st.nextToken(), false));
111             }
112         }
113         catch(Exception e)
114         {
115             throw new GroupException("Failed to retrieve groups ", e);
116         }
117 
118         return groups.iterator();
119     }
120 
121     /***
122      * Retrieves all <code>Group</code>s.
123      *
124      * The security service may optionally check the current user context
125      * to determine if the requestor has permission to perform this action.
126      *
127      * @return Iterator over all groups.
128      * @exception GroupException when the security provider has a general failure.
129      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
130      */
131     public Iterator getGroups()
132         throws JetspeedSecurityException
133     {
134         BasicAttributes attr= new BasicAttributes();
135         Vector groups = new Vector();
136         Vector groupurls;
137 
138         try
139         {
140             groupurls = JetspeedLDAP.search(JetspeedLDAP.buildURL("ou=groups"),
141                                         "(objectclass=jetspeedgroup)", ATTRS, true);
142             if (groupurls.size() > 0)
143             {
144                 for (Enumeration enum = groupurls.elements();enum.hasMoreElements() ;)
145                 {
146                     groups.add(new LDAPGroup((LDAPURL) (((Vector)enum.nextElement()).firstElement())));
147                 }
148             }
149             else
150             {
151                 throw new UnknownUserException("No groups");
152             }
153         }
154         catch(Exception e)
155         {
156             throw new GroupException("Failed to retrieve groups ", e);
157         }
158 
159         return groups.iterator();
160     }
161 
162     /***
163      * Adds a <code>Group</code> into permanent storage.
164      *
165      * The security service can throw a <code>NotUniqueEntityException</code> when the public
166      * credentials fail to meet the security provider-specific unique constraints.
167      * The security service may optionally check the current user context
168      * to determine if the requestor has permission to perform this action.
169      *
170      * @exception GroupException when the security provider has a general failure.
171      * @exception NotUniqueEntityException when the public credentials fail to meet
172      *                                   the security provider-specific unique constraints.
173      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
174      *
175      */
176     public void addGroup(Group group)
177         throws JetspeedSecurityException
178     {
179         LDAPGroup ldapGroup = null;
180 
181         if(groupExists(group.getName()))
182         {
183             throw new GroupException("The group '" +
184                 group.getName() + "' already exists");
185         }
186         try
187         {
188             ldapGroup = new LDAPGroup(group.getName(), true);
189             ldapGroup.update(true);
190         }
191         catch(Exception e)
192         {
193             throw new GroupException("Failed to create group '" +
194                 group.getName() + "'", e);
195         }
196 
197         try
198         {
199             addDefaultGroupPSML(ldapGroup);
200         }
201         catch (Exception e)
202         {
203             try
204             {
205                 removeGroup(ldapGroup.getName());
206             }
207             catch (Exception e2)
208             {
209             }
210             throw new GroupException("failed to add default PSML for Group resource", e);
211         }
212 
213     }
214     protected void addDefaultGroupPSML(Group group)
215         throws GroupException
216     {
217         try
218         {
219             JetspeedRunDataService runDataService =
220                (JetspeedRunDataService)TurbineServices.getInstance()
221                    .getService(RunDataService.SERVICE_NAME);
222 
223             JetspeedRunData rundata = runDataService.getCurrentRunData();
224             Profile profile = Profiler.createProfile();
225             profile.setGroup(group);
226             profile.setMediaType("html");
227             Profiler.createProfile(rundata, profile);
228         }
229         catch (ProfileException e)
230         {
231             try
232             {
233                 removeGroup(group.getName());
234             }
235             catch(Exception e2)
236             {
237             }
238             throw new GroupException("Failed to create Group PSML", e);
239         }
240     }
241 
242     /***
243      * Saves a <code>Group</code> into permanent storage.
244      *
245      * The security service can throw a <code>NotUniqueEntityException</code> when the public
246      * credentials fail to meet the security provider-specific unique constraints.
247      * The security service may optionally check the current user context
248      * to determine if the requestor has permission to perform this action.
249      *
250      * @exception GroupException when the security provider has a general failure.
251      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
252      */
253     public void saveGroup(Group group)
254         throws JetspeedSecurityException
255     {
256         if(!groupExists(group.getName()))
257         {
258             throw new GroupException("The group '" +
259                 group.getName() + "' doesn't exists");
260         }
261 
262         try
263         {
264         }
265         catch(Exception e)
266         {
267             throw new GroupException("Failed to create group '" +
268                 group.getName() + "'", e);
269         }
270     }
271 
272     /***
273      * Removes a <code>Group</code> from the permanent store.
274      *
275      * The security service may optionally check the current user context
276      * to determine if the requestor has permission to perform this action.
277      *
278      * @param groupname the principal identity of the group to be retrieved.
279      * @exception GroupException when the security provider has a general failure.
280      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
281      */
282     public void removeGroup(String groupname)
283         throws JetspeedSecurityException
284     {
285         try
286         {
287             LDAPGroup group = new LDAPGroup(groupname, false);
288             JetspeedLDAP.deleteEntry(group.getldapurl());
289 
290             if(cascadeDelete)
291             {
292             }
293 
294             PsmlManager.removeGroupDocuments(group);
295         }
296         catch(Exception e)
297         {
298             throw new GroupException("Failed to remove group '" +
299                 groupname + "'", e);
300         }
301     }
302 
303     /***
304      * Join a user to a group.
305      *
306      * The security service may optionally check the current user context
307      * to determine if the requestor has permission to perform this action.
308      *
309      * @exception GroupException when the security provider has a general failure retrieving users.
310      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
311      */
312     public void joinGroup(String username, String groupname)
313         throws JetspeedSecurityException
314     {
315         LDAPUser user;
316         try
317         {
318             user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
319         }
320         catch(JetspeedSecurityException e)
321         {
322             throw new GroupException("Failed to Retrieve User: ", e);
323         }
324         try
325         {
326             user.addGroupRole(groupname, defaultRole);
327             user.update(false);
328         }
329         catch(Exception e)
330         {
331             throw new GroupException("Failed to add group info ", e);
332         }
333     }
334 
335     /***
336      * Join a user to a group - specific role.
337      *
338      * The security service may optionally check the current user context
339      * to determine if the requestor has permission to perform this action.
340      *
341      * @exception GroupException when the security provider has a general failure retrieving groups.
342      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
343      */
344     public void joinGroup(String username, String groupname, String rolename)
345         throws JetspeedSecurityException
346     {
347         LDAPUser user;
348         LDAPRole role;
349 
350         try
351         {
352             user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
353             role = (LDAPRole)JetspeedSecurity.getRole(rolename);
354         }
355         catch(JetspeedSecurityException e)
356         {
357             throw new GroupException("Failed to Retrieve User: ", e);
358         }
359         try
360         {
361             user.addGroupRole(groupname, rolename);
362             user.update(false);
363         }
364         catch(Exception e)
365         {
366             throw new GroupException("Failed to add group info ", e);
367         }
368     }
369 
370     /***
371      * Unjoin a user from a group.
372      *
373      * The security service may optionally check the current user context
374      * to determine if the requestor has permission to perform this action.
375      *
376      * @exception GroupException when the security provider has a general failure retrieving users.
377      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
378      */
379     public void unjoinGroup(String username, String groupName)
380         throws JetspeedSecurityException
381     {
382         LDAPUser user;
383 
384         try
385         {
386             user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
387         }
388         catch(JetspeedSecurityException e)
389         {
390             throw new GroupException("Failed to Retrieve User: ", e);
391         }
392 
393         try
394         {
395             user.removeGroup(groupName);
396             user.update(false);
397         }
398         catch(Exception e)
399         {
400             throw new GroupException("Failed to add group info ", e);
401         }
402     }
403 
404     /***
405      * Unjoin a user from a group in which the user has a specific role.
406      *
407      * The security service may optionally check the current user context
408      * to determine if the requestor has permission to perform this action.
409      *
410      * @exception GroupException when the security provider has a general failure retrieving users.
411      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
412      */
413     public void unjoinGroup(String username, String groupName, String rolename)
414         throws JetspeedSecurityException
415     {
416         LDAPUser user;
417 
418         try
419         {
420             user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
421         }
422         catch(JetspeedSecurityException e)
423         {
424             throw new GroupException("Failed to Retrieve User: ", e);
425         }
426 
427         try
428         {
429             user.removeGroup(groupName);
430             user.update(false);
431         }
432         catch(Exception e)
433         {
434             throw new GroupException("Failed to add group info ", e);
435         }
436     }
437 
438 
439     /***
440      * Checks for the relationship of user in a group. Returns true when the user is in the given group.
441      *
442      * The security service may optionally check the current user context
443      * to determine if the requestor has permission to perform this action.
444      *
445      * @exception GroupException when the security provider has a general failure retrieving users.
446      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
447      */
448     public boolean inGroup(String username, String groupname)
449         throws JetspeedSecurityException
450     {
451         Vector groups= new Vector();
452         StringTokenizer st;
453         LDAPUser user;
454 
455         try
456         {
457             user = (LDAPUser)JetspeedSecurity.getUser(new UserNamePrincipal(username));
458         }
459         catch(JetspeedSecurityException e)
460         {
461             throw new GroupException("Failed to Retrieve User: ", e);
462         }
463 
464         try
465         {
466             for (Enumeration enum = user.getGroupRoles().elements() ;enum.hasMoreElements() ;)
467             {
468                 st = new StringTokenizer((String)enum.nextElement(),",");
469 
470                 if (st.nextToken().equalsIgnoreCase(groupname))
471                 {
472                     return true;
473                 }
474             }
475         }
476         catch(Exception e)
477         {
478             throw new GroupException("Failed to retrieve groups ", e);
479         }
480 
481         return false;
482     }
483 
484     /***
485      * Retrieves a single <code>Group</code> for a given groupname principal.
486      *
487      * The security service may optionally check the current user context
488      * to determine if the requestor has permission to perform this action.
489      *
490      * @param groupname a group principal identity to be retrieved.
491      *
492      * @return Group the group record retrieved.
493      *
494      * @exception GroupException when the security provider has a general failure.
495      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
496      *
497      */
498     public Group getGroup(String groupname)
499         throws JetspeedSecurityException
500     {
501         BasicAttributes attr= new BasicAttributes();
502         LDAPGroup group;
503         Vector groupurls;
504 
505         try
506         {
507             groupurls = JetspeedLDAP.search(JetspeedLDAP.buildURL("ou=groups"),
508                          "(&(uid="+ groupname+")(objectclass=jetspeedgroup))", ATTRS, true);
509             if (groupurls.size() == 1)
510             {
511                 return new LDAPGroup((LDAPURL)((Vector)groupurls.elementAt(0)).firstElement());
512             }
513             else if(groupurls.size() > 1)
514             {
515                 throw new GroupException("Multiple groups with same name");
516             }
517 			else
518 			{
519 		        throw new GroupException("Unknown group '" + groupname + "'");
520 			}
521         }
522         catch(Exception e)
523         {
524             throw new GroupException("Failed to retrieve groups ", e);
525         }
526     }
527     /***
528      * Retrieves a hashtable which associates Groups with Roles for a given username principal.
529      *
530      * The security service may optionally check the current user context
531      * to determine if the requestor has permission to perform this action.
532      *
533      * @param username a user principal identity to be retrieved.
534      * @return Hashtable record retrieved.
535      * @exception GroupException when the security provider has a general failure.
536      */
537     public HashMap getTurbineGroupRole(String username)
538          throws JetspeedSecurityException
539     {
540       BasicAttributes attr= new BasicAttributes();
541       LDAPGroup group;
542       Vector groupurls;
543       HashMap h = new HashMap();
544       return h;
545     }
546 
547 
548     ///////////////////////////////////////////////////////////////////////////
549     // Internal
550     ///////////////////////////////////////////////////////////////////////////
551 
552     protected JetspeedRunData getRunData()
553     {
554         JetspeedRunData rundata = null;
555 
556         if (this.runDataService != null)
557         {
558             rundata = this.runDataService.getCurrentRunData();
559         }
560 
561         return rundata;
562     }
563 
564     /***
565      * Check whether a specified group exists.
566      *
567      * The login name is used for looking up the account.
568      *
569      * @param groupName the name of the group to check for existence.
570      * @return true if the specified account exists
571      * @throws GroupException if there was a general db access error
572      *
573      */
574     protected boolean groupExists(String groupName)
575         throws GroupException
576     {
577         BasicAttributes attr= new BasicAttributes();
578         Vector groupurls;
579 
580         try
581         {
582             groupurls = JetspeedLDAP.search(JetspeedLDAP.buildURL("ou=groups"),
583                                         "(&(uid="+ groupName+")(objectclass=jetspeedgroup))", ATTRS, true);
584             if (groupurls.size() > 0)
585             {
586             	return true;
587             }
588             else
589             {
590             	return false;
591             }
592         }
593         catch(Exception e)
594         {
595             throw new GroupException("Failed to retrieve groups ", e);
596         }
597     }
598 
599     ///////////////////////////////////////////////////////////////////////////
600     // Service Init
601     ///////////////////////////////////////////////////////////////////////////
602 
603     /***
604      * This is the early initialization method called by the
605      * Turbine <code>Service</code> framework
606      * @param conf The <code>ServletConfig</code>
607      * @exception throws a <code>InitializationException</code> if the service
608      * fails to initialize
609      */
610     public synchronized void init(ServletConfig conf)
611         throws InitializationException
612     {
613         if (getInit()) return;
614         super.init(conf);
615 
616         // get configuration parameters from Jetspeed Resources
617         ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
618                                                      .getResources(JetspeedSecurityService.SERVICE_NAME);
619 
620         this.runDataService =
621            (JetspeedRunDataService)TurbineServices.getInstance()
622                .getService(RunDataService.SERVICE_NAME);
623 
624         defaultRole = serviceConf.getString(CONFIG_DEFAULT_ROLE, DEFAULT_DEFAULT_ROLE);
625         cascadeDelete = serviceConf.getBoolean( CASCADE_DELETE, DEFAULT_CASCADE_DELETE );
626 
627         setInit(true);
628      }
629 
630 
631 }