ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
Revision: 1.7
Committed: Mon Dec 31 01:49:13 2001 UTC (22 years, 4 months ago) by tdb
Branch: MAIN
Changes since 1.6: +122 -6 lines
Log Message:
Some significant internal changes. It should be noted that this code is still in
the debugging stage, and thus contains lots of println's :-)
The most obvious change is that when adding a rule we try to determine if it's
and IP address given as the expression. If it is, we store this in a short[] in the
ACLRule inner class. Then when performing a check we look to see if it's an
IP address rule, and then do a special check for IP addresses - which is much
more efficient than comparing two strings. We have also halved the checks
done by only comparing a rule to either the name or IP, rather than both.

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.5 2001/12/23 01:05:35 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.5 $";
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 // finally print out what we've found.
132 System.out.println("IP("+ip+"): "+expression);
133 if(ip) {
134 for(int j=0; j < ipaddr.length; j++) {
135 System.out.print(ipaddr[j] + " ");
136 }
137 System.out.println();
138 }
139 _acl.add(new ACLRule(allow, expression, ipaddr, ip));
140 }
141
142 /**
143 * Check to see if a string is permitted by the
144 * ACL. Useful for testing, and non-Socket uses
145 * of this class.
146 *
147 * @param address the string to check
148 * @return whether the address was permitted by the ACL
149 */
150 public boolean check(String address) {
151 for(int i=0; i < _acl.size(); i++) {
152 ACLRule rule = (ACLRule) _acl.get(i);
153 if(StringUtils.wildcardCheck(address, rule._expression)) {
154 return rule._allow;
155 }
156 }
157 return _defaultMode;
158 }
159
160 /**
161 * Check to see if an InetAddress is permitted
162 * by the ACL. Perfect for Socket uses of this
163 * class. It should be made clear that this will
164 * check both the hostname AND IP address against
165 * each rule in turn. The hostname will always be
166 * checked BEFORE the IP address.
167 *
168 * @param address the InetAddress to check
169 * @return whether the InetAddress was permitted by the ACL
170 */
171 public boolean check(InetAddress address) {
172 String hostname = address.getHostName();
173 String ip = address.getHostAddress();
174 short[] ipaddr = ipStringToShort(ip);
175 for(int i=0; i < _acl.size(); i++) {
176 ACLRule rule = (ACLRule) _acl.get(i);
177 if(rule._iprule) {
178 System.out.println("checking ip rule "+rule._expression);
179 //if(StringUtils.wildcardCheck(ip, rule._expression)) {
180 if(compareShorts(ipaddr, rule._ipaddr)) {
181 return rule._allow;
182 }
183 }
184 else {
185 System.out.println("checking name rule: "+rule._expression);
186 if(StringUtils.wildcardCheck(hostname, rule._expression)) {
187 return rule._allow;
188 }
189 }
190
191 }
192 return _defaultMode;
193 }
194
195 /**
196 * Gives a String representation of this ACL.
197 *
198 * @return A String representation of this ACL.
199 */
200 public String toString() {
201 StringBuffer acl = new StringBuffer();
202 acl.append("{");
203 for(int i=0; i < _acl.size(); i++) {
204 acl.append((ACLRule) _acl.get(i));
205 acl.append(",");
206 }
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 private short[] ipStringToShort(String ip) {
220 short[] ipaddr = {-1, -1, -1, -1};
221 StringTokenizer st = new StringTokenizer(ip, ".");
222 for(int i=0; i < 4 && st.hasMoreTokens(); i++) {
223 try {
224 ipaddr[i] = Short.parseShort(st.nextToken());
225 }
226 catch(NumberFormatException e) {
227 // do nothing?
228 }
229 }
230 return ipaddr;
231 }
232
233 private boolean compareShorts(short[] first, short[] second) {
234 if(first.length != second.length) {
235 System.out.println("not equal length");
236 return false;
237 }
238 for(int i=0; i < first.length; i++) {
239 // -- might want to consider specify which is the wildcard one?
240 System.out.println(i + ":" + first[i] + "," + second[i]);
241 if(first[i] == -1 || second[i] == -1) {
242 continue;
243 }
244 if(first[i] != second[i]) {
245 System.out.println("not equal");
246 return false;
247 }
248 }
249 System.out.println("equal");
250 return true;
251 }
252
253 //---ACCESSOR/MUTATOR METHODS---
254
255 //---ATTRIBUTES---
256
257 /**
258 * This is the friendly identifier of the
259 * component this class is running in.
260 * eg, a Filter may be called "filter1",
261 * If this class does not have an owning
262 * component, a name from the configuration
263 * can be placed here. This name could also
264 * be changed to null for utility classes.
265 */
266 private String _name = null;
267
268 /**
269 * The ACL is stored in this ArrayList.
270 */
271 private ArrayList _acl = new ArrayList();
272
273 /**
274 * The default mode of this ACL.
275 */
276 private boolean _defaultMode;
277
278 //---STATIC ATTRIBUTES---
279
280 //---INNER CLASSES---
281
282 /**
283 * Wrapper class for an ACL rule.
284 */
285 private class ACLRule implements Serializable {
286
287 /**
288 * Construct an ACL rule.
289 *
290 * @param allow whether this is an ALLOW or DENY rule
291 * @param expression what this rule matches
292 * @param iprule whether this is an IP rule
293 */
294 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
295 _allow = allow;
296 _expression = expression;
297 _ipaddr = ipaddr;
298 _iprule = iprule;
299 }
300
301 /**
302 * Returns a String representation of this rule.
303 *
304 * @return A String representation of this rule.
305 */
306 public String toString() {
307 if(_allow) {
308 return _expression + "=ALLOW";
309 }
310 else {
311 return _expression + "=DENY";
312 }
313 }
314
315 /**
316 * Whether this is an ALLOW or DENY rule.
317 */
318 private boolean _allow;
319
320 /**
321 * What this rule matches.
322 */
323 private String _expression;
324
325 private short[] _ipaddr;
326
327 /**
328 * Whether this is an IP rule.
329 */
330 private boolean _iprule;
331
332 }
333
334 }