1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19
20
21
22
23
24 package javax.security.jacc;
25
26 import java.util.Iterator;
27 import java.util.LinkedList;
28 import javax.servlet.http.HttpServletRequest;
29
30
31 /**
32 * @version $Rev: 431818 $ $Date: 2006-08-15 21:55:26 -0700 (Tue, 15 Aug 2006) $
33 */
34 final class URLPatternSpec {
35
36 private final String pattern;
37 private final URLPattern first;
38 private final LinkedList qualifiers = new LinkedList();
39
40 public URLPatternSpec(String name) {
41 if (name == null) throw new java.lang.IllegalArgumentException("URLPatternSpec cannot be null");
42 if (name.length() == 0) name = "/";
43
44 pattern = name;
45
46 String[] tokens = pattern.split(":", -1);
47 first = new URLPattern(tokens[0]);
48
49 URLPattern candidate;
50 for (int i = 1; i < tokens.length; i++) {
51 candidate = new URLPattern(tokens[i]);
52
53
54 if (candidate.matches(first)) {
55 throw new java.lang.IllegalArgumentException("Qualifier patterns in the URLPatternSpec cannot match the first URLPattern");
56 }
57
58 if (first.type == URLPattern.PATH_PREFIX) {
59
60
61
62
63
64 if (candidate.type == URLPattern.EXACT && !first.matches(candidate)) {
65 throw new java.lang.IllegalArgumentException("Exact qualifier patterns in the URLPatternSpec must be matched by the first URLPattern");
66 } else if (candidate.type == URLPattern.PATH_PREFIX
67 && !(first.matches(candidate) && first.pattern.length() < candidate.pattern.length()))
68 {
69 throw new java.lang.IllegalArgumentException("path-prefix qualifier patterns in the URLPatternSpec must be matched by, but different from, the first URLPattern");
70 } else if (candidate.type == URLPattern.EXTENSION) {
71 throw new java.lang.IllegalArgumentException("extension qualifier patterns in the URLPatternSpec are not allowed when the first URLPattern is path-prefix");
72 }
73 } else if (first.type == URLPattern.EXTENSION) {
74
75
76
77
78
79 if (candidate.type == URLPattern.EXACT && !first.matches(candidate)) {
80 throw new java.lang.IllegalArgumentException("Exact qualifier patterns in the URLPatternSpec must be matched when first URLPattern is an extension pattern");
81 } else if (candidate.type != URLPattern.PATH_PREFIX) {
82 throw new java.lang.IllegalArgumentException("Only exact and path-prefix qualifiers in the URLPatternSpec are allowed when first URLPattern is an extension pattern");
83 }
84 } else if (first.type == URLPattern.DEFAULT) {
85
86
87
88
89 if (candidate.type == URLPattern.DEFAULT) {
90 throw new java.lang.IllegalArgumentException("Qualifier patterns must not be default when first URLPattern is a default pattern");
91 }
92 } else if (first.type == URLPattern.EXACT) {
93
94
95
96
97 throw new java.lang.IllegalArgumentException("Qualifier patterns must be present when first URLPattern is an exact pattern");
98 }
99
100 qualifiers.add(candidate);
101 }
102 }
103
104 public boolean equals(URLPatternSpec o) {
105 return implies(o) && o.implies(this);
106 }
107
108 public int hashCode() {
109 return pattern.hashCode();
110 }
111
112 public String getPatternSpec() {
113 return pattern;
114 }
115
116 public boolean implies(URLPatternSpec p) {
117
118
119
120 if (!first.matches(p.first)) return false;
121
122
123
124
125 Iterator iter1 = qualifiers.iterator();
126 while (iter1.hasNext()) {
127 if (((URLPattern) iter1.next()).matches(p.first)) return false;
128 }
129
130
131
132
133
134
135 if (p.first.matches(first)) {
136 Iterator iter2 = p.qualifiers.iterator();
137
138 while (iter2.hasNext()) {
139 Iterator iter3 = qualifiers.iterator();
140 URLPattern test = (URLPattern) iter2.next();
141 boolean found = false;
142
143 while (iter3.hasNext()) {
144 if (test.matches((URLPattern) iter3.next())) {
145 found = true;
146 break;
147 }
148 }
149 if (!found) return false;
150 }
151 }
152
153 return true;
154 }
155
156 static String encodeColons(HttpServletRequest request) {
157 String result = request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo());
158
159 if (result.indexOf("%3A") > -1) result = result.replaceAll("%3A", "%3A%3A");
160 if (result.indexOf(":") > -1) result = result.replaceAll(":", "%3A");
161
162 return result;
163 }
164
165 private class URLPattern {
166
167 public final static int EXACT = 0x0;
168 public final static int PATH_PREFIX = 0x1;
169 public final static int EXTENSION = 0x2;
170 public final static int DEFAULT = 0x4;
171
172 public int type;
173 public String pattern;
174
175 public URLPattern(String pat) {
176 if (pat == null) throw new java.lang.IllegalArgumentException("URLPattern cannot be null");
177 if (pat.length() == 0) throw new java.lang.IllegalArgumentException("URLPattern cannot be empty");
178
179 if (pat.equals("/") || pat.equals("/*")) {
180 type = DEFAULT;
181 } else if (pat.charAt(0) == '/' && pat.endsWith("/*")) {
182 type = PATH_PREFIX;
183 } else if (pat.charAt(0) == '*') {
184 type = EXTENSION;
185 } else {
186 type = EXACT;
187 }
188 pattern = pat;
189 }
190
191 public boolean matches(URLPattern p) {
192
193 String test = p.pattern;
194
195
196 if (pattern.equals(test)) return true;
197
198 switch (type) {
199
200
201
202
203
204
205 case PATH_PREFIX: {
206 int length = pattern.length() - 2;
207 if (length > test.length()) return false;
208
209 for (int i = 0; i < length; i++) {
210 if (pattern.charAt(i) != test.charAt(i)) return false;
211 }
212
213 if (test.length() == length) return true;
214 else if (test.charAt(length) != '/') return false;
215
216 return true;
217 }
218
219
220
221 case EXTENSION: {
222 return test.endsWith(pattern.substring(1));
223 }
224
225
226
227
228 case DEFAULT: {
229 return true;
230 }
231 }
232 return false;
233 }
234 }
235 }