View Javadoc

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