You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by dj...@apache.org on 2006/11/30 20:02:43 UTC

svn commit: r481038 - in /geronimo/specs/trunk/geronimo-jacc_1.1_spec: ./ src/main/java/javax/security/jacc/ src/test/java/javax/security/jacc/

Author: djencks
Date: Thu Nov 30 11:02:41 2006
New Revision: 481038

URL: http://svn.apache.org/viewvc?view=rev&rev=481038
Log:
GERONIMO-2608 update jacc specs to 1.1/MR4, change naming a bit, implement http extension methods and http exclusion lists

Added:
    geronimo/specs/trunk/geronimo-jacc_1.1_spec/
      - copied from r473397, geronimo/specs/trunk/geronimo-j2ee-jacc_1.0_spec/
Modified:
    geronimo/specs/trunk/geronimo-jacc_1.1_spec/pom.xml
    geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/main/java/javax/security/jacc/HTTPMethodSpec.java
    geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebResourcePermissionTest.java
    geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebUserDataPermissionTest.java

Modified: geronimo/specs/trunk/geronimo-jacc_1.1_spec/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-jacc_1.1_spec/pom.xml?view=diff&rev=481038&r1=473397&r2=481038
==============================================================================
--- geronimo/specs/trunk/geronimo-jacc_1.1_spec/pom.xml (original)
+++ geronimo/specs/trunk/geronimo-jacc_1.1_spec/pom.xml Thu Nov 30 11:02:41 2006
@@ -20,7 +20,8 @@
 
 <!-- $Rev$ $Date$ -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
     <modelVersion>4.0.0</modelVersion>
 
@@ -31,16 +32,37 @@
         <relativePath>../pom.xml</relativePath>
     </parent>
 
-    <artifactId>geronimo-j2ee-jacc_1.0_spec</artifactId>
+    <artifactId>geronimo-jacc_1.1_spec</artifactId>
     <name>J2EE JACC 1.0</name>
     <version>1.1-SNAPSHOT</version>
 
     <dependencies>
         <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-servlet_2.4_spec</artifactId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
             <version>1.1-SNAPSHOT</version>
         </dependency>
     </dependencies>
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-idea-plugin</artifactId>
+                <configuration>
+                    <jdkName>1.5</jdkName>
+                    <linkModules>true</linkModules>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>

Modified: geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/main/java/javax/security/jacc/HTTPMethodSpec.java
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/main/java/javax/security/jacc/HTTPMethodSpec.java?view=diff&rev=481038&r1=473397&r2=481038
==============================================================================
--- geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/main/java/javax/security/jacc/HTTPMethodSpec.java (original)
+++ geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/main/java/javax/security/jacc/HTTPMethodSpec.java Thu Nov 30 11:02:41 2006
@@ -25,6 +25,12 @@
 
 package javax.security.jacc;
 
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
 
 /**
  * @version $Rev$ $Date$
@@ -40,8 +46,12 @@
     final static int NONE = INTEGRAL | CONFIDENTIAL;
 
     private final int mask;
+    private final String[] extensionMethods;
+    private final boolean isExcluded;
     private final int transport;
     private String actions;
+    private static final String[] NO_METHODS = new String[0];
+    private static final Pattern TOKEN_PATTERN = Pattern.compile("[!-~&&[^\\(\\)\\<\\>@,;:\\\\\"/\\[\\]\\?=\\{\\}]]*");
 
     public HTTPMethodSpec(String[] HTTPMethods) {
         this(HTTPMethods, null);
@@ -74,8 +84,14 @@
         }
 
         if (name == null || name.length() == 0) {
-            this.mask = 0x7F;
+            this.mask = 0x00;
+            this.extensionMethods = NO_METHODS;
+            this.isExcluded = true;
         } else {
+            ArrayList<String> extensions = null;
+            if (isExcluded = name.charAt(0) == '!') {
+                name = name.substring(1);
+            }
             String[] methods = name.split(",", -1);
             int tmpMask = 0;
 
@@ -90,9 +106,20 @@
                         break;
                     }
                 }
-                if (!found) throw new IllegalArgumentException("Invalid HTTPMethodSpec");
+                if (!found) {
+                    checkToken(methods[i]);
+                    if (extensions == null) {
+                        extensions = new ArrayList<String>(methods.length);
+                    }
+                    add(extensions, methods[i]);
+                }
             }
             this.mask = tmpMask;
+            if (extensions == null) {
+                extensionMethods = NO_METHODS;
+            } else {
+                extensionMethods = extensions.toArray(new String[extensions.size()]);
+            }
         }
     }
 
@@ -100,22 +127,39 @@
         boolean parseTransportType = transport != null;
 
         if (HTTPMethods == null || HTTPMethods.length == 0) {
-            this.mask = 0x7F;
+            this.mask = 0x00;
+            this.extensionMethods = NO_METHODS;
+            this.isExcluded = true;
         } else {
             int tmpMask = 0;
+            this.isExcluded = false;
+            ArrayList<String> extensions = null;
 
             for (int i = 0; i < HTTPMethods.length; i++) {
+                boolean found = false;
 
                 for (int j = 0; j < HTTP_METHODS.length; j++) {
                     if (HTTPMethods[i].equals(HTTP_METHODS[j])) {
                         tmpMask |= HTTP_MASKS[j];
+                        found = true;
 
                         break;
                     }
                 }
-                if (tmpMask == 0) throw new IllegalArgumentException("Invalid HTTPMethodSpec");
+                if (!found) {
+                    checkToken(HTTPMethods[i]);
+                    if (extensions == null) {
+                        extensions = new ArrayList<String>(HTTPMethods.length);
+                    }
+                    add(extensions, HTTPMethods[i]);
+                }
             }
             this.mask = tmpMask;
+            if (extensions == null) {
+                extensionMethods = NO_METHODS;
+            } else {
+                extensionMethods = extensions.toArray(new String[extensions.size()]);
+            }
         }
 
         if (parseTransportType) {
@@ -143,19 +187,52 @@
                 break;
             }
         }
-        if (tmpMask == 0) throw new IllegalArgumentException("Invalid HTTPMethodSpec");
+        if (tmpMask == 0) {
+            checkToken(singleMethod);
+            this.extensionMethods = new String[]{singleMethod};
+        } else {
+            this.extensionMethods = NO_METHODS;
+        }
+
         this.mask = tmpMask;
+        this.isExcluded = false;
         this.transport = transport;
     }
 
+
+    private void checkToken(String method) {
+        if (!TOKEN_PATTERN.matcher(method).matches()) {
+            throw new IllegalArgumentException("Invalid HTTPMethodSpec");
+        }
+    }
+
+    private void add(ArrayList<String> extensions, String httpMethod) {
+        for (int i = 0; i < extensions.size(); i++) {
+            String existingMethod = extensions.get(i);
+            int compare = existingMethod.compareTo(httpMethod);
+            if (compare == 0) {
+                return;
+            }
+            if (compare > 0) {
+                extensions.add(i, httpMethod);
+                return;
+            }
+        }
+        extensions.add(httpMethod);
+    }
+
+
     public boolean equals(HTTPMethodSpec o) {
         return mask == o.mask && transport == o.transport;
     }
 
     public String getActions() {
-        if (actions == null) {
+        if (actions == null && !isAll()) {
             boolean first = true;
             StringBuffer buffer = new StringBuffer();
+            if (isExcluded) {
+                buffer.append("!");
+            }
 
             for (int i = 0; i < HTTP_MASKS.length; i++) {
                 if ((mask & HTTP_MASKS[i]) > 0) {
@@ -167,6 +244,15 @@
                     buffer.append(HTTP_METHODS[i]);
                 }
             }
+            for (int i = 0; i < extensionMethods.length; i++) {
+                String method = extensionMethods[i];
+                if (first) {
+                    first = false;
+                } else {
+                    buffer.append(",");
+                }
+                buffer.append(method);
+            }
 
             if (transport == INTEGRAL) {
                 buffer.append(":INTEGRAL");
@@ -179,11 +265,73 @@
         return actions;
     }
 
+    private boolean isAll() {
+        return isExcluded && mask == 0x00;
+    }
+
     public int hashCode() {
         return mask ^ transport;
     }
 
     public boolean implies(HTTPMethodSpec p) {
-        return ((mask & p.mask) == p.mask) && ((transport & p.transport) == p.transport);
+        if ((transport & p.transport) != p.transport) {
+            return false;
+        }
+        if (isExcluded) {
+            if (p.isExcluded) {
+                return ((mask & p.mask) == mask) && contains(p.extensionMethods, extensionMethods);
+            } else {
+                return ((mask & p.mask) == 0x00) && isDisjoint(extensionMethods, p.extensionMethods);
+            }
+        } else {
+            if (p.isExcluded) {
+                return false;
+            } else {
+                return ((mask & p.mask) == p.mask) && contains(extensionMethods, p.extensionMethods);
+            }
+        }
+    }
+
+    private boolean isDisjoint(String[] a, String[] b) {
+        int start = 0;
+        for (int i = 0; i < a.length; i++) {
+            String s = a[i];
+            for (int j = start; j < b.length; j++) {
+                String s1 = b[j];
+                int compare = s.compareTo(s1);
+                if (compare == 0) {
+                    return false;
+                }
+                if (compare < 0) {
+                    start = j;
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean contains(String[] set, String[] subset) {
+        int start = 0;
+        for (int i = 0; i < subset.length; i++) {
+            boolean found = false;
+            String s = subset[i];
+            for (int j = start; j < set.length; j++) {
+                String s1 = set[j];
+                int compare = s.compareTo(s1);
+                if (compare == 0) {
+                    found = true;
+                    start = j + 1;
+                    break;
+                }
+                if (compare < 0) {
+                    return false;
+                }
+            }
+            if (!found) {
+                return false;
+            }
+        }
+        return true;
     }
 }

Modified: geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebResourcePermissionTest.java
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebResourcePermissionTest.java?view=diff&rev=481038&r1=473397&r2=481038
==============================================================================
--- geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebResourcePermissionTest.java (original)
+++ geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebResourcePermissionTest.java Thu Nov 30 11:02:41 2006
@@ -59,10 +59,10 @@
         assertTrue(permission.equals(permission));
         assertEquals(permission.getName(), "/foo");
         assertEquals(permission.getActions(), "GET,POST");
-        
+
         permission = new WebResourcePermission("/foo", "GET,POST,POST,GET");
         assertEquals(permission.getActions(), "GET,POST");
-        
+
         permission = new WebResourcePermission("/", "GET,POST");
         permission = new WebResourcePermission("/:/foo", "GET,POST");
         permission = new WebResourcePermission("/:*.asp", "GET,POST");
@@ -73,70 +73,105 @@
         permission = new WebResourcePermission("/*:/bar/stool", "GET,POST");
         permission = new WebResourcePermission("/bar/*:/bar/stool", "GET,POST");
 
+        permission = new WebResourcePermission("/foo", "GET,POST,BAR");
         // bad HTTP method
         try {
-            permission = new WebResourcePermission("/foo", "GET,POST,BAR");
+            permission = new WebResourcePermission("/foo", "GET,POST,B A R");
             fail("Bad HTTP method");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         // bad HTTP method for a WebResourcePermission
         try {
             permission = new WebResourcePermission("/foo", "GET,POST:INTEGRAL");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         // null URLPatternSpec for a WebResourcePermission
         try {
             permission = new WebResourcePermission(null, "GET,POST");
             fail("null URLPatternSpec for a WebResourcePermission");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         // missing qualifiers
         try {
             permission = new WebResourcePermission("/foo:", "GET,POST");
             fail("/foo:");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         // qualifer provided when first pattern isn't path-prefix
         try {
             permission = new WebResourcePermission("/foo:/foo/bar", "GET,POST");
             fail("/foo:/foo/bar");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         try {
             permission = new WebResourcePermission("/foo/*:*.asp", "GET,POST");
             fail("/foo/*:*.asp");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         try {
             permission = new WebResourcePermission("/foo:/", "GET,POST");
             fail("/foo:/");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         try {
             permission = new WebResourcePermission("/bar/*:/cat/stool/*", "GET,POST");
             fail("/bar/*:/cat/stool/*");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         try {
             permission = new WebResourcePermission("/bar/*:/*", "GET,POST");
             fail("/bar/*:/");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
 
         try {
             permission = new WebResourcePermission("/bar/stool/*:/bar", "GET,POST");
             fail("/bar/stool/*:/bar");
-        } catch(IllegalArgumentException iae) {
+        } catch (IllegalArgumentException iae) {
         }
-        
+
+    }
+
+    public void testExcluded() {
+        WebResourcePermission permission = new WebResourcePermission("/foo", "!GET,POST");
+
+        assertTrue(permission.equals(permission));
+        assertEquals(permission.getName(), "/foo");
+        assertEquals(permission.getActions(), "!GET,POST");
+
+        permission = new WebResourcePermission("/foo", "!GET,POST,POST,GET");
+        assertEquals(permission.getActions(), "!GET,POST");
+
+        permission = new WebResourcePermission("/foo", "!GET,POST,BAR");
+        // bad HTTP method
+        try {
+            permission = new WebResourcePermission("/foo", "!GET,POST,B A R");
+            fail("Bad HTTP method");
+        } catch (IllegalArgumentException iae) {
+        }
+
+        // bad HTTP method for a WebResourcePermission
+        try {
+            permission = new WebResourcePermission("/foo", "!GET,POST:INTEGRAL");
+        } catch (IllegalArgumentException iae) {
+        }
+
+        // null URLPatternSpec for a WebResourcePermission
+        try {
+            permission = new WebResourcePermission(null, "!GET,POST");
+            fail("null URLPatternSpec for a WebResourcePermission");
+        } catch (IllegalArgumentException iae) {
+        }
+
+
     }
 
     public void testImpliesStringString() {
@@ -144,19 +179,19 @@
         // The argument is an instanceof WebResourcePermission 
         Permission pA = new WebResourcePermission("/foo", "");
         Permission pB = new WebUserDataPermission("/foo", "");
-        
+
         assertFalse(pA.implies(pB));
         assertFalse(pB.implies(pA));
-    
+
         pA = new WebResourcePermission("/foo", "");
         pB = new WebResourcePermission("/foo", "GET,POST");
-        
+
         assertTrue(pA.implies(pB));
         assertFalse(pB.implies(pA));
-        
+
         pA = new WebResourcePermission("/foo/*:/foo/bar", "");
         pB = new WebResourcePermission("/foo/bar", "");
-        
+
         assertFalse(pA.implies(pB));
         assertFalse(pB.implies(pA));
 
@@ -169,8 +204,98 @@
         pA = new WebResourcePermission("/:/a.jsp:/b.jsp:/c.jsp", "GET,POST,PUT,DELETE,HEAD,OPTIONS,TRACE");
         pB = new WebResourcePermission("/:/a.jsp:/c.jsp:/b.jsp", (String) null);
 
-        assertTrue(pA.implies(pB));
+//        assertTrue(pA.implies(pB));  // no longer true with extension methods
+        assertTrue(pB.implies(pA));
+    }
+
+    public void testImpliesExtensionExcludes() {
+        //test against all permissions
+        WebResourcePermission pA = new WebResourcePermission("/foo", "FOO,BAR,fizzle");
+        WebResourcePermission pB = new WebResourcePermission("/foo", (String) null);
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+        assertTrue(pA.implies(pA));
+        assertTrue(pB.implies(pB));
+
+        pA = new WebResourcePermission("/foo", "!FOO,BAR,fizzle");
+        pB = new WebResourcePermission("/foo", (String) null);
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+        assertTrue(pA.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "GET,POST");
+        pB = new WebResourcePermission("/foo", (String) null);
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "!GET,POST");
+        pB = new WebResourcePermission("/foo", (String) null);
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        //both positive sets
+        pA = new WebResourcePermission("/foo", "GET,POST");
+        pB = new WebResourcePermission("/foo", "GET,POST,OPTIONS");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "GET,POST");
+        pB = new WebResourcePermission("/foo", "GET,POST,FOO");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "GET,FOO");
+        pB = new WebResourcePermission("/foo", "GET,BAR,FOO");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "FOO,BAR");
+        pB = new WebResourcePermission("/foo", "FOO,BAR,fizzle");
+        assertFalse(pA.implies(pB));
         assertTrue(pB.implies(pA));
+
+        //both exclusions
+        pA = new WebResourcePermission("/foo", "!FOO,BAR,fizzle");
+        pB = new WebResourcePermission("/foo", "!FOO,BAR");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "!GET,POST,FOO");
+        pB = new WebResourcePermission("/foo", "!GET,POST");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "!GET,BAR,FOO");
+        pB = new WebResourcePermission("/foo", "!GET,BAR");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "!GET,POST,OPTIONS");
+        pB = new WebResourcePermission("/foo", "!GET,POST");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        //one of each
+        pA = new WebResourcePermission("/foo", "GET");
+        pB = new WebResourcePermission("/foo", "!FOO,BAR");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "fizzle");
+        pB = new WebResourcePermission("/foo", "!FOO,BAR");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "GET");
+        pB = new WebResourcePermission("/foo", "!POST");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
+        pA = new WebResourcePermission("/foo", "GET");
+        pB = new WebResourcePermission("/foo", "!POST,BAR");
+        assertFalse(pA.implies(pB));
+        assertTrue(pB.implies(pA));
+
     }
 
     /*
@@ -178,7 +303,7 @@
      */
     public void testConstructorStringStringArray() {
     }
-    
+
     public void testImpliesStringStringArray() {
     }
 
@@ -187,10 +312,29 @@
      */
     public void testConstructorHttpServletRequest() {
     }
-    
+
     public void testImpliesHttpServletRequest() {
     }
-    
+
+    public void testGetActions() {
+        WebResourcePermission p = new WebResourcePermission("/foo", "");
+        assertNull(p.getActions());
+        p = new WebResourcePermission("/foo", "!GET,POST");
+        assertEquals(p.getActions(), "!GET,POST");
+        p = new WebResourcePermission("/foo", "!POST,GET");
+        assertEquals(p.getActions(), "!GET,POST");
+        p = new WebResourcePermission("/foo", "!POST,GET,GET,POST");
+        assertEquals(p.getActions(), "!GET,POST");
+
+        //extension methods follow regular methods
+        p = new WebResourcePermission("/foo", "FOO,BAR,POST,FOO,GET,GET,POST");
+        assertEquals("GET,POST,BAR,FOO", p.getActions());
+
+        p = new WebResourcePermission("/foo", "!FOO,BAR,POST,FOO,GET,GET,POST");
+        assertEquals("!GET,POST,BAR,FOO", p.getActions());
+
+    }
+
     public static void main(String[] args) {
         WebResourcePermissionTest test = new WebResourcePermissionTest();
         test.testConstructorStringString();

Modified: geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebUserDataPermissionTest.java
URL: http://svn.apache.org/viewvc/geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebUserDataPermissionTest.java?view=diff&rev=481038&r1=473397&r2=481038
==============================================================================
--- geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebUserDataPermissionTest.java (original)
+++ geronimo/specs/trunk/geronimo-jacc_1.1_spec/src/test/java/javax/security/jacc/WebUserDataPermissionTest.java Thu Nov 30 11:02:41 2006
@@ -54,9 +54,12 @@
         permission = new WebUserDataPermission("/foo", "GET,POST,POST,GET:INTEGRAL");
         assertEquals(permission.getActions(), "GET,POST:INTEGRAL");
 
+        //extension method
+        permission = new WebUserDataPermission("/foo", "GET,POST,BAR:INTEGRAL");
+
         // bad HTTP method
         try {
-            permission = new WebUserDataPermission("/foo", "GET,POST,BAR:INTEGRAL");
+            permission = new WebUserDataPermission("/foo", "GET,POST,B A R:INTEGRAL");
             fail("Bad HTTP method");
         } catch (IllegalArgumentException iae) {
         }