taylor 2004/09/17 22:26:28 Modified: commons/src/java/org/apache/jetspeed/security FolderPermission.java Log: Enhanced the FolderPermission to support inherited permissions a la Java File Permission supporting pathnames ending in /- (recursive), /* all contents of the folder Patch provided by Christophe Lombard CVS: ---------------------------------------------------------------------- CVS: PR: CVS: If this change addresses a PR in the problem report tracking CVS: database, then enter the PR number(s) here. CVS: Obtained from: CVS: If this change has been taken from another system, such as NCSA, CVS: then name the system in this line, otherwise delete it. CVS: Submitted by: CVS: If this code has been contributed to Apache by someone else; i.e., CVS: they sent us a patch or a new module, then include their name/email CVS: address here. If this is your work then delete this line. CVS: Reviewed by: CVS: If we are doing pre-commit code reviews and someone else has CVS: reviewed your changes, include their name(s) here. CVS: If you have not had it reviewed then delete this line. Revision Changes Path 1.2 +262 -76 jakarta-jetspeed-2/commons/src/java/org/apache/jetspeed/security/FolderPermission.java Index: FolderPermission.java =================================================================== RCS file: /home/cvs/jakarta-jetspeed-2/commons/src/java/org/apache/jetspeed/security/FolderPermission.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- FolderPermission.java 3 Sep 2004 18:22:26 -0000 1.1 +++ FolderPermission.java 18 Sep 2004 05:26:28 -0000 1.2 @@ -14,93 +14,279 @@ */ package org.apache.jetspeed.security; -import java.security.AccessControlContext; -import java.security.AccessController; import java.security.Permission; import java.security.PermissionCollection; +import java.util.StringTokenizer; import javax.security.auth.Subject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jetspeed.JetspeedActions; +import org.apache.jetspeed.security.PortalResourcePermission; +import org.apache.jetspeed.security.PortalResourcePermissionCollection; + /** * <p>Folder permission.</p> - * <p>This code was partially inspired from articles from:</p> + * <p>This code was partially inspired from:</p> * <ul> - * <li><a href="http://www-106.ibm.com/developerworks/library/j-jaas/"> + * <li>The article : <a href="http://www-106.ibm.com/developerworks/library/j-jaas/"> * Extend JAAS for class instance-level authorization.</a></li> + * <li>The FilePermission implementation from the JDK in order to support recursive permissions & wild card</li> * </ul> + * + * This class represents access to a portal content/folder or document. A FolderPermission consists + * of a pathname and a set of actions valid for that pathname. + * <P> + * Pathname is the pathname of the folder or document granted the specified + * actions. A pathname that ends in "/*" (where "/" is + * the separator character) indicates all the folders and documents contained in that folder. + * A pathname that ends with "/-" indicates (recursively) all documents + * and subfolders contained in that directory. A pathname consisting of + * the special token "<<ALL FILES>>" matches <b>any</b> folder or document. + * <P> + * * @author <a href="mailto:[EMAIL PROTECTED]">David Sean Taylor</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Christophe Lombart</a> + * @version $Id$ */ public class FolderPermission extends PortalResourcePermission -{ - /** - * <p>Constructor for FolderPermission.</p> - * @param name The portlet name. - * @param actions The actions on the portlet. - */ - public FolderPermission(String name, String actions) - { - this(name, actions, null); - } - - /** - * <p>Constructor for FolderPermission.</p> - * @param name The portlet name. - * @param actions The actions on the portlet. - */ - public FolderPermission(String name, String actions, Subject subject) - { - super(name, actions, subject); - } - - public boolean implies(Permission permission) - { - // The permission must be an instance - // of the PortletPermission. - if (!(permission instanceof FolderPermission)) - { - return false; - } - - // The portlet name must be the same. - if (!(permission.getName().equals(getName()))) - { - return false; - } - - FolderPermission folderPerm = (FolderPermission) permission; - - // Get the subject. - // It was either provide in the constructor. - Subject user = folderPerm.getSubject(); - // Or we get it from the AccessControlContext. - if (null == user) - { - AccessControlContext context = AccessController.getContext(); - user = Subject.getSubject(context); - } - // No user was passed. The permission must be denied. - if (null == user) - { - return false; - } - - // The action bits in FolderPerm (permission) - // must be set in the current mask permission. - if ((mask & folderPerm.mask) != folderPerm.mask) - { - return false; - } - - return true; - } - - /** - * <p>Overrides <code>Permission.newPermissionCollection()</code>.</p> - * @see java.security.Permission#newPermissionCollection() - */ - public PermissionCollection newPermissionCollection() - { - return new PortalResourcePermissionCollection(); - } +{ + + private final static Log log = LogFactory.getLog(FolderPermission.class); + + // does path indicate a folder? (wildcard or recursive) + private transient boolean folder; + + // is it a recursive directory specification? + private transient boolean recursive; + + private static final char RECURSIVE_CHAR = '-'; + private static final char WILD_CHAR = '*'; + private static final char FOLDER_SEPARATOR = '/'; + + private transient String cpath; + + /** + * <p>Constructor for FolderPermission.</p> + * @param name The portlet name. + * @param actions The actions on the portlet. + */ + public FolderPermission(String name, String actions) + { + this(name, actions, null); + } + + /** + * <p>Constructor for FolderPermission.</p> + * @param name The portlet name. + * @param actions The actions on the portlet. + */ + public FolderPermission(String name, String actions, Subject subject) + { + super(name, actions, subject); + parseActions(actions); + this.subject = subject; + } + + + /** + * <p>Overrides <code>Permission.newPermissionCollection()</code>.</p> + * @see java.security.Permission#newPermissionCollection() + */ + public PermissionCollection newPermissionCollection() + { + return new PortalResourcePermissionCollection(); + } + + /** + * <p>Parses the actions string.</p> + * <p>Actions are separated by commas or white space.</p> + * @param actions The actions + */ + private void parseActions(String actions) + { + mask = 0; + if (actions != null) + { + StringTokenizer tokenizer = new StringTokenizer(actions, ",\t "); + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken(); + if (token.equals(JetspeedActions.VIEW)) + mask |= JetspeedActions.MASK_VIEW; + else if (token.equals(JetspeedActions.VIEW) || token.equals(JetspeedActions.RESTORE)) + mask |= JetspeedActions.MASK_VIEW; + else if (token.equals(JetspeedActions.EDIT)) + mask |= JetspeedActions.MASK_EDIT; + else if (token.equals(JetspeedActions.MINIMIZE)) + mask |= JetspeedActions.MASK_MINIMIZE; + else if (token.equals(JetspeedActions.MAXIMIZE)) + mask |= JetspeedActions.MASK_MAXIMIZE; + else if (token.equals(JetspeedActions.HELP)) + mask |= JetspeedActions.MASK_HELP; + else if (token.equals(JetspeedActions.SECURE)) + mask |= JetspeedActions.MASK_SECURE; + else + throw new IllegalArgumentException("Unknown action: " + token); + } + } + + if ((cpath = getName()) == null) + throw new NullPointerException("name can't be null"); + + if (cpath.equals("<<ALL FILES>>")) + { + folder = true; + recursive = true; + cpath = ""; + return; + } + int len = cpath.length(); + + if (len == 0) + { + throw new IllegalArgumentException("invalid folder reference"); + } + + char last = cpath.charAt(len - 1); + + if (last == RECURSIVE_CHAR && (len == 1 || cpath.charAt(len - 2) == FOLDER_SEPARATOR)) + { + folder = true; + recursive = true; + cpath = cpath.substring(0, --len); + } + else if (last == WILD_CHAR && (len == 1 || cpath.charAt(len - 2) == FOLDER_SEPARATOR)) + { + folder = true; + //recursive = false; + cpath = cpath.substring(0, --len); + } + + } + + /** + * Checks if this FolderPermission object "implies" the specified permission. + * <P> + * More specifically, this method returns true if:<p> + * <ul> + * <li> <i>p</i> is an instanceof FolderPermission,<p> + * <li> <i>p</i>'s actions are a proper subset of this + * object's actions, and <p> + * <li> <i>p</i>'s pathname is implied by this object's + * pathname. For example, "/tmp/*" implies "/tmp/foo", since + * "/tmp/*" encompasses the "/tmp" folder and all subfolders or documents in that + * directory, including the one named "foo". + * </ul> + * @param p the permission to check against. + * + * @return true if the specified permission is implied by this object, + * false if not. + */ + public boolean implies(Permission p) + { + if (!(p instanceof FolderPermission)) + { + return false; + } + + FolderPermission that = (FolderPermission) p; + return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that); + } + + /** + * Checks if the Permission's actions are a proper subset of the + * this object's actions. Returns the effective mask iff the + * this FolderPermission's path also implies that FolderPermission's path. + * + * @param that the FolderPermission to check against. + * @return the effective mask + */ + boolean impliesIgnoreMask(FolderPermission that) + { + if (this.folder) + { + if (this.recursive) + { + // make sure that.path is longer then path so + // something like /foo/- does not imply /foo + if (that.folder) + { + return (that.cpath.length() >= this.cpath.length()) && that.cpath.startsWith(this.cpath); + } + else + { + return ((that.cpath.length() > this.cpath.length()) && that.cpath.startsWith(this.cpath)); + } + } + else + { + if (that.folder) + { + // if the permission passed in is a folder + // specification, make sure that a non-recursive + // permission (i.e., this object) can't imply a recursive + // permission. + if (that.recursive) + return false; + else + return (this.cpath.equals(that.cpath)); + } + else + { + int last = that.cpath.lastIndexOf(FOLDER_SEPARATOR); + if (last == -1) + return false; + else + { + // this.cpath.equals(that.cpath.substring(0, last+1)); + // Use regionMatches to avoid creating new string + + return (this.cpath.length() == (last + 1)) && this.cpath.regionMatches(0, that.cpath, 0, last + 1); + } + } + } + } + else + { + return (this.cpath.equals(that.cpath)); + } + } + + /** + * Checks two FolderPermission objects for equality. Checks that <i>obj</i> is + * a FolderPermission, and has the same pathname and actions as this object. + * <P> + * @param obj the object we are testing for equality with this object. + * @return true if obj is a FolderPermission, and has the same pathname and + * actions as this FolderPermission object. + */ + public boolean equals(Object obj) + { + if (obj == this) + return true; + + if (!(obj instanceof FolderPermission)) + return false; + + FolderPermission that = (FolderPermission) obj; + + return (this.mask == that.mask) && this.cpath.equals(that.cpath) && (this.folder == that.folder) + && (this.recursive == that.recursive); + } + + /** + * Returns the hash code value for this object. + * + * @return a hash code value for this object. + */ + + public int hashCode() + { + return this.cpath.hashCode(); + } + + -} +} \ No newline at end of file
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]