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.om.page.impl;
18  
19  import java.security.AccessController;
20  import java.security.Principal;
21  import java.util.Iterator;
22  import java.util.LinkedList;
23  import java.util.List;
24  
25  import javax.security.auth.Subject;
26  
27  import org.apache.jetspeed.JetspeedActions;
28  import org.apache.jetspeed.om.common.SecurityConstraint;
29  import org.apache.jetspeed.om.common.SecurityConstraints;
30  import org.apache.jetspeed.om.page.BaseElement;
31  import org.apache.jetspeed.om.page.PageSecurity;
32  import org.apache.jetspeed.om.page.SecurityConstraintImpl;
33  import org.apache.jetspeed.page.impl.DatabasePageManagerUtils;
34  import org.apache.jetspeed.security.FolderPermission;
35  import org.apache.jetspeed.security.GroupPrincipal;
36  import org.apache.jetspeed.security.JSSubject;
37  import org.apache.jetspeed.security.PagePermission;
38  import org.apache.jetspeed.security.PortalResourcePermission;
39  import org.apache.jetspeed.security.RolePrincipal;
40  import org.apache.jetspeed.security.UserPrincipal;
41  
42  /***
43   * BaseElementImpl
44   *
45   * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
46   * @version $Id$
47   */
48  public abstract class BaseElementImpl implements BaseElement
49  {
50      private int id;
51      private String name;
52      private String title;
53      private String shortTitle;
54      private SecurityConstraintsImpl constraints;
55  
56      private boolean constraintsEnabled;
57      private boolean permissionsEnabled;
58  
59      protected BaseElementImpl(SecurityConstraintsImpl constraints)
60      {
61          this.constraints = constraints;
62      }
63  
64      /***
65       * getName
66       *
67       * @return element name
68       */
69      public String getName()
70      {
71          return name;
72      }
73  
74      /***
75       * setName
76       *
77       * @param name element name
78       */
79      public void setName(String name)
80      {
81          this.name = name;
82      }
83  
84      /***
85       * setConstraintsEnabled
86       *
87       * @param enabled enable/disable security constraints checks
88       */
89      public void setConstraintsEnabled(boolean enabled)
90      {
91          constraintsEnabled = enabled;
92      }
93      
94      /***
95       * setPermissionsEnabled
96       *
97       * @param enabled enable/disable security permissions checks
98       */
99      public void setPermissionsEnabled(boolean enabled)
100     {
101         permissionsEnabled = enabled;
102     }
103 
104     /***
105      * grantViewActionAccess
106      *
107      * @return granted access for view action
108      */
109     public boolean grantViewActionAccess()
110     {
111         // by default, access must be checked
112         return false;
113     }
114 
115     /***
116      * getEffectivePageSecurity
117      *
118      * @return effective page security object
119      */
120     public PageSecurity getEffectivePageSecurity()
121     {
122         // no page security available by default
123         return null;
124     }
125 
126     /***
127      * checkConstraints
128      *
129      * Check fully parameterized principal against specified security constraint scope.
130      *
131      * @param actions actions to check
132      * @param userPrincipals principal users list
133      * @param rolePrincipals principal roles list
134      * @param groupPrincipals principal group list
135      * @param checkNodeOnly check node scope only
136      * @param checkParentsOnly check parent folder scope only
137      * @throws SecurityException
138      */
139     public void checkConstraints(List actions, List userPrincipals, List rolePrincipals, List groupPrincipals, boolean checkNodeOnly, boolean checkParentsOnly) throws SecurityException
140     {
141         // check node constraints if available
142         if ((constraints != null) && !constraints.isEmpty())
143         {
144             constraints.checkConstraints(actions, userPrincipals, rolePrincipals, groupPrincipals, getEffectivePageSecurity());
145         }
146     }
147 
148     /***
149      * getLogicalPermissionPath
150      *
151      * @return path used for permissions checks
152      */
153     public String getLogicalPermissionPath()
154     {
155         // same as physical path by default
156         return getPhysicalPermissionPath();
157     }
158 
159     /***
160      * getPhysicalPermissionPath
161      *
162      * @return path used for permissions checks
163      */
164     public String getPhysicalPermissionPath()
165     {
166         // no permissions path available by default
167         return null;
168     }
169 
170     /***
171      * checkPermissions
172      *
173      * @param mask mask of actions to check
174      * @param checkNodeOnly check node scope only
175      * @param checkParentsOnly check parent folder scope only
176      * @throws SecurityException
177      */
178     public void checkPermissions(int mask, boolean checkNodeOnly, boolean checkParentsOnly) throws SecurityException
179     {
180         // check page and folder permissions
181         String physicalPermissionPath = getPhysicalPermissionPath();
182         if (physicalPermissionPath != null)
183         {
184             // check permissions using physical path
185             try
186             {
187                 checkPermissions(physicalPermissionPath, mask, checkNodeOnly, checkParentsOnly);
188             }
189             catch (SecurityException physicalSE)
190             {
191                 // fallback check using logical path if available and different
192                 String logicalPermissionPath = getLogicalPermissionPath();
193                 if ((logicalPermissionPath != null) && !logicalPermissionPath.equals(physicalPermissionPath))
194                 {
195                     checkPermissions(logicalPermissionPath, mask, checkNodeOnly, checkParentsOnly);
196                 }
197                 else
198                 {
199                     throw physicalSE;
200                 }
201             }
202         }
203     }
204 
205     /***
206      * checkPermissions
207      *
208      * @param path permissions path to check
209      * @param mask mask of actions to check
210      * @param checkNodeOnly check node scope only
211      * @param checkParentsOnly check parent folder scope only
212      * @throws SecurityException
213      */
214     public void checkPermissions(String path, int mask, boolean checkNodeOnly, boolean checkParentsOnly) throws SecurityException
215     {
216         // check actions permissions
217         try
218         {
219             // check for granted page permissions
220             PagePermission permission = new PagePermission(path, mask);
221             AccessController.checkPermission(permission);
222         }
223         catch (SecurityException se)
224         {
225             // fallback check for granted folder permissions
226             FolderPermission permission = new FolderPermission(path, mask);
227             AccessController.checkPermission(permission);
228         }
229     }
230 
231     /* (non-Javadoc)
232      * @see org.apache.jetspeed.om.common.SecuredResource#getConstraintsEnabled()
233      */
234     public boolean getConstraintsEnabled()
235     {
236         return constraintsEnabled;
237     }
238     
239     /* (non-Javadoc)
240      * @see java.lang.Object#equals(java.lang.Object)
241      */
242     public boolean equals(Object o)
243     {
244         // compare element by id
245         return ((o != null) && getClass().equals(o.getClass()) && (id != 0) && (id == ((BaseElementImpl)o).id));
246     }
247 
248     /* (non-Javadoc)
249      * @see java.lang.Object#hashCode()
250      */
251     public int hashCode()
252     {
253         // use id to generate hashCode
254         return id;
255     }
256 
257     /* (non-Javadoc)
258      * @see org.apache.jetspeed.om.common.SecuredResource#getSecurityConstraints()
259      */
260     public SecurityConstraints getSecurityConstraints()
261     {
262         return constraints;
263     }
264     
265     /* (non-Javadoc)
266      * @see org.apache.jetspeed.om.common.SecuredResource#newSecurityConstraints()
267      */
268     public SecurityConstraints newSecurityConstraints()
269     {
270         // return universal security constraints instance
271         // since object members are copied on assignment to
272         // maintain persistent collection members
273         return new SecurityConstraintsImpl();
274     }
275 
276     /* (non-Javadoc)
277      * @see org.apache.jetspeed.om.common.SecuredResource#newSecurityConstraint()
278      */
279     public SecurityConstraint newSecurityConstraint()
280     {
281         // return constraints specific security constraint instance
282         if ((constraints != null) && (constraints.getSecurityConstraintClass() != null))
283         {
284             try
285             {
286                 return (SecurityConstraintImpl)constraints.getSecurityConstraintClass().newInstance();
287             }
288             catch (InstantiationException ie)
289             {
290                 throw new ClassCastException("Unable to create security constraint instance: " + constraints.getSecurityConstraintClass().getName() + ", (" + ie + ").");
291             }
292             catch (IllegalAccessException iae)
293             {
294                 throw new ClassCastException("Unable to create security constraint instance: " + constraints.getSecurityConstraintClass().getName() + ", (" + iae + ").");
295             }
296         }
297         // return universal security constraint instance
298         return new SecurityConstraintImpl();
299     }
300 
301     /* (non-Javadoc)
302      * @see org.apache.jetspeed.om.common.SecuredResource#setSecurityConstraints(org.apache.jetspeed.om.common.SecurityConstraints)
303      */
304     public void setSecurityConstraints(SecurityConstraints constraints)
305     {
306         if (this.constraints != null)
307         {
308             // set constraints configuration in nested om implementation instance
309             this.constraints.setOwner(constraints.getOwner());
310             this.constraints.setSecurityConstraints(constraints.getSecurityConstraints());
311             this.constraints.setSecurityConstraintsRefs(constraints.getSecurityConstraintsRefs());
312         }
313     }
314 
315     /* (non-Javadoc)
316      * @see org.apache.jetspeed.om.common.SecuredResource#checkConstraints(java.lang.String)
317      */
318     public void checkConstraints(String actions) throws SecurityException
319     {
320         // skip checks if not enabled
321         if (!getConstraintsEnabled())
322         {
323             return;
324         }
325 
326         // validate specified actions
327         if (actions == null)
328         {
329             throw new SecurityException("BaseElementImpl.checkConstraints(): No actions specified.");
330         }
331 
332         // get action names lists; separate view and other
333         // actions to mimic file system permissions logic
334         List viewActionList = SecurityConstraintImpl.parseCSVList(actions);
335         List otherActionsList = null;
336         if (viewActionList.size() == 1)
337         {
338             if (!viewActionList.contains(JetspeedActions.VIEW))
339             {
340                 otherActionsList = viewActionList;
341                 viewActionList = null;
342             }
343         }
344         else
345         {
346             otherActionsList = viewActionList;
347             viewActionList = null;
348             if (otherActionsList.remove(JetspeedActions.VIEW))
349             {
350                 viewActionList = DatabasePageManagerUtils.createList();
351                 viewActionList.add(JetspeedActions.VIEW);
352             }
353         }
354 
355         // get current request context subject
356         Subject subject = JSSubject.getSubject(AccessController.getContext());
357         if (subject == null)
358         {
359             throw new SecurityException("BaseElementImpl.checkConstraints(): Missing JSSubject.");
360         }
361 
362         // get user/group/role principal names
363         List userPrincipals = null;
364         List rolePrincipals = null;
365         List groupPrincipals = null;
366         Iterator principals = subject.getPrincipals().iterator();
367         while (principals.hasNext())
368         {
369             Principal principal = (Principal) principals.next();
370             if (principal instanceof UserPrincipal)
371             {
372                 if (userPrincipals == null)
373                 {
374                     userPrincipals = new LinkedList();
375                 }
376                 userPrincipals.add(principal.getName());
377             }
378             else if (principal instanceof RolePrincipal)
379             {
380                 if (rolePrincipals == null)
381                 {
382                     rolePrincipals = new LinkedList();
383                 }
384                 rolePrincipals.add(principal.getName());
385             }
386             else if (principal instanceof GroupPrincipal)
387             {
388                 if (groupPrincipals == null)
389                 {
390                     groupPrincipals = new LinkedList();
391                 }
392                 groupPrincipals.add(principal.getName());
393             }
394         }
395 
396         // check constraints using parsed action and access lists
397         if (viewActionList != null)
398         {
399             checkConstraints(viewActionList, userPrincipals, rolePrincipals, groupPrincipals, false, grantViewActionAccess());
400         }
401         if (otherActionsList != null)
402         {
403             checkConstraints(otherActionsList, userPrincipals, rolePrincipals, groupPrincipals, true, false);
404         }
405     }
406 
407     /***
408      * resetCachedSecurityConstraints
409      */
410     public void resetCachedSecurityConstraints()
411     {
412         // propagate to constraints
413         if (constraints != null)
414         {
415             constraints.resetCachedSecurityConstraints();
416         }
417     }
418 
419     /* (non-Javadoc)
420      * @see org.apache.jetspeed.om.common.SecuredResource#getPermissionsEnabled()
421      */
422     public boolean getPermissionsEnabled()
423     {
424         return permissionsEnabled;
425     }
426     
427     /* (non-Javadoc)
428      * @see org.apache.jetspeed.om.common.SecuredResource#checkPermissions(java.lang.String)
429      */
430     public void checkPermissions(int mask) throws SecurityException
431     {
432         // skip checks if not enabled
433         if (!getPermissionsEnabled())
434         {
435             return;
436         }
437 
438         // separate view and other actions to mimic file system permissions logic
439         boolean viewAction = (mask & JetspeedActions.MASK_VIEW) == JetspeedActions.MASK_VIEW;
440         int otherMask = mask & ~JetspeedActions.MASK_VIEW;
441 
442         // check permissions using parsed actions
443         if (viewAction)
444         {
445             checkPermissions(JetspeedActions.MASK_VIEW, false, grantViewActionAccess());
446         }
447         if (otherMask != 0)
448         {
449             checkPermissions(otherMask, true, false);
450         }
451     }
452 
453     /* (non-Javadoc)
454      * @see org.apache.jetspeed.om.common.SecuredResource#checkAccess(java.lang.String)
455      */
456     public void checkAccess(String actions) throws SecurityException
457     {
458         // check access permissions and constraints as enabled
459         if (getPermissionsEnabled())
460         {
461             int mask = PortalResourcePermission.parseActions(actions);
462             checkPermissions(mask);
463         }
464         if (getConstraintsEnabled())
465         {
466             checkConstraints(actions);
467         }
468     }
469 
470     /* (non-Javadoc)
471      * @see org.apache.jetspeed.om.page.BaseElement#getId()
472      */
473     public String getId()
474     {
475         return Integer.toString(id);
476     }
477 
478     /* (non-Javadoc)
479      * @see org.apache.jetspeed.om.page.BaseElement#getTitle()
480      */
481     public String getTitle()
482     {
483         return title;
484     }
485 
486     /* (non-Javadoc)
487      * @see org.apache.jetspeed.om.page.BaseElement#setTitle(java.lang.String)
488      */
489     public void setTitle(String title)
490     {
491         this.title = title;
492     }
493 
494     /* (non-Javadoc)
495      * @see org.apache.jetspeed.om.page.BaseElement#getShortTitle()
496      */
497     public String getShortTitle()
498     {
499         return shortTitle;
500     }
501 
502     /* (non-Javadoc)
503      * @see org.apache.jetspeed.om.page.BaseElement#setShortTitle(java.lang.String)
504      */
505     public void setShortTitle(String shortTitle)
506     {
507         this.shortTitle = shortTitle;
508     }
509 }