--- experimental/server/ACL/ACL.java 2001/12/24 04:17:29 1.6 +++ experimental/server/ACL/ACL.java 2002/01/08 13:31:34 1.12 @@ -4,6 +4,7 @@ //---IMPORTS--- import uk.org.iscream.cms.server.util.*; import java.util.ArrayList; +import java.util.StringTokenizer; import java.net.InetAddress; import java.io.Serializable; @@ -16,7 +17,7 @@ import java.io.Serializable; * the relevant check method. * * @author $Author: tdb $ - * @version $Id: ACL.java,v 1.6 2001/12/24 04:17:29 tdb Exp $ + * @version $Id: ACL.java,v 1.12 2002/01/08 13:31:34 tdb Exp $ */ public class ACL implements Serializable { @@ -25,7 +26,7 @@ public class ACL implements Serializable { /** * The current CVS revision of this class */ - public static final String REVISION = "$Revision: 1.6 $"; + public static final String REVISION = "$Revision: 1.12 $"; /** * static to be used when adding an ALLOW rule to the ACL. @@ -75,7 +76,16 @@ public class ACL implements Serializable { * param expression what this rule matches using wildcards */ public void add(boolean allow, String expression) { - _acl.add(new ACLRule(allow, expression)); + // try and convert the expression into an IP address + short[] ipaddr = ipStringToShort(expression); + // a result of null means it's not an IP address + // add either a name rule or an IP rule + if(ipaddr != null) { + _acl.add(new ACLRule(allow, expression, ipaddr, true)); + } + else { + _acl.add(new ACLRule(allow, expression, ipaddr, false)); + } } /** @@ -89,7 +99,7 @@ public class ACL implements Serializable { public boolean check(String address) { for(int i=0; i < _acl.size(); i++) { ACLRule rule = (ACLRule) _acl.get(i); - if(StringUtils.wildcardCheck(address, rule._expression)) { + if(StringUtils.wildcardMatch(address, rule._expression)) { return rule._allow; } } @@ -99,24 +109,38 @@ public class ACL implements Serializable { /** * Check to see if an InetAddress is permitted * by the ACL. Perfect for Socket uses of this - * class. It should be made clear that this will - * check both the hostname AND IP address against - * each rule in turn. The hostname will always be - * checked BEFORE the IP address. + * class. A rule will either be for a name, or + * an IP address (this is determined in the add + * method), and the appropriate comparison will + * be performed. * * @param address the InetAddress to check * @return whether the InetAddress was permitted by the ACL */ public boolean check(InetAddress address) { + // gather the details first + String hostname = address.getHostName(); + String ip = address.getHostAddress(); + short[] ipaddr = ipStringToShort(ip); + // check each rule against this InetAddress for(int i=0; i < _acl.size(); i++) { ACLRule rule = (ACLRule) _acl.get(i); - if(StringUtils.wildcardCheck(address.getHostName(), rule._expression)) { - return rule._allow; + if(rule._iprule) { + // if this is an IP rule do a short comparison + // must specify the wildcarded rule first + if(compareShorts(rule._ipaddr, ipaddr)) { + return rule._allow; + } } - if(StringUtils.wildcardCheck(address.getHostAddress(), rule._expression)) { - return rule._allow; + else { + // if not do a full blown String comparsion + if(StringUtils.wildcardMatch(hostname, rule._expression)) { + return rule._allow; + } } + } + // if we haven't matched a rule, return the default return _defaultMode; } @@ -127,11 +151,15 @@ public class ACL implements Serializable { */ public String toString() { StringBuffer acl = new StringBuffer(); + // put in the i-scream toString code + acl.append(FormatName.getName(_name, getClass().getName(), REVISION)); acl.append("{"); + // put the value of each Rule in the result for(int i=0; i < _acl.size(); i++) { acl.append((ACLRule) _acl.get(i)); acl.append(","); } + // put the default mode in the result if(_defaultMode) { acl.append("DEFAULT=ALLOW"); } @@ -144,6 +172,93 @@ public class ACL implements Serializable { //---PRIVATE METHODS--- + /** + * Converts an IP address in String format into + * a short array of length 4. Any wildcards, *, + * found in the IP address are represented by + * a -1. If the given String is not an IP address + * null is returned instead. + * + * @param ip The IP address in String format + * @return The IP address in a short[] + */ + private short[] ipStringToShort(String ip) { + // default to expecting it to be an IP + // we will try to disprove this :) + short[] ipaddr = {-1, -1, -1, -1}; + int i = 0; + String s = ""; + // tokenize the String on fullstops, so we can break + // up the quads of an IP (if it's an IP!) + StringTokenizer st = new StringTokenizer(ip, "."); + while(st.hasMoreTokens() && i++ < 4) { + s = st.nextToken(); + // if it's a wildcard, we'll skip to the next one + // as no more checks are required + if(s.equals("*")) { + continue; + } + // attempt to parse it into a short + try { + short n = Short.parseShort(s); + // if it's an int but outside of the + // valid range, it can't be an IP + if(n < 0 || n > 255) { + // give up checking further + return null; + } + ipaddr[i-1] = n; + } + // if it didn't parse as a short it can't be an IP + catch (NumberFormatException e) { + // give up checking further + return null; + } + } + // we've done 4 parts, so if there's any + // more this can't be an IP + if(st.hasMoreTokens()) { + return null; + } + // if we've done less than 4, see if the last one + // was a wildcard - if it isn't then it's not an IP + // -- this allows 129.12.* + if(i < 4 && !s.equals("*")) { + return null; + } + // if we had one or less entries it can't be an IP + // -- this disallows * matching as an IP due + // to the rule above + if(i <= 1) { + return null; + } + return ipaddr; + } + + /** + * Compares two short arrays. The first array can contain a -1, + * which will always match any value -- it's a wildcard. + * They must be the same length to match. + * + * @param first The first array to compare (with -1 wildcard if required) + * @param second The second array to compare + * @result the result of the comparison + */ + private boolean compareShorts(short[] first, short[] second) { + if(first.length != second.length) { + return false; + } + for(int i=0; i < first.length; i++) { + if(first[i] == -1) { + continue; + } + if(first[i] != second[i]) { + return false; + } + } + return true; + } + //---ACCESSOR/MUTATOR METHODS--- //---ATTRIBUTES--- @@ -183,10 +298,14 @@ public class ACL implements Serializable { * * @param allow whether this is an ALLOW or DENY rule * @param expression what this rule matches + * @param ipaddr the IP address wildcard this rule matches if it's an IP rule + * @param iprule whether this is an IP rule */ - private ACLRule(boolean allow, String expression) { + private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) { _allow = allow; _expression = expression; + _ipaddr = ipaddr; + _iprule = iprule; } /** @@ -212,6 +331,17 @@ public class ACL implements Serializable { * What this rule matches. */ private String _expression; + + /** + * The IP wildcard, only valid if this + * is an IP rule. + */ + private short[] _ipaddr; + + /** + * Whether this is an IP rule. + */ + private boolean _iprule; }