1
2
3
4
5
6
7
8
9
10
11
12
13
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
64
65 private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
66
67
68
69 private List requestMap = new Vector();
70 private boolean convertUrlToLowercaseBeforeComparison = false;
71
72
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
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 }