📄 urlsubtree.java
字号:
/*
* Copyright (c) 2000-2005, University of Salford
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the University of Salford nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package issrg.pba.rbac.policies;
import issrg.utils.ParsedURL;
import issrg.pba.rbac.BadURLException;
import issrg.pba.rbac.URLPrincipal;
import issrg.utils.repository.Entry;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* This Subtree implementation specifies a subtree of Entries identified by
* URL. It uses a issrg.utils.ParsedURL utility class to decompose the URL
* and identify the patterns in it, hence support for HTTP-like URLs.
*
* <p>The format of the URL is described in issrg.utils.ParsedURL. Note that
* the host name is either a valid DNS name, or an IP address, or "*"; the port
* can be a number specifying a single port, or a range of ports specified as
* number "-" number.
*
* <p>To match the URLSubtree, the Entry must:
* <ul>
* <li>return a URLPrincipal as the result of getEntryName</li>
* <li>have a protocol that matches the one specified in the Subtree (case of
* the characters is ignored)</li>
* <li>either the Entry and the Subtree specification don't have the user name
* specified, or they should match (case sensitive)</li>
* <li>either the Entry and the Subtree specification don't have the password
* specified, or they should match (case sensitive)</li>
* <li>either the Entry has the same host name, as specified in the Subtree,
* or it must be one of the IP addresses of the host specified in the Subtree,
* or the Subtree host must be specified as "any host" wildcard - "*"</li>
* <li>either the Entry has the same port number as the Subtree (the default
* one is used, if it is not specified explicitly), or the Entry's port must
* match the range of ports specified in the Subtree, or the Subtree doesn't
* have any port specified</li>
* <li>the number of path components in the Entry must exceed the number of
* path components in the Subtree by at least the minimum specified in the
* Subtree (the paths are normalised prior to comparison, as explained below)</li>
* <li>the number of path components in the Entry may exceed the number of
* path components in the Subtree by no more than the maximum specified in the
* Subtree (the paths are normalised prior to comparison, as explained below)</li>
* <li>Entry must have path components matching all of the path components of
* the Subtree (case sensitive; the paths are normalised prior to comparison,
* as explained below)</li>
* </ul>
*
* <p>During path normalisation all the "." and ".." (current directory and
* parent directory respectively) are dereferenced, as explained in
* issrg.utils.ParsedURL.
*/
public class URLSubtree implements Subtree {
/**
* Wildcard used in the policy to specify any host - so any host will be
* matched
* as part of the URL subtree.
*/
public static final String ANY_HOST="*";
public static final String LOCALHOST="localhost";
protected int defaultPort;
protected int min;
protected int max;
protected int minPort;
protected int maxPort;
protected ParsedURL pu;
protected Subtree [] exclude;
protected String [] altIP = {}; // alternative IP addresses for the named host
protected URLSubtree(){}
/**
* This constructor builds a URLSubtree, given a URL string (exceptions are
* outlined below), a default port, the min and max levels from the base
* directory.
*
* <p>The URL may contain a range of ports, not just one port. The range is
* specified as nn-mm, where nn is the starting port number, and mm - the
* ending port number. The subtree then matches any URLs with the port
* matching any of the numbers between nn and mm, inclusive.
*
* <p>If the URL has the host specified by DNS name, then its IP addresses
* will be looked up, so that the Entries will match the Subtree by either
* of the IP addresses, or by the DNS name. If the host is specified as a
* wildcard "*", Entries with any host will match.
*
* @param url is the URL string
* @param defaultPort is the default port to assume for Entries with URLs
* that do not specify any port
* @param min is the minimum number of levels below the base URL that the
* Entry URL should be in; if the Entry is above this level, it doesn't
* match this subtree
* @param max is the maximum number of levels below the base URL that the
* Entry URL should be in; if the Entry is below this level, it doesn't
* match this subtree
*
* @throws BadURLException, if the url string doesn't match the URL
* specification
* (except for the port range bit), or the port numbers are not valid
* integers
*/
public URLSubtree(String url, int defaultPort, int min, int max, Subtree [] exclude) throws BadURLException {
Exception e=null;
int minPort=-1; // unlimited
int maxPort=-1; // unlimited
pu = ParsedURL.parseURL(url);
String port;
if (pu!=null && (port=pu.getPort())!=null){
try{
int j=port.indexOf('-');
if (port.indexOf('-')<0) { // no range of ports has been specified
j=port.length();
port+="-"+port; // treat it as a range of ports: n <=> n-n
}
if (j>=port.length()-1) port+="65535"; // if no port is specified at the end, append the port
minPort = Integer.parseInt(port.substring(0, j));
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 "-"
} catch (NumberFormatException nfe) {
e=nfe;
pu=null;
}
}
if (pu==null) throw new BadURLException("Malformed URL: "+url, e);
if (!pu.getHost().equals(ANY_HOST)) {
InetAddress [] hostAddresses = new InetAddress[0];
InetAddress [] lhAddresses = new InetAddress[0];
try{
hostAddresses = InetAddress.getAllByName(pu.getHost());
}catch (UnknownHostException uhe){
// log that the host wasn't found
}
try{
if (pu.getHost().compareToIgnoreCase(LOCALHOST)==0)
lhAddresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName()); // if it is a "localhost", then look up other host names
}catch (UnknownHostException uhe){
// this shouldn't happen
}
// and their addresses
altIP = new String[hostAddresses.length+lhAddresses.length];
for (int i=0; i<hostAddresses.length; i++){
altIP[i]=hostAddresses[i].getHostAddress();
}
for (int i=0; i<lhAddresses.length; i++){
altIP[i+hostAddresses.length]=lhAddresses[i].getHostAddress();
}
}
this.defaultPort=defaultPort;
this.min=min;
this.max=max;
this.minPort=minPort;
this.maxPort=maxPort;
this.exclude=exclude;
}
/**
* This method tests whether Entry e is part of this Subtree.
*
* @return true, if e's getEntryName returns a URLPrincipal
* (e.g. URLEntry) and that URLPrincipal matches the Subtree, as
* explained above; false otherwise
*/
public boolean contains(Entry e){
URLPrincipal upi;
if (!(e.getEntryName() instanceof URLPrincipal)) return false; // cannot compare non-URL entries
upi=(URLPrincipal)e.getEntryName();
int port = upi.getPort(); // it may be -1
if (port<0) port=defaultPort; // assume the default port for this protocol, if port is not specified in the URL
String [] up=upi.getPath(); // up and p now will be normalized paths
String [] p=pu.getPath();
//System.out.println("*** Matching subtrees: "+this+" and "+upi.getName()); //**********
boolean result = upi.getProtocol().compareToIgnoreCase(pu.getProtocol())==0
&& (
(upi.getUserName()!=null && pu.getUserName()!=null && upi.getUserName().equals(pu.getUserName()))
|| (upi.getUserName()==null && pu.getUserName()==null)
)
&& (
(upi.getPassword()!=null && pu.getPassword()!=null && upi.getPassword().equals(pu.getPassword()))
|| (upi.getPassword()==null && pu.getPassword()==null)
)
&& port>=minPort && (port<=maxPort || maxPort<0) // I don't need to do the same for minPort, since any port number is greater than -1
&& (max<0 || up.length-p.length<=max) // up==upi.getPath(), p=pu.getPath() - the normalised paths of the URLs
&& up.length-p.length>=min // up should be longer than p - the difference should always be greater than 0
;
if (result) {
if (pu.getHost()!=null && upi.getHost()!=null) {
if (!pu.getHost().equals(ANY_HOST)){
if (upi.getHost().compareToIgnoreCase(pu.getHost())!=0){ // look through the alternative IP addresses then
result=false;
for (int i=0; !result && i<altIP.length; i++){ // loop until result==true or i>=altIP.length
result=altIP[i].equals(upi.getHost()); // the upi.getHost() should be an IP address then - match any of the IP addresses in the array
}
}
}
} else result=(upi.getHost()==null && pu.getHost()==null);
}
//System.out.println("\tURL matched criteria: "+result+"\n\tmatching paths now: "); //**********
// 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
for (int i=0; result && i<p.length; i++){ // i<up.length always - up is the same length, or longer than p
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
//System.out.println("\t\tmatching: "+up[i]+"=="+p[i]+": "+result); //**********
}
//System.out.println("\tURL matched path: "+result+"\n\tmatching excludes now: "); //**********
// ok, it matched the subtree; let's see if it matches any of the exclude statements
if (exclude!=null){
for (int i=0; result && i<exclude.length; i++){
result=!exclude[i].contains(e);
}
}
//System.out.println("\tresult: "+result); //**********
return result;
}
public String toString(){
String exclude=null;
if (this.exclude!=null){
exclude=", excluding [";
for (int i=0; i<this.exclude.length; i++){
exclude+=(i==0?"":", ")+this.exclude[i].toString();
}
exclude+="]";
}
return "URLSubtree with base URL="+pu.getNormalizedURL()+", min="+min+", max="+max+
", minPort="+minPort+", maxPort="+maxPort+", defaultPort="+defaultPort+
", protocol="+pu.getProtocol()+", user="+pu.getUserName()+
", password="+pu.getPassword()+", host="+pu.getHost()+
", path="+pu.getPathString()+
(exclude==null?"":exclude);
}
public Object clone() {
Subtree[] a = null;
if (exclude != null) {
a = new Subtree[exclude.length];
System.arraycopy(exclude, 0, a, 0, a.length);
}
try {
return new URLSubtree(pu.getURL(), defaultPort, min, max, a);
} catch (issrg.pba.rbac.BadURLException bu) {
bu.printStackTrace();
return null;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -