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:
018: package org.apache.jetspeed.om.page.psml;
019:
020: import java.security.AccessController;
021: import java.security.Principal;
022: import java.util.ArrayList;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025: import java.util.List;
026:
027: import javax.security.auth.Subject;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.apache.jetspeed.JetspeedActions;
032: import org.apache.jetspeed.om.common.SecuredResource;
033: import org.apache.jetspeed.om.common.SecurityConstraint;
034: import org.apache.jetspeed.om.common.SecurityConstraints;
035: import org.apache.jetspeed.om.page.BaseElement;
036: import org.apache.jetspeed.om.page.PageSecurity;
037: import org.apache.jetspeed.om.page.SecurityConstraintImpl;
038: import org.apache.jetspeed.page.document.DocumentHandlerFactory;
039: import org.apache.jetspeed.page.document.Node;
040: import org.apache.jetspeed.page.document.NodeSet;
041: import org.apache.jetspeed.page.document.psml.NodeSetImpl;
042: import org.apache.jetspeed.security.FolderPermission;
043: import org.apache.jetspeed.security.GroupPrincipal;
044: import org.apache.jetspeed.security.JSSubject;
045: import org.apache.jetspeed.security.PagePermission;
046: import org.apache.jetspeed.security.PortalResourcePermission;
047: import org.apache.jetspeed.security.RolePrincipal;
048: import org.apache.jetspeed.security.UserPrincipal;
049:
050: /**
051: *
052: * @version $Id: AbstractBaseElement.java 516448 2007-03-09 16:25:47Z ate $
053: */
054: public abstract class AbstractBaseElement implements
055: java.io.Serializable, SecuredResource {
056: private final static Log log = LogFactory
057: .getLog(AbstractBaseElement.class);
058:
059: private String id = null;
060:
061: private String title = null;
062:
063: private String shortTitle = null;
064:
065: private boolean constraintsEnabled;
066:
067: private SecurityConstraints constraints = null;
068:
069: private boolean permissionsEnabled;
070:
071: private DocumentHandlerFactory handlerFactory = null;
072:
073: public String getId() {
074: return this .id;
075: }
076:
077: public void setId(String id) {
078: this .id = id;
079: }
080:
081: /**
082: * <p>
083: * getTitle
084: * </p>
085: *
086: * @see org.apache.jetspeed.om.page.BaseElement#getTitle()
087: * @return
088: */
089: public String getTitle() {
090: return this .title;
091: }
092:
093: /**
094: * <p>
095: * setTitle
096: * </p>
097: *
098: * @see org.apache.jetspeed.om.page.BaseElement#setTitle(java.lang.String)
099: * @param title
100: */
101: public void setTitle(String title) {
102: this .title = title;
103: }
104:
105: /**
106: * <p>
107: * getShortTitle
108: * </p>
109: *
110: * @see org.apache.jetspeed.om.page.BaseElement#getShortTitle()
111: * @return short title
112: */
113: public String getShortTitle() {
114: // default to title if not specified
115: String title = this .shortTitle;
116: if (title == null) {
117: title = this .title;
118: }
119: return title;
120: }
121:
122: /**
123: * <p>
124: * setShortTitle
125: * </p>
126: *
127: * @see org.apache.jetspeed.om.page.BaseElement#setShortTitle(java.lang.String)
128: * @param title
129: */
130: public void setShortTitle(String title) {
131: this .shortTitle = title;
132: }
133:
134: /**
135: * <p>
136: * getConstraintsEnabled
137: * </p>
138: *
139: * @see org.apache.jetspeed.om.common.SecureResource#getConstraintsEnabled()
140: * @return whether security relies on PSML constraints
141: */
142: public boolean getConstraintsEnabled() {
143: return constraintsEnabled;
144: }
145:
146: /**
147: * <p>
148: * setConstraintsEnabled
149: * </p>
150: *
151: * @param enabled indicator
152: */
153: public void setConstraintsEnabled(boolean enabled) {
154: constraintsEnabled = enabled;
155: }
156:
157: /**
158: * <p>
159: * getSecurityConstraints
160: * </p>
161: *
162: * @see org.apache.jetspeed.om.common.SecureResource#getSecurityConstraints()
163: * @return the PSML security constraints
164: */
165: public SecurityConstraints getSecurityConstraints() {
166: return constraints;
167: }
168:
169: /**
170: * <p>
171: * newSecurityConstraints
172: * </p>
173: *
174: * @see org.apache.jetspeed.om.common.SecureResource#newSecurityConstraints()
175: * @return a new security constraints object
176: */
177: public SecurityConstraints newSecurityConstraints() {
178: return new SecurityConstraintsImpl();
179: }
180:
181: /**
182: * <p>
183: * newSecurityConstraint
184: * </p>
185: *
186: * @see org.apache.jetspeed.om.common.SecureResource#newSecurityConstraint()
187: * @return security constraint
188: */
189: public SecurityConstraint newSecurityConstraint() {
190: return new SecurityConstraintImpl();
191: }
192:
193: /**
194: * <p>
195: * setSecurityConstraints
196: * </p>
197: *
198: * @see org.apache.jetspeed.om.common.SecureResource#setSecurityConstraints(org.apache.jetspeed.om.common.SecurityConstraints)
199: * @param constraints
200: */
201: public void setSecurityConstraints(SecurityConstraints constraints) {
202: this .constraints = constraints;
203: }
204:
205: /**
206: * <p>
207: * checkConstraints
208: * </p>
209: *
210: * @see org.apache.jetspeed.om.common.SecureResource#checkConstraints(java.lang.String)
211: * @param actions
212: * @throws SecurityException
213: */
214: public void checkConstraints(String actions)
215: throws SecurityException {
216: // skip checks if not enabled
217: if (!getConstraintsEnabled()) {
218: return;
219: }
220:
221: // validate specified actions
222: if (actions == null) {
223: throw new SecurityException(
224: "AbstractBaseElement.checkConstraints(): No actions specified.");
225: }
226:
227: // get action names lists; separate view and other
228: // actions to mimic file system permissions logic
229: List viewActionList = SecurityConstraintImpl
230: .parseCSVList(actions);
231: List otherActionsList = null;
232: if (viewActionList.size() == 1) {
233: if (!viewActionList.contains(JetspeedActions.VIEW)) {
234: otherActionsList = viewActionList;
235: viewActionList = null;
236: }
237: } else {
238: otherActionsList = viewActionList;
239: viewActionList = null;
240: if (otherActionsList.remove(JetspeedActions.VIEW)) {
241: viewActionList = new ArrayList(1);
242: viewActionList.add(JetspeedActions.VIEW);
243: }
244: }
245:
246: // get current request context subject
247: Subject subject = JSSubject.getSubject(AccessController
248: .getContext());
249: if (subject == null) {
250: throw new SecurityException(
251: "AbstractBaseElement.checkConstraints(): Missing JSSubject");
252: }
253:
254: // get user/group/role principal names
255: List userPrincipals = null;
256: List rolePrincipals = null;
257: List groupPrincipals = null;
258: Iterator principals = subject.getPrincipals().iterator();
259: while (principals.hasNext()) {
260: Principal principal = (Principal) principals.next();
261: if (principal instanceof UserPrincipal) {
262: if (userPrincipals == null) {
263: userPrincipals = new LinkedList();
264: }
265: userPrincipals.add(principal.getName());
266: } else if (principal instanceof RolePrincipal) {
267: if (rolePrincipals == null) {
268: rolePrincipals = new LinkedList();
269: }
270: rolePrincipals.add(principal.getName());
271: } else if (principal instanceof GroupPrincipal) {
272: if (groupPrincipals == null) {
273: groupPrincipals = new LinkedList();
274: }
275: groupPrincipals.add(principal.getName());
276: }
277: }
278:
279: // check constraints using parsed action and access lists
280: if (viewActionList != null) {
281: checkConstraints(viewActionList, userPrincipals,
282: rolePrincipals, groupPrincipals, false,
283: grantViewActionAccess());
284: }
285: if (otherActionsList != null) {
286: checkConstraints(otherActionsList, userPrincipals,
287: rolePrincipals, groupPrincipals, true, false);
288: }
289: }
290:
291: /**
292: * <p>
293: * checkConstraints
294: * </p>
295: *
296: * @param actions
297: * @param userPrincipals
298: * @param rolePrincipals
299: * @param groupPrincipals
300: * @param checkNodeOnly
301: * @param checkParentsOnly
302: * @throws SecurityException
303: */
304: public void checkConstraints(List actions, List userPrincipals,
305: List rolePrincipals, List groupPrincipals,
306: boolean checkNodeOnly, boolean checkParentsOnly)
307: throws SecurityException {
308: // check node constraints if available
309: if ((constraints != null) && !constraints.isEmpty()) {
310: ((SecurityConstraintsImpl) constraints).checkConstraints(
311: actions, userPrincipals, rolePrincipals,
312: groupPrincipals, getEffectivePageSecurity());
313: }
314: }
315:
316: /**
317: * <p>
318: * getPermissionsEnabled
319: * </p>
320: *
321: * @see org.apache.jetspeed.om.common.SecureResource#getPermissionsEnabled()
322: * @return
323: */
324: public boolean getPermissionsEnabled() {
325: return permissionsEnabled;
326: }
327:
328: /**
329: * <p>
330: * setPermissionsEnabled
331: * </p>
332: *
333: * @param enabled indicator
334: */
335: public void setPermissionsEnabled(boolean enabled) {
336: permissionsEnabled = enabled;
337: }
338:
339: /**
340: * <p>
341: * checkPermissions
342: * </p>
343: *
344: * @see org.apache.jetspeed.om.common.SecuredResource#checkPermissions(int)
345: * @param mask Mask of actions requested
346: * @throws SecurityException
347: */
348: public void checkPermissions(int mask) throws SecurityException {
349: // skip checks if not enabled
350: if (!getPermissionsEnabled()) {
351: return;
352: }
353:
354: // separate view and other actions to mimic file system permissions logic
355: boolean viewAction = (mask & JetspeedActions.MASK_VIEW) == JetspeedActions.MASK_VIEW;
356: int otherMask = mask & ~JetspeedActions.MASK_VIEW;
357:
358: // check permissions using parsed actions
359: if (viewAction) {
360: checkPermissions(JetspeedActions.MASK_VIEW, false,
361: grantViewActionAccess());
362: }
363: if (otherMask != 0) {
364: checkPermissions(otherMask, true, false);
365: }
366: }
367:
368: /**
369: * <p>
370: * checkPermissions
371: * </p>
372: *
373: * @param mask of actions
374: * @param checkNodeOnly
375: * @param checkParentsOnly
376: * @throws SecurityException
377: */
378: public void checkPermissions(int mask, boolean checkNodeOnly,
379: boolean checkParentsOnly) throws SecurityException {
380: // check page and folder permissions
381: String physicalPermissionPath = getPhysicalPermissionPath();
382: if (physicalPermissionPath != null) {
383: // check permissions using physical path
384: try {
385: checkPermissions(physicalPermissionPath, mask,
386: checkNodeOnly, checkParentsOnly);
387: } catch (SecurityException physicalSE) {
388: // fallback check using logical path if available and different
389: String logicalPermissionPath = getLogicalPermissionPath();
390: if ((logicalPermissionPath != null)
391: && !logicalPermissionPath
392: .equals(physicalPermissionPath)) {
393: checkPermissions(logicalPermissionPath, mask,
394: checkNodeOnly, checkParentsOnly);
395: } else {
396: throw physicalSE;
397: }
398: }
399: }
400: }
401:
402: /**
403: * <p>
404: * checkPermissions
405: * </p>
406: *
407: * @param path
408: * @param mask Mask of actions requested
409: * @param checkNodeOnly
410: * @param checkParentsOnly
411: * @throws SecurityException
412: */
413: public void checkPermissions(String path, int mask,
414: boolean checkNodeOnly, boolean checkParentsOnly)
415: throws SecurityException {
416: // check actions permissions
417: try {
418: // check for granted page permissions
419: PagePermission permission = new PagePermission(path, mask);
420: AccessController.checkPermission(permission);
421: } catch (SecurityException se) {
422: // fallback check for granted folder permissions
423: FolderPermission permission = new FolderPermission(path,
424: mask);
425: AccessController.checkPermission(permission);
426: }
427: }
428:
429: /**
430: * <p>
431: * getLogicalPermissionPath
432: * </p>
433: *
434: * @return path used for permissions checks
435: */
436: public String getLogicalPermissionPath() {
437: return getPhysicalPermissionPath();
438: }
439:
440: /**
441: * <p>
442: * getPhysicalPermissionPath
443: * </p>
444: *
445: * @return path used for permissions checks
446: */
447: public String getPhysicalPermissionPath() {
448: // no permissions path available by default
449: log
450: .warn("getPhysicalPermissionPath(): no permission path available for "
451: + this + " element.");
452: return null;
453: }
454:
455: /**
456: * <p>
457: * checkAccess
458: * </p>
459: *
460: * @see org.apache.jetspeed.om.common.SecureResource#checkAccess(java.lang.String)
461: * @param actions
462: * @throws SecurityException
463: */
464: public void checkAccess(String actions) throws SecurityException {
465: // check access permissions and constraints as enabled
466: if (getPermissionsEnabled()) {
467: int mask = PortalResourcePermission.parseActions(actions);
468: checkPermissions(mask);
469: }
470: if (getConstraintsEnabled()) {
471: checkConstraints(actions);
472: }
473: }
474:
475: /**
476: * <p>
477: * grantViewActionAccess
478: * </p>
479: *
480: * @return granted access for view action
481: */
482: public boolean grantViewActionAccess() {
483: // by default, access must be checked
484: return false;
485: }
486:
487: /**
488: * getEffectivePageSecurity
489: *
490: * @return effective page security object
491: */
492: public PageSecurity getEffectivePageSecurity() {
493: // no page security available by default
494: return null;
495: }
496:
497: /**
498: * <p>
499: * getHandlerFactory
500: * </p>
501: *
502: * @return element handler factory
503: */
504: public DocumentHandlerFactory getHandlerFactory() {
505: return handlerFactory;
506: }
507:
508: /**
509: * <p>
510: * setHandlerFactory
511: * </p>
512: *
513: * @param factory element handler factory
514: */
515: public void setHandlerFactory(DocumentHandlerFactory factory) {
516: this .handlerFactory = factory;
517: }
518:
519: /**
520: * <p>
521: * equals
522: * </p>
523: *
524: * @see java.lang.Object#equals(java.lang.Object)
525: * @param obj
526: * @return whether the supplied object equals this one
527: */
528: public boolean equals(Object obj) {
529: if (obj instanceof BaseElement) {
530: AbstractBaseElement element = (AbstractBaseElement) obj;
531: return id != null && element.getId() != null
532: && id.equals(element.getId());
533: } else {
534: return false;
535: }
536: }
537:
538: /**
539: * <p>
540: * hashCode
541: * </p>
542: *
543: * @see java.lang.Object#hashCode()
544: * @return the hashcode for this object
545: */
546: public int hashCode() {
547: return ((null != id) ? id.hashCode() : -1);
548: }
549:
550: /**
551: * <p>
552: * toString
553: * </p>
554: *
555: * @see java.lang.Object#toString()
556: * @return the id as a string representation of this object
557: */
558: public String toString() {
559: return getId();
560: }
561:
562: /**
563: * <p>
564: * checkAccess returns a set of nodes we can access. It may be the passed in node set or a partial copy.
565: * </p>
566: *
567: * @param nodes
568: * @param actions
569: * @return a NodeSet containing the nodes allowing access
570: */
571: public static NodeSet checkAccess(NodeSet nodes, String actions) {
572: if ((nodes != null) && !nodes.isEmpty()) {
573: // check permissions and constraints, filter nodes as required
574: NodeSetImpl filteredNodes = null;
575: Iterator checkAccessIter = nodes.iterator();
576: while (checkAccessIter.hasNext()) {
577: AbstractBaseElement node = (AbstractBaseElement) checkAccessIter
578: .next();
579: try {
580: // check access
581: node.checkAccess(actions);
582:
583: // add to filteredNodes nodes if copying
584: if (filteredNodes != null) {
585: // permitted, add to filteredNodes nodes
586: filteredNodes.add((Node) node);
587: }
588: } catch (SecurityException se) {
589: // create filteredNodes nodes if not already copying
590: if (filteredNodes == null) {
591: // not permitted, copy previously permitted nodes
592: // to new filteredNodes node set with same comparator
593: filteredNodes = new NodeSetImpl(null,
594: ((NodeSetImpl) nodes).getComparator());
595: Iterator copyIter = nodes.iterator();
596: while (copyIter.hasNext()) {
597: Node copyNode = (Node) copyIter.next();
598: if (copyNode != node) {
599: filteredNodes.add(copyNode);
600: } else {
601: break;
602: }
603: }
604: }
605: }
606: }
607:
608: // return filteredNodes nodes if generated
609: if (filteredNodes != null) {
610: return filteredNodes;
611: }
612: }
613: return nodes;
614: }
615:
616: /**
617: * unmarshalled - notification that this instance has been
618: * loaded from the persistent store
619: */
620: public void unmarshalled() {
621: // by default, no action required
622: }
623:
624: /**
625: * marshalling - notification that this instance is to
626: * be saved to the persistent store
627: */
628: public void marshalling() {
629: // by default, no action required
630: }
631: }
|