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.12 by tdb, Tue Jan 8 13:31:34 2002 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 >        // 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 <        Iterator i = _acl.iterator();
101 <        while(i.hasNext()) {
102 <            ACLItem item = (ACLItem) i.next();
103 <            if(StringUtils.wildcardCheck(address, item._expression)) {
52 <                return item._allow;
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          }
55        // what to do here?
56        // -- basically a default of deny/allow is needed
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 <        Iterator i = _acl.iterator();
122 <        while(i.hasNext()) {
123 <            ACLItem item = (ACLItem) i.next();
124 <            if(StringUtils.wildcardCheck(address.getHostName(), item._expression)) {
125 <                return item._allow;
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 <            if(StringUtils.wildcardCheck(address.getHostAddress(), item._expression)) {
136 <                return item._allow;
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 <        // what to do here?
72 <        // -- basically a default of deny/allow is needed
143 >        // if we haven't matched a rule, return the default
144          return _defaultMode;
145      }
146      
147 <    public String getACL() {
148 <        String acl = "";
149 <        Iterator i = _acl.iterator();
150 <        while(i.hasNext()) {
151 <            ACLItem item = (ACLItem) i.next();
152 <            if(item._allow) {
153 <                acl += "ALLOW:" + item._expression + " ";
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 <            else {
202 <                acl += "DENY:" + item._expression + " ";
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 <        return acl.substring(0, acl.length()-1);
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 <     * Overrides the {@link java.lang.Object#toString() Object.toString()}
240 <     * method to provide clean logging (every class should have this).
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 <     * This uses the uk.org.iscream.cms.server.util.FormatName class
244 <     * to format the toString()
245 <     *
98 <     * @return the name of this class and its CVS revision
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 <    public String toString() {
248 <        return FormatName.getName(
249 <            _name,
250 <            getClass().getName(),
251 <            REVISION);
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  
107 //---PRIVATE METHODS---
108
262   //---ACCESSOR/MUTATOR METHODS---
263  
264   //---ATTRIBUTES---
# Line 120 | Line 273 | public class ACL {
273       * be changed to null for utility classes.
274       */
275      private String _name = null;
276 <
277 <    private LinkedList _acl = new LinkedList();
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 <    private class ACLItem {
291 >    /**
292 >     * Wrapper class for an ACL rule.
293 >     */
294 >    private class ACLRule implements Serializable {
295          
296 <        private ACLItem(boolean allow, String expression) {
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  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines