001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.om.page.impl;
018:
019: import java.security.AccessController;
020: import java.security.Principal;
021: import java.util.Iterator;
022: import java.util.LinkedList;
023: import java.util.List;
024:
025: import javax.security.auth.Subject;
026:
027: import org.apache.jetspeed.JetspeedActions;
028: import org.apache.jetspeed.om.common.SecurityConstraint;
029: import org.apache.jetspeed.om.common.SecurityConstraints;
030: import org.apache.jetspeed.om.page.BaseElement;
031: import org.apache.jetspeed.om.page.PageSecurity;
032: import org.apache.jetspeed.om.page.SecurityConstraintImpl;
033: import org.apache.jetspeed.page.impl.DatabasePageManagerUtils;
034: import org.apache.jetspeed.security.FolderPermission;
035: import org.apache.jetspeed.security.GroupPrincipal;
036: import org.apache.jetspeed.security.JSSubject;
037: import org.apache.jetspeed.security.PagePermission;
038: import org.apache.jetspeed.security.PortalResourcePermission;
039: import org.apache.jetspeed.security.RolePrincipal;
040: import org.apache.jetspeed.security.UserPrincipal;
041:
042: /**
043: * BaseElementImpl
044: *
045: * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
046: * @version $Id$
047: */
048: public abstract class BaseElementImpl implements BaseElement {
049: private int id;
050: private String name;
051: private String title;
052: private String shortTitle;
053: private SecurityConstraintsImpl constraints;
054:
055: private boolean constraintsEnabled;
056: private boolean permissionsEnabled;
057:
058: protected BaseElementImpl(SecurityConstraintsImpl constraints) {
059: this .constraints = constraints;
060: }
061:
062: /**
063: * getName
064: *
065: * @return element name
066: */
067: public String getName() {
068: return name;
069: }
070:
071: /**
072: * setName
073: *
074: * @param name element name
075: */
076: public void setName(String name) {
077: this .name = name;
078: }
079:
080: /**
081: * setConstraintsEnabled
082: *
083: * @param enabled enable/disable security constraints checks
084: */
085: public void setConstraintsEnabled(boolean enabled) {
086: constraintsEnabled = enabled;
087: }
088:
089: /**
090: * setPermissionsEnabled
091: *
092: * @param enabled enable/disable security permissions checks
093: */
094: public void setPermissionsEnabled(boolean enabled) {
095: permissionsEnabled = enabled;
096: }
097:
098: /**
099: * grantViewActionAccess
100: *
101: * @return granted access for view action
102: */
103: public boolean grantViewActionAccess() {
104: // by default, access must be checked
105: return false;
106: }
107:
108: /**
109: * getEffectivePageSecurity
110: *
111: * @return effective page security object
112: */
113: public PageSecurity getEffectivePageSecurity() {
114: // no page security available by default
115: return null;
116: }
117:
118: /**
119: * checkConstraints
120: *
121: * Check fully parameterized principal against specified security constraint scope.
122: *
123: * @param actions actions to check
124: * @param userPrincipals principal users list
125: * @param rolePrincipals principal roles list
126: * @param groupPrincipals principal group list
127: * @param checkNodeOnly check node scope only
128: * @param checkParentsOnly check parent folder scope only
129: * @throws SecurityException
130: */
131: public void checkConstraints(List actions, List userPrincipals,
132: List rolePrincipals, List groupPrincipals,
133: boolean checkNodeOnly, boolean checkParentsOnly)
134: throws SecurityException {
135: // check node constraints if available
136: if ((constraints != null) && !constraints.isEmpty()) {
137: constraints.checkConstraints(actions, userPrincipals,
138: rolePrincipals, groupPrincipals,
139: getEffectivePageSecurity());
140: }
141: }
142:
143: /**
144: * getLogicalPermissionPath
145: *
146: * @return path used for permissions checks
147: */
148: public String getLogicalPermissionPath() {
149: // same as physical path by default
150: return getPhysicalPermissionPath();
151: }
152:
153: /**
154: * getPhysicalPermissionPath
155: *
156: * @return path used for permissions checks
157: */
158: public String getPhysicalPermissionPath() {
159: // no permissions path available by default
160: return null;
161: }
162:
163: /**
164: * checkPermissions
165: *
166: * @param mask mask of actions to check
167: * @param checkNodeOnly check node scope only
168: * @param checkParentsOnly check parent folder scope only
169: * @throws SecurityException
170: */
171: public void checkPermissions(int mask, boolean checkNodeOnly,
172: boolean checkParentsOnly) throws SecurityException {
173: // check page and folder permissions
174: String physicalPermissionPath = getPhysicalPermissionPath();
175: if (physicalPermissionPath != null) {
176: // check permissions using physical path
177: try {
178: checkPermissions(physicalPermissionPath, mask,
179: checkNodeOnly, checkParentsOnly);
180: } catch (SecurityException physicalSE) {
181: // fallback check using logical path if available and different
182: String logicalPermissionPath = getLogicalPermissionPath();
183: if ((logicalPermissionPath != null)
184: && !logicalPermissionPath
185: .equals(physicalPermissionPath)) {
186: checkPermissions(logicalPermissionPath, mask,
187: checkNodeOnly, checkParentsOnly);
188: } else {
189: throw physicalSE;
190: }
191: }
192: }
193: }
194:
195: /**
196: * checkPermissions
197: *
198: * @param path permissions path to check
199: * @param mask mask of actions to check
200: * @param checkNodeOnly check node scope only
201: * @param checkParentsOnly check parent folder scope only
202: * @throws SecurityException
203: */
204: public void checkPermissions(String path, int mask,
205: boolean checkNodeOnly, boolean checkParentsOnly)
206: throws SecurityException {
207: // check actions permissions
208: try {
209: // check for granted page permissions
210: PagePermission permission = new PagePermission(path, mask);
211: AccessController.checkPermission(permission);
212: } catch (SecurityException se) {
213: // fallback check for granted folder permissions
214: FolderPermission permission = new FolderPermission(path,
215: mask);
216: AccessController.checkPermission(permission);
217: }
218: }
219:
220: /* (non-Javadoc)
221: * @see org.apache.jetspeed.om.common.SecuredResource#getConstraintsEnabled()
222: */
223: public boolean getConstraintsEnabled() {
224: return constraintsEnabled;
225: }
226:
227: /* (non-Javadoc)
228: * @see java.lang.Object#equals(java.lang.Object)
229: */
230: public boolean equals(Object o) {
231: // compare element by id
232: return ((o != null) && getClass().equals(o.getClass())
233: && (id != 0) && (id == ((BaseElementImpl) o).id));
234: }
235:
236: /* (non-Javadoc)
237: * @see java.lang.Object#hashCode()
238: */
239: public int hashCode() {
240: // use id to generate hashCode
241: return id;
242: }
243:
244: /* (non-Javadoc)
245: * @see org.apache.jetspeed.om.common.SecuredResource#getSecurityConstraints()
246: */
247: public SecurityConstraints getSecurityConstraints() {
248: return constraints;
249: }
250:
251: /* (non-Javadoc)
252: * @see org.apache.jetspeed.om.common.SecuredResource#newSecurityConstraints()
253: */
254: public SecurityConstraints newSecurityConstraints() {
255: // return universal security constraints instance
256: // since object members are copied on assignment to
257: // maintain persistent collection members
258: return new SecurityConstraintsImpl();
259: }
260:
261: /* (non-Javadoc)
262: * @see org.apache.jetspeed.om.common.SecuredResource#newSecurityConstraint()
263: */
264: public SecurityConstraint newSecurityConstraint() {
265: // return constraints specific security constraint instance
266: if ((constraints != null)
267: && (constraints.getSecurityConstraintClass() != null)) {
268: try {
269: return (SecurityConstraintImpl) constraints
270: .getSecurityConstraintClass().newInstance();
271: } catch (InstantiationException ie) {
272: throw new ClassCastException(
273: "Unable to create security constraint instance: "
274: + constraints
275: .getSecurityConstraintClass()
276: .getName() + ", (" + ie + ").");
277: } catch (IllegalAccessException iae) {
278: throw new ClassCastException(
279: "Unable to create security constraint instance: "
280: + constraints
281: .getSecurityConstraintClass()
282: .getName() + ", (" + iae + ").");
283: }
284: }
285: // return universal security constraint instance
286: return new SecurityConstraintImpl();
287: }
288:
289: /* (non-Javadoc)
290: * @see org.apache.jetspeed.om.common.SecuredResource#setSecurityConstraints(org.apache.jetspeed.om.common.SecurityConstraints)
291: */
292: public void setSecurityConstraints(SecurityConstraints constraints) {
293: if (this .constraints != null) {
294: // set constraints configuration in nested om implementation instance
295: this .constraints.setOwner(constraints.getOwner());
296: this .constraints.setSecurityConstraints(constraints
297: .getSecurityConstraints());
298: this .constraints.setSecurityConstraintsRefs(constraints
299: .getSecurityConstraintsRefs());
300: }
301: }
302:
303: /* (non-Javadoc)
304: * @see org.apache.jetspeed.om.common.SecuredResource#checkConstraints(java.lang.String)
305: */
306: public void checkConstraints(String actions)
307: throws SecurityException {
308: // skip checks if not enabled
309: if (!getConstraintsEnabled()) {
310: return;
311: }
312:
313: // validate specified actions
314: if (actions == null) {
315: throw new SecurityException(
316: "BaseElementImpl.checkConstraints(): No actions specified.");
317: }
318:
319: // get action names lists; separate view and other
320: // actions to mimic file system permissions logic
321: List viewActionList = SecurityConstraintImpl
322: .parseCSVList(actions);
323: List otherActionsList = null;
324: if (viewActionList.size() == 1) {
325: if (!viewActionList.contains(JetspeedActions.VIEW)) {
326: otherActionsList = viewActionList;
327: viewActionList = null;
328: }
329: } else {
330: otherActionsList = viewActionList;
331: viewActionList = null;
332: if (otherActionsList.remove(JetspeedActions.VIEW)) {
333: viewActionList = DatabasePageManagerUtils.createList();
334: viewActionList.add(JetspeedActions.VIEW);
335: }
336: }
337:
338: // get current request context subject
339: Subject subject = JSSubject.getSubject(AccessController
340: .getContext());
341: if (subject == null) {
342: throw new SecurityException(
343: "BaseElementImpl.checkConstraints(): Missing JSSubject.");
344: }
345:
346: // get user/group/role principal names
347: List userPrincipals = null;
348: List rolePrincipals = null;
349: List groupPrincipals = null;
350: Iterator principals = subject.getPrincipals().iterator();
351: while (principals.hasNext()) {
352: Principal principal = (Principal) principals.next();
353: if (principal instanceof UserPrincipal) {
354: if (userPrincipals == null) {
355: userPrincipals = new LinkedList();
356: }
357: userPrincipals.add(principal.getName());
358: } else if (principal instanceof RolePrincipal) {
359: if (rolePrincipals == null) {
360: rolePrincipals = new LinkedList();
361: }
362: rolePrincipals.add(principal.getName());
363: } else if (principal instanceof GroupPrincipal) {
364: if (groupPrincipals == null) {
365: groupPrincipals = new LinkedList();
366: }
367: groupPrincipals.add(principal.getName());
368: }
369: }
370:
371: // check constraints using parsed action and access lists
372: if (viewActionList != null) {
373: checkConstraints(viewActionList, userPrincipals,
374: rolePrincipals, groupPrincipals, false,
375: grantViewActionAccess());
376: }
377: if (otherActionsList != null) {
378: checkConstraints(otherActionsList, userPrincipals,
379: rolePrincipals, groupPrincipals, true, false);
380: }
381: }
382:
383: /**
384: * resetCachedSecurityConstraints
385: */
386: public void resetCachedSecurityConstraints() {
387: // propagate to constraints
388: if (constraints != null) {
389: constraints.resetCachedSecurityConstraints();
390: }
391: }
392:
393: /* (non-Javadoc)
394: * @see org.apache.jetspeed.om.common.SecuredResource#getPermissionsEnabled()
395: */
396: public boolean getPermissionsEnabled() {
397: return permissionsEnabled;
398: }
399:
400: /* (non-Javadoc)
401: * @see org.apache.jetspeed.om.common.SecuredResource#checkPermissions(java.lang.String)
402: */
403: public void checkPermissions(int mask) throws SecurityException {
404: // skip checks if not enabled
405: if (!getPermissionsEnabled()) {
406: return;
407: }
408:
409: // separate view and other actions to mimic file system permissions logic
410: boolean viewAction = (mask & JetspeedActions.MASK_VIEW) == JetspeedActions.MASK_VIEW;
411: int otherMask = mask & ~JetspeedActions.MASK_VIEW;
412:
413: // check permissions using parsed actions
414: if (viewAction) {
415: checkPermissions(JetspeedActions.MASK_VIEW, false,
416: grantViewActionAccess());
417: }
418: if (otherMask != 0) {
419: checkPermissions(otherMask, true, false);
420: }
421: }
422:
423: /* (non-Javadoc)
424: * @see org.apache.jetspeed.om.common.SecuredResource#checkAccess(java.lang.String)
425: */
426: public void checkAccess(String actions) throws SecurityException {
427: // check access permissions and constraints as enabled
428: if (getPermissionsEnabled()) {
429: int mask = PortalResourcePermission.parseActions(actions);
430: checkPermissions(mask);
431: }
432: if (getConstraintsEnabled()) {
433: checkConstraints(actions);
434: }
435: }
436:
437: /* (non-Javadoc)
438: * @see org.apache.jetspeed.om.page.BaseElement#getId()
439: */
440: public String getId() {
441: return Integer.toString(id);
442: }
443:
444: /* (non-Javadoc)
445: * @see org.apache.jetspeed.om.page.BaseElement#getTitle()
446: */
447: public String getTitle() {
448: return title;
449: }
450:
451: /* (non-Javadoc)
452: * @see org.apache.jetspeed.om.page.BaseElement#setTitle(java.lang.String)
453: */
454: public void setTitle(String title) {
455: this .title = title;
456: }
457:
458: /* (non-Javadoc)
459: * @see org.apache.jetspeed.om.page.BaseElement#getShortTitle()
460: */
461: public String getShortTitle() {
462: return shortTitle;
463: }
464:
465: /* (non-Javadoc)
466: * @see org.apache.jetspeed.om.page.BaseElement#setShortTitle(java.lang.String)
467: */
468: public void setShortTitle(String shortTitle) {
469: this.shortTitle = shortTitle;
470: }
471: }
|