ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/util/uk/org/iscream/cms/util/ACL.java
Revision: 1.8
Committed: Sun Aug 1 10:41:08 2004 UTC (19 years, 9 months ago) by tdb
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +3 -3 lines
Log Message:
Catch a lot of old URL's and update them. Also remove a couple of old files
that aren't used.

File Contents

# User Rev Content
1 tdb 1.5 /*
2     * i-scream central monitoring system
3 tdb 1.8 * http://www.i-scream.org
4 tdb 1.5 * Copyright (C) 2000-2002 i-scream
5     *
6     * This program is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU General Public License
8     * as published by the Free Software Foundation; either version 2
9     * of the License, or (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19     */
20    
21 tdb 1.1 //---PACKAGE DECLARATION---
22 tdb 1.7 package uk.org.iscream.cms.util;
23 tdb 1.1
24     //---IMPORTS---
25     import java.util.ArrayList;
26     import java.util.StringTokenizer;
27     import java.net.InetAddress;
28     import java.io.Serializable;
29    
30     /**
31     * Access Control List for use primarily
32     * with the ACLServerSocket. It could, however
33     * have other uses as it has a fairly generic
34     * behaviour. Rules are added using the add
35     * method, and then checks can be made using
36     * the relevant check method.
37     *
38     * @author $Author: tdb $
39 tdb 1.8 * @version $Id: ACL.java,v 1.7 2003/02/05 14:27:58 tdb Exp $
40 tdb 1.1 */
41     public class ACL implements Serializable {
42    
43     //---FINAL ATTRIBUTES---
44    
45     /**
46     * The current CVS revision of this class
47     */
48 tdb 1.8 public static final String REVISION = "$Revision: 1.7 $";
49 tdb 1.1
50     /**
51     * static to be used when adding an ALLOW rule to the ACL.
52     */
53     public static final boolean ALLOW = true;
54    
55     /**
56     * static to be used when adding a DENY rule to the ACL.
57     */
58     public static final boolean DENY = false;
59 tdb 1.4
60     /**
61     * default setting for the default mode for a new ACL.
62     */
63     public static final boolean DEFMODE = ACL.ALLOW;
64 tdb 1.1
65     //---STATIC METHODS---
66    
67     //---CONSTRUCTORS---
68    
69     /**
70     * Construct a new Access Control List. The default
71     * mode is to ALLOW anything that isn't explicitly
72     * blocked by a rule.
73     */
74     public ACL() {
75 tdb 1.4 // default to DEFMODE
76     this(DEFMODE);
77 tdb 1.1 }
78    
79     /**
80     * Construct a new Access Control List with a given
81     * default mode. This mode specifies what should
82     * happen if a check does not match any rules.
83     *
84     * @param defaultMode the default mode for non-matched checks
85     */
86     public ACL(boolean defaultMode) {
87 tdb 1.4 setDefaultMode(defaultMode);
88 tdb 1.3 }
89    
90     /**
91     * Construct a new Access Control List with a given
92     * String representation of the ACL rules. The String
93     * should be of the format:
94     * expression:rule;expression:rule;expression:rule...
95     * Where expression is a wildcard to match against, and
96     * rule is either 'ALLOW' or 'DENY'. There is a special
97     * expression of 'DEFAULT' which represents the default
98     * rule (what should happen if no expression is matched
99     * when performing a check).
100     * The default mode is set to ALLOW if one is not
101 tdb 1.4 * specified in the String.
102 tdb 1.3 *
103     * @param acl a String representation of the ACL.
104     */
105     public ACL(String acl) {
106 tdb 1.4 setDefaultMode(DEFMODE);
107     add(acl);
108     }
109    
110     //---PUBLIC METHODS---
111    
112     /**
113     * Add a new rule to the ACL immediately after the
114     * previous rule. The rule can either be an ACL.ALLOW
115     * rule, or an ACL.DENY rule. The expression can
116     * contain a wildcard (a * only). Rules can only be
117     * added to the end of the list.
118     *
119     * param allow whether this is an ALLOW or DENY rule
120     * param expression what this rule matches using wildcards
121     */
122     public void add(boolean allow, String expression) {
123     // try and convert the expression into an IP address
124     short[] ipaddr = ipStringToShort(expression);
125     // a result of null means it's not an IP address
126     // add either a name rule or an IP rule
127     if(ipaddr != null) {
128     _acl.add(new ACLRule(allow, expression, ipaddr, true));
129     }
130     else {
131     _acl.add(new ACLRule(allow, expression, ipaddr, false));
132     }
133     }
134    
135     /**
136     * Add some new rules to the Access Control List in
137     * the form of a String. The String should be of the
138     * following format:
139     * expression:rule;expression:rule;expression:rule...
140     * Where expression is a wildcard to match against, and
141     * rule is either 'ALLOW' or 'DENY'. There is a special
142     * expression of 'DEFAULT' which represents the default
143     * rule (what should happen if no expression is matched
144     * when performing a check).
145     *
146     * @param acl a String representation of the ACL.
147     */
148     public void add(String acl) {
149 tdb 1.3 if(acl != null) {
150     // split the String into expression:rule parts
151     StringTokenizer st1 = new StringTokenizer(acl, ";");
152     while(st1.hasMoreTokens()) {
153     String token1 = st1.nextToken();
154     // if it doesn't have a :, it's not the correct format
155     if(token1.indexOf(":") != -1) {
156     // split into expression and rule part
157     StringTokenizer st2 = new StringTokenizer(token1, ":");
158     String expression = "";
159     String rule = "";
160     if(st2.hasMoreTokens()) {
161     expression = st2.nextToken();
162     }
163     else {
164     // mall-formed?
165     continue;
166     }
167     if(st2.hasMoreTokens()) {
168     rule = st2.nextToken();
169     }
170     else {
171     // mall-formed?
172     continue;
173     }
174     // check to see what sort of rule
175     if(rule.equals("ALLOW")) {
176     // case for special 'DEFAULT' expression
177     if(expression.equals("DEFAULT")) {
178 tdb 1.4 setDefaultMode(ACL.ALLOW);
179 tdb 1.3 }
180     else {
181     add(ACL.ALLOW, expression);
182     }
183     }
184     else if(rule.equals("DENY")) {
185     // case for special 'DEFAULT' expression
186     if(expression.equals("DEFAULT")) {
187 tdb 1.4 setDefaultMode(ACL.DENY);
188 tdb 1.3 }
189     else {
190     add(ACL.DENY, expression);
191     }
192     }
193     // if it's not ALLOW or DENY, it's not a
194     // proper rule, so we'll ignore it
195     }
196     }
197     }
198 tdb 1.1 }
199    
200     /**
201     * Check to see if a string is permitted by the
202     * ACL. Useful for testing, and non-Socket uses
203     * of this class.
204     *
205     * @param address the string to check
206     * @return whether the address was permitted by the ACL
207     */
208     public boolean check(String address) {
209     for(int i=0; i < _acl.size(); i++) {
210     ACLRule rule = (ACLRule) _acl.get(i);
211     if(StringUtils.wildcardMatch(address, rule._expression)) {
212     return rule._allow;
213     }
214     }
215     return _defaultMode;
216     }
217    
218     /**
219     * Check to see if an InetAddress is permitted
220     * by the ACL. Perfect for Socket uses of this
221     * class. A rule will either be for a name, or
222     * an IP address (this is determined in the add
223     * method), and the appropriate comparison will
224     * be performed.
225     *
226     * @param address the InetAddress to check
227     * @return whether the InetAddress was permitted by the ACL
228     */
229     public boolean check(InetAddress address) {
230     // gather the details first
231     String hostname = address.getHostName();
232     String ip = address.getHostAddress();
233     short[] ipaddr = ipStringToShort(ip);
234     // check each rule against this InetAddress
235     for(int i=0; i < _acl.size(); i++) {
236     ACLRule rule = (ACLRule) _acl.get(i);
237     if(rule._iprule) {
238     // if this is an IP rule do a short comparison
239     // must specify the wildcarded rule first
240     if(compareShorts(rule._ipaddr, ipaddr)) {
241     return rule._allow;
242     }
243     }
244     else {
245     // if not do a full blown String comparsion
246     if(StringUtils.wildcardMatch(hostname, rule._expression)) {
247     return rule._allow;
248     }
249     }
250    
251     }
252     // if we haven't matched a rule, return the default
253     return _defaultMode;
254     }
255    
256     /**
257 tdb 1.4 * Clears the ACL and resets the default mode.
258     */
259     public void clear() {
260     // just clear out our underlying ArrayList
261     // containing our ACL objects
262     _acl.clear();
263     // and reset the default mode to the default
264     setDefaultMode(DEFMODE);
265     }
266    
267     /**
268     * Changes the default mode of the ACL. This is what
269     * the check will return if it does not find an explict
270     * rule to match against.
271     *
272     * @param defaultMode the new default mode
273     */
274     public void setDefaultMode(boolean defaultMode) {
275     _defaultMode = defaultMode;
276     }
277    
278     /**
279 tdb 1.1 * Gives a String representation of this ACL.
280     *
281     * @return A String representation of this ACL.
282     */
283     public String toString() {
284     StringBuffer acl = new StringBuffer();
285     // put in the i-scream toString code
286     acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
287     acl.append("{");
288     // put the value of each Rule in the result
289     for(int i=0; i < _acl.size(); i++) {
290     acl.append((ACLRule) _acl.get(i));
291     acl.append(",");
292     }
293     // put the default mode in the result
294     if(_defaultMode) {
295     acl.append("DEFAULT=ALLOW");
296     }
297     else {
298     acl.append("DEFAULT=DENY");
299     }
300     acl.append("}");
301     return acl.toString();
302     }
303    
304     //---PRIVATE METHODS---
305    
306     /**
307     * Converts an IP address in String format into
308     * a short array of length 4. Any wildcards, *,
309     * found in the IP address are represented by
310     * a -1. If the given String is not an IP address
311     * null is returned instead.
312     *
313     * @param ip The IP address in String format
314     * @return The IP address in a short[]
315     */
316     private short[] ipStringToShort(String ip) {
317     // default to expecting it to be an IP
318     // we will try to disprove this :)
319     short[] ipaddr = {-1, -1, -1, -1};
320     int i = 0;
321     String s = "";
322     // tokenize the String on fullstops, so we can break
323     // up the quads of an IP (if it's an IP!)
324     StringTokenizer st = new StringTokenizer(ip, ".");
325     while(st.hasMoreTokens() && i++ < 4) {
326     s = st.nextToken();
327     // if it's a wildcard, we'll skip to the next one
328     // as no more checks are required
329     if(s.equals("*")) {
330     continue;
331     }
332     // attempt to parse it into a short
333     try {
334     short n = Short.parseShort(s);
335     // if it's an int but outside of the
336     // valid range, it can't be an IP
337     if(n < 0 || n > 255) {
338     // give up checking further
339     return null;
340     }
341     ipaddr[i-1] = n;
342     }
343     // if it didn't parse as a short it can't be an IP
344     catch (NumberFormatException e) {
345     // give up checking further
346     return null;
347     }
348     }
349     // we've done 4 parts, so if there's any
350     // more this can't be an IP
351     if(st.hasMoreTokens()) {
352     return null;
353     }
354     // if we've done less than 4, see if the last one
355     // was a wildcard - if it isn't then it's not an IP
356     // -- this allows 129.12.*
357     if(i < 4 && !s.equals("*")) {
358     return null;
359     }
360     // if we had one or less entries it can't be an IP
361     // -- this disallows * matching as an IP due
362     // to the rule above
363     if(i <= 1) {
364     return null;
365     }
366     return ipaddr;
367     }
368    
369     /**
370     * Compares two short arrays. The first array can contain a -1,
371     * which will always match any value -- it's a wildcard.
372     * They must be the same length to match.
373     *
374     * @param first The first array to compare (with -1 wildcard if required)
375     * @param second The second array to compare
376 tdb 1.2 * @return the result of the comparison
377 tdb 1.1 */
378     private boolean compareShorts(short[] first, short[] second) {
379     if(first.length != second.length) {
380     return false;
381     }
382     for(int i=0; i < first.length; i++) {
383     if(first[i] == -1) {
384     continue;
385     }
386     if(first[i] != second[i]) {
387     return false;
388     }
389     }
390     return true;
391     }
392    
393     //---ACCESSOR/MUTATOR METHODS---
394    
395     //---ATTRIBUTES---
396    
397     /**
398     * This is the friendly identifier of the
399     * component this class is running in.
400     * eg, a Filter may be called "filter1",
401     * If this class does not have an owning
402     * component, a name from the configuration
403     * can be placed here. This name could also
404     * be changed to null for utility classes.
405     */
406     private String _name = null;
407    
408     /**
409     * The ACL is stored in this ArrayList.
410     */
411     private ArrayList _acl = new ArrayList();
412    
413     /**
414     * The default mode of this ACL.
415     */
416 tdb 1.4 private boolean _defaultMode = DEFMODE;
417 tdb 1.1
418     //---STATIC ATTRIBUTES---
419    
420     //---INNER CLASSES---
421    
422     /**
423     * Wrapper class for an ACL rule.
424     */
425     private class ACLRule implements Serializable {
426    
427     /**
428     * Construct an ACL rule.
429     *
430     * @param allow whether this is an ALLOW or DENY rule
431     * @param expression what this rule matches
432     * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
433     * @param iprule whether this is an IP rule
434     */
435     private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
436     _allow = allow;
437     _expression = expression;
438     _ipaddr = ipaddr;
439     _iprule = iprule;
440     }
441    
442     /**
443     * Returns a String representation of this rule.
444     *
445     * @return A String representation of this rule.
446     */
447     public String toString() {
448     if(_allow) {
449     return _expression + "=ALLOW";
450     }
451     else {
452     return _expression + "=DENY";
453     }
454     }
455    
456     /**
457     * Whether this is an ALLOW or DENY rule.
458     */
459     private boolean _allow;
460    
461     /**
462     * What this rule matches.
463     */
464     private String _expression;
465    
466     /**
467     * The IP wildcard, only valid if this
468     * is an IP rule.
469     */
470     private short[] _ipaddr;
471    
472     /**
473     * Whether this is an IP rule.
474     */
475     private boolean _iprule;
476    
477     }
478    
479     }