ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
Revision: 1.10
Committed: Mon Dec 31 19:25:39 2001 UTC (22 years, 4 months ago) by tdb
Branch: MAIN
Changes since 1.9: +1 -0 lines
Log Message:
Opps. Lost a bracket. Right, it's time to go out for New Year :-) In fact, this
commit log will be mailed at about 1 minute into 2002 ;-)

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.9 * @version $Id: ACL.java,v 1.8 2001/12/31 02:57:00 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.9 public static final String REVISION = "$Revision: 1.8 $";
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.7 if(compareShorts(ipaddr, rule._ipaddr)) {
175     return rule._allow;
176     }
177 tdb 1.1 }
178 tdb 1.7 else {
179 tdb 1.9 // if not do a full blown String comparsion
180 tdb 1.7 if(StringUtils.wildcardCheck(hostname, rule._expression)) {
181     return rule._allow;
182     }
183 tdb 1.1 }
184 tdb 1.7
185 tdb 1.1 }
186 tdb 1.9 // if we haven't matched a rule, return the default
187 tdb 1.1 return _defaultMode;
188     }
189    
190 tdb 1.2 /**
191 tdb 1.5 * Gives a String representation of this ACL.
192 tdb 1.2 *
193     * @return A String representation of this ACL.
194     */
195 tdb 1.5 public String toString() {
196     StringBuffer acl = new StringBuffer();
197 tdb 1.9 // put in the i-scream toString code
198 tdb 1.8 acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
199 tdb 1.5 acl.append("{");
200 tdb 1.9 // put the value of each Rule in the result
201 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
202 tdb 1.6 acl.append((ACLRule) _acl.get(i));
203 tdb 1.5 acl.append(",");
204 tdb 1.1 }
205 tdb 1.9 // put the default mode in the result
206 tdb 1.3 if(_defaultMode) {
207 tdb 1.5 acl.append("DEFAULT=ALLOW");
208 tdb 1.3 }
209     else {
210 tdb 1.5 acl.append("DEFAULT=DENY");
211 tdb 1.3 }
212 tdb 1.5 acl.append("}");
213     return acl.toString();
214 tdb 1.1 }
215    
216     //---PRIVATE METHODS---
217    
218 tdb 1.9 /**
219     * Converts an IP address in String format into
220     * a short array of length 4. Any wildcards, *,
221     * found in the IP address are represented by
222     * a -1.
223     *
224     * @param ip The IP address in String format
225     * @return The IP address in a short[]
226     */
227 tdb 1.7 private short[] ipStringToShort(String ip) {
228     short[] ipaddr = {-1, -1, -1, -1};
229     StringTokenizer st = new StringTokenizer(ip, ".");
230     for(int i=0; i < 4 && st.hasMoreTokens(); i++) {
231     try {
232     ipaddr[i] = Short.parseShort(st.nextToken());
233     }
234     catch(NumberFormatException e) {
235     // do nothing?
236 tdb 1.9 // we just want to leave it as -1
237     // -- actually, maybe we want to do more checks in here?
238     // although in this code context it'll probably be ok,
239     // it might be worth verifying wildcards and that the
240     // number is in range...
241 tdb 1.7 }
242     }
243     return ipaddr;
244     }
245    
246 tdb 1.9 /**
247     * Compares two short arrays. The array can contain a -1, which
248     * will always match any value -- it's a wildcard. They must be
249     * the same length to match. At the moment the order of the
250     * parameters does not matter.
251     *
252     * @param first The first array to compare
253     * @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     // -- might want to consider specify which is the wildcard one?
262     if(first[i] == -1 || second[i] == -1) {
263     continue;
264     }
265     if(first[i] != second[i]) {
266     return false;
267     }
268 tdb 1.10 }
269 tdb 1.7 return true;
270     }
271    
272 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
273    
274     //---ATTRIBUTES---
275    
276     /**
277     * This is the friendly identifier of the
278     * component this class is running in.
279     * eg, a Filter may be called "filter1",
280     * If this class does not have an owning
281     * component, a name from the configuration
282     * can be placed here. This name could also
283     * be changed to null for utility classes.
284     */
285     private String _name = null;
286 tdb 1.2
287     /**
288 tdb 1.3 * The ACL is stored in this ArrayList.
289 tdb 1.2 */
290 tdb 1.3 private ArrayList _acl = new ArrayList();
291 tdb 1.2
292     /**
293     * The default mode of this ACL.
294     */
295 tdb 1.1 private boolean _defaultMode;
296    
297     //---STATIC ATTRIBUTES---
298    
299     //---INNER CLASSES---
300    
301 tdb 1.2 /**
302     * Wrapper class for an ACL rule.
303     */
304 tdb 1.4 private class ACLRule implements Serializable {
305 tdb 1.1
306 tdb 1.2 /**
307     * Construct an ACL rule.
308     *
309     * @param allow whether this is an ALLOW or DENY rule
310     * @param expression what this rule matches
311 tdb 1.9 * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
312 tdb 1.7 * @param iprule whether this is an IP rule
313 tdb 1.2 */
314 tdb 1.7 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
315 tdb 1.1 _allow = allow;
316     _expression = expression;
317 tdb 1.7 _ipaddr = ipaddr;
318     _iprule = iprule;
319 tdb 1.6 }
320    
321     /**
322     * Returns a String representation of this rule.
323     *
324     * @return A String representation of this rule.
325     */
326     public String toString() {
327     if(_allow) {
328     return _expression + "=ALLOW";
329     }
330     else {
331     return _expression + "=DENY";
332     }
333 tdb 1.1 }
334    
335 tdb 1.2 /**
336     * Whether this is an ALLOW or DENY rule.
337     */
338 tdb 1.1 private boolean _allow;
339 tdb 1.2
340     /**
341     * What this rule matches.
342     */
343 tdb 1.1 private String _expression;
344 tdb 1.7
345 tdb 1.9 /**
346     * The IP wildcard, only valid if this
347     * is an IP rule.
348     */
349 tdb 1.7 private short[] _ipaddr;
350    
351     /**
352     * Whether this is an IP rule.
353     */
354     private boolean _iprule;
355 tdb 1.1
356     }
357    
358     }