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.turbine;
18  
19  import java.sql.Connection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
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.BaseJetspeedGroupRole;
29  import org.apache.jetspeed.om.security.Group;
30  import org.apache.jetspeed.om.security.GroupRole;
31  import org.apache.jetspeed.om.security.JetspeedUser;
32  import org.apache.jetspeed.om.security.Role;
33  import org.apache.jetspeed.om.security.UserNamePrincipal;
34  import org.apache.jetspeed.om.security.turbine.TurbineRole;
35  import org.apache.jetspeed.om.security.turbine.TurbineRolePeer;
36  import org.apache.jetspeed.om.security.turbine.TurbineRolePermissionPeer;
37  import org.apache.jetspeed.om.security.turbine.TurbineUserGroupRole;
38  import org.apache.jetspeed.om.security.turbine.TurbineUserGroupRolePeer;
39  import org.apache.jetspeed.services.JetspeedSecurity;
40  import org.apache.jetspeed.services.Profiler;
41  import org.apache.jetspeed.services.PsmlManager;
42  import org.apache.jetspeed.services.rundata.JetspeedRunData;
43  import org.apache.jetspeed.services.rundata.JetspeedRunDataService;
44  import org.apache.jetspeed.services.security.CachedAcl;
45  import org.apache.jetspeed.services.security.GroupManagement;
46  import org.apache.jetspeed.services.security.JetspeedSecurityCache;
47  import org.apache.jetspeed.services.security.JetspeedSecurityException;
48  import org.apache.jetspeed.services.security.JetspeedSecurityService;
49  import org.apache.jetspeed.services.security.RoleException;
50  import org.apache.jetspeed.services.security.RoleManagement;
51  import org.apache.torque.Torque;
52  import org.apache.torque.om.NumberKey;
53  import org.apache.torque.util.Criteria;
54  import org.apache.turbine.services.InitializationException;
55  import org.apache.turbine.services.TurbineBaseService;
56  import org.apache.turbine.services.TurbineServices;
57  import org.apache.turbine.services.resources.ResourceService;
58  import org.apache.turbine.services.rundata.RunDataService;
59  import org.apache.turbine.util.Log;
60  
61  /***
62   * Default Jetspeed-Turbine Role Management implementation
63   *
64   *
65   * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
66   * @author <a href="mailto:morciuch@apache.org">Mark Orciuch</a>
67   * @version $Id: TurbineRoleManagement.java,v 1.14 2004/02/23 03:54:49 jford Exp $
68   */
69  
70  public class TurbineRoleManagement extends TurbineBaseService
71                                     implements RoleManagement
72  {
73      private JetspeedRunDataService runDataService = null;
74      private final static String CASCADE_DELETE = "programmatic.cascade.delete";
75      private final static boolean DEFAULT_CASCADE_DELETE = true;
76      private boolean cascadeDelete;
77      private final static String CACHING_ENABLE = "caching.enable";
78      private boolean cachingEnable = true;
79  
80  
81      ///////////////////////////////////////////////////////////////////////////
82      // Role Management Interfaces
83      ///////////////////////////////////////////////////////////////////////////
84  
85      /***
86       * Retrieves all <code>Role</code>s for a given username principal.
87       *
88       * The security service may optionally check the current user context
89       * to determine if the requestor has permission to perform this action.
90       *
91       * @param username a user principal identity to be retrieved.
92       * @return Iterator over all roles associated to the user principal (iterator of GroupRole objects keyed on group+role).
93       * @exception RoleException when the security provider has a general failure.
94       * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
95       */
96      public Iterator getRoles(String username)
97          throws JetspeedSecurityException
98      {
99          JetspeedUser user = null;
100         try
101         {
102             if (cachingEnable)
103             {
104                 Iterator result = JetspeedSecurityCache.getRoles(username);
105                 if (null != result)
106                 {
107                     return result;
108                 }
109             }
110             user = JetspeedSecurity.getUser(new UserNamePrincipal(username));
111         }
112         catch(JetspeedSecurityException e)
113         {
114             throw new RoleException("Failed to Retrieve User: ", e);
115         }
116         Criteria criteria = new Criteria();
117         criteria.add(TurbineUserGroupRolePeer.USER_ID, user.getUserId());
118         List rels;
119         HashMap roles;
120 
121         try
122         {
123             rels = TurbineUserGroupRolePeer.doSelect(criteria);
124             if (rels.size() > 0)
125             {
126                 roles = new HashMap(rels.size());
127             }
128             else
129             {
130 				roles = new HashMap();
131             }
132 
133             for (int ix = 0; ix < rels.size(); ix++)
134             {
135 				TurbineUserGroupRole rel = (TurbineUserGroupRole) rels.get(ix);
136 				Role role = rel.getTurbineRole();
137 				Group group = rel.getTurbineGroup();
138 				GroupRole groupRole = new BaseJetspeedGroupRole();
139 				groupRole.setGroup(group);
140 				groupRole.setRole(role);
141 				roles.put(group.getName() + role.getName(), groupRole);
142             }
143         }
144         catch(Exception e)
145         {
146             throw new RoleException("Failed to retrieve roles ", e);
147         }
148         return roles.values().iterator();
149     }
150 
151     /***
152      * Retrieves all <code>Role</code>s.
153      *
154      * The security service may optionally check the current user context
155      * to determine if the requestor has permission to perform this action.
156      *
157      * @return Iterator over all roles.
158      * @exception RoleException when the security provider has a general failure.
159      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
160      */
161     public Iterator getRoles()
162         throws JetspeedSecurityException
163     {
164         Criteria criteria = new Criteria();
165         List roles;
166         try
167         {
168             roles = TurbineRolePeer.doSelect(criteria);
169         }
170         catch(Exception e)
171         {
172             throw new RoleException("Failed to retrieve roles ", e);
173         }
174         return roles.iterator();
175     }
176 
177     /***
178      * Adds a <code>Role</code> into permanent storage.
179      *
180      * The security service may optionally check the current user context
181      * to determine if the requestor has permission to perform this action.
182      *
183      * @exception RoleException when the security provider has a general failure.
184      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
185      */
186     public void addRole(Role role)
187         throws JetspeedSecurityException
188     {
189         if(roleExists(role.getName()))
190         {
191             throw new RoleException("The role '" +
192                 role.getName() + "' already exists");
193         }
194 
195         try
196         {
197             TurbineRole trole = new TurbineRole();
198             trole.setRoleName(role.getName());
199             Criteria criteria = TurbineRolePeer.buildCriteria(trole);
200             NumberKey key = (NumberKey)TurbineRolePeer.doInsert(criteria);
201             role.setId(key.toString());
202         }
203         catch(Exception e)
204         {
205             throw new RoleException("Failed to create role '" +
206                 role.getName() + "'", e);
207         }
208 
209         if (cachingEnable)
210         {
211             JetspeedSecurityCache.addRole(role);
212         }
213 
214         try
215         {
216             addDefaultRolePSML(role);
217         }
218         catch (Exception e)
219         {
220             try
221             {
222                 removeRole(role.getName());
223             }
224             catch (Exception e2)
225             {
226             }
227             throw new RoleException("failed to add default PSML for Role resource", e);
228         }
229 
230     }
231 
232     protected void addDefaultRolePSML(Role role)
233         throws RoleException
234     {
235         try
236         {
237             JetspeedRunDataService runDataService =
238                (JetspeedRunDataService)TurbineServices.getInstance()
239                    .getService(RunDataService.SERVICE_NAME);
240             JetspeedRunData rundata = runDataService.getCurrentRunData();
241             Profile profile = Profiler.createProfile();
242             profile.setRole(role);
243             profile.setMediaType("html");
244             Profiler.createProfile(rundata, profile);
245         }
246         catch (ProfileException e)
247         {
248             try
249             {
250                 removeRole(role.getName());
251             }
252             catch(Exception e2)
253             {
254             }
255             throw new RoleException("Failed to create Role PSML", e);
256         }
257     }
258 
259     /***
260      * Saves a <code>Role</code> into permanent storage.
261      *
262      * The security service can throw a <code>NotUniqueEntityException</code> when the public
263      * credentials fail to meet the security provider-specific unique constraints.
264      * The security service may optionally check the current user context
265      * to determine if the requestor has permission to perform this action.
266      *
267      * @exception RoleException when the security provider has a general failure.
268      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
269      */
270     public void saveRole(Role role)
271         throws JetspeedSecurityException
272     {
273         if(!roleExists(role.getName()))
274         {
275             throw new RoleException("The role '" +
276                 role.getName() + "' doesn't exists");
277         }
278 
279         try
280         {
281             if (role instanceof TurbineRole)
282             {
283                 TurbineRolePeer.doUpdate((TurbineRole)role);
284             }
285             else
286             {
287                 throw new RoleException("TurbineRoleManagment: Role is not a Turbine role, cannot update");
288             }
289 
290         }
291         catch(Exception e)
292         {
293             throw new RoleException("Failed to create role '" +
294                 role.getName() + "'", e);
295         }
296 
297     }
298 
299     /***
300      * Removes a <code>Role</code> from the permanent store.
301      *
302      * The security service may optionally check the current user context
303      * to determine if the requestor has permission to perform this action.
304      *
305      * @param rolename the principal identity of the role to be retrieved.
306      * @exception RoleException when the security provider has a general failure.
307      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
308      */
309     public void removeRole(String rolename)
310         throws JetspeedSecurityException
311     {
312         Connection conn = null;
313         try
314         {
315             conn = Torque.getConnection();
316             Role role = this.getRole(rolename);
317 
318             Criteria criteria = new Criteria();
319             criteria.add(TurbineRolePeer.ROLE_NAME, rolename);
320 
321             if(cascadeDelete)
322             {
323                 // CASCADE TURBINE_USER_GROUP_ROLE, TURBINE_ROLE_PERMISSION
324                 Criteria criteria1 = new Criteria();
325                 criteria1.add(TurbineUserGroupRolePeer.ROLE_ID, role.getId());
326                 TurbineUserGroupRolePeer.doDelete(criteria1, conn);
327 
328                 Criteria criteria2 = new Criteria();
329                 criteria2.add(TurbineRolePermissionPeer.ROLE_ID, role.getId());
330                 TurbineRolePermissionPeer.doDelete(criteria2, conn);
331             }
332 
333             TurbineRolePeer.doDelete(criteria, conn);
334             PsmlManager.removeRoleDocuments(role);
335 
336             conn.commit();
337 
338             if (cachingEnable)
339             {
340                 JetspeedSecurityCache.removeAllRoles(rolename);
341             }
342         }
343         catch(Exception e)
344         {
345             try
346             {
347                 conn.rollback();
348             }
349             catch (java.sql.SQLException sqle)
350             {
351                 Log.error(sqle);
352             }
353             throw new RoleException("Failed to remove role '" +
354                 rolename + "'", e);
355         }
356         finally
357         {
358             try
359             {
360                 Torque.closeConnection(conn);
361             }
362             catch (Exception e){}
363         }
364 
365     }
366 
367     /***
368      * Grants a role to a user.
369      *
370      * The security service may optionally check the current user context
371      * to determine if the requestor has permission to perform this action.
372      *
373      * @exception RoleException when the security provider has a general failure retrieving users.
374      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
375      */
376 	public void grantRole(String username, String rolename)
377 		throws JetspeedSecurityException
378 	{
379 		grantRole(username, rolename, GroupManagement.DEFAULT_GROUP_NAME);
380 	}
381     public void grantRole(String username, String rolename, String groupname)
382         throws JetspeedSecurityException
383     {
384         try
385         {
386             JetspeedUser user = JetspeedSecurity.getUser(username);
387             Role role = this.getRole(rolename);
388             Group group = JetspeedSecurity.getGroup(groupname);
389 
390             Criteria criteria = new Criteria();
391             criteria.add(TurbineUserGroupRolePeer.USER_ID, user.getUserId());
392             criteria.add(TurbineUserGroupRolePeer.GROUP_ID, group.getId());
393             criteria.add(TurbineUserGroupRolePeer.ROLE_ID, role.getId());
394             TurbineUserGroupRolePeer.doInsert(criteria);
395 
396             if (cachingEnable)
397             {
398                 JetspeedSecurityCache.addRole(username, role, group);
399             }
400         }
401         catch(Exception e)
402         {
403             throw new RoleException("Grant role '" + rolename + "' to user '" + username + "' failed: ", e);
404         }
405     }
406 
407     /***
408      * Revokes a role from a user.
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 void revokeRole(String username, String rolename)
417 		throws JetspeedSecurityException
418 	{
419 		revokeRole(username, rolename, GroupManagement.DEFAULT_GROUP_NAME);
420 	}
421 
422     public void revokeRole(String username, String rolename, String groupname)
423         throws JetspeedSecurityException
424     {
425         try
426         {
427             JetspeedUser user = JetspeedSecurity.getUser(username);
428             Role role = this.getRole(rolename);
429             Group group = JetspeedSecurity.getGroup(groupname);
430 
431             Criteria criteria = new Criteria();
432             criteria.add(TurbineUserGroupRolePeer.USER_ID, user.getUserId());
433             criteria.add(TurbineUserGroupRolePeer.GROUP_ID, group.getId());
434             criteria.add(TurbineUserGroupRolePeer.ROLE_ID, role.getId());
435             TurbineUserGroupRolePeer.doDelete(criteria);
436 
437             if (cachingEnable)
438             {
439                 JetspeedSecurityCache.removeRole(username, rolename, groupname);
440             }
441 
442         }
443         catch(Exception e)
444         {
445             throw new RoleException("Revoke role '" + rolename + "' to user '" + username + "' failed: ", e);
446         }
447 
448     }
449 
450     /***
451      * Checks for the relationship of user has a role. Returns true when the user has the given role.
452      *
453      * The security service may optionally check the current user context
454      * to determine if the requestor has permission to perform this action.
455      *
456      * @exception RoleException when the security provider has a general failure retrieving users.
457      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
458      */
459 	public boolean hasRole(String username, String rolename)
460 		throws JetspeedSecurityException
461 	{
462 		return hasRole(username, rolename, GroupManagement.DEFAULT_GROUP_NAME);
463 	}
464 	
465     public boolean hasRole(String username, String rolename, String groupname)
466         throws JetspeedSecurityException
467     {
468         List roles;
469 
470         try
471         {
472             if (cachingEnable)
473             {
474                 CachedAcl acl = JetspeedSecurityCache.getAcl(username);
475                 if (null != acl)
476                 {
477                     return acl.hasRole(rolename, groupname);
478                 }
479             }
480             JetspeedUser user = JetspeedSecurity.getUser(username);
481             Role role = this.getRole(rolename);
482             Group group = JetspeedSecurity.getGroup(groupname);
483 
484             Criteria criteria = new Criteria();
485             criteria.add(TurbineUserGroupRolePeer.USER_ID, user.getUserId());
486             criteria.add(TurbineUserGroupRolePeer.GROUP_ID, group.getId());
487             criteria.add(TurbineUserGroupRolePeer.ROLE_ID, role.getId());
488             roles = TurbineUserGroupRolePeer.doSelect(criteria);
489 
490         }
491         catch(Exception e)
492         {
493             throw new RoleException("Failed to check role '" +
494                 rolename + "'", e);
495         }
496         return ( roles.size() > 0 );
497     }
498 
499 
500     /***
501      * Retrieves a single <code>Role</code> for a given rolename principal.
502      *
503      * The security service may optionally check the current user context
504      * to determine if the requestor has permission to perform this action.
505      *
506      * @param rolename a role principal identity to be retrieved.
507      * @return Role the role record retrieved.
508      * @exception RoleException when the security provider has a general failure.
509      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
510      */
511     public Role getRole(String rolename)
512         throws JetspeedSecurityException
513     {
514         List roles;
515         try
516         {
517             Criteria criteria = new Criteria();
518             criteria.add(TurbineRolePeer.ROLE_NAME, rolename);
519             roles = TurbineRolePeer.doSelect(criteria);
520         }
521         catch(Exception e)
522         {
523             throw new RoleException("Failed to retrieve role '" +
524                 rolename + "'", e);
525         }
526         if ( roles.size() > 1 )
527         {
528             throw new RoleException(
529                 "Multiple Roles with same rolename '" + rolename + "'");
530         }
531         if ( roles.size() == 1 )
532         {
533             TurbineRole role = (TurbineRole)roles.get(0);
534             return role;
535         }
536         throw new RoleException("Unknown role '" + rolename + "'");
537 
538     }
539 
540 
541     ///////////////////////////////////////////////////////////////////////////
542     // Internal
543     ///////////////////////////////////////////////////////////////////////////
544 
545     protected JetspeedRunData getRunData()
546      {
547          JetspeedRunData rundata = null;
548          if (this.runDataService != null)
549          {
550              rundata = this.runDataService.getCurrentRunData();
551          }
552          return rundata;
553      }
554 
555     /***
556      * Check whether a specified role exists.
557      *
558      * The login name is used for looking up the account.
559      *
560      * @param roleName the name of the role to check for existence.
561      * @return true if the specified account exists
562      * @throws RoleException if there was a general db access error
563      *
564      */
565     protected boolean roleExists(String roleName)
566         throws RoleException
567     {
568         Criteria criteria = new Criteria();
569         criteria.add(TurbineRolePeer.ROLE_NAME, roleName);
570         List roles;
571         try
572         {
573             roles = TurbineRolePeer.doSelect(criteria);
574         }
575         catch(Exception e)
576         {
577             throw new RoleException(
578                 "Failed to check account's presence", e);
579         }
580         if (roles.size() < 1)
581         {
582             return false;
583         }
584         return true;
585     }
586 
587     ///////////////////////////////////////////////////////////////////////////
588     // Service Init
589     ///////////////////////////////////////////////////////////////////////////
590 
591 
592     /***
593      * This is the early initialization method called by the
594      * Turbine <code>Service</code> framework
595      * @param conf The <code>ServletConfig</code>
596      * @exception throws a <code>InitializationException</code> if the service
597      * fails to initialize
598      */
599     public synchronized void init(ServletConfig conf)
600         throws InitializationException
601     {
602         if (getInit()) return;
603 
604         super.init(conf);
605 
606         // get configuration parameters from Jetspeed Resources
607         ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
608                                                      .getResources(JetspeedSecurityService.SERVICE_NAME);
609 
610         this.runDataService =
611            (JetspeedRunDataService)TurbineServices.getInstance()
612                .getService(RunDataService.SERVICE_NAME);
613 
614         cascadeDelete = serviceConf.getBoolean( CASCADE_DELETE, DEFAULT_CASCADE_DELETE );
615         cachingEnable = serviceConf.getBoolean( CACHING_ENABLE, cachingEnable );
616 
617         setInit(true);
618      }
619 
620 
621 
622 }
623 
624