View Javadoc

1   /* 
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.security.impl;
18  
19  import java.lang.reflect.Constructor;
20  import java.security.AccessController;
21  import java.security.Permission;
22  import java.security.Permissions;
23  import java.security.Principal;
24  import java.security.PrivilegedAction;
25  import java.sql.Timestamp;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.Iterator;
31  import java.util.LinkedList;
32  
33  import javax.security.auth.Subject;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.jetspeed.i18n.KeyedMessage;
38  import org.apache.jetspeed.security.JSSubject;
39  import org.apache.jetspeed.security.PermissionManager;
40  import org.apache.jetspeed.security.RolePrincipal;
41  import org.apache.jetspeed.security.SecurityException;
42  import org.apache.jetspeed.security.SecurityHelper;
43  import org.apache.jetspeed.security.UserPrincipal;
44  import org.apache.jetspeed.security.om.InternalPermission;
45  import org.apache.jetspeed.security.om.InternalPrincipal;
46  import org.apache.jetspeed.security.om.impl.InternalPermissionImpl;
47  import org.apache.jetspeed.security.om.impl.InternalPrincipalImpl;
48  import org.apache.jetspeed.util.ArgUtil;
49  import org.apache.ojb.broker.query.Criteria;
50  import org.apache.ojb.broker.query.Query;
51  import org.apache.ojb.broker.query.QueryByCriteria;
52  import org.apache.ojb.broker.query.QueryFactory;
53  import org.springframework.orm.ojb.support.PersistenceBrokerDaoSupport;
54  
55  /***
56   * <p>
57   * Implementation for managing {@link Permission}and permission association to
58   * {@link Principal}. Permissions are used to manage Principals access
59   * entitlement on specified resources.
60   * </p>
61   * <p>
62   * For instance:
63   * </p>
64   * 
65   * <pre><code>
66   * 
67   *  
68   *   grant principal o.a.j.security.UserPrincipal &quot;theUserPrincipal&quot;
69   *   {
70   *       permission o.a.j.security.PortletPermission &quot;myportlet&quot;, &quot;view,edit,minimize,maximize&quot;;
71   *   };
72   *   
73   *  
74   * </code>
75   * 
76   *  &lt;pre&gt;
77   *   @author &lt;a href=&quot;mailto:dlestrat@apache.org&quot;&gt;David Le Strat&lt;/a&gt;
78   * 
79   * 
80   */
81  public class PermissionManagerImpl extends PersistenceBrokerDaoSupport implements PermissionManager 
82  {
83      private static final Log log = LogFactory.getLog(PermissionManagerImpl.class);
84      private static ThreadLocal permissionsCache = new ThreadLocal();
85      
86      /***
87       * @see org.apache.jetspeed.security.PermissionManager#getPermissions(java.security.Principal)
88       */
89      public Permissions getPermissions(Principal principal)
90      {        
91          String fullPath = SecurityHelper.getPreferencesFullPath(principal);
92          ArgUtil.notNull(new Object[] { fullPath }, new String[] { "fullPath" },
93                  "removePermission(java.security.Principal)");
94  
95          HashMap permissionsMap = (HashMap)permissionsCache.get();
96          if ( permissionsMap == null )
97          {
98              permissionsMap = new HashMap();
99              permissionsCache.set(permissionsMap);
100         }
101         HashSet principalPermissions = (HashSet)permissionsMap.get(fullPath);
102         if ( principalPermissions == null )
103         {
104             InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
105             if (null != internalPrincipal)
106             {
107                 principalPermissions = getSecurityPermissions(internalPrincipal.getPermissions());
108             }
109             if ( principalPermissions == null)
110             {
111                 principalPermissions = new HashSet();
112             }
113             permissionsMap.put(fullPath, principalPermissions);
114         }
115         
116         Permissions permissions = new Permissions();
117         Iterator iter =principalPermissions.iterator();
118         while (iter.hasNext())
119         {
120             permissions.add((Permission)iter.next());
121         }
122         
123         return permissions;
124     }
125 
126     /***
127      * @see org.apache.jetspeed.security.PermissionManager#getPermissions(java.util.Collection)
128      */
129     public Permissions getPermissions(Collection principals)
130     {
131         ArgUtil.notNull(new Object[] { principals }, new String[] { "principals" },
132                 "getPermissions(java.util.Collection)");
133 
134         Permissions permissions = new Permissions();
135         Collection principalsFullPath = getPrincipalsFullPath(principals);
136         if ((null != principalsFullPath) && principalsFullPath.size() > 0)
137         {
138             HashSet permissionsSet = new HashSet();
139             HashMap permissionsMap = (HashMap)permissionsCache.get();
140             if (permissionsMap == null)
141             {
142                 permissionsMap = new HashMap();
143                 permissionsCache.set(permissionsMap);
144             }
145             
146             Iterator iter = principalsFullPath.iterator();
147             HashSet principalPermissions;
148             while ( iter.hasNext())
149             {
150                 principalPermissions = (HashSet)permissionsMap.get(iter.next());
151                 if ( principalPermissions != null )
152                 {
153                     iter.remove();
154                     permissionsSet.addAll(principalPermissions);
155                 }
156             }
157             if ( principalsFullPath.size() > 0)
158             {
159                 Criteria filter = new Criteria();
160                 filter.addIn("fullPath", principalsFullPath);
161                 Query query = QueryFactory.newQuery(InternalPrincipalImpl.class, filter);
162                 Collection internalPrincipals = getPersistenceBrokerTemplate().getCollectionByQuery(query);
163                 Iterator internalPrincipalsIter = internalPrincipals.iterator();
164                 while (internalPrincipalsIter.hasNext())
165                 {
166                     InternalPrincipal internalPrincipal = (InternalPrincipal) internalPrincipalsIter.next();
167                     Collection internalPermissions = internalPrincipal.getPermissions();
168                     if (null != internalPermissions)
169                     {
170                         principalPermissions = getSecurityPermissions(internalPermissions);
171                         permissionsSet.addAll(principalPermissions);
172                     }
173                     else
174                     {
175                         principalPermissions = new HashSet();
176                     }
177                     permissionsMap.put(internalPrincipal.getFullPath(),principalPermissions);
178                 }
179             }
180             iter = permissionsSet.iterator();
181             while (iter.hasNext())
182             {
183                 permissions.add((Permission)iter.next());
184             }
185         }
186         return permissions;
187     }
188 
189     /***
190      * <p>
191      * Get the full path for the {@link Principal}in the collection.
192      * </p>
193      * 
194      * @param principals The collection of principals.
195      * @return The collection of principals names.
196      */
197     private Collection getPrincipalsFullPath(Collection principals)
198     {
199         Collection principalsFullPath = new ArrayList();
200         Iterator principalsIterator = principals.iterator();
201         while (principalsIterator.hasNext())
202         {
203             Principal principal = (Principal) principalsIterator.next();
204             String fullPath = SecurityHelper.getPreferencesFullPath(principal);
205             if (null != fullPath)
206             {
207                 principalsFullPath.add(fullPath);
208             }
209         }
210         return principalsFullPath;
211     }
212 
213     /***
214      * <p>
215      * Iterate through a collection of {@link InternalPermission}and build a
216      * unique collection of {@link java.security.Permission}.
217      * </p>
218      * 
219      * @param omPermissions The collection of {@link InternalPermission}.
220      */
221     private HashSet getSecurityPermissions(Collection omPermissions)
222     {     
223         HashSet permissions = new HashSet();
224         Iterator internalPermissionsIter = omPermissions.iterator();
225         while (internalPermissionsIter.hasNext())
226         {
227             InternalPermission internalPermission = (InternalPermission) internalPermissionsIter.next();
228             Permission permission = null;
229             try
230             {
231                 Class permissionClass = Class.forName(internalPermission.getClassname());
232                 Class[] parameterTypes = { String.class, String.class };
233                 Constructor permissionConstructor = permissionClass.getConstructor(parameterTypes);
234                 Object[] initArgs = { internalPermission.getName(), internalPermission.getActions() };
235                 permission = (Permission) permissionConstructor.newInstance(initArgs);
236                 if(permissions.add(permission))
237                 {
238                     if (log.isDebugEnabled())
239                     {
240                         log.debug("Added permimssion: [class, " + permission.getClass().getName() + "], " + "[name, "
241                                 + permission.getName() + "], " + "[actions, " + permission.getActions() + "]");
242                     }                   
243                 }
244             }
245             catch (Exception e)
246             {
247                 log.error("Internal error", e);
248             }
249         }
250         return permissions;
251     }
252 
253     /***
254      * @see org.apache.jetspeed.security.PermissionManager#addPermission(java.security.Permission)
255      */
256     public void addPermission(Permission permission) throws SecurityException
257     {
258         ArgUtil.notNull(new Object[] { permission }, new String[] { "permission" },
259                 "addPermission(java.security.Permission)");
260 
261         InternalPermission internalPermission = new InternalPermissionImpl(permission.getClass().getName(), permission
262                 .getName(), permission.getActions());
263         try
264         {            
265             getPersistenceBrokerTemplate().store(internalPermission);            
266         }
267         catch (Exception e)
268         {
269             KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.addPermission",
270                                                                    "store", e.getMessage());
271             logger.error(msg, e);            
272             throw new SecurityException(msg, e);
273         }
274     }
275 
276     /***
277      * @see org.apache.jetspeed.security.PermissionManager#removePermission(java.security.Permission)
278      */
279     public void removePermission(Permission permission) throws SecurityException
280     {
281         ArgUtil.notNull(new Object[] { permission }, new String[] { "permission" },
282                 "removePermission(java.security.Permission)");
283 
284         InternalPermission internalPermission = getInternalPermission(permission);
285         if (null != internalPermission)
286         {
287             // clear the whole ThreadLocal permissions cache
288             permissionsCache.set(null);
289             try
290             {
291                 // Remove permission.
292                 getPersistenceBrokerTemplate().delete(internalPermission);
293             }
294             catch (Exception e)
295             {
296                 KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.removePermission",
297                                                                        "delete", e.getMessage());
298                 logger.error(msg, e);            
299                 throw new SecurityException(msg, e);
300             }
301         }
302     }
303 
304     /***
305      * @see org.apache.jetspeed.security.PermissionManager#removePermissions(java.security.Principal)
306      */
307     public void removePermissions(Principal principal) throws SecurityException
308     {
309         String fullPath = SecurityHelper.getPreferencesFullPath(principal);
310         ArgUtil.notNull(new Object[] { fullPath }, new String[] { "fullPath" },
311                 "removePermission(java.security.Principal)");
312 
313         // Remove permissions on principal.
314         InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
315         if (null != internalPrincipal)
316         {
317             Collection internalPermissions = internalPrincipal.getPermissions();
318             if (null != internalPermissions)
319             {
320                 internalPermissions.clear();
321             }
322             // clear the whole ThreadLocal permissions cache
323             permissionsCache.set(null);
324             try
325             {
326                 internalPrincipal.setModifiedDate(new Timestamp(System.currentTimeMillis()));
327                 internalPrincipal.setPermissions(internalPermissions);
328                 
329                 getPersistenceBrokerTemplate().store(internalPrincipal);
330             }
331             catch (Exception e)
332             {
333                 KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.removePermissions",
334                                                                        "store", e.getMessage());
335                 logger.error(msg, e);                
336                 throw new SecurityException(msg, e);
337             }
338         }
339     }
340 
341     /***
342      * @see org.apache.jetspeed.security.PermissionManager#grantPermission(java.security.Principal,
343      *      java.security.Permission)
344      */
345     public void grantPermission(Principal principal, Permission permission) throws SecurityException
346     {
347         String fullPath = SecurityHelper.getPreferencesFullPath(principal);
348         ArgUtil.notNull(new Object[] { fullPath, permission }, new String[] { "fullPath", "permission" },
349                 "grantPermission(java.security.Principal, java.security.Permission)");
350 
351         Collection internalPermissions = new ArrayList();
352 
353         InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
354         if (null == internalPrincipal)
355         {
356             if ( principal instanceof UserPrincipal )
357             {
358                 throw new SecurityException(SecurityException.USER_DOES_NOT_EXIST.create(principal.getName()));
359             }
360             else if ( principal instanceof RolePrincipal )
361             {
362                 throw new SecurityException(SecurityException.ROLE_DOES_NOT_EXIST.create(principal.getName()));
363             }
364             // must/should be GroupPrincipal
365             throw new SecurityException(SecurityException.GROUP_DOES_NOT_EXIST.create(principal.getName()));
366         }
367         InternalPermission internalPermission = getInternalPermission(permission);
368         if (null == internalPermission)
369         {
370             throw new SecurityException(SecurityException.PERMISSION_DOES_NOT_EXIST.create(permission.getName()));
371         }
372 
373         if (null != internalPrincipal.getPermissions())
374         {
375             internalPermissions.addAll(internalPrincipal.getPermissions());
376         }
377         if (!internalPermissions.contains(internalPermission))
378         {
379             internalPermissions.add(internalPermission);
380         }
381         // clear the whole ThreadLocal permissions cache
382         permissionsCache.set(null);
383         try
384         {
385             internalPrincipal.setModifiedDate(new Timestamp(System.currentTimeMillis()));
386             internalPrincipal.setPermissions(internalPermissions);
387             
388             getPersistenceBrokerTemplate().store(internalPrincipal);
389         }
390         catch (Exception e)
391         {
392             KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.grantPermission",
393                                                                    "store", e.getMessage());
394             logger.error(msg, e);            
395             throw new SecurityException(msg, e);
396         }
397     }
398 
399     /***
400      * @see org.apache.jetspeed.security.PermissionManager#permissionExists(java.security.Permission)
401      */
402     public boolean permissionExists(Permission permission)
403     {
404         boolean permissionExists = true;
405         InternalPermission internalPermission = getInternalPermission(permission);
406         if (null == internalPermission)
407         {
408             permissionExists = false;
409         }
410         return permissionExists;
411     }
412 
413     /***
414      * @see org.apache.jetspeed.security.PermissionManager#revokePermission(java.security.Principal,
415      *      java.security.Permission)
416      */
417     public void revokePermission(Principal principal, Permission permission) throws SecurityException
418     {
419         String fullPath = SecurityHelper.getPreferencesFullPath(principal);
420         ArgUtil.notNull(new Object[] { fullPath, permission }, new String[] { "fullPath", "permission" },
421                 "revokePermission(java.security.Principal, java.security.Permission)");
422 
423         // Remove permissions on principal.
424         InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
425         if (null != internalPrincipal)
426         {
427             Collection internalPermissions = internalPrincipal.getPermissions();
428             if (null != internalPermissions)
429             {
430                 boolean revokePermission = false;
431                 ArrayList newInternalPermissions = new ArrayList();
432                 Iterator internalPermissionsIter = internalPermissions.iterator();
433                 while (internalPermissionsIter.hasNext())
434                 {
435                     InternalPermission internalPermission = (InternalPermission) internalPermissionsIter.next();
436                     if (!((internalPermission.getClassname().equals(permission.getClass().getName()))
437                             && (internalPermission.getName().equals(permission.getName())) && (internalPermission.getActions()
438                             .equals(permission.getActions()))))
439                     {
440                         newInternalPermissions.add(internalPermission);
441                     }
442                     else
443                     {
444                         revokePermission = true;
445                     }
446                 }
447                 if (revokePermission)
448                 {
449                     // clear the whole ThreadLocal permissions cache
450                     permissionsCache.set(null);
451                     try
452                     {
453                         internalPrincipal.setModifiedDate(new Timestamp(System.currentTimeMillis()));
454                         internalPrincipal.setPermissions(newInternalPermissions);
455 
456                         getPersistenceBrokerTemplate().store(internalPrincipal);
457                     }
458                     catch (Exception e)
459                     {
460                         KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.revokePermission",
461                                                                                "store", e.getMessage());
462                         logger.error(msg, e);                      
463                         throw new SecurityException(msg, e);
464                     }
465                 }
466             }
467         }
468     }
469 
470     /***
471      * <p>
472      * Returns the {@link InternalPrincipal}from the full path.
473      * </p>
474      * 
475      * @param fullPath The full path.
476      * @return The {@link InternalPrincipal}.
477      */
478     InternalPrincipal getInternalPrincipal(String fullPath)
479     {
480         Criteria filter = new Criteria();
481         filter.addEqualTo("fullPath", fullPath);
482         Query query = QueryFactory.newQuery(InternalPrincipalImpl.class, filter);
483         InternalPrincipal internalPrincipal = (InternalPrincipal) getPersistenceBrokerTemplate().getObjectByQuery(query);
484         return internalPrincipal;
485     }
486 
487     /***
488      * <p>
489      * Returns the {@link InternalPermission} from a Permission.
490      * </p>
491      * 
492      * @param permission The permission.
493      * @return The {@link InternalPermission}.
494      */
495     InternalPermission getInternalPermission(Permission permission)
496     {
497         Criteria filter = new Criteria();
498         filter.addEqualTo("classname", permission.getClass().getName());
499         filter.addEqualTo("name", permission.getName());
500         filter.addEqualTo("actions", permission.getActions());
501         Query query = QueryFactory.newQuery(InternalPermissionImpl.class, filter);
502         InternalPermission internalPermission = (InternalPermission) getPersistenceBrokerTemplate().getObjectByQuery(query);
503         return internalPermission;
504     }
505     
506     public boolean checkPermission(Subject subject, final Permission permission) 
507     {
508         try
509         {
510             //JSSubject.doAs(subject, new PrivilegedAction()
511             JSSubject.doAsPrivileged(subject, new PrivilegedAction()                
512             {
513                 public Object run()
514                 {
515                     AccessController.checkPermission(permission);
516                     return null;
517                 }
518             }, null);
519         }
520         catch (Exception e)
521         {
522             return false;
523         }
524         return true;         
525     }
526     
527     public Collection getPermissions()
528     {
529         QueryByCriteria query = QueryFactory.newQuery(InternalPermissionImpl.class, new Criteria());
530         query.addOrderByAscending("classname");
531         query.addOrderByAscending("name");
532         Collection internalPermissions = getPersistenceBrokerTemplate().getCollectionByQuery(query);
533         return internalPermissions;
534     }
535     
536     public Permissions getPermissions(String classname, String resource)
537     {
538         Criteria filter = new Criteria();
539         filter.addEqualTo("classname", classname);
540         filter.addEqualTo("name", resource);
541         Query query = QueryFactory.newQuery(InternalPermissionImpl.class, filter);
542         Collection internalPermissions = getPersistenceBrokerTemplate().getCollectionByQuery(query);        
543         Permissions permissions = new Permissions();
544         Iterator iter = internalPermissions.iterator();
545         try
546         {
547             while (iter.hasNext())
548             {
549                 InternalPermission internalPermission = (InternalPermission)iter.next();
550                 Class permissionClass = Class.forName(internalPermission.getClassname());
551                 Class[] parameterTypes = { String.class, String.class };
552                 Constructor permissionConstructor = permissionClass.getConstructor(parameterTypes);
553                 Object[] initArgs = { internalPermission.getName(), internalPermission.getActions() };
554                 Permission permission = (Permission) permissionConstructor.newInstance(initArgs);            
555                 permissions.add(permission);
556             }
557         }
558         catch (Exception e)
559         {
560             logger.error("Failed to retrieve permissions", e);            
561         }
562         return permissions;        
563     }    
564     
565     public int updatePermission(Permission permission, Collection principals)
566     throws SecurityException
567     {
568         int count = 0;
569         InternalPermission internal = getInternalPermission(permission);
570         Iterator iter = principals.iterator();
571         Collection newPrincipals = new LinkedList();
572         while (iter.hasNext())
573         {
574             Principal principal = (Principal)iter.next();
575             String fullPath = SecurityHelper.getPreferencesFullPath(principal);
576             InternalPrincipal internalPrincipal = getInternalPrincipal(fullPath);
577             newPrincipals.add(internalPrincipal);            
578         }
579         internal.setPrincipals(newPrincipals);
580         internal.setModifiedDate(new Timestamp(System.currentTimeMillis()));
581         try
582         {            
583             getPersistenceBrokerTemplate().store(internal);            
584         }
585         catch (Exception e)
586         {
587             KeyedMessage msg = SecurityException.UNEXPECTED.create("PermissionManager.updatePermission",
588                                                                    "store", e.getMessage());
589             logger.error(msg, e);            
590             throw new SecurityException(msg, e);
591         }
592 
593         return count;
594     }
595     
596     public Collection getPrincipals(Permission permission)
597     {
598         Collection result = new LinkedList();        
599         InternalPermission internalPermission = this.getInternalPermission(permission);
600         if (internalPermission == null)
601         {
602             return result;
603         }
604         Iterator principals = internalPermission.getPrincipals().iterator();
605         while (principals.hasNext())
606         {
607             InternalPrincipal internalPrincipal = (InternalPrincipal)principals.next();            
608             Principal principal = 
609                 SecurityHelper.createPrincipalFromFullPath(internalPrincipal.getFullPath());
610             result.add(principal);
611         }
612         return  result;
613     }
614     
615     
616 }