ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
Revision: 1.11
Committed: Sun Jan 6 23:32:27 2002 UTC (22 years, 4 months ago) by tdb
Branch: MAIN
Changes since 1.10: +10 -11 lines
Log Message:
Minor tweak to the short[] comparing code. By ensuring the wildcarded array
is the first one, we can perform less checks :-) As this is just in a local context,
the tighter coupling to the rest of the code is probably ok.
One more change to be made in the String to short[] method -- it needs to do
some more rigourous tests, and possibly return an error if the String cannot be
parsed into an IP address. At the moment it assumes the add method has
already done this. This could also make the add method neater as it would
not need to do as many checks, and would therefore look neater.

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 tdb 1.11 * @version $Id: ACL.java,v 1.10 2001/12/31 19:25:39 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.11 public static final String REVISION = "$Revision: 1.10 $";
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 tdb 1.9 // add the rule to our array
132 tdb 1.7 _acl.add(new ACLRule(allow, expression, ipaddr, ip));
133 tdb 1.1 }
134    
135 tdb 1.2 /**
136     * Check to see if a string is permitted by the
137     * ACL. Useful for testing, and non-Socket uses
138     * of this class.
139     *
140     * @param address the string to check
141     * @return whether the address was permitted by the ACL
142     */
143 tdb 1.1 public boolean check(String address) {
144 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
145     ACLRule rule = (ACLRule) _acl.get(i);
146     if(StringUtils.wildcardCheck(address, rule._expression)) {
147     return rule._allow;
148 tdb 1.1 }
149     }
150     return _defaultMode;
151     }
152    
153 tdb 1.2 /**
154     * Check to see if an InetAddress is permitted
155     * by the ACL. Perfect for Socket uses of this
156 tdb 1.9 * class. A rule will either be for a name, or
157     * an IP address (this is determined in the add
158     * method), and the appropriate comparison will
159     * be performed.
160 tdb 1.2 *
161     * @param address the InetAddress to check
162     * @return whether the InetAddress was permitted by the ACL
163     */
164 tdb 1.1 public boolean check(InetAddress address) {
165 tdb 1.9 // gather the details first
166 tdb 1.7 String hostname = address.getHostName();
167     String ip = address.getHostAddress();
168     short[] ipaddr = ipStringToShort(ip);
169 tdb 1.9 // check each rule against this InetAddress
170 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
171     ACLRule rule = (ACLRule) _acl.get(i);
172 tdb 1.7 if(rule._iprule) {
173 tdb 1.9 // if this is an IP rule do a short comparison
174 tdb 1.11 // must specify the wildcarded rule first
175     if(compareShorts(rule._ipaddr, ipaddr)) {
176 tdb 1.7 return rule._allow;
177     }
178 tdb 1.1 }
179 tdb 1.7 else {
180 tdb 1.9 // if not do a full blown String comparsion
181 tdb 1.7 if(StringUtils.wildcardCheck(hostname, rule._expression)) {
182     return rule._allow;
183     }
184 tdb 1.1 }
185 tdb 1.7
186 tdb 1.1 }
187 tdb 1.9 // if we haven't matched a rule, return the default
188 tdb 1.1 return _defaultMode;
189     }
190    
191 tdb 1.2 /**
192 tdb 1.5 * Gives a String representation of this ACL.
193 tdb 1.2 *
194     * @return A String representation of this ACL.
195     */
196 tdb 1.5 public String toString() {
197     StringBuffer acl = new StringBuffer();
198 tdb 1.9 // put in the i-scream toString code
199 tdb 1.8 acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
200 tdb 1.5 acl.append("{");
201 tdb 1.9 // put the value of each Rule in the result
202 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
203 tdb 1.6 acl.append((ACLRule) _acl.get(i));
204 tdb 1.5 acl.append(",");
205 tdb 1.1 }
206 tdb 1.9 // put the default mode in the result
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.9 /**
220     * Converts an IP address in String format into
221     * a short array of length 4. Any wildcards, *,
222     * found in the IP address are represented by
223     * a -1.
224     *
225     * @param ip The IP address in String format
226     * @return The IP address in a short[]
227     */
228 tdb 1.7 private short[] ipStringToShort(String ip) {
229     short[] ipaddr = {-1, -1, -1, -1};
230     StringTokenizer st = new StringTokenizer(ip, ".");
231     for(int i=0; i < 4 && st.hasMoreTokens(); i++) {
232     try {
233     ipaddr[i] = Short.parseShort(st.nextToken());
234     }
235     catch(NumberFormatException e) {
236 tdb 1.11 // do nothing...
237 tdb 1.9 // we just want to leave it as -1
238     // -- actually, maybe we want to do more checks in here?
239     // although in this code context it'll probably be ok,
240     // it might be worth verifying wildcards and that the
241     // number is in range...
242 tdb 1.7 }
243     }
244     return ipaddr;
245     }
246    
247 tdb 1.9 /**
248 tdb 1.11 * Compares two short arrays. The first array can contain a -1,
249     * which will always match any value -- it's a wildcard.
250     * They must be the same length to match.
251 tdb 1.9 *
252 tdb 1.11 * @param first The first array to compare (with -1 wildcard if required)
253 tdb 1.9 * @param second The second array to compare
254     * @result the result of the comparison
255     */
256 tdb 1.7 private boolean compareShorts(short[] first, short[] second) {
257     if(first.length != second.length) {
258     return false;
259     }
260     for(int i=0; i < first.length; i++) {
261 tdb 1.11 if(first[i] == -1) {
262 tdb 1.7 continue;
263     }
264     if(first[i] != second[i]) {
265     return false;
266     }
267 tdb 1.10 }
268 tdb 1.7 return true;
269     }
270    
271 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
272    
273     //---ATTRIBUTES---
274    
275     /**
276     * This is the friendly identifier of the
277     * component this class is running in.
278     * eg, a Filter may be called "filter1",
279     * If this class does not have an owning
280     * component, a name from the configuration
281     * can be placed here. This name could also
282     * be changed to null for utility classes.
283     */
284     private String _name = null;
285 tdb 1.2
286     /**
287 tdb 1.3 * The ACL is stored in this ArrayList.
288 tdb 1.2 */
289 tdb 1.3 private ArrayList _acl = new ArrayList();
290 tdb 1.2
291     /**
292     * The default mode of this ACL.
293     */
294 tdb 1.1 private boolean _defaultMode;
295    
296     //---STATIC ATTRIBUTES---
297    
298     //---INNER CLASSES---
299    
300 tdb 1.2 /**
301     * Wrapper class for an ACL rule.
302     */
303 tdb 1.4 private class ACLRule implements Serializable {
304 tdb 1.1
305 tdb 1.2 /**
306     * Construct an ACL rule.
307     *
308     * @param allow whether this is an ALLOW or DENY rule
309     * @param expression what this rule matches
310 tdb 1.9 * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
311 tdb 1.7 * @param iprule whether this is an IP rule
312 tdb 1.2 */
313 tdb 1.7 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
314 tdb 1.1 _allow = allow;
315     _expression = expression;
316 tdb 1.7 _ipaddr = ipaddr;
317     _iprule = iprule;
318 tdb 1.6 }
319    
320     /**
321     * Returns a String representation of this rule.
322     *
323     * @return A String representation of this rule.
324     */
325     public String toString() {
326     if(_allow) {
327     return _expression + "=ALLOW";
328     }
329     else {
330     return _expression + "=DENY";
331     }
332 tdb 1.1 }
333    
334 tdb 1.2 /**
335     * Whether this is an ALLOW or DENY rule.
336     */
337 tdb 1.1 private boolean _allow;
338 tdb 1.2
339     /**
340     * What this rule matches.
341     */
342 tdb 1.1 private String _expression;
343 tdb 1.7
344 tdb 1.9 /**
345     * The IP wildcard, only valid if this
346     * is an IP rule.
347     */
348 tdb 1.7 private short[] _ipaddr;
349    
350     /**
351     * Whether this is an IP rule.
352     */
353     private boolean _iprule;
354 tdb 1.1
355     }
356    
357     }