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

# Content
1 //---PACKAGE DECLARATION---
2 //package uk.org.iscream.cms.server.util;
3
4 //---IMPORTS---
5 import uk.org.iscream.cms.server.util.*;
6 import java.util.ArrayList;
7 import java.util.StringTokenizer;
8 import java.net.InetAddress;
9 import java.io.Serializable;
10
11 /**
12 * 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 *
19 * @author $Author: tdb $
20 * @version $Id: ACL.java,v 1.10 2001/12/31 19:25:39 tdb Exp $
21 */
22 public class ACL implements Serializable {
23
24 //---FINAL ATTRIBUTES---
25
26 /**
27 * The current CVS revision of this class
28 */
29 public static final String REVISION = "$Revision: 1.10 $";
30
31 /**
32 * static to be used when adding an ALLOW rule to the ACL.
33 */
34 public static final boolean ALLOW = true;
35
36 /**
37 * static to be used when adding a DENY rule to the ACL.
38 */
39 public static final boolean DENY = false;
40
41 //---STATIC METHODS---
42
43 //---CONSTRUCTORS---
44
45 /**
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 public ACL() {
51 // default to ACL.ALLOW
52 this(ACL.ALLOW);
53 }
54
55 /**
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 public ACL(boolean defaultMode) {
63 _defaultMode = defaultMode;
64 }
65
66 //---PUBLIC METHODS---
67
68 /**
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 public void add(boolean allow, String expression) {
79 // 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 // add the rule to our array
132 _acl.add(new ACLRule(allow, expression, ipaddr, ip));
133 }
134
135 /**
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 public boolean check(String address) {
144 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 }
149 }
150 return _defaultMode;
151 }
152
153 /**
154 * Check to see if an InetAddress is permitted
155 * by the ACL. Perfect for Socket uses of this
156 * 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 *
161 * @param address the InetAddress to check
162 * @return whether the InetAddress was permitted by the ACL
163 */
164 public boolean check(InetAddress address) {
165 // gather the details first
166 String hostname = address.getHostName();
167 String ip = address.getHostAddress();
168 short[] ipaddr = ipStringToShort(ip);
169 // check each rule against this InetAddress
170 for(int i=0; i < _acl.size(); i++) {
171 ACLRule rule = (ACLRule) _acl.get(i);
172 if(rule._iprule) {
173 // if this is an IP rule do a short comparison
174 // must specify the wildcarded rule first
175 if(compareShorts(rule._ipaddr, ipaddr)) {
176 return rule._allow;
177 }
178 }
179 else {
180 // if not do a full blown String comparsion
181 if(StringUtils.wildcardCheck(hostname, rule._expression)) {
182 return rule._allow;
183 }
184 }
185
186 }
187 // if we haven't matched a rule, return the default
188 return _defaultMode;
189 }
190
191 /**
192 * Gives a String representation of this ACL.
193 *
194 * @return A String representation of this ACL.
195 */
196 public String toString() {
197 StringBuffer acl = new StringBuffer();
198 // put in the i-scream toString code
199 acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
200 acl.append("{");
201 // put the value of each Rule in the result
202 for(int i=0; i < _acl.size(); i++) {
203 acl.append((ACLRule) _acl.get(i));
204 acl.append(",");
205 }
206 // put the default mode in the result
207 if(_defaultMode) {
208 acl.append("DEFAULT=ALLOW");
209 }
210 else {
211 acl.append("DEFAULT=DENY");
212 }
213 acl.append("}");
214 return acl.toString();
215 }
216
217 //---PRIVATE METHODS---
218
219 /**
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 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 // do nothing...
237 // 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 }
243 }
244 return ipaddr;
245 }
246
247 /**
248 * 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 *
252 * @param first The first array to compare (with -1 wildcard if required)
253 * @param second The second array to compare
254 * @result the result of the comparison
255 */
256 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 if(first[i] == -1) {
262 continue;
263 }
264 if(first[i] != second[i]) {
265 return false;
266 }
267 }
268 return true;
269 }
270
271 //---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
286 /**
287 * The ACL is stored in this ArrayList.
288 */
289 private ArrayList _acl = new ArrayList();
290
291 /**
292 * The default mode of this ACL.
293 */
294 private boolean _defaultMode;
295
296 //---STATIC ATTRIBUTES---
297
298 //---INNER CLASSES---
299
300 /**
301 * Wrapper class for an ACL rule.
302 */
303 private class ACLRule implements Serializable {
304
305 /**
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 * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
311 * @param iprule whether this is an IP rule
312 */
313 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
314 _allow = allow;
315 _expression = expression;
316 _ipaddr = ipaddr;
317 _iprule = iprule;
318 }
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 }
333
334 /**
335 * Whether this is an ALLOW or DENY rule.
336 */
337 private boolean _allow;
338
339 /**
340 * What this rule matches.
341 */
342 private String _expression;
343
344 /**
345 * The IP wildcard, only valid if this
346 * is an IP rule.
347 */
348 private short[] _ipaddr;
349
350 /**
351 * Whether this is an IP rule.
352 */
353 private boolean _iprule;
354
355 }
356
357 }