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.Iterator;
21  import java.util.List;
22  import java.util.HashMap;
23  import java.util.Vector;
24  
25  import javax.servlet.ServletConfig;
26  
27  
28  // Jetspeed Security
29  import org.apache.jetspeed.services.security.PermissionManagement;
30  import org.apache.jetspeed.services.security.JetspeedSecurityCache;
31  
32  import org.apache.jetspeed.om.security.Role;
33  import org.apache.jetspeed.om.security.Permission;
34  
35  import org.apache.jetspeed.services.JetspeedSecurity;
36  import org.apache.jetspeed.services.security.JetspeedSecurityService;
37  
38  // Jetspeed Security Exceptions
39  import org.apache.jetspeed.services.security.PermissionException;
40  import org.apache.jetspeed.services.security.JetspeedSecurityException;
41  
42  // Jetspeed Database OM
43  import org.apache.jetspeed.om.security.turbine.TurbinePermission;
44  import org.apache.jetspeed.om.security.turbine.TurbinePermissionPeer;
45  import org.apache.jetspeed.om.security.turbine.TurbineRolePermission;
46  import org.apache.jetspeed.om.security.turbine.TurbineRolePermissionPeer;
47  
48  // Jetspeed logging 
49  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
50  import org.apache.jetspeed.services.logging.JetspeedLogger;
51  
52  // Torque
53  import org.apache.torque.util.Criteria;
54  import org.apache.torque.om.NumberKey;
55  import org.apache.torque.Torque;
56  
57  // Rundata
58  import org.apache.jetspeed.services.rundata.JetspeedRunDataService;
59  import org.apache.jetspeed.services.rundata.JetspeedRunData;
60  import org.apache.turbine.services.rundata.RunDataService;
61  
62  // Turbine
63  import org.apache.turbine.services.TurbineBaseService;
64  import org.apache.turbine.services.TurbineServices;
65  import org.apache.turbine.services.InitializationException;
66  import org.apache.turbine.services.resources.ResourceService;
67  
68  /***
69   * Default Jetspeed-Turbine Permission Management implementation
70   *
71   *
72   * @author <a href="mailto:david@bluesunrise.com">David Sean Taylor</a>
73   * @version $Id: TurbinePermissionManagement.java,v 1.10 2004/02/23 03:54:49 jford Exp $
74   */
75  
76  public class TurbinePermissionManagement extends TurbineBaseService
77                                     implements PermissionManagement
78  {
79      /***
80       * Static initialization of the logger for this class
81       */    
82      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(TurbinePermissionManagement.class.getName());
83      
84      private JetspeedRunDataService runDataService = null;
85      private final static String CASCADE_DELETE = "programmatic.cascade.delete";
86      private final static boolean DEFAULT_CASCADE_DELETE = true;
87      private final static String CONFIG_SYSTEM_PERMISSIONS = "system.permissions";
88      private boolean cascadeDelete;
89      private final static String CACHING_ENABLE = "caching.enable";
90      private boolean cachingEnable = true;
91      private Vector systemPermissions = null;
92  
93      ///////////////////////////////////////////////////////////////////////////
94      // Permission Management Interfaces
95      ///////////////////////////////////////////////////////////////////////////
96  
97      /***
98       * Retrieves all <code>Permission</code>s for a given rolename principal.
99       *
100      * The security service may optionally check the current user context
101      * to determine if the requestor has permission to perform this action.
102      *
103      * @param rolename a role name identity to be retrieved.
104      * @return Iterator over all permissions associated to the role principal.
105      * @exception PermissionException when the security provider has a general failure.
106      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
107      */
108     public Iterator getPermissions(String rolename)
109         throws JetspeedSecurityException
110     {
111         Role role = null;
112         try
113         {
114             if (cachingEnable)
115             {
116                 Iterator iterator = JetspeedSecurityCache.getPermissions(rolename);
117                 if (iterator != null)
118                 {
119                     return iterator;
120                 }
121             }
122             role = JetspeedSecurity.getRole(rolename);
123         }
124         catch(JetspeedSecurityException e)
125         {
126             logger.error( "Failed to Retrieve Role: ", e );
127             throw new PermissionException("Failed to Retrieve Role: ", e);
128         }
129         Criteria criteria = new Criteria();
130         criteria.add(TurbineRolePermissionPeer.ROLE_ID, role.getId());
131         List rels;
132         HashMap perms;
133 
134         try
135         {
136             rels = TurbineRolePermissionPeer.doSelect(criteria);
137             if (rels.size() > 0)
138             {
139                 perms = new HashMap(rels.size());
140             }
141             else
142                 perms = new HashMap();
143 
144             for (int ix = 0; ix < rels.size(); ix++)
145             {
146                 TurbineRolePermission rel = (TurbineRolePermission)rels.get(ix);
147                 Permission perm = rel.getTurbinePermission();
148                 perms.put(perm.getName(), perm);
149             }
150         }
151         catch(Exception e)
152         {
153             logger.error( "Failed to retrieve permissions ", e );
154             throw new PermissionException("Failed to retrieve permissions ", e);
155         }
156         return perms.values().iterator();
157     }
158 
159     /***
160      * Retrieves all <code>Permission</code>s.
161      *
162      * The security service may optionally check the current user context
163      * to determine if the requestor has permission to perform this action.
164      *
165      * @return Iterator over all permissions.
166      * @exception PermissionException when the security provider has a general failure.
167      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
168      */
169     public Iterator getPermissions()
170         throws JetspeedSecurityException
171     {
172         Criteria criteria = new Criteria();
173         List permissions;
174         try
175         {
176             permissions = TurbinePermissionPeer.doSelect(criteria);
177         }
178         catch(Exception e)
179         {
180             logger.error( "Failed to retrieve permissions ", e);
181             throw new PermissionException("Failed to retrieve permissions ", e);
182         }
183         return permissions.iterator();
184     }
185 
186     /***
187      * Adds a <code>Permission</code> into permanent storage.
188      *
189      * The security service may optionally check the current user context
190      * to determine if the requestor has permission to perform this action.
191      *
192      * @exception PermissionException when the security provider has a general failure.
193      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
194      */
195     public void addPermission(Permission permission)
196         throws JetspeedSecurityException
197     {
198         if(permissionExists(permission.getName()))
199         {
200             throw new PermissionException("The permission '" +
201                 permission.getName() + "' already exists");
202         }
203 
204         try
205         {
206             TurbinePermission tpermission = new TurbinePermission();
207             tpermission.setPermissionName(permission.getName());
208             Criteria criteria = TurbinePermissionPeer.buildCriteria(tpermission);
209             NumberKey key = (NumberKey)TurbinePermissionPeer.doInsert(criteria);
210             permission.setId(key.toString());
211         }
212         catch(Exception e)
213         {
214             String message = "Failed to create permission '" + permission.getName() + "'";
215             logger.error( message, e );
216             throw new PermissionException(message, e);
217         }
218     }
219 
220 
221     /***
222      * Saves a <code>Permission</code> into permanent storage.
223      *
224      * The security service may optionally check the current user context
225      * to determine if the requestor has permission to perform this action.
226      *
227      * @exception PermissionException when the security provider has a general failure.
228      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
229      */
230     public void savePermission(Permission permission)
231         throws JetspeedSecurityException
232     {
233         if(!permissionExists(permission.getName()))
234         {
235             throw new PermissionException("The permission '" +
236                 permission.getName() + "' doesn't exists");
237         }
238 
239         try
240         {
241             if (permission instanceof TurbinePermission)
242             {
243                 TurbinePermissionPeer.doUpdate((TurbinePermission)permission);
244             }
245             else
246             {
247                 throw new PermissionException("TurbinePermissionManagment: Permission is not a Turbine permission, cannot update");
248             }
249 
250         }
251         catch(Exception e)
252         {
253             String message = "Failed to create permission '" + permission.getName() + "'";
254             logger.error( message, e );
255             throw new PermissionException( message, e );
256         }
257 
258     }
259 
260     /***
261      * Removes a <code>Permission</code> from the permanent store.
262      *
263      * The security service may optionally check the current user context
264      * to determine if the requestor has permission to perform this action.
265      *
266      * @param permissionName the principal identity of the permission to be retrieved.
267      * @exception PermissionException when the security provider has a general failure.
268      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
269      */
270     public void removePermission(String permissionName)
271         throws JetspeedSecurityException
272     {
273         Connection conn = null;
274         try
275         {
276 
277             if (systemPermissions.contains(permissionName))
278             {
279                 throw new PermissionException("[" + permissionName + "] is a system permission and cannot be removed");
280             }
281 
282             conn = Torque.getConnection();
283             Permission permission = this.getPermission(permissionName);
284 
285             Criteria criteria = new Criteria();
286             criteria.add(TurbinePermissionPeer.PERMISSION_NAME, permissionName);
287 
288             if(cascadeDelete)
289             {
290                 // CASCADE to TURBINE_ROLE_PERMISSION
291                 Criteria critRolePerm = new Criteria();
292                 critRolePerm.add(TurbineRolePermissionPeer.PERMISSION_ID, permission.getId());
293                 TurbineRolePermissionPeer.doDelete(critRolePerm, conn);
294             }
295             TurbinePermissionPeer.doDelete(criteria, conn);
296                 
297             conn.commit();
298             
299             if (cachingEnable)
300             {
301                 JetspeedSecurityCache.removeAllPermissions(permissionName);
302             }
303         }
304         catch(Exception e)
305         {
306             try
307             {
308                 conn.rollback();
309             }
310             catch (java.sql.SQLException sqle)
311             {
312                 logger.error("SQLException", sqle);
313             }
314             String message = "Failed to remove permission '" + permissionName + "'";
315             logger.error( message, e );
316             throw new PermissionException( message, e );
317         }
318         finally
319         {
320             try
321             {
322                 Torque.closeConnection(conn);
323             }
324             catch (Throwable e)
325             {
326                 logger.error( "Error closing Torque connection", e );
327             }
328         }
329 
330     }
331 
332     /***
333      * Grants a permission to a role.
334      *
335      * The security service may optionally check the current user context
336      * to determine if the requestor has permission to perform this action.
337      *
338      * @param roleName grant a permission to this role.
339      * @param permissionName the permission to grant to the role.
340      * @exception PermissionException when the security provider has a general failure retrieving permissions.
341      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
342      */
343     public void grantPermission(String roleName, String permissionName)
344         throws JetspeedSecurityException
345     {
346         try
347         {
348             Role role = JetspeedSecurity.getRole(roleName);
349             Permission permission = this.getPermission(permissionName);
350 
351             Criteria criteria = new Criteria();
352             criteria.add(TurbineRolePermissionPeer.ROLE_ID, role.getId());
353             criteria.add(TurbineRolePermissionPeer.PERMISSION_ID, permission.getId());
354             TurbineRolePermissionPeer.doInsert(criteria);
355             if (cachingEnable)
356             {
357                 JetspeedSecurityCache.addPermission(roleName,permission);
358             }
359         }
360         catch(Exception e)
361         {
362             String message = "Grant permission '" + permissionName + "' to role '" + roleName + "' failed: ";
363             logger.error( message, e );
364             throw new PermissionException( message, e );
365         }
366     }
367 
368     /***
369      * Revokes a permission from a role.
370      *
371      * The security service may optionally check the current user context
372      * to determine if the requestor has permission to perform this action.
373      *
374      * @param roleName grant a permission to this role.
375      * @param permissionName the permission to grant to the role.
376      * @exception PermissionException when the security provider has a general failure retrieving permissions.
377      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
378      */
379     public void revokePermission(String roleName, String permissionName)
380         throws JetspeedSecurityException
381     {
382         try
383         {
384             Role role = JetspeedSecurity.getRole(roleName);
385             Permission permission = this.getPermission(permissionName);
386 
387             Criteria criteria = new Criteria();
388             criteria.add(TurbineRolePermissionPeer.ROLE_ID, role.getId());
389             criteria.add(TurbineRolePermissionPeer.PERMISSION_ID, permission.getId());
390             TurbineRolePermissionPeer.doDelete(criteria);
391             if (cachingEnable)
392             {
393                 JetspeedSecurityCache.removePermission(roleName, permissionName);
394             }
395         }
396         catch(Exception e)
397         {
398             String message = "Revoke permission '" + permissionName + "' to role '" + roleName + "' failed: ";
399             logger.error( message, e );
400             throw new PermissionException( message, e);
401         }
402 
403     }
404 
405     /***
406      * Checks for the relationship of role has a permission. Returns true when the role has the given permission.
407      *
408      * The security service may optionally check the current user context
409      * to determine if the requestor has permission to perform this action.
410      *
411      * @param roleName grant a permission to this role.
412      * @param permissionName the permission to grant to the role.
413      * @exception PermissionException when the security provider has a general failure retrieving permissions.
414      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
415      */
416     public boolean hasPermission(String roleName, String permissionName)
417         throws JetspeedSecurityException
418     {
419         List permissions;
420 
421         try
422         {
423             if (cachingEnable)
424             {
425                 return JetspeedSecurityCache.hasPermission(roleName, permissionName);
426             }
427 
428             Role role = JetspeedSecurity.getRole(roleName);
429             Permission permission = this.getPermission(permissionName);
430 
431             Criteria criteria = new Criteria();
432             criteria.add(TurbineRolePermissionPeer.ROLE_ID, role.getId());
433             criteria.add(TurbineRolePermissionPeer.PERMISSION_ID, permission.getId());
434             permissions = TurbineRolePermissionPeer.doSelect(criteria);
435 
436         }
437         catch(Exception e)
438         {
439             String message = "Failed to check permission '" + permissionName + "'";
440             logger.error( message , e );
441             throw new PermissionException( message, e );
442         }
443         return ( permissions.size() > 0 );
444     }
445 
446 
447     /***
448      * Retrieves a single <code>Permission</code> for a given permissionName principal.
449      *
450      * The security service may optionally check the current user context
451      * to determine if the requestor has permission to perform this action.
452      *
453      * @param permissionName a permission principal identity to be retrieved.
454      * @return Permission the permission record retrieved.
455      * @exception PermissionException when the security provider has a general failure.
456      * @exception InsufficientPrivilegeException when the requestor is denied due to insufficient privilege
457      */
458     public Permission getPermission(String permissionName)
459         throws JetspeedSecurityException
460     {
461         List permissions;
462 
463         try
464         {
465             Criteria criteria = new Criteria();
466             criteria.add(TurbinePermissionPeer.PERMISSION_NAME, permissionName);
467             permissions = TurbinePermissionPeer.doSelect(criteria);
468         }
469         catch(Exception e)
470         {
471             String message = "Failed to retrieve permission '" + permissionName + "'";
472             logger.error( message, e );
473             throw new PermissionException( message, e );
474         }
475         if ( permissions.size() > 1 )
476         {
477             throw new PermissionException(
478                 "Multiple Permissions with same permissionname '" + permissionName + "'");
479         }
480         if ( permissions.size() == 1 )
481         {
482             TurbinePermission permission = (TurbinePermission)permissions.get(0);
483             return permission;
484         }
485         throw new PermissionException("Unknown permission '" + permissionName + "'");
486 
487     }
488 
489 
490     ///////////////////////////////////////////////////////////////////////////
491     // Internal
492     ///////////////////////////////////////////////////////////////////////////
493 
494     protected JetspeedRunData getRunData()
495      {
496          JetspeedRunData rundata = null;
497          if (this.runDataService != null)
498          {
499              rundata = this.runDataService.getCurrentRunData();
500          }
501          return rundata;
502      }
503 
504     /***
505      * Check whether a specified permission exists.
506      *
507      * The login name is used for looking up the account.
508      *
509      * @param permissionName the name of the permission to check for existence.
510      * @return true if the specified account exists
511      * @throws PermissionException if there was a general db access error
512      *
513      */
514     protected boolean permissionExists(String permissionName)
515         throws PermissionException
516     {
517         Criteria criteria = new Criteria();
518         criteria.add(TurbinePermissionPeer.PERMISSION_NAME, permissionName);
519         List permissions;
520         try
521         {
522             permissions = TurbinePermissionPeer.doSelect(criteria);
523         }
524         catch(Exception e)
525         {
526             logger.error( "Failed to check account's presence", e );
527             throw new PermissionException(
528                 "Failed to check account's presence", e);
529         }
530         if (permissions.size() < 1)
531         {
532             return false;
533         }
534         return true;
535     }
536 
537     ///////////////////////////////////////////////////////////////////////////
538     // Service Init
539     ///////////////////////////////////////////////////////////////////////////
540 
541 
542     /***
543      * This is the early initialization method called by the
544      * Turbine <code>Service</code> framework
545      * @param conf The <code>ServletConfig</code>
546      * @exception throws a <code>InitializationException</code> if the service
547      * fails to initialize
548      */
549     public synchronized void init(ServletConfig conf)
550         throws InitializationException
551     {
552         if (getInit()) return;
553 
554         super.init(conf);
555 
556         // get configuration parameters from Jetspeed Resources
557         ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
558                                                      .getResources(JetspeedSecurityService.SERVICE_NAME);
559 
560         this.runDataService =
561            (JetspeedRunDataService)TurbineServices.getInstance()
562                .getService(RunDataService.SERVICE_NAME);
563 
564         cascadeDelete = serviceConf.getBoolean( CASCADE_DELETE, DEFAULT_CASCADE_DELETE );
565         cachingEnable = serviceConf.getBoolean( CACHING_ENABLE, cachingEnable );
566         systemPermissions = serviceConf.getVector( CONFIG_SYSTEM_PERMISSIONS, new Vector() );
567         setInit(true);
568      }
569 
570 
571 
572 }
573 
574 
575