Skip to content
Browse files

More robust VirtualFilePermission; also add testing and permission ch…

…ecks at VirtualFile call sites
  • Loading branch information...
1 parent e6adb44 commit 871b86c06cd1437dd5d5cf2575bcd15cc887bf29 @dmlloyd dmlloyd committed Mar 7, 2013
View
26 pom.xml
@@ -55,6 +55,9 @@
<version.jboss.logging>3.1.3.GA</version.jboss.logging>
<version.jboss.test>1.1.5.GA</version.jboss.test>
<version.junit>4.4</version.junit>
+ <skip.enforcer>false</skip.enforcer>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <maven.compiler.source>1.7</maven.compiler.source>
</properties>
<build>
@@ -71,6 +74,29 @@
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
+ <plugin>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.0.1</version>
+ <executions>
+ <execution>
+ <!-- Enforce Java 7 version -->
+ <id>enforce-java-7-version</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <skip>${skip.enforcer}</skip>
+ <rules>
+ <requireJavaVersion>
+ <!-- version >= 1.7 -->
+ <version>[1.7,)</version>
+ <message>Java 7 or higher required to build this project</message>
+ </requireJavaVersion>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
<pluginManagement>
View
73 src/main/java/org/jboss/vfs/VFSUtils.java
@@ -956,4 +956,77 @@ public static Pattern getGlobPattern(final String glob) {
patternBuilder.append("$");
return Pattern.compile(patternBuilder.toString());
}
+
+ /**
+ * Canonicalize the given path. Removes all {@code .} and {@code ..} segments from the path.
+ *
+ * @param path the relative or absolute possibly non-canonical path
+ * @return the canonical path
+ */
+ @SuppressWarnings("UnusedLabel") // for documentation
+ public static String canonicalize(final String path) {
+ final int length = path.length();
+ // 0 - start
+ // 1 - got one .
+ // 2 - got two .
+ // 3 - got /
+ int state = 0;
+ if (length == 0) {
+ return path;
+ }
+ final char[] targetBuf = new char[length];
+ // string segment end exclusive
+ int e = length;
+ // string cursor position
+ int i = length;
+ // buffer cursor position
+ int a = length - 1;
+ // number of segments to skip
+ int skip = 0;
+ loop: while (--i >= 0) {
+ char c = path.charAt(i);
+ outer: switch (c) {
+ case '/': {
+ inner: switch (state) {
+ case 0: state = 3; e = i; break outer;
+ case 1: state = 3; e = i; break outer;
+ case 2: state = 3; e = i; skip ++; break outer;
+ case 3: e = i; break outer;
+ default: throw new IllegalStateException();
+ }
+ // not reached!
+ }
+ case '.': {
+ inner: switch (state) {
+ case 0: state = 1; break outer;
+ case 1: state = 2; break outer;
+ case 2: break inner; // emit!
+ case 3: state = 1; break outer;
+ default: throw new IllegalStateException();
+ }
+ // fall thru
+ }
+ default: {
+ final int newE = e > 0 ? path.lastIndexOf('/', e - 1) : -1;
+ final int segmentLength = e - newE - 1;
+ if (skip > 0) {
+ skip--;
+ } else {
+ if (state == 3) {
+ targetBuf[a--] = '/';
+ }
+ path.getChars(newE + 1, e, targetBuf, (a -= segmentLength) + 1);
+ }
+ state = 0;
+ i = newE + 1;
+ e = newE;
+ break;
+ }
+ }
+ }
+ if (state == 3) {
+ targetBuf[a--] = '/';
+ }
+ return new String(targetBuf, a + 1, length - a - 1);
+ }
}
View
43 src/main/java/org/jboss/vfs/VirtualFile.java
@@ -156,6 +156,10 @@ String getPathName(boolean url) {
* @return the last modified time
*/
public long getLastModified() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().getLastModified(mount.getMountPoint(), this);
}
@@ -166,6 +170,10 @@ public long getLastModified() {
* @return the size
*/
public long getSize() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().getSize(mount.getMountPoint(), this);
}
@@ -176,6 +184,10 @@ public long getSize() {
* @return true if the file exists, false otherwise.
*/
public boolean exists() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().exists(mount.getMountPoint(), this);
}
@@ -209,6 +221,10 @@ public boolean isLeaf() {
* @return {@code true} if it is a plain file, {@code false} otherwise
*/
public boolean isFile() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().isFile(mount.getMountPoint(), this);
}
@@ -219,6 +235,10 @@ public boolean isFile() {
* @return {@code true} if it is a directory, {@code false} otherwise
*/
public boolean isDirectory() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().isDirectory(mount.getMountPoint(), this);
}
@@ -231,6 +251,10 @@ public boolean isDirectory() {
* @throws IOException for any error accessing the file system
*/
public InputStream openStream() throws IOException {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
if(isDirectory()) {
return new VirtualJarInputStream(this);
}
@@ -244,21 +268,29 @@ public InputStream openStream() throws IOException {
* @return {@code true} if file was deleted
*/
public boolean delete() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "delete"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().delete(mount.getMountPoint(), this);
}
/**
* Get a physical file for this virtual file. Depending on the underlying file system type, this may simply return
* an already-existing file; it may create a copy of a file; or it may reuse a preexisting copy of the file.
- * Furthermore, the retured file may or may not have any relationship to other files from the same or any other
+ * Furthermore, the returned file may or may not have any relationship to other files from the same or any other
* virtual directory.
*
* @return the physical file
*
* @throws IOException if an I/O error occurs while producing the physical file
*/
public File getPhysicalFile() throws IOException {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "getfile"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().getFile(mount.getMountPoint(), this);
}
@@ -310,6 +342,7 @@ public VirtualFile getParent() {
* @return the children
*/
public List<VirtualFile> getChildren() {
+ // isDirectory does the read security check
if (!isDirectory())
return Collections.emptyList();
final VFS.Mount mount = VFS.getMount(this);
@@ -339,6 +372,7 @@ public VirtualFile getParent() {
* @throws IllegalStateException if the file is closed or it is a leaf node
*/
public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException {
+ // isDirectory does the read security check
if (!isDirectory())
return Collections.emptyList();
if (filter == null)
@@ -375,6 +409,7 @@ public VirtualFile getParent() {
* @throws IllegalStateException if the file is closed or it is a leaf node
*/
public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException {
+ // isDirectory does the read security check
if (!isDirectory())
return Collections.emptyList();
if (filter == null)
@@ -401,6 +436,7 @@ private void visit(VirtualFileVisitor visitor, boolean root) throws IOException
final VisitorAttributes visitorAttributes = visitor.getAttributes();
if (root && visitorAttributes.isIncludeRoot())
visitor.visit(this);
+ // isDirectory does the read security check
if (!isDirectory())
return;
for (VirtualFile child : getChildren()) {
@@ -523,6 +559,10 @@ public URI asFileURI() throws URISyntaxException {
* @return the {@link CodeSigner}s for the virtual file, or {@code null} if not signed
*/
public CodeSigner[] getCodeSigners() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new VirtualFilePermission(getPathName(), "read"));
+ }
final VFS.Mount mount = VFS.getMount(this);
return mount.getFileSystem().getCodeSigners(mount.getMountPoint(), this);
}
@@ -534,6 +574,7 @@ public URI asFileURI() throws URISyntaxException {
* @return the certificates for the virtual file, or {@code null} if not signed
*/
public Certificate[] getCertificates() {
+ // getCodeSigners() does the sec check
final CodeSigner[] codeSigners = getCodeSigners();
if (codeSigners == null) {
return null;
View
195 src/main/java/org/jboss/vfs/VirtualFilePermission.java
@@ -22,6 +22,7 @@
package org.jboss.vfs;
+import java.io.File;
import java.io.FilePermission;
import java.io.Serializable;
import java.security.Permission;
@@ -34,8 +35,37 @@
*
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
*/
-public final class VirtualFilePermission extends Permission {
- private final FilePermission filePermission;
+public final class VirtualFilePermission extends Permission implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @serial the action flags (must be within {@link #VALID_FLAGS})
+ */
+ private final int actionFlags;
+
+ /**
+ * The flag value for the "read" action.
+ */
+ public static final int FLAG_READ = 0b0000_0000_0000_0001;
+ /**
+ * The flag value for the "delete" action.
+ */
+ public static final int FLAG_DELETE = 0b0000_0000_0000_0010;
+ /**
+ * The flag value for the "getfile" action.
+ */
+ public static final int FLAG_GET_FILE = 0b0000_0000_0000_0100;
+
+ /**
+ * The set of valid action flags for this permission.
+ */
+ public static final int VALID_FLAGS = 0b0000_0000_0000_0111;
+
+ VirtualFilePermission(final String path, final int actionFlags, final boolean canonicalize) {
+ super(canonicalize ? VFSUtils.canonicalize(path) : path);
+ this.actionFlags = actionFlags & VALID_FLAGS;
+ }
/**
* Construct a new instance.
@@ -44,64 +74,163 @@
* @param actions the actions to grant
*/
public VirtualFilePermission(final String path, final String actions) {
- super(path);
- filePermission = new FilePermission(path, actions);
+ this(path, parseActions(actions), true);
+ }
+
+ /**
+ * Construct a new instance. Any flags outside of {@link #VALID_FLAGS} are ignored.
+ *
+ * @param path the path
+ * @param actionFlags the action flags to set
+ */
+ public VirtualFilePermission(final String path, final int actionFlags) {
+ this(path, actionFlags, true);
+ }
+
+ private static boolean in(char c, char t1, char t2) {
+ return c == t1 || c == t2;
+ }
+
+ private static boolean lenIs(String s, int idx, int len, int wlen) {
+ return idx == len - wlen || idx < len - wlen && s.charAt(idx + wlen) == ',';
+ }
+
+ static int parseActions(String actions) {
+ final int len = actions.length();
+ int res = 0;
+ for (int i = 0; i < len; i ++) {
+ if (lenIs(actions, i, len, 4)
+ && in(actions.charAt(i ), 'r', 'R')
+ && in(actions.charAt(i + 1), 'e', 'E')
+ && in(actions.charAt(i + 2), 'a', 'A')
+ && in(actions.charAt(i + 3), 'd', 'D')) {
+ res |= FLAG_READ;
+ i += 4;
+ } else if (lenIs(actions, i, len, 6)
+ && in(actions.charAt(i ), 'd', 'D')
+ && in(actions.charAt(i + 1), 'e', 'E')
+ && in(actions.charAt(i + 2), 'l', 'L')
+ && in(actions.charAt(i + 3), 'e', 'E')
+ && in(actions.charAt(i + 4), 't', 'T')
+ && in(actions.charAt(i + 5), 'e', 'E')) {
+ res |= FLAG_DELETE;
+ i += 6;
+ } else if (lenIs(actions, i, len, 7)
+ && in(actions.charAt(i ), 'g', 'G')
+ && in(actions.charAt(i + 1), 'e', 'E')
+ && in(actions.charAt(i + 2), 't', 'T')
+ && in(actions.charAt(i + 3), 'f', 'F')
+ && in(actions.charAt(i + 4), 'i', 'I')
+ && in(actions.charAt(i + 5), 'l', 'L')
+ && in(actions.charAt(i + 6), 'e', 'E')) {
+ res |= FLAG_GET_FILE;
+ i += 7;
+ } else if (lenIs(actions, i, len, 1) && actions.charAt(i) == '*'){
+ res |= FLAG_READ | FLAG_DELETE | FLAG_GET_FILE;
+ } else {
+ throw new IllegalArgumentException("Invalid actions string");
+ }
+ }
+ return res;
}
public boolean implies(final Permission permission) {
return permission instanceof VirtualFilePermission && implies((VirtualFilePermission) permission);
}
public boolean implies(final VirtualFilePermission permission) {
- return permission != null && filePermission.implies(permission.filePermission);
+ return permission != null && impliesUnchecked(permission);
}
- public boolean equals(final Object permission) {
- return permission instanceof VirtualFilePermission && equals((VirtualFilePermission) permission);
+ private boolean impliesUnchecked(final VirtualFilePermission permission) {
+ final int theirFlags = permission.actionFlags;
+ return (actionFlags & theirFlags) == theirFlags && impliesPath(getName(), permission.getName());
}
- public boolean equals(final Permission permission) {
- return permission instanceof VirtualFilePermission && equals((VirtualFilePermission) permission);
+ private static int ourIndexOf(String str, char ch, int start) {
+ final int idx = str.indexOf(ch, start);
+ return idx == -1 ? str.length() : idx;
}
- public boolean equals(final VirtualFilePermission permission) {
- return permission != null && filePermission.equals(permission.filePermission);
+ static boolean impliesPath(String ourName, String theirName) {
+ if ("<<ALL FILES>>".equals(ourName)) {
+ return true;
+ }
+ return impliesPath(ourName, theirName, 0);
}
- public int hashCode() {
- return filePermission.hashCode();
+ private static boolean impliesPath(String ourName, String theirName, int idx) {
+ final int ourLen = ourName.length();
+ final int theirLen = theirName.length();
+ final int ei1 = ourIndexOf(ourName, File.separatorChar, idx);
+ final int ei2 = ourIndexOf(theirName, File.separatorChar, idx);
+ if (ei1 == idx + 1) {
+ final char ch = ourName.charAt(idx);
+ if (ch == '-') {
+ // recursive wildcard...
+ // if they are non-empty, match
+ return theirLen > idx; // otherwise their segment is empty (no match)
+ } else if (ch == '*') {
+ // non-recursive wildcard...
+ // if they are non-empty, and this is their last segment, match, unless they are '-'
+ return theirLen > idx && ei2 == theirLen && (ei2 != ei1 || theirName.charAt(idx) != '-');
+ }
+ }
+ if (ei1 == ei2) {
+ if (ei1 == ourLen && ei2 == theirLen) {
+ // exact match
+ return true;
+ } else {
+ // leading sequence matches, check next segment
+ return impliesPath(ourName, theirName, ei1 + 1);
+ }
+ } else {
+ return false;
+ }
}
public String getActions() {
- return filePermission.getActions();
+ final StringBuilder builder = new StringBuilder();
+ if ((actionFlags & FLAG_READ) != 0) {
+ builder.append("read");
+ }
+ if ((actionFlags & FLAG_DELETE) != 0) {
+ if (builder.length() > 0) builder.append(',');
+ builder.append("delete");
+ }
+ if ((actionFlags & FLAG_GET_FILE) != 0) {
+ if (builder.length() > 0) builder.append(',');
+ builder.append("getfile");
+ }
+ return builder.toString();
}
- public PermissionCollection newPermissionCollection() {
- return new VirtualFilePermissionCollection(filePermission.newPermissionCollection());
+ /**
+ * Get the action flags for this permission.
+ *
+ * @return the action flags for this permission
+ */
+ public int getActionFlags() {
+ return actionFlags;
}
- FilePermission getFilePermission() {
- return filePermission;
+ public PermissionCollection newPermissionCollection() {
+ return new VirtualFilePermissionCollection();
}
- Object writeReplace() {
- return new Serialized(getName(), getActions());
+ public boolean equals(final Object permission) {
+ return permission instanceof VirtualFilePermission && equals((VirtualFilePermission) permission);
}
- public static final class Serialized implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- final String path;
- final String actions;
+ public boolean equals(final Permission permission) {
+ return permission instanceof VirtualFilePermission && equals((VirtualFilePermission) permission);
+ }
- public Serialized(final String path, final String actions) {
- this.path = path;
- this.actions = actions;
- }
+ public boolean equals(final VirtualFilePermission permission) {
+ return permission != null && permission.actionFlags == actionFlags && permission.getName().equals(permission.getName());
+ }
- Object readResolve() {
- return new VirtualFilePermission(path, actions);
- }
+ public int hashCode() {
+ return getName().hashCode() * 11 + actionFlags;
}
}
View
102 src/main/java/org/jboss/vfs/VirtualFilePermissionCollection.java
@@ -22,42 +22,61 @@
package org.jboss.vfs;
-import java.io.FilePermission;
-import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamField;
+import java.lang.reflect.Field;
+import java.security.AccessController;
import java.security.Permission;
import java.security.PermissionCollection;
-import java.util.ArrayList;
+import java.security.PrivilegedAction;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Enumeration;
final class VirtualFilePermissionCollection extends PermissionCollection {
- private final PermissionCollection collection;
- private final ArrayList<Permission> list;
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("list", VirtualFilePermission[].class)
+ };
- VirtualFilePermissionCollection(final PermissionCollection collection) {
- this.collection = collection;
- list = new ArrayList<Permission>();
+ private static final VirtualFilePermission[] NO_PERMISSIONS = new VirtualFilePermission[0];
+
+ private volatile VirtualFilePermission[] permissions = NO_PERMISSIONS;
+
+ private static final Field listField;
+
+ static {
+ listField = AccessController.doPrivileged(new PrivilegedAction<Field>() {
+ public Field run() {
+ final Field field;
+ try {
+ field = VirtualFilePermissionCollection.class.getDeclaredField("permissions");
+ } catch (NoSuchFieldException e) {
+ throw new NoSuchFieldError(e.getMessage());
+ }
+ field.setAccessible(true);
+ return field;
+ }
+ });
}
- VirtualFilePermissionCollection(final PermissionCollection collection, final ArrayList<Permission> list) {
- this.collection = collection;
- this.list = list;
+ VirtualFilePermissionCollection() {
}
public void add(final Permission permission) {
if (permission instanceof VirtualFilePermission) {
- final VirtualFilePermission virtualFilePermission = (VirtualFilePermission) permission;
- add(virtualFilePermission);
+ add((VirtualFilePermission) permission);
} else {
throw new IllegalArgumentException();
}
}
- public void add(final VirtualFilePermission permission) {
+ public synchronized void add(final VirtualFilePermission permission) {
if (permission != null) {
- collection.add(permission.getFilePermission());
- list.add(permission);
+ final VirtualFilePermission[] permissions = this.permissions;
+ final int length = permissions.length;
+ final VirtualFilePermission[] newPermissions = Arrays.copyOf(permissions, length + 1);
+ newPermissions[length] = permission;
+ this.permissions = newPermissions;
} else {
throw new IllegalArgumentException();
}
@@ -67,29 +86,44 @@ public boolean implies(final Permission permission) {
return permission instanceof VirtualFilePermission && implies((VirtualFilePermission) permission);
}
- public boolean implies(final VirtualFilePermission permission) {
- return permission != null && collection.implies(permission.getFilePermission());
+ private boolean implies(final VirtualFilePermission permission) {
+ assert permission != null; // else the above check would have failed
+ int remainingFlags = permission.getActionFlags();
+ if (remainingFlags == 0) return true;
+ // snapshot
+ final VirtualFilePermission[] permissions = this.permissions;
+ final String theirName = permission.getName();
+ for (VirtualFilePermission ourPermission : permissions) {
+ if (VirtualFilePermission.impliesPath(ourPermission.getName(), theirName)) {
+ remainingFlags &= ~ourPermission.getActionFlags();
+ if (remainingFlags == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
}
+ @SuppressWarnings("unchecked")
public Enumeration<Permission> elements() {
- return Collections.enumeration(list);
- }
+ final VirtualFilePermission[] permissions = this.permissions;
+ return new Enumeration<Permission>() {
+ private int idx = 0;
+ public boolean hasMoreElements() {
+ return idx < permissions.length;
+ }
- Object writeReplace() {
- return new Serialized(list.toArray(new VirtualFilePermission[list.size()]));
+ public Permission nextElement() {
+ return permissions[idx++];
+ }
+ };
}
- static final class Serialized implements Serializable {
- private static final long serialVersionUID = 1L;
-
- final VirtualFilePermission[] permissions;
-
- Serialized(final VirtualFilePermission[] permissions) {
- this.permissions = permissions;
- }
-
- Object readResolve() {
- return new VirtualFilePermissionCollection(new FilePermission("/", "*").newPermissionCollection(), new ArrayList<Permission>(Arrays.asList(permissions)));
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ try {
+ listField.set(this, ois.readFields().get("list", null));
+ } catch (IllegalAccessException e) {
+ throw new IllegalAccessError(e.getMessage());
}
}
}
View
125 src/test/java/org/jboss/test/vfs/VirtualFilePermissionTestCase.java
@@ -0,0 +1,125 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2013, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.test.vfs;
+
+import java.security.PermissionCollection;
+import junit.framework.TestCase;
+import org.jboss.vfs.VirtualFilePermission;
+
+import static org.jboss.vfs.VirtualFilePermission.FLAG_DELETE;
+import static org.jboss.vfs.VirtualFilePermission.FLAG_GET_FILE;
+import static org.jboss.vfs.VirtualFilePermission.FLAG_READ;
+
+public final class VirtualFilePermissionTestCase extends TestCase {
+
+ public void testFlagParsing() {
+ assertEquals(new VirtualFilePermission("foo", "read").getActionFlags(), FLAG_READ);
+ assertEquals(new VirtualFilePermission("foo", "delete").getActionFlags(), FLAG_DELETE);
+ assertEquals(new VirtualFilePermission("foo", "getfile").getActionFlags(), FLAG_GET_FILE);
+ assertEquals(new VirtualFilePermission("foo", "read,delete").getActionFlags(), FLAG_READ | FLAG_DELETE);
+ assertEquals(new VirtualFilePermission("foo", "read,getfile").getActionFlags(), FLAG_READ | FLAG_GET_FILE);
+ assertEquals(new VirtualFilePermission("foo", "delete,getfile").getActionFlags(), FLAG_DELETE | FLAG_GET_FILE);
+ assertEquals(new VirtualFilePermission("foo", "delete,getfile,read").getActionFlags(), FLAG_DELETE | FLAG_GET_FILE | FLAG_READ);
+ assertEquals(new VirtualFilePermission("foo", "*").getActionFlags(), FLAG_DELETE | FLAG_GET_FILE | FLAG_READ);
+ assertEquals(new VirtualFilePermission("foo", "").getActionFlags(), 0);
+ try {
+ new VirtualFilePermission("foo", "blah");
+ fail("expected exception");
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void testPathCanonicalization() {
+ assertEquals(new VirtualFilePermission("/simple/test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/simple//test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("//simple//test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/./simple//test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/simple/./test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/simple/not/../test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/simple/not/./../test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("/simple/not/.././test", 0).getName(), "/simple/test");
+ assertEquals(new VirtualFilePermission("simple/not/.././test", 0).getName(), "simple/test");
+ assertEquals(new VirtualFilePermission("/../../..", 0).getName(), "/");
+ assertEquals(new VirtualFilePermission("/././.", 0).getName(), "/");
+ assertEquals(new VirtualFilePermission("/..", 0).getName(), "/");
+ assertEquals(new VirtualFilePermission("/.", 0).getName(), "/");
+ assertEquals(new VirtualFilePermission("../../..", 0).getName(), "");
+ assertEquals(new VirtualFilePermission("..", 0).getName(), "");
+ assertEquals(new VirtualFilePermission(".", 0).getName(), "");
+ }
+
+ public void testImpliesSimple() {
+ assertTrue(new VirtualFilePermission("foo", "read").implies(new VirtualFilePermission("foo", FLAG_READ)));
+ assertTrue(new VirtualFilePermission("foo", "delete").implies(new VirtualFilePermission("foo", FLAG_DELETE)));
+ assertTrue(new VirtualFilePermission("foo", "getfile").implies(new VirtualFilePermission("foo", FLAG_GET_FILE)));
+ assertTrue(new VirtualFilePermission("foo", "read,delete").implies(new VirtualFilePermission("foo", FLAG_READ | FLAG_DELETE)));
+ assertTrue(new VirtualFilePermission("foo", "read,getfile").implies(new VirtualFilePermission("foo", FLAG_READ | FLAG_GET_FILE)));
+ assertTrue(new VirtualFilePermission("foo", "delete,getfile").implies(new VirtualFilePermission("foo", FLAG_DELETE | FLAG_GET_FILE)));
+ assertTrue(new VirtualFilePermission("foo", "delete,getfile,read").implies(new VirtualFilePermission("foo", FLAG_DELETE | FLAG_GET_FILE | FLAG_READ)));
+ assertTrue(new VirtualFilePermission("foo", "*").implies(new VirtualFilePermission("foo", FLAG_DELETE | FLAG_GET_FILE | FLAG_READ)));
+ assertTrue(new VirtualFilePermission("foo", "").implies(new VirtualFilePermission("foo", 0)));
+ }
+
+ public void testImpliesMatch() {
+ assertTrue(new VirtualFilePermission("/foo/bar/*", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/baz", "read")));
+ assertTrue(new VirtualFilePermission("/foo/bar/*", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/*", "read")));
+ assertFalse(new VirtualFilePermission("/foo/bar/*", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/-", "read")));
+ assertFalse(new VirtualFilePermission("/foo/bar/*", FLAG_READ).implies(new VirtualFilePermission("/foo/bar", "read")));
+ assertTrue(new VirtualFilePermission("/foo/bar/-", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/baz", "read")));
+ assertTrue(new VirtualFilePermission("/foo/bar/-", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/*", "read")));
+ assertTrue(new VirtualFilePermission("/foo/bar/-", FLAG_READ).implies(new VirtualFilePermission("/foo/bar/-", "read")));
+ assertFalse(new VirtualFilePermission("/foo/bar/-", FLAG_READ).implies(new VirtualFilePermission("/foo/bar", "read")));
+
+ assertTrue(new VirtualFilePermission("/*", FLAG_READ).implies(new VirtualFilePermission("/baz", "read")));
+ assertTrue(new VirtualFilePermission("/*", FLAG_READ).implies(new VirtualFilePermission("/*", "read")));
+ assertFalse(new VirtualFilePermission("/*", FLAG_READ).implies(new VirtualFilePermission("/-", "read")));
+ assertFalse(new VirtualFilePermission("/*", FLAG_READ).implies(new VirtualFilePermission("", "read")));
+ assertTrue(new VirtualFilePermission("/-", FLAG_READ).implies(new VirtualFilePermission("/baz", "read")));
+ assertTrue(new VirtualFilePermission("/-", FLAG_READ).implies(new VirtualFilePermission("/*", "read")));
+ assertTrue(new VirtualFilePermission("/-", FLAG_READ).implies(new VirtualFilePermission("/-", "read")));
+ assertFalse(new VirtualFilePermission("/-", FLAG_READ).implies(new VirtualFilePermission("", "read")));
+
+ assertTrue(new VirtualFilePermission("*", FLAG_READ).implies(new VirtualFilePermission("baz", "read")));
+ assertTrue(new VirtualFilePermission("*", FLAG_READ).implies(new VirtualFilePermission("*", "read")));
+ assertFalse(new VirtualFilePermission("*", FLAG_READ).implies(new VirtualFilePermission("-", "read")));
+ assertFalse(new VirtualFilePermission("*", FLAG_READ).implies(new VirtualFilePermission("", "read")));
+ assertTrue(new VirtualFilePermission("-", FLAG_READ).implies(new VirtualFilePermission("baz", "read")));
+ assertTrue(new VirtualFilePermission("-", FLAG_READ).implies(new VirtualFilePermission("*", "read")));
+ assertTrue(new VirtualFilePermission("-", FLAG_READ).implies(new VirtualFilePermission("-", "read")));
+ assertFalse(new VirtualFilePermission("-", FLAG_READ).implies(new VirtualFilePermission("", "read")));
+ }
+
+ public void testCollection() {
+ final PermissionCollection collection = new VirtualFilePermission("foo", 0).newPermissionCollection();
+ collection.add(new VirtualFilePermission("/foo/bar/*", "read"));
+ collection.add(new VirtualFilePermission("/foo/bar/-", "delete"));
+ collection.add(new VirtualFilePermission("/foo/bar/baz", "getfile,read"));
+ collection.add(new VirtualFilePermission("foo/bar/baz", "delete"));
+
+ assertTrue(collection.implies(new VirtualFilePermission("/foo/bar/blah", "read,delete")));
+ assertFalse(collection.implies(new VirtualFilePermission("/foo/bar/blah", "read,delete,getfile")));
+ assertTrue(collection.implies(new VirtualFilePermission("/foo/bar/baz/zap", "delete")));
+ assertFalse(collection.implies(new VirtualFilePermission("/foo/bar/baz/zap", "read")));
+ assertFalse(collection.implies(new VirtualFilePermission("/foo/bar", "read")));
+ assertFalse(collection.implies(new VirtualFilePermission("/foo", "read")));
+ }
+}

0 comments on commit 871b86c

Please sign in to comment.
Something went wrong with that request. Please try again.