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, 11 months ago) by tdb
Branch: MAIN
CVS Tags: HEAD
Changes since 1.11: +57 -66 lines
Error occurred while calculating annotation data.
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

# 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.11 2002/01/06 23:32:27 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.11 $";
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 // 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 }
86 else {
87 _acl.add(new ACLRule(allow, expression, ipaddr, false));
88 }
89 }
90
91 /**
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 public boolean check(String address) {
100 for(int i=0; i < _acl.size(); i++) {
101 ACLRule rule = (ACLRule) _acl.get(i);
102 if(StringUtils.wildcardMatch(address, rule._expression)) {
103 return rule._allow;
104 }
105 }
106 return _defaultMode;
107 }
108
109 /**
110 * Check to see if an InetAddress is permitted
111 * by the ACL. Perfect for Socket uses of this
112 * 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 *
117 * @param address the InetAddress to check
118 * @return whether the InetAddress was permitted by the ACL
119 */
120 public boolean check(InetAddress address) {
121 // gather the details first
122 String hostname = address.getHostName();
123 String ip = address.getHostAddress();
124 short[] ipaddr = ipStringToShort(ip);
125 // check each rule against this InetAddress
126 for(int i=0; i < _acl.size(); i++) {
127 ACLRule rule = (ACLRule) _acl.get(i);
128 if(rule._iprule) {
129 // if this is an IP rule do a short comparison
130 // must specify the wildcarded rule first
131 if(compareShorts(rule._ipaddr, ipaddr)) {
132 return rule._allow;
133 }
134 }
135 else {
136 // if not do a full blown String comparsion
137 if(StringUtils.wildcardMatch(hostname, rule._expression)) {
138 return rule._allow;
139 }
140 }
141
142 }
143 // if we haven't matched a rule, return the default
144 return _defaultMode;
145 }
146
147 /**
148 * Gives a String representation of this ACL.
149 *
150 * @return A String representation of this ACL.
151 */
152 public String toString() {
153 StringBuffer acl = new StringBuffer();
154 // put in the i-scream toString code
155 acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
156 acl.append("{");
157 // put the value of each Rule in the result
158 for(int i=0; i < _acl.size(); i++) {
159 acl.append((ACLRule) _acl.get(i));
160 acl.append(",");
161 }
162 // put the default mode in the result
163 if(_defaultMode) {
164 acl.append("DEFAULT=ALLOW");
165 }
166 else {
167 acl.append("DEFAULT=DENY");
168 }
169 acl.append("}");
170 return acl.toString();
171 }
172
173 //---PRIVATE METHODS---
174
175 /**
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 * a -1. If the given String is not an IP address
180 * null is returned instead.
181 *
182 * @param ip The IP address in String format
183 * @return The IP address in a short[]
184 */
185 private short[] ipStringToShort(String ip) {
186 // default to expecting it to be an IP
187 // we will try to disprove this :)
188 short[] ipaddr = {-1, -1, -1, -1};
189 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 StringTokenizer st = new StringTokenizer(ip, ".");
194 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 try {
203 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 }
212 // 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 }
217 }
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 }
235 return ipaddr;
236 }
237
238 /**
239 * 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 *
243 * @param first The first array to compare (with -1 wildcard if required)
244 * @param second The second array to compare
245 * @result the result of the comparison
246 */
247 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 if(first[i] == -1) {
253 continue;
254 }
255 if(first[i] != second[i]) {
256 return false;
257 }
258 }
259 return true;
260 }
261
262 //---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
277 /**
278 * The ACL is stored in this ArrayList.
279 */
280 private ArrayList _acl = new ArrayList();
281
282 /**
283 * The default mode of this ACL.
284 */
285 private boolean _defaultMode;
286
287 //---STATIC ATTRIBUTES---
288
289 //---INNER CLASSES---
290
291 /**
292 * Wrapper class for an ACL rule.
293 */
294 private class ACLRule implements Serializable {
295
296 /**
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 * @param ipaddr the IP address wildcard this rule matches if it's an IP rule
302 * @param iprule whether this is an IP rule
303 */
304 private ACLRule(boolean allow, String expression, short[] ipaddr, boolean iprule) {
305 _allow = allow;
306 _expression = expression;
307 _ipaddr = ipaddr;
308 _iprule = iprule;
309 }
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 }
324
325 /**
326 * Whether this is an ALLOW or DENY rule.
327 */
328 private boolean _allow;
329
330 /**
331 * What this rule matches.
332 */
333 private String _expression;
334
335 /**
336 * The IP wildcard, only valid if this
337 * is an IP rule.
338 */
339 private short[] _ipaddr;
340
341 /**
342 * Whether this is an IP rule.
343 */
344 private boolean _iprule;
345
346 }
347
348 }