View Javadoc

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