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.apache.oro.text.regex.MalformedPatternException;
24  import org.apache.oro.text.regex.Pattern;
25  import org.apache.oro.text.regex.PatternMatcher;
26  import org.apache.oro.text.regex.Perl5Compiler;
27  import org.apache.oro.text.regex.Perl5Matcher;
28  
29  import java.util.HashSet;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Set;
33  import java.util.Vector;
34  
35  
36  /***
37   * Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
38   * associated with different HTTP request URL regular expression patterns.
39   * 
40   * <P>
41   * Regular expressions are used to match a HTTP request URL against a
42   * <code>ConfigAttributeDefinition</code>.
43   * </p>
44   * 
45   * <p>
46   * The order of registering the regular expressions using the {@link
47   * #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
48   * system will identify the <B>first</B>  matching regular expression for a
49   * given HTTP URL. It will not proceed to evaluate later regular expressions
50   * if a match has already been found. Accordingly, the most specific regular
51   * expressions should be registered first, with the most general regular
52   * expressions registered last.
53   * </p>
54   * 
55   * <P>
56   * If no registered regular expressions match the HTTP URL, <code>null</code>
57   * is returned.
58   * </p>
59   */
60  public class RegExpBasedFilterInvocationDefinitionMap
61      extends AbstractFilterInvocationDefinitionSource
62      implements FilterInvocationDefinitionMap {
63      //~ Static fields/initializers =============================================
64  
65      private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
66  
67      //~ Instance fields ========================================================
68  
69      private List requestMap = new Vector();
70      private boolean convertUrlToLowercaseBeforeComparison = false;
71  
72      //~ Methods ================================================================
73  
74      public Iterator getConfigAttributeDefinitions() {
75          Set set = new HashSet();
76          Iterator iter = requestMap.iterator();
77  
78          while (iter.hasNext()) {
79              EntryHolder entryHolder = (EntryHolder) iter.next();
80              set.add(entryHolder.getConfigAttributeDefinition());
81          }
82  
83          return set.iterator();
84      }
85  
86      public void setConvertUrlToLowercaseBeforeComparison(
87          boolean convertUrlToLowercaseBeforeComparison) {
88          this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
89      }
90  
91      public boolean isConvertUrlToLowercaseBeforeComparison() {
92          return convertUrlToLowercaseBeforeComparison;
93      }
94  
95      public int getMapSize() {
96          return this.requestMap.size();
97      }
98  
99      public void addSecureUrl(String perl5RegExp, ConfigAttributeDefinition attr) {
100         Pattern compiledPattern;
101         Perl5Compiler compiler = new Perl5Compiler();
102 
103         try {
104             compiledPattern = compiler.compile(perl5RegExp,
105                     Perl5Compiler.READ_ONLY_MASK);
106         } catch (MalformedPatternException mpe) {
107             throw new IllegalArgumentException("Malformed regular expression: "
108                 + perl5RegExp);
109         }
110 
111         requestMap.add(new EntryHolder(compiledPattern, attr));
112 
113         if (logger.isDebugEnabled()) {
114             logger.debug("Added regular expression: "
115                 + compiledPattern.getPattern().toString() + "; attributes: "
116                 + attr);
117         }
118     }
119 
120     public ConfigAttributeDefinition lookupAttributes(String url) {
121         PatternMatcher matcher = new Perl5Matcher();
122 
123         Iterator iter = requestMap.iterator();
124 
125         if (convertUrlToLowercaseBeforeComparison) {
126             url = url.toLowerCase();
127 
128             if (logger.isDebugEnabled()) {
129                 logger.debug("Converted URL to lowercase, from: '" + url
130                     + "'; to: '" + url + "'");
131             }
132         }
133 
134         while (iter.hasNext()) {
135             EntryHolder entryHolder = (EntryHolder) iter.next();
136 
137             boolean matched = matcher.matches(url,
138                     entryHolder.getCompiledPattern());
139 
140             if (logger.isDebugEnabled()) {
141                 logger.debug("Candidate is: '" + url + "'; pattern is "
142                     + entryHolder.getCompiledPattern().getPattern()
143                     + "; matched=" + matched);
144             }
145 
146             if (matched) {
147                 return entryHolder.getConfigAttributeDefinition();
148             }
149         }
150 
151         return null;
152     }
153 
154     //~ Inner Classes ==========================================================
155 
156     protected class EntryHolder {
157         private ConfigAttributeDefinition configAttributeDefinition;
158         private Pattern compiledPattern;
159 
160         public EntryHolder(Pattern compiledPattern,
161             ConfigAttributeDefinition attr) {
162             this.compiledPattern = compiledPattern;
163             this.configAttributeDefinition = attr;
164         }
165 
166         protected EntryHolder() {
167             throw new IllegalArgumentException("Cannot use default constructor");
168         }
169 
170         public Pattern getCompiledPattern() {
171             return compiledPattern;
172         }
173 
174         public ConfigAttributeDefinition getConfigAttributeDefinition() {
175             return configAttributeDefinition;
176         }
177     }
178 }