ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/ACL/ACL.java
(Generate patch)

Comparing experimental/server/ACL/ACL.java (file contents):
Revision 1.1 by tdb, Wed Dec 19 23:43:27 2001 UTC vs.
Revision 1.9 by tdb, Mon Dec 31 19:19:03 2001 UTC

# Line 3 | Line 3
3  
4   //---IMPORTS---
5   import uk.org.iscream.cms.server.util.*;
6 < import java.util.LinkedList;
7 < import java.util.Iterator;
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
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$
20   * @version $Id$
21   */
22 < public class ACL {
22 > public class ACL implements Serializable {
23  
24   //---FINAL ATTRIBUTES---
25  
# Line 21 | Line 27 | public class ACL {
27       * The current CVS revision of this class
28       */
29      public static final String REVISION = "$Revision$";
30 <
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 <        _acl.add(new ACLItem(allow, 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 <        Iterator i = _acl.iterator();
145 <        while(i.hasNext()) {
146 <            ACLItem item = (ACLItem) i.next();
147 <            if(StringUtils.wildcardCheck(address, item._expression)) {
52 <                return item._allow;
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          }
55        // what to do here?
56        // -- basically a default of deny/allow is needed
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 <        Iterator i = _acl.iterator();
166 <        while(i.hasNext()) {
167 <            ACLItem item = (ACLItem) i.next();
168 <            if(StringUtils.wildcardCheck(address.getHostName(), item._expression)) {
169 <                return item._allow;
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 >                if(compareShorts(ipaddr, rule._ipaddr)) {
175 >                    return rule._allow;
176 >                }
177              }
178 <            if(StringUtils.wildcardCheck(address.getHostAddress(), item._expression)) {
179 <                return item._allow;
178 >            else {
179 >                // if not do a full blown String comparsion
180 >                if(StringUtils.wildcardCheck(hostname, rule._expression)) {
181 >                    return rule._allow;
182 >                }
183              }
184 +            
185          }
186 <        // what to do here?
72 <        // -- basically a default of deny/allow is needed
186 >        // if we haven't matched a rule, return the default
187          return _defaultMode;
188      }
189      
190 <    public String getACL() {
191 <        String acl = "";
192 <        Iterator i = _acl.iterator();
193 <        while(i.hasNext()) {
194 <            ACLItem item = (ACLItem) i.next();
195 <            if(item._allow) {
196 <                acl += "ALLOW:" + item._expression + " ";
190 >    /**
191 >     * Gives a String representation of this ACL.
192 >     *
193 >     * @return A String representation of this ACL.
194 >     */
195 >    public String toString() {
196 >        StringBuffer acl = new StringBuffer();
197 >        // put in the i-scream toString code
198 >        acl.append(FormatName.getName(_name, getClass().getName(), REVISION));
199 >        acl.append("{");
200 >        // put the value of each Rule in the result
201 >        for(int i=0; i < _acl.size(); i++) {
202 >            acl.append((ACLRule) _acl.get(i));
203 >            acl.append(",");
204 >        }
205 >        // put the default mode in the result
206 >        if(_defaultMode) {
207 >            acl.append("DEFAULT=ALLOW");
208 >        }
209 >        else {
210 >            acl.append("DEFAULT=DENY");
211 >        }
212 >        acl.append("}");
213 >        return acl.toString();
214 >    }
215 >
216 > //---PRIVATE METHODS---
217 >
218 >    /**
219 >     * Converts an IP address in String format into
220 >     * a short array of length 4. Any wildcards, *,
221 >     * found in the IP address are represented by
222 >     * a -1.
223 >     *
224 >     * @param ip The IP address in String format
225 >     * @return The IP address in a short[]
226 >     */
227 >    private short[] ipStringToShort(String ip) {
228 >        short[] ipaddr = {-1, -1, -1, -1};
229 >        StringTokenizer st = new StringTokenizer(ip, ".");
230 >        for(int i=0; i < 4 && st.hasMoreTokens(); i++) {
231 >            try {
232 >                ipaddr[i] = Short.parseShort(st.nextToken());
233              }
234 <            else {
235 <                acl += "DENY:" + item._expression + " ";
234 >            catch(NumberFormatException e) {
235 >                // do nothing?
236 >                // we just want to leave it as -1
237 >                // -- actually, maybe we want to do more checks in here?
238 >                //    although in this code context it'll probably be ok,
239 >                //    it might be worth verifying wildcards and that the
240 >                //    number is in range...
241              }
242          }
243 <        return acl.substring(0, acl.length()-1);
243 >        return ipaddr;
244      }
245      
246      /**
247 <     * Overrides the {@link java.lang.Object#toString() Object.toString()}
248 <     * method to provide clean logging (every class should have this).
247 >     * Compares two short arrays. The array can contain a -1, which
248 >     * will always match any value -- it's a wildcard. They must be
249 >     * the same length to match. At the moment the order of the
250 >     * parameters does not matter.
251       *
252 <     * This uses the uk.org.iscream.cms.server.util.FormatName class
253 <     * to format the toString()
254 <     *
98 <     * @return the name of this class and its CVS revision
252 >     * @param first The first array to compare
253 >     * @param second The second array to compare
254 >     * @result the result of the comparison
255       */
256 <    public String toString() {
257 <        return FormatName.getName(
258 <            _name,
259 <            getClass().getName(),
260 <            REVISION);
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 >            // -- might want to consider specify which is the wildcard one?
262 >            if(first[i] == -1 || second[i] == -1) {
263 >                continue;
264 >            }
265 >            if(first[i] != second[i]) {
266 >                return false;
267 >            }
268 >        return true;
269      }
270  
107 //---PRIVATE METHODS---
108
271   //---ACCESSOR/MUTATOR METHODS---
272  
273   //---ATTRIBUTES---
# Line 120 | Line 282 | public class ACL {
282       * be changed to null for utility classes.
283       */
284      private String _name = null;
285 <
286 <    private LinkedList _acl = new LinkedList();
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 <    private class ACLItem {
300 >    /**
301 >     * Wrapper class for an ACL rule.
302 >     */
303 >    private class ACLRule implements Serializable {
304          
305 <        private ACLItem(boolean allow, String expression) {
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  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines