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.1
Committed: Tue Jan 8 14:24:28 2002 UTC (22 years, 3 months ago) by tdb
Branch: MAIN
Branch point for: SERVER_PIRCBOT
Log Message:
Merged ACL code into the util package.
This code was previously in CVS:experimental/server/ACL.

File Contents

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