浏览代码

SEC-599: Refactoring of FilterInvocationDefinitionSource implementations to use a LinkedHashMap internally rather than list of "EntryHolder" classes.

Luke Taylor 17 年之前
父节点
当前提交
01569e5746

+ 5 - 6
core/src/main/java/org/springframework/security/intercept/web/AbstractFilterInvocationDefinitionSource.java

@@ -17,8 +17,8 @@ package org.springframework.security.intercept.web;
 
 
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.ConfigAttributeDefinition;
 
 
-import java.util.List;
-import java.util.Vector;
+import java.util.Map;
+import java.util.LinkedHashMap;
 
 
 
 
 /**
 /**
@@ -29,14 +29,13 @@ import java.util.Vector;
  */
  */
 public abstract class AbstractFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource {
 public abstract class AbstractFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource {
 
 
-    protected List requestMap = new Vector();
+    private Map requestMap = new LinkedHashMap();
 
 
     private boolean convertUrlToLowercaseBeforeComparison = false;
     private boolean convertUrlToLowercaseBeforeComparison = false;
 
 
     //~ Methods ========================================================================================================
     //~ Methods ========================================================================================================
 
 
-    public ConfigAttributeDefinition getAttributes(Object object)
-        throws IllegalArgumentException {
+    public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
         if ((object == null) || !this.supports(object.getClass())) {
         if ((object == null) || !this.supports(object.getClass())) {
             throw new IllegalArgumentException("Object must be a FilterInvocation");
             throw new IllegalArgumentException("Object must be a FilterInvocation");
         }
         }
@@ -78,7 +77,7 @@ public abstract class AbstractFilterInvocationDefinitionSource implements Filter
         this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
         this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
     }
     }
 
 
-    List getRequestMap() {
+    Map getRequestMap() {
         return requestMap;
         return requestMap;
     }
     }
 }
 }

+ 22 - 37
core/src/main/java/org/springframework/security/intercept/web/FIDSToFilterChainMapConverter.java

@@ -1,12 +1,14 @@
 package org.springframework.security.intercept.web;
 package org.springframework.security.intercept.web;
 
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContext;
+import org.springframework.util.Assert;
 import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttribute;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.ConfigAttributeDefinition;
 import org.springframework.security.util.FilterChainProxy;
 import org.springframework.security.util.FilterChainProxy;
 
 
 import javax.servlet.Filter;
 import javax.servlet.Filter;
 import java.util.*;
 import java.util.*;
+import java.util.regex.Pattern;
 
 
 /**
 /**
  * Used internally to provide backward compatibility for configuration of FilterChainProxy using a
  * Used internally to provide backward compatibility for configuration of FilterChainProxy using a
@@ -23,51 +25,34 @@ public class FIDSToFilterChainMapConverter {
 
 
     private LinkedHashMap filterChainMap = new LinkedHashMap();
     private LinkedHashMap filterChainMap = new LinkedHashMap();
 
 
-    public FIDSToFilterChainMapConverter(FilterInvocationDefinitionSource fids, ApplicationContext appContext) {
-
-        List requestMap;
-
-        // TODO: Check if this is necessary. Retained from refactoring of FilterChainProxy 
-        if (fids.getConfigAttributeDefinitions() == null) {
-            throw new IllegalArgumentException("FilterChainProxy requires the FilterInvocationDefinitionSource to " +
-                    "return a non-null response to getConfigAttributeDefinitions()");
-        }
-
-        if (fids instanceof PathBasedFilterInvocationDefinitionMap) {
-            requestMap = ((PathBasedFilterInvocationDefinitionMap)fids).getRequestMap();
-        } else if (fids instanceof RegExpBasedFilterInvocationDefinitionMap) {
-            requestMap = ((RegExpBasedFilterInvocationDefinitionMap)fids).getRequestMap();
-        } else {
-            throw new IllegalArgumentException("Can't handle FilterInvocationDefinitionSource type " + fids.getClass());
-        }
-
-        Iterator entries = requestMap.iterator();
-
-        while (entries.hasNext()) {
-            Object entry = entries.next();
-            String path;
-            ConfigAttributeDefinition configAttributeDefinition;
-
-            if (entry instanceof PathBasedFilterInvocationDefinitionMap.EntryHolder) {
-                path = ((PathBasedFilterInvocationDefinitionMap.EntryHolder)entry).getAntPath();
-                configAttributeDefinition = ((PathBasedFilterInvocationDefinitionMap.EntryHolder)entry).getConfigAttributeDefinition();
-            } else {
-                path = ((RegExpBasedFilterInvocationDefinitionMap.EntryHolder)entry).getCompiledPattern().pattern();
-                configAttributeDefinition = ((RegExpBasedFilterInvocationDefinitionMap.EntryHolder)entry).getConfigAttributeDefinition();
-            }
+    public FIDSToFilterChainMapConverter(FilterInvocationDefinitionSource source, ApplicationContext appContext) {
+        // TODO: Check if this is necessary. Retained from refactoring of FilterChainProxy
+        Assert.notNull(source.getConfigAttributeDefinitions(), "FilterChainProxy requires the " +
+                "FilterInvocationDefinitionSource to return a non-null response to getConfigAttributeDefinitions()");
+        Assert.isTrue(
+            source instanceof PathBasedFilterInvocationDefinitionMap ||
+            source instanceof RegExpBasedFilterInvocationDefinitionMap,
+                "Can't handle FilterInvocationDefinitionSource type " + source.getClass());
+        
+
+        AbstractFilterInvocationDefinitionSource fids = (AbstractFilterInvocationDefinitionSource)source;
+        Map requestMap = fids.getRequestMap();
+        Iterator paths = requestMap.keySet().iterator();
+
+        while (paths.hasNext()) {
+            Object entry = paths.next();
+            String path = entry instanceof Pattern ? ((Pattern)entry).pattern() : (String)entry;
+            ConfigAttributeDefinition configAttributeDefinition = (ConfigAttributeDefinition) requestMap.get(entry);
 
 
             List filters = new ArrayList();
             List filters = new ArrayList();
-
             Iterator attributes = configAttributeDefinition.getConfigAttributes();
             Iterator attributes = configAttributeDefinition.getConfigAttributes();
 
 
             while (attributes.hasNext()) {
             while (attributes.hasNext()) {
                 ConfigAttribute attr = (ConfigAttribute) attributes.next();
                 ConfigAttribute attr = (ConfigAttribute) attributes.next();
                 String filterName = attr.getAttribute();
                 String filterName = attr.getAttribute();
 
 
-                if (filterName == null) {
-                    throw new IllegalArgumentException("Configuration attribute: '" + attr
-                        + "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
-                }
+                Assert.notNull(filterName, "Configuration attribute: '" + attr + "' returned null to the getAttribute() " +
+                        "method, which is invalid when used with FilterChainProxy");
 
 
                 if (!filterName.equals(FilterChainProxy.TOKEN_NONE)) {
                 if (!filterName.equals(FilterChainProxy.TOKEN_NONE)) {
                     filters.add(appContext.getBean(filterName, Filter.class));
                     filters.add(appContext.getBean(filterName, Filter.class));

+ 14 - 49
core/src/main/java/org/springframework/security/intercept/web/PathBasedFilterInvocationDefinitionMap.java

@@ -23,22 +23,20 @@ import org.apache.commons.logging.LogFactory;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.AntPathMatcher;
 import org.springframework.util.PathMatcher;
 import org.springframework.util.PathMatcher;
 
 
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
 
 
 
 
 /**
 /**
  * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
  * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
  * URL Apache Ant path-based patterns.<p>Apache Ant path expressions are used to match a HTTP request URL against a
  * URL Apache Ant path-based patterns.<p>Apache Ant path expressions are used to match a HTTP request URL against a
- * <code>ConfigAttributeDefinition</code>.</p>
- * <p>The order of registering the Ant paths using the {@link #addSecureUrl(String,ConfigAttributeDefinition)} is
+ * <code>ConfigAttributeDefinition</code>.
+ * <p>
+ * The order of registering the Ant paths using the {@link #addSecureUrl(String,ConfigAttributeDefinition)} is
  * very important. The system will identify the <b>first</b>  matching path for a given HTTP URL. It will not proceed
  * very important. The system will identify the <b>first</b>  matching path for a given HTTP URL. It will not proceed
  * to evaluate later paths if a match has already been found. Accordingly, the most specific paths should be
  * to evaluate later paths if a match has already been found. Accordingly, the most specific paths should be
- * registered first, with the most general paths registered last.</p>
- * <p>If no registered paths match the HTTP URL, <code>null</code> is returned.</p>
+ * registered first, with the most general paths registered last.
+ * <p>
+ * If no registered paths match the HTTP URL, <code>null</code> is returned.
  *
  *
  * @author Ben Alex
  * @author Ben Alex
  * @version $Id$
  * @version $Id$
@@ -60,7 +58,7 @@ public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvoca
             antPath = antPath.toLowerCase();
             antPath = antPath.toLowerCase();
         }
         }
 
 
-        getRequestMap().add(new EntryHolder(antPath, attr));
+        getRequestMap().put(antPath, attr);
 
 
         if (logger.isDebugEnabled()) {
         if (logger.isDebugEnabled()) {
             logger.debug("Added Ant path: " + antPath + "; attributes: " + attr);
             logger.debug("Added Ant path: " + antPath + "; attributes: " + attr);
@@ -68,15 +66,7 @@ public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvoca
     }
     }
 
 
     public Iterator getConfigAttributeDefinitions() {
     public Iterator getConfigAttributeDefinitions() {
-        Set set = new HashSet();
-        Iterator iter = getRequestMap().iterator();
-
-        while (iter.hasNext()) {
-            EntryHolder entryHolder = (EntryHolder) iter.next();
-            set.add(entryHolder.getConfigAttributeDefinition());
-        }
-
-        return set.iterator();
+        return getRequestMap().values().iterator();
     }
     }
 
 
     public ConfigAttributeDefinition lookupAttributes(String url) {
     public ConfigAttributeDefinition lookupAttributes(String url) {
@@ -95,47 +85,22 @@ public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvoca
             }
             }
         }
         }
 
 
-        Iterator iter = requestMap.iterator();
+        Iterator paths = getRequestMap().keySet().iterator();
 
 
-        while (iter.hasNext()) {
-            EntryHolder entryHolder = (EntryHolder) iter.next();
+        while (paths.hasNext()) {
+            String path = (String) paths.next();
 
 
-            boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);
+            boolean matched = pathMatcher.match(path, url);
 
 
             if (logger.isDebugEnabled()) {
             if (logger.isDebugEnabled()) {
-                logger.debug("Candidate is: '" + url + "'; pattern is " + entryHolder.getAntPath() + "; matched="
-                        + matched);
+                logger.debug("Candidate is: '" + url + "'; pattern is " + path + "; matched=" + matched);
             }
             }
 
 
             if (matched) {
             if (matched) {
-                return entryHolder.getConfigAttributeDefinition();
+                return (ConfigAttributeDefinition) getRequestMap().get(path);
             }
             }
         }
         }
 
 
         return null;
         return null;
     }
     }
-
-    //~ Inner Classes ==================================================================================================
-
-    protected class EntryHolder {
-        private ConfigAttributeDefinition configAttributeDefinition;
-        private String antPath;
-
-        public EntryHolder(String antPath, ConfigAttributeDefinition attr) {
-            this.antPath = antPath;
-            this.configAttributeDefinition = attr;
-        }
-
-        protected EntryHolder() {
-            throw new IllegalArgumentException("Cannot use default constructor");
-        }
-
-        public String getAntPath() {
-            return antPath;
-        }
-
-        public ConfigAttributeDefinition getConfigAttributeDefinition() {
-            return configAttributeDefinition;
-        }
-    }
 }
 }

+ 16 - 55
core/src/main/java/org/springframework/security/intercept/web/RegExpBasedFilterInvocationDefinitionMap.java

@@ -20,25 +20,22 @@ import org.springframework.security.ConfigAttributeDefinition;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.logging.LogFactory;
 
 
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
-import java.util.regex.Matcher;
-
 
 
 /**
 /**
  * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
  * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
- * URL regular expression patterns.<p>Regular expressions are used to match a HTTP request URL against a
- * <code>ConfigAttributeDefinition</code>.</p>
- *  <p>The order of registering the regular expressions using the {@link #addSecureUrl(String,
+ * URL regular expression patterns.
+ * <p>
+ * Regular expressions are used to match a HTTP request URL against a <code>ConfigAttributeDefinition</code>.
+ * <p>
+ * The order of registering the regular expressions using the {@link #addSecureUrl(String,
  * ConfigAttributeDefinition)} is very important. The system will identify the <b>first</b>  matching regular
  * ConfigAttributeDefinition)} is very important. The system will identify the <b>first</b>  matching regular
  * expression for a given HTTP URL. It will not proceed to evaluate later regular expressions if a match has already
  * expression for a given HTTP URL. It will not proceed to evaluate later regular expressions if a match has already
  * been found. Accordingly, the most specific regular expressions should be registered first, with the most general
  * been found. Accordingly, the most specific regular expressions should be registered first, with the most general
- * regular expressions registered last.</p>
- *  <p>If no registered regular expressions match the HTTP URL, <code>null</code> is returned.</p>
+ * regular expressions registered last.
+ * <p>
+ * If no registered regular expressions match the HTTP URL, <code>null</code> is returned.
  */
  */
 public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
 public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
     implements FilterInvocationDefinition {
     implements FilterInvocationDefinition {
@@ -51,7 +48,7 @@ public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvo
     public void addSecureUrl(String regExp, ConfigAttributeDefinition attr) {
     public void addSecureUrl(String regExp, ConfigAttributeDefinition attr) {
         Pattern pattern = Pattern.compile(regExp);
         Pattern pattern = Pattern.compile(regExp);
 
 
-        getRequestMap().add(new EntryHolder(pattern, attr));
+        getRequestMap().put(pattern, attr);
 
 
         if (logger.isDebugEnabled()) {
         if (logger.isDebugEnabled()) {
             logger.debug("Added regular expression: " + regExp + "; attributes: " + attr);
             logger.debug("Added regular expression: " + regExp + "; attributes: " + attr);
@@ -59,20 +56,10 @@ public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvo
     }
     }
 
 
     public Iterator getConfigAttributeDefinitions() {
     public Iterator getConfigAttributeDefinitions() {
-        Set set = new HashSet();
-        Iterator iter = getRequestMap().iterator();
-
-        while (iter.hasNext()) {
-            EntryHolder entryHolder = (EntryHolder) iter.next();
-            set.add(entryHolder.getConfigAttributeDefinition());
-        }
-
-        return set.iterator();
+        return getRequestMap().values().iterator();
     }
     }
 
 
     public ConfigAttributeDefinition lookupAttributes(String url) {
     public ConfigAttributeDefinition lookupAttributes(String url) {
-        Iterator iter = getRequestMap().iterator();
-
         if (isConvertUrlToLowercaseBeforeComparison()) {
         if (isConvertUrlToLowercaseBeforeComparison()) {
             url = url.toLowerCase();
             url = url.toLowerCase();
 
 
@@ -81,47 +68,21 @@ public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvo
             }
             }
         }
         }
 
 
-        while (iter.hasNext()) {
-            EntryHolder entryHolder = (EntryHolder) iter.next();
+        Iterator patterns = getRequestMap().keySet().iterator();
 
 
-            Matcher matcher = entryHolder.getCompiledPattern().matcher(url);
-
-            boolean matched = matcher.matches();
+        while (patterns.hasNext()) {
+            Pattern p = (Pattern) patterns.next();
+            boolean matched = p.matcher(url).matches();
 
 
             if (logger.isDebugEnabled()) {
             if (logger.isDebugEnabled()) {
-                logger.debug("Candidate is: '" + url + "'; pattern is " + entryHolder.getCompiledPattern()
-                    + "; matched=" + matched);
+                logger.debug("Candidate is: '" + url + "'; pattern is " + p.pattern() + "; matched=" + matched);
             }
             }
 
 
             if (matched) {
             if (matched) {
-                return entryHolder.getConfigAttributeDefinition();
+                return (ConfigAttributeDefinition) getRequestMap().get(p);
             }
             }
         }
         }
 
 
         return null;
         return null;
     }
     }
-
-    //~ Inner Classes ==================================================================================================
-
-    protected class EntryHolder {
-        private ConfigAttributeDefinition configAttributeDefinition;
-        private Pattern compiledPattern;
-
-        public EntryHolder(Pattern compiledPattern, ConfigAttributeDefinition attr) {
-            this.compiledPattern = compiledPattern;
-            this.configAttributeDefinition = attr;
-        }
-
-        protected EntryHolder() {
-            throw new IllegalArgumentException("Cannot use default constructor");
-        }
-
-        public Pattern getCompiledPattern() {
-            return compiledPattern;
-        }
-
-        public ConfigAttributeDefinition getConfigAttributeDefinition() {
-            return configAttributeDefinition;
-        }
-    }
 }
 }

+ 0 - 11
core/src/test/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditorTests.java

@@ -177,17 +177,6 @@ public class FilterInvocationDefinitionSourceEditorTests extends TestCase {
         assertEquals(2, map.getMapSize());
         assertEquals(2, map.getMapSize());
     }
     }
 
 
-    public void testNoArgConstructorDoesntExist() {
-        Class clazz = RegExpBasedFilterInvocationDefinitionMap.EntryHolder.class;
-
-        try {
-            clazz.getDeclaredConstructor((Class[]) null);
-            fail("Should have thrown NoSuchMethodException");
-        } catch (NoSuchMethodException expected) {
-            assertTrue(true);
-        }
-    }
-
     public void testNullReturnsEmptyMap() {
     public void testNullReturnsEmptyMap() {
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         editor.setAsText(null);
         editor.setAsText(null);

+ 0 - 19
core/src/test/java/org/springframework/security/intercept/web/FilterInvocationDefinitionSourceEditorWithPathsTests.java

@@ -47,14 +47,6 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
 
 
     //~ Methods ========================================================================================================
     //~ Methods ========================================================================================================
 
 
-    public static void main(String[] args) {
-        junit.textui.TestRunner.run(FilterInvocationDefinitionSourceEditorWithPathsTests.class);
-    }
-
-    public final void setUp() throws Exception {
-        super.setUp();
-    }
-
     public void testAntPathDirectiveIsDetected() {
     public void testAntPathDirectiveIsDetected() {
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         editor.setAsText(
         editor.setAsText(
@@ -133,17 +125,6 @@ public class FilterInvocationDefinitionSourceEditorWithPathsTests extends TestCa
         assertEquals(2, map.getMapSize());
         assertEquals(2, map.getMapSize());
     }
     }
 
 
-    public void testNoArgConstructorDoesntExist() {
-        Class clazz = PathBasedFilterInvocationDefinitionMap.EntryHolder.class;
-
-        try {
-            clazz.getDeclaredConstructor((Class[]) null);
-            fail("Should have thrown NoSuchMethodException");
-        } catch (NoSuchMethodException expected) {
-            assertTrue(true);
-        }
-    }
-
     public void testOrderOfEntriesIsPreservedOrderA() {
     public void testOrderOfEntriesIsPreservedOrderA() {
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         FilterInvocationDefinitionSourceEditor editor = new FilterInvocationDefinitionSourceEditor();
         editor.setAsText(
         editor.setAsText(