ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
Revision: 1.7
Committed: Mon Dec 31 01:49:13 2001 UTC (22 years, 11 months ago) by tdb
Branch: MAIN
Changes since 1.6: +122 -6 lines
Log Message:
Some significant internal changes. It should be noted that this code is still in
the debugging stage, and thus contains lots of println's :-)
The most obvious change is that when adding a rule we try to determine if it's
and IP address given as the expression. If it is, we store this in a short[] in the
ACLRule inner class. Then when performing a check we look to see if it's an
IP address rule, and then do a special check for IP addresses - which is much
more efficient than comparing two strings. We have also halved the checks
done by only comparing a rule to either the name or IP, rather than both.

File Contents

# User Rev Content
1 tdb 1.1 //---PACKAGE DECLARATION---
2     //package uk.org.iscream.cms.server.util;
3    
4     //---IMPORTS---
5     import uk.org.iscream.cms.server.util.*;
6 tdb 1.3 import java.util.ArrayList;
7 tdb 1.7 import java.util.StringTokenizer;
8 tdb 1.1 import java.net.InetAddress;
9 tdb 1.4 import java.io.Serializable;
10 tdb 1.1
11     /**
12 tdb 1.2 * Access Control List for use primarily
13     * with the ACLServerSocket. It could, however
14     * have other uses as it has a fairly generic
15     * behaviour. Rules are added using the add
16     * method, and then checks can be made using
17     * the relevant check method.
18 tdb 1.1 *
19 tdb 1.6 * @author $Author: tdb $
20     * @version $Id: ACL.java,v 1.5 2001/12/23 01:05:35 tdb Exp $
21 tdb 1.1 */
22 tdb 1.4 public class ACL implements Serializable {
23 tdb 1.1
24     //---FINAL ATTRIBUTES---
25    
26     /**
27     * The current CVS revision of this class
28     */
29 tdb 1.6 public static final String REVISION = "$Revision: 1.5 $";
30 tdb 1.2
31     /**
32     * static to be used when adding an ALLOW rule to the ACL.
33     */
34 tdb 1.1 public static final boolean ALLOW = true;
35 tdb 1.2
36     /**
37     * static to be used when adding a DENY rule to the ACL.
38     */
39 tdb 1.1 public static final boolean DENY = false;
40    
41     //---STATIC METHODS---
42    
43     //---CONSTRUCTORS---
44    
45 tdb 1.2 /**
46     * Construct a new Access Control List. The default
47     * mode is to ALLOW anything that isn't explicitly
48     * blocked by a rule.
49     */
50 tdb 1.1 public ACL() {
51     // default to ACL.ALLOW
52     this(ACL.ALLOW);
53     }
54    
55 tdb 1.2 /**
56     * Construct a new Access Control List with a given
57     * default mode. This mode specifies what should
58     * happen if a check does not match any rules.
59     *
60     * @param defaultMode the default mode for non-matched checks
61     */
62 tdb 1.1 public ACL(boolean defaultMode) {
63     _defaultMode = defaultMode;
64     }
65    
66     //---PUBLIC METHODS---
67    
68 tdb 1.2 /**
69     * Add a new rule to the ACL immediately after the
70     * previous rule. The rule can either be an ACL.ALLOW
71     * rule, or an ACL.DENY rule. The expression can
72     * contain a wildcard (a * only). Rules can only be
73     * added to the end of the list.
74     *
75     * param allow whether this is an ALLOW or DENY rule
76     * param expression what this rule matches using wildcards
77     */
78 tdb 1.1 public void add(boolean allow, String expression) {
79 tdb 1.7 // default to expecting it to be an IP
80     // we will try to disprove this :)
81     boolean ip = true;
82     short[] ipaddr = {-1, -1, -1, -1};
83     int i = 0;
84     String s = "";
85     // tokenize the expression on fullstops, so we can break
86     // up the quads of an IP (if it's an IP!)
87     StringTokenizer st = new StringTokenizer(expression, ".");
88     while(st.hasMoreTokens() && i++ < 4) {
89     s = st.nextToken();
90     // if it's a wildcard, we'll skip to the next one
91     // as no more checks are required
92     if(s.equals("*")) {
93     continue;
94     }
95     // attempt to parse it into a short
96     try {
97     short n = Short.parseShort(s);
98     // if it's an int but outside of the
99     // valid range, it can't be an IP
100     if(n < 0 || n > 255) {
101     ip = false;
102     // give up checking further
103     break;
104     }
105     ipaddr[i-1] = n;
106     }
107     // if it didn't parse as an int it can't be an IP
108     catch (NumberFormatException e) {
109     ip = false;
110     // give up checking further
111     break;
112     }
113     }
114     // we've done 4 parts, so if there's any
115     // more this can't be an IP
116     if(st.hasMoreTokens()) {
117     ip = false;
118     }
119     // if we've done less than 4, see if the last one
120     // was a wildcard - if it isn't then it's not an IP
121     // -- this allows 129.12.*
122     if(i < 4 && !s.equals("*")) {
123     ip = false;
124     }
125     // if we had one or less entries it can't be an IP
126     // -- this disallows * matching as an IP due
127     // to the rule above
128     if(i <= 1) {
129     ip = false;
130     }
131     // finally print out what we've found.
132     System.out.println("IP("+ip+"): "+expression);
133     if(ip) {
134     for(int j=0; j < ipaddr.length; j++) {
135     System.out.print(ipaddr[j] + " ");
136     }
137     System.out.println();
138     }
139     _acl.add(new ACLRule(allow, expression, ipaddr, ip));
140 tdb 1.1 }
141    
142 tdb 1.2 /**
143     * Check to see if a string is permitted by the
144     * ACL. Useful for testing, and non-Socket uses
145     * of this class.
146     *
147     * @param address the string to check
148     * @return whether the address was permitted by the ACL
149     */
150 tdb 1.1 public boolean check(String address) {
151 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
152     ACLRule rule = (ACLRule) _acl.get(i);
153     if(StringUtils.wildcardCheck(address, rule._expression)) {
154     return rule._allow;
155 tdb 1.1 }
156     }
157     return _defaultMode;
158     }
159    
160 tdb 1.2 /**
161     * Check to see if an InetAddress is permitted
162     * by the ACL. Perfect for Socket uses of this
163     * class. It should be made clear that this will
164     * check both the hostname AND IP address against
165     * each rule in turn. The hostname will always be
166     * checked BEFORE the IP address.
167     *
168     * @param address the InetAddress to check
169     * @return whether the InetAddress was permitted by the ACL
170     */
171 tdb 1.1 public boolean check(InetAddress address) {
172 tdb 1.7 String hostname = address.getHostName();
173     String ip = address.getHostAddress();
174     short[] ipaddr = ipStringToShort(ip);
175 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
176     ACLRule rule = (ACLRule) _acl.get(i);
177 tdb 1.7 if(rule._iprule) {
178     System.out.println("checking ip rule "+rule._expression);
179     //if(StringUtils.wildcardCheck(ip, rule._expression)) {
180     if(compareShorts(ipaddr, rule._ipaddr)) {
181     return rule._allow;
182     }
183 tdb 1.1 }
184 tdb 1.7 else {
185     System.out.println("checking name rule: "+rule._expression);
186     if(StringUtils.wildcardCheck(hostname, rule._expression)) {
187     return rule._allow;
188     }
189 tdb 1.1 }
190 tdb 1.7
191 tdb 1.1 }
192     return _defaultMode;
193     }
194    
195 tdb 1.2 /**
196 tdb 1.5 * Gives a String representation of this ACL.
197 tdb 1.2 *
198     * @return A String representation of this ACL.
199     */
200 tdb 1.5 public String toString() {
201     StringBuffer acl = new StringBuffer();
202     acl.append("{");
203 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
204 tdb 1.6 acl.append((ACLRule) _acl.get(i));
205 tdb 1.5 acl.append(",");
206 tdb 1.1 }
207 tdb 1.3 if(_defaultMode) {
208 tdb 1.5 acl.append("DEFAULT=ALLOW");
209 tdb 1.3 }
210     else {
211 tdb 1.5 acl.append("DEFAULT=DENY");
212 tdb 1.3 }
213 tdb 1.5 acl.append("}");
214     return acl.toString();
215 tdb 1.1 }
216    
217     //---PRIVATE METHODS---
218    
219 tdb 1.7 private short[] ipStringToShort(String ip) {
220     short[] ipaddr = {-1, -1, -1, -1};
221     StringTokenizer st = new StringTokenizer(ip, ".");
222     for(int i=0; i < 4 && st.hasMoreTokens(); i++) {
223     try {
224     ipaddr[i] = Short.parseShort(st.nextToken());
225     }
226     catch(NumberFormatException e) {
227     // do nothing?
228     }
229     }
230     return ipaddr;
231     }
232    
233     private boolean compareShorts(short[] first, short[] second) {
234     if(first.length != second.length) {
235     System.out.println("not equal length");
236     return false;
237     }
238     for(int i=0; i < first.length; i++) {
239     // -- might want to consider specify which is the wildcard one?
240     System.out.println(i + ":" + first[i] + "," + second[i]);
241     if(first[i] == -1 || second[i] == -1) {
242     continue;
243     }
244     if(first[i] != second[i]) {
245     System.out.println("not equal");
246     return false;
247     }
248     }
249     System.out.println("equal");
250     return true;
251     }
252    
253 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
254    
255     //---ATTRIBUTES---
256    
257     /**
258     * This is the friendly identifier of the
259     * component this class is running in.
260     * eg, a Filter may be called "filter1",
261     * If this class does not have an owning
262     * component, a name from the configuration
263     * can be placed here. This name could also
264     * be changed to null for utility classes.
265     */
266     private String _name = null;
267 tdb 1.2
268     /**
269 tdb 1.3 * The ACL is stored in this ArrayList.
270 tdb 1.2 */
271 tdb 1.3 private ArrayList _acl = new ArrayList();
272 tdb 1.2
273     /**
274     * The default mode of this ACL.
275     */
276 tdb 1.1 private boolean _defaultMode;
277    
278     //---STATIC ATTRIBUTES---
279    
280     //---INNER CLASSES---
281    
282 tdb 1.2 /**
283     * Wrapper class for an ACL rule.
284     */
285 tdb 1.4 private class ACLRule implements Serializable {
286 tdb 1.1
287 tdb 1.2 /**
288     * Construct an ACL rule.
289     *
290     * @param allow whether this is an ALLOW or DENY rule
291     * @param expression what this rule matches
292 tdb 1.7 * @param iprule whether this is an IP rule
293 tdb 1.2 */
294 tdb 1.7 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
295 tdb 1.1 _allow = allow;
296     _expression = expression;
297 tdb 1.7 _ipaddr = ipaddr;
298     _iprule = iprule;
299 tdb 1.6 }
300    
301     /**
302     * Returns a String representation of this rule.
303     *
304     * @return A String representation of this rule.
305     */
306     public String toString() {
307     if(_allow) {
308     return _expression + "=ALLOW";
309     }
310     else {
311     return _expression + "=DENY";
312     }
313 tdb 1.1 }
314    
315 tdb 1.2 /**
316     * Whether this is an ALLOW or DENY rule.
317     */
318 tdb 1.1 private boolean _allow;
319 tdb 1.2
320     /**
321     * What this rule matches.
322     */
323 tdb 1.1 private String _expression;
324 tdb 1.7
325     private short[] _ipaddr;
326    
327     /**
328     * Whether this is an IP rule.
329     */
330     private boolean _iprule;
331 tdb 1.1
332     }
333    
334     }