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]