ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
Revision: 1.12
Committed: Tue Jan 8 13:31:34 2002 UTC (22 years, 4 months ago) by tdb
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +57 -66 lines
Log Message:
Some final tidying to the ACL code. The IP address checking has been moved
out of the add method to a more suitable location. The code now seems to be
more readable. This should be the last 'feature' that needs doing.

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.12 * @version $Id: ACL.java,v 1.11 2002/01/06 23:32:27 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.12 public static final String REVISION = "$Revision: 1.11 $";
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.12 // try and convert the expression into an IP address
80     short[] ipaddr = ipStringToShort(expression);
81     // a result of null means it's not an IP address
82     // add either a name rule or an IP rule
83     if(ipaddr != null) {
84     _acl.add(new ACLRule(allow, expression, ipaddr, true));
85 tdb 1.7 }
86 tdb 1.12 else {
87     _acl.add(new ACLRule(allow, expression, ipaddr, false));
88 tdb 1.7 }
89 tdb 1.1 }
90    
91 tdb 1.2 /**
92     * Check to see if a string is permitted by the
93     * ACL. Useful for testing, and non-Socket uses
94     * of this class.
95     *
96     * @param address the string to check
97     * @return whether the address was permitted by the ACL
98     */
99 tdb 1.1 public boolean check(String address) {
100 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
101     ACLRule rule = (ACLRule) _acl.get(i);
102 tdb 1.12 if(StringUtils.wildcardMatch(address, rule._expression)) {
103 tdb 1.3 return rule._allow;
104 tdb 1.1 }
105     }
106     return _defaultMode;
107     }
108    
109 tdb 1.2 /**
110     * Check to see if an InetAddress is permitted
111     * by the ACL. Perfect for Socket uses of this
112 tdb 1.9 * class. A rule will either be for a name, or
113     * an IP address (this is determined in the add
114     * method), and the appropriate comparison will
115     * be performed.
116 tdb 1.2 *
117     * @param address the InetAddress to check
118     * @return whether the InetAddress was permitted by the ACL
119     */
120 tdb 1.1 public boolean check(InetAddress address) {
121 tdb 1.9 // gather the details first
122 tdb 1.7 String hostname = address.getHostName();
123     String ip = address.getHostAddress();
124     short[] ipaddr = ipStringToShort(ip);
125 tdb 1.9 // check each rule against this InetAddress
126 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
127     ACLRule rule = (ACLRule) _acl.get(i);
128 tdb 1.7 if(rule._iprule) {
129 tdb 1.9 // if this is an IP rule do a short comparison
130 tdb 1.11 // must specify the wildcarded rule first
131     if(compareShorts(rule._ipaddr, ipaddr)) {
132 tdb 1.7 return rule._allow;
133     }
134 tdb 1.1 }
135 tdb 1.7 else {
136 tdb 1.9 // if not do a full blown String comparsion
137 tdb 1.12 if(StringUtils.wildcardMatch(hostname, rule._expression)) {
138 tdb 1.7 return rule._allow;
139     }
140 tdb 1.1 }
141 tdb 1.7
142 tdb 1.1 }
143 tdb 1.9 // if we haven't matched a rule, return the default
144 tdb 1.1 return _defaultMode;
145     }
146    
147 tdb 1.2 /**
148 tdb 1.5 * Gives a String representation of this ACL.
149 tdb 1.2 *
150     * @return A String representation of this ACL.
151     */
152 tdb 1.5 public String toString() {
153     StringBuffer acl = new StringBuffer();
154 tdb 1.9 // put in the i-scream toString code
155 tdb 1.8 acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
156 tdb 1.5 acl.append("{");
157 tdb 1.9 // put the value of each Rule in the result
158 tdb 1.3 for(int i=0; i < _acl.size(); i++) {
159 tdb 1.6 acl.append((ACLRule) _acl.get(i));
160 tdb 1.5 acl.append(",");
161 tdb 1.1 }
162 tdb 1.9 // put the default mode in the result
163 tdb 1.3 if(_defaultMode) {
164 tdb 1.5 acl.append("DEFAULT=ALLOW");
165 tdb 1.3 }
166     else {
167 tdb 1.5 acl.append("DEFAULT=DENY");
168 tdb 1.3 }
169 tdb 1.5 acl.append("}");
170     return acl.toString();
171 tdb 1.1 }
172    
173     //---PRIVATE METHODS---
174    
175 tdb 1.9 /**
176     * Converts an IP address in String format into
177     * a short array of length 4. Any wildcards, *,
178     * found in the IP address are represented by
179 tdb 1.12 * a -1. If the given String is not an IP address
180     * null is returned instead.
181 tdb 1.9 *
182     * @param ip The IP address in String format
183     * @return The IP address in a short[]
184     */
185 tdb 1.7 private short[] ipStringToShort(String ip) {
186 tdb 1.12 // default to expecting it to be an IP
187     // we will try to disprove this :)
188 tdb 1.7 short[] ipaddr = {-1, -1, -1, -1};
189 tdb 1.12 int i = 0;
190     String s = "";
191     // tokenize the String on fullstops, so we can break
192     // up the quads of an IP (if it's an IP!)
193 tdb 1.7 StringTokenizer st = new StringTokenizer(ip, ".");
194 tdb 1.12 while(st.hasMoreTokens() && i++ < 4) {
195     s = st.nextToken();
196     // if it's a wildcard, we'll skip to the next one
197     // as no more checks are required
198     if(s.equals("*")) {
199     continue;
200     }
201     // attempt to parse it into a short
202 tdb 1.7 try {
203 tdb 1.12 short n = Short.parseShort(s);
204     // if it's an int but outside of the
205     // valid range, it can't be an IP
206     if(n < 0 || n > 255) {
207     // give up checking further
208     return null;
209     }
210     ipaddr[i-1] = n;
211 tdb 1.7 }
212 tdb 1.12 // if it didn't parse as a short it can't be an IP
213     catch (NumberFormatException e) {
214     // give up checking further
215     return null;
216 tdb 1.7 }
217 tdb 1.12 }
218     // we've done 4 parts, so if there's any
219     // more this can't be an IP
220     if(st.hasMoreTokens()) {
221     return null;
222     }
223     // if we've done less than 4, see if the last one
224     // was a wildcard - if it isn't then it's not an IP
225     // -- this allows 129.12.*
226     if(i < 4 && !s.equals("*")) {
227     return null;
228     }
229     // if we had one or less entries it can't be an IP
230     // -- this disallows * matching as an IP due
231     // to the rule above
232     if(i <= 1) {
233     return null;
234 tdb 1.7 }
235     return ipaddr;
236     }
237    
238 tdb 1.9 /**
239 tdb 1.11 * Compares two short arrays. The first array can contain a -1,
240     * which will always match any value -- it's a wildcard.
241     * They must be the same length to match.
242 tdb 1.9 *
243 tdb 1.11 * @param first The first array to compare (with -1 wildcard if required)
244 tdb 1.9 * @param second The second array to compare
245     * @result the result of the comparison
246     */
247 tdb 1.7 private boolean compareShorts(short[] first, short[] second) {
248     if(first.length != second.length) {
249     return false;
250     }
251     for(int i=0; i < first.length; i++) {
252 tdb 1.11 if(first[i] == -1) {
253 tdb 1.7 continue;
254     }
255     if(first[i] != second[i]) {
256     return false;
257     }
258 tdb 1.10 }
259 tdb 1.7 return true;
260     }
261    
262 tdb 1.1 //---ACCESSOR/MUTATOR METHODS---
263    
264     //---ATTRIBUTES---
265    
266     /**
267     * This is the friendly identifier of the
268     * component this class is running in.
269     * eg, a Filter may be called "filter1",
270     * If this class does not have an owning
271     * component, a name from the configuration
272     * can be placed here. This name could also
273     * be changed to null for utility classes.
274     */
275     private String _name = null;
276 tdb 1.2
277     /**
278 tdb 1.3 * The ACL is stored in this ArrayList.
279 tdb 1.2 */
280 tdb 1.3 private ArrayList _acl = new ArrayList();
281 tdb 1.2
282     /**
283     * The default mode of this ACL.
284     */
285 tdb 1.1 private boolean _defaultMode;
286    
287     //---STATIC ATTRIBUTES---
288    
289     //---INNER CLASSES---
290    
291 tdb 1.2 /**
292     * Wrapper class for an ACL rule.
293     */
294 tdb 1.4 private class ACLRule implements Serializable {
295 tdb 1.1
296 tdb 1.2 /**
297     * Construct an ACL rule.
298     *
299     * @param allow whether this is an ALLOW or DENY rule
300     * @param expression what this rule matches
301 tdb 1.9 * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
302 tdb 1.7 * @param iprule whether this is an IP rule
303 tdb 1.2 */
304 tdb 1.7 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
305 tdb 1.1 _allow = allow;
306     _expression = expression;
307 tdb 1.7 _ipaddr = ipaddr;
308     _iprule = iprule;
309 tdb 1.6 }
310    
311     /**
312     * Returns a String representation of this rule.
313     *
314     * @return A String representation of this rule.
315     */
316     public String toString() {
317     if(_allow) {
318     return _expression + "=ALLOW";
319     }
320     else {
321     return _expression + "=DENY";
322     }
323 tdb 1.1 }
324    
325 tdb 1.2 /**
326     * Whether this is an ALLOW or DENY rule.
327     */
328 tdb 1.1 private boolean _allow;
329 tdb 1.2
330     /**
331     * What this rule matches.
332     */
333 tdb 1.1 private String _expression;
334 tdb 1.7
335 tdb 1.9 /**
336     * The IP wildcard, only valid if this
337     * is an IP rule.
338     */
339 tdb 1.7 private short[] _ipaddr;
340    
341     /**
342     * Whether this is an IP rule.
343     */
344     private boolean _iprule;
345 tdb 1.1
346     }
347    
348     }