URLSubtree | Line # 83 | 77 | 31 | 75% |
0.75
|
No Tests | |||
1 | /* | |
2 | * Copyright (c) 2000-2005, University of Salford | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions are met: | |
7 | * | |
8 | * Redistributions of source code must retain the above copyright notice, this | |
9 | * list of conditions and the following disclaimer. | |
10 | * | |
11 | * Redistributions in binary form must reproduce the above copyright notice, | |
12 | * this list of conditions and the following disclaimer in the documentation | |
13 | * and/or other materials provided with the distribution. | |
14 | * | |
15 | * Neither the name of the University of Salford nor the names of its | |
16 | * contributors may be used to endorse or promote products derived from this | |
17 | * software without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | |
31 | ||
32 | package issrg.pba.rbac.policies; | |
33 | ||
34 | import issrg.utils.ParsedURL; | |
35 | import issrg.pba.rbac.BadURLException; | |
36 | import issrg.pba.rbac.URLPrincipal; | |
37 | import issrg.utils.repository.Entry; | |
38 | ||
39 | import java.net.InetAddress; | |
40 | import java.net.UnknownHostException; | |
41 | ||
42 | /** | |
43 | * This Subtree implementation specifies a subtree of Entries identified by | |
44 | * URL. It uses a issrg.utils.ParsedURL utility class to decompose the URL | |
45 | * and identify the patterns in it, hence support for HTTP-like URLs. | |
46 | * | |
47 | * <p>The format of the URL is described in issrg.utils.ParsedURL. Note that | |
48 | * the host name is either a valid DNS name, or an IP address, or "*"; the port | |
49 | * can be a number specifying a single port, or a range of ports specified as | |
50 | * number "-" number. | |
51 | * | |
52 | * <p>To match the URLSubtree, the Entry must: | |
53 | * <ul> | |
54 | * <li>return a URLPrincipal as the result of getEntryName</li> | |
55 | * <li>have a protocol that matches the one specified in the Subtree (case of | |
56 | * the characters is ignored)</li> | |
57 | * <li>either the Entry and the Subtree specification don't have the user name | |
58 | * specified, or they should match (case sensitive)</li> | |
59 | * <li>either the Entry and the Subtree specification don't have the password | |
60 | * specified, or they should match (case sensitive)</li> | |
61 | * <li>either the Entry has the same host name, as specified in the Subtree, | |
62 | * or it must be one of the IP addresses of the host specified in the Subtree, | |
63 | * or the Subtree host must be specified as "any host" wildcard - "*"</li> | |
64 | * <li>either the Entry has the same port number as the Subtree (the default | |
65 | * one is used, if it is not specified explicitly), or the Entry's port must | |
66 | * match the range of ports specified in the Subtree, or the Subtree doesn't | |
67 | * have any port specified</li> | |
68 | * <li>the number of path components in the Entry must exceed the number of | |
69 | * path components in the Subtree by at least the minimum specified in the | |
70 | * Subtree (the paths are normalised prior to comparison, as explained below)</li> | |
71 | * <li>the number of path components in the Entry may exceed the number of | |
72 | * path components in the Subtree by no more than the maximum specified in the | |
73 | * Subtree (the paths are normalised prior to comparison, as explained below)</li> | |
74 | * <li>Entry must have path components matching all of the path components of | |
75 | * the Subtree (case sensitive; the paths are normalised prior to comparison, | |
76 | * as explained below)</li> | |
77 | * </ul> | |
78 | * | |
79 | * <p>During path normalisation all the "." and ".." (current directory and | |
80 | * parent directory respectively) are dereferenced, as explained in | |
81 | * issrg.utils.ParsedURL. | |
82 | */ | |
83 | public class URLSubtree implements Subtree { | |
84 | /** | |
85 | * Wildcard used in the policy to specify any host - so any host will be | |
86 | * matched | |
87 | * as part of the URL subtree. | |
88 | */ | |
89 | public static final String ANY_HOST="*"; | |
90 | public static final String LOCALHOST="localhost"; | |
91 | ||
92 | protected int defaultPort; | |
93 | protected int min; | |
94 | protected int max; | |
95 | protected int minPort; | |
96 | protected int maxPort; | |
97 | protected ParsedURL pu; | |
98 | protected Subtree [] exclude; | |
99 | ||
100 | protected String [] altIP = {}; // alternative IP addresses for the named host | |
101 | ||
102 | 0 | protected URLSubtree(){} |
103 | ||
104 | /** | |
105 | * This constructor builds a URLSubtree, given a URL string (exceptions are | |
106 | * outlined below), a default port, the min and max levels from the base | |
107 | * directory. | |
108 | * | |
109 | * <p>The URL may contain a range of ports, not just one port. The range is | |
110 | * specified as nn-mm, where nn is the starting port number, and mm - the | |
111 | * ending port number. The subtree then matches any URLs with the port | |
112 | * matching any of the numbers between nn and mm, inclusive. | |
113 | * | |
114 | * <p>If the URL has the host specified by DNS name, then its IP addresses | |
115 | * will be looked up, so that the Entries will match the Subtree by either | |
116 | * of the IP addresses, or by the DNS name. If the host is specified as a | |
117 | * wildcard "*", Entries with any host will match. | |
118 | * | |
119 | * @param url is the URL string | |
120 | * @param defaultPort is the default port to assume for Entries with URLs | |
121 | * that do not specify any port | |
122 | * @param min is the minimum number of levels below the base URL that the | |
123 | * Entry URL should be in; if the Entry is above this level, it doesn't | |
124 | * match this subtree | |
125 | * @param max is the maximum number of levels below the base URL that the | |
126 | * Entry URL should be in; if the Entry is below this level, it doesn't | |
127 | * match this subtree | |
128 | * | |
129 | * @throws BadURLException, if the url string doesn't match the URL | |
130 | * specification | |
131 | * (except for the port range bit), or the port numbers are not valid | |
132 | * integers | |
133 | */ | |
134 | 44 | public URLSubtree(String url, int defaultPort, int min, int max, Subtree [] exclude) throws BadURLException { |
135 | 44 | Exception e=null; |
136 | 44 | int minPort=-1; // unlimited |
137 | 44 | int maxPort=-1; // unlimited |
138 | 44 | pu = ParsedURL.parseURL(url); |
139 | ||
140 | 44 | String port; |
141 | ||
142 | 0 | if (pu!=null && (port=pu.getPort())!=null){ |
143 | 4 | try{ |
144 | 4 | int j=port.indexOf('-'); |
145 | 4 | if (port.indexOf('-')<0) { // no range of ports has been specified |
146 | 0 | j=port.length(); |
147 | 0 | port+="-"+port; // treat it as a range of ports: n <=> n-n |
148 | } | |
149 | 0 | if (j>=port.length()-1) port+="65535"; // if no port is specified at the end, append the port |
150 | ||
151 | 4 | minPort = Integer.parseInt(port.substring(0, j)); |
152 | 4 | maxPort = Integer.parseInt(port.substring(j+1)); // this shouldn't cause IndexOutOfBoundsException: port cannot be an empty string (it would be null then), so port+"-"+port doesn't end with a "-" |
153 | } catch (NumberFormatException nfe) { | |
154 | 0 | e=nfe; |
155 | 0 | pu=null; |
156 | } | |
157 | } | |
158 | 0 | if (pu==null) throw new BadURLException("Malformed URL: "+url, e); |
159 | ||
160 | 44 | if (!pu.getHost().equals(ANY_HOST)) { |
161 | 40 | InetAddress [] hostAddresses = new InetAddress[0]; |
162 | 40 | InetAddress [] lhAddresses = new InetAddress[0]; |
163 | 40 | try{ |
164 | 40 | hostAddresses = InetAddress.getAllByName(pu.getHost()); |
165 | }catch (UnknownHostException uhe){ | |
166 | // log that the host wasn't found | |
167 | } | |
168 | ||
169 | 40 | try{ |
170 | 40 | if (pu.getHost().compareToIgnoreCase(LOCALHOST)==0) |
171 | 0 | lhAddresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); // if it is a "localhost", then look up other host names |
172 | }catch (UnknownHostException uhe){ | |
173 | // this shouldn't happen | |
174 | } | |
175 | // and their addresses | |
176 | 40 | altIP = new String[hostAddresses.length+lhAddresses.length]; |
177 | ||
178 | 48 | for (int i=0; i<hostAddresses.length; i++){ |
179 | 8 | altIP[i]=hostAddresses[i].getHostAddress(); |
180 | } | |
181 | ||
182 | 40 | for (int i=0; i<lhAddresses.length; i++){ |
183 | 0 | altIP[i+hostAddresses.length]=lhAddresses[i].getHostAddress(); |
184 | } | |
185 | } | |
186 | ||
187 | 44 | this.defaultPort=defaultPort; |
188 | 44 | this.min=min; |
189 | 44 | this.max=max; |
190 | 44 | this.minPort=minPort; |
191 | 44 | this.maxPort=maxPort; |
192 | 44 | this.exclude=exclude; |
193 | } | |
194 | ||
195 | /** | |
196 | * This method tests whether Entry e is part of this Subtree. | |
197 | * | |
198 | * @return true, if e's getEntryName returns a URLPrincipal | |
199 | * (e.g. URLEntry) and that URLPrincipal matches the Subtree, as | |
200 | * explained above; false otherwise | |
201 | */ | |
202 | 490 | public boolean contains(Entry e){ |
203 | 490 | URLPrincipal upi; |
204 | 490 | if (!(e.getEntryName() instanceof URLPrincipal)) return false; // cannot compare non-URL entries |
205 | ||
206 | 453 | upi=(URLPrincipal)e.getEntryName(); |
207 | ||
208 | 453 | int port = upi.getPort(); // it may be -1 |
209 | 0 | if (port<0) port=defaultPort; // assume the default port for this protocol, if port is not specified in the URL |
210 | ||
211 | 453 | String [] up=upi.getPath(); // up and p now will be normalized paths |
212 | 453 | String [] p=pu.getPath(); |
213 | ||
214 | //System.out.println("*** Matching subtrees: "+this+" and "+upi.getName()); //********** | |
215 | ||
216 | 453 | boolean result = upi.getProtocol().compareToIgnoreCase(pu.getProtocol())==0 |
217 | && ( | |
218 | (upi.getUserName()!=null && pu.getUserName()!=null && upi.getUserName().equals(pu.getUserName())) | |
219 | || (upi.getUserName()==null && pu.getUserName()==null) | |
220 | ) | |
221 | && ( | |
222 | (upi.getPassword()!=null && pu.getPassword()!=null && upi.getPassword().equals(pu.getPassword())) | |
223 | || (upi.getPassword()==null && pu.getPassword()==null) | |
224 | ) | |
225 | && port>=minPort && (port<=maxPort || maxPort<0) // I don't need to do the same for minPort, since any port number is greater than -1 | |
226 | && (max<0 || up.length-p.length<=max) // up==upi.getPath(), p=pu.getPath() - the normalised paths of the URLs | |
227 | && up.length-p.length>=min // up should be longer than p - the difference should always be greater than 0 | |
228 | ; | |
229 | ||
230 | 453 | if (result) { |
231 | 415 | if (pu.getHost()!=null && upi.getHost()!=null) { |
232 | 415 | if (!pu.getHost().equals(ANY_HOST)){ |
233 | 318 | if (upi.getHost().compareToIgnoreCase(pu.getHost())!=0){ // look through the alternative IP addresses then |
234 | 35 | result=false; |
235 | ||
236 | 63 | for (int i=0; !result && i<altIP.length; i++){ // loop until result==true or i>=altIP.length |
237 | 28 | result=altIP[i].equals(upi.getHost()); // the upi.getHost() should be an IP address then - match any of the IP addresses in the array |
238 | } | |
239 | } | |
240 | } | |
241 | 0 | } else result=(upi.getHost()==null && pu.getHost()==null); |
242 | ||
243 | } | |
244 | //System.out.println("\tURL matched criteria: "+result+"\n\tmatching paths now: "); //********** | |
245 | ||
246 | // ok, if all other criteria matched, match the paths; check that result is true before each iteration and stop comparing as soon as it becomes false | |
247 | 879 | for (int i=0; result && i<p.length; i++){ // i<up.length always - up is the same length, or longer than p |
248 | 426 | result=up[i].equals(p[i]) || (i==p.length-1 && p[i].equals(".")); // if the path components are not equal (or it is the last component, and the subtree says to match the whole subdirectory), result=false, stop comparing |
249 | //System.out.println("\t\tmatching: "+up[i]+"=="+p[i]+": "+result); //********** | |
250 | } | |
251 | ||
252 | //System.out.println("\tURL matched path: "+result+"\n\tmatching excludes now: "); //********** | |
253 | // ok, it matched the subtree; let's see if it matches any of the exclude statements | |
254 | 453 | if (exclude!=null){ |
255 | 453 | for (int i=0; result && i<exclude.length; i++){ |
256 | 54 | result=!exclude[i].contains(e); |
257 | } | |
258 | } | |
259 | ||
260 | //System.out.println("\tresult: "+result); //********** | |
261 | 453 | return result; |
262 | } | |
263 | ||
264 | 435 | public String toString(){ |
265 | 435 | String exclude=null; |
266 | 435 | if (this.exclude!=null){ |
267 | 409 | exclude=", excluding ["; |
268 | 435 | for (int i=0; i<this.exclude.length; i++){ |
269 | 26 | exclude+=(i==0?"":", ")+this.exclude[i].toString(); |
270 | } | |
271 | 409 | exclude+="]"; |
272 | } | |
273 | ||
274 | 435 | return "URLSubtree with base URL="+pu.getNormalizedURL()+", min="+min+", max="+max+ |
275 | ", minPort="+minPort+", maxPort="+maxPort+", defaultPort="+defaultPort+ | |
276 | ", protocol="+pu.getProtocol()+", user="+pu.getUserName()+ | |
277 | ", password="+pu.getPassword()+", host="+pu.getHost()+ | |
278 | ", path="+pu.getPathString()+ | |
279 | 435 | (exclude==null?"":exclude); |
280 | } | |
281 | ||
282 | 0 | public Object clone() { |
283 | 0 | Subtree[] a = null; |
284 | 0 | if (exclude != null) { |
285 | 0 | a = new Subtree[exclude.length]; |
286 | 0 | System.arraycopy(exclude, 0, a, 0, a.length); |
287 | } | |
288 | 0 | try { |
289 | 0 | return new URLSubtree(pu.getURL(), defaultPort, min, max, a); |
290 | } catch (issrg.pba.rbac.BadURLException bu) { | |
291 | 0 | bu.printStackTrace(); |
292 | 0 | return null; |
293 | } | |
294 | ||
295 | } | |
296 | } |
|