Clover Coverage Report
Coverage timestamp: Sun Mar 23 2008 08:24:39 GMT
77   296   31   15.4
46   141   0.45   5
5     7  
1    
 
 
  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 toggle 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 toggle 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.&nbsp;URLEntry) and that URLPrincipal matches the Subtree, as
200    * explained above; false otherwise
201    */
 
202  490 toggle 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 toggle 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 toggle 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    }