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

# Content
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 }