View Javadoc

1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.intercept.web;
17  
18  import org.acegisecurity.ConfigAttributeDefinition;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  
23  import org.springframework.util.PathMatcher;
24  import org.springframework.util.AntPathMatcher;
25  
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Set;
30  import java.util.Vector;
31  
32  
33  /***
34   * Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
35   * associated with different HTTP request URL Apache Ant path-based patterns.
36   * 
37   * <P>
38   * Apache Ant path expressions are used to match a HTTP request URL against a
39   * <code>ConfigAttributeDefinition</code>.
40   * </p>
41   * 
42   * <p>
43   * The order of registering the Ant paths using the {@link
44   * #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
45   * system will identify the <b>first</b>  matching path for a given HTTP URL.
46   * It will not proceed to evaluate later paths if a match has already been
47   * found. Accordingly, the most specific paths should be registered first,
48   * with the most general paths registered last.
49   * </p>
50   * 
51   * <P>
52   * If no registered paths match the HTTP URL, <code>null</code> is returned.
53   * </p>
54   */
55  public class PathBasedFilterInvocationDefinitionMap
56      extends AbstractFilterInvocationDefinitionSource
57      implements FilterInvocationDefinitionMap {
58      //~ Static fields/initializers =============================================
59  
60      private static final Log logger = LogFactory.getLog(PathBasedFilterInvocationDefinitionMap.class);
61  
62      //~ Instance fields ========================================================
63  
64      private List requestMap = new Vector();
65      private boolean convertUrlToLowercaseBeforeComparison = false;
66      private PathMatcher pathMatcher = new AntPathMatcher();
67  
68      //~ Methods ================================================================
69  
70      public Iterator getConfigAttributeDefinitions() {
71          Set set = new HashSet();
72          Iterator iter = requestMap.iterator();
73  
74          while (iter.hasNext()) {
75              EntryHolder entryHolder = (EntryHolder) iter.next();
76              set.add(entryHolder.getConfigAttributeDefinition());
77          }
78  
79          return set.iterator();
80      }
81  
82      public void setConvertUrlToLowercaseBeforeComparison(
83          boolean convertUrlToLowercaseBeforeComparison) {
84          this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
85      }
86  
87      public boolean isConvertUrlToLowercaseBeforeComparison() {
88          return convertUrlToLowercaseBeforeComparison;
89      }
90  
91      public int getMapSize() {
92          return this.requestMap.size();
93      }
94  
95      public void addSecureUrl(String antPath, ConfigAttributeDefinition attr) {
96          requestMap.add(new EntryHolder(antPath, attr));
97  
98          if (logger.isDebugEnabled()) {
99              logger.debug("Added Ant path: " + antPath + "; attributes: " + attr);
100         }
101     }
102 
103     public ConfigAttributeDefinition lookupAttributes(String url) {
104         Iterator iter = requestMap.iterator();
105 
106         if (convertUrlToLowercaseBeforeComparison) {
107             url = url.toLowerCase();
108 
109             if (logger.isDebugEnabled()) {
110                 logger.debug("Converted URL to lowercase, from: '" + url
111                     + "'; to: '" + url + "'");
112             }
113         }
114 
115         while (iter.hasNext()) {
116             EntryHolder entryHolder = (EntryHolder) iter.next();
117 
118             boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);
119 
120             if (logger.isDebugEnabled()) {
121                 logger.debug("Candidate is: '" + url + "'; pattern is "
122                     + entryHolder.getAntPath() + "; matched=" + matched);
123             }
124 
125             if (matched) {
126                 return entryHolder.getConfigAttributeDefinition();
127             }
128         }
129 
130         return null;
131     }
132 
133     //~ Inner Classes ==========================================================
134 
135     protected class EntryHolder {
136         private ConfigAttributeDefinition configAttributeDefinition;
137         private String antPath;
138 
139         public EntryHolder(String antPath, ConfigAttributeDefinition attr) {
140             this.antPath = antPath;
141             this.configAttributeDefinition = attr;
142         }
143 
144         protected EntryHolder() {
145             throw new IllegalArgumentException("Cannot use default constructor");
146         }
147 
148         public String getAntPath() {
149             return antPath;
150         }
151 
152         public ConfigAttributeDefinition getConfigAttributeDefinition() {
153             return configAttributeDefinition;
154         }
155     }
156 }