KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jguard > core > authorization > permissions > URLPermission


1 /*
2  jGuard is a security framework based on top of jaas (java authentication and authorization security).
3  it is written for web applications, to resolve simply, access control problems.
4  version $Name$
5  http://sourceforge.net/projects/jguard/
6
7  Copyright (C) 2004 Charles GAY
8
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23
24  jGuard project home page:
25  http://sourceforge.net/projects/jguard/
26
27  */

28 package net.sf.jguard.core.authorization.permissions;
29
30 import java.io.Serializable JavaDoc;
31 import java.net.URI JavaDoc;
32 import java.net.URISyntaxException JavaDoc;
33 import java.security.AccessController JavaDoc;
34 import java.security.Guard JavaDoc;
35 import java.security.Permission JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.Collection JavaDoc;
38 import java.util.logging.Level JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40 import java.util.regex.Matcher JavaDoc;
41 import java.util.regex.Pattern JavaDoc;
42
43 /**
44  * this permission, <strong>only</strong> implies URLPermission.
45  *
46  * @see java.lang.IllegalArgumentException which wrap the
47  * @see java.net.URISyntaxException thrown if the URI is not correct.
48  * @author <a HREF="mailto:diabolo512@users.sourceforge.net">Charles Gay</a>
49  *
50  */

51 public final class URLPermission extends java.security.BasicPermission JavaDoc implements Serializable JavaDoc, Cloneable JavaDoc, Comparable JavaDoc {
52
53     /** Logger for this class */
54     private static final Logger JavaDoc logger = Logger.getLogger(URLPermission.class.getName());
55     
56     //HTTP methods
57
public static final String JavaDoc DELETE ="DELETE";
58     public static final String JavaDoc GET ="GET";
59     public static final String JavaDoc HEAD ="HEAD";
60     public static final String JavaDoc OPTIONS ="OPTIONS";
61     public static final String JavaDoc POST ="POST";
62     public static final String JavaDoc PUT ="PUT";
63     public static final String JavaDoc TRACE ="TRACE";
64     public static final String JavaDoc ANY ="ANY";
65
66     //protocoles
67
public static final String JavaDoc HTTP="http";
68     public static final String JavaDoc HTTPS="https";
69     
70     
71     
72     /**
73      * serial version id.
74      */

75     private static final long serialVersionUID = 3257283643243574067L;
76
77     private Pattern JavaDoc pattern;
78
79     /**
80      * regexp to display (include /* instead of /.*)
81      */

82     private String JavaDoc prettyPattern;
83
84     private URI JavaDoc uri;
85
86     /**
87      * unique permission's name.
88      */

89     private String JavaDoc name;
90
91     /**
92      * explain permission
93      */

94     private String JavaDoc description = "";
95
96     private URLParameterCollection parameters;
97     
98     private Collection JavaDoc methods = new ArrayList JavaDoc();
99
100     /**
101      * protocol (http, https...). default value is 'http'
102      */

103     private String JavaDoc scheme= URLPermission.ANY;
104
105     /**
106      * actions
107      */

108     private StringBuffer JavaDoc actions = new StringBuffer JavaDoc();
109
110     /**
111      * Creates a new instance of URLPermission.
112      *
113      * @param n
114      * permission's name
115      */

116     public URLPermission(String JavaDoc n) {
117         super(n);
118         this.name = n;
119         try {
120             uri = new URI JavaDoc("");
121         } catch (URISyntaxException JavaDoc e) {
122             throw new IllegalArgumentException JavaDoc(e.getMessage());
123         }
124         parameters = new URLParameterCollection();
125     }
126
127     /**
128      * Creates a new instance of URLPermission.
129      *
130      * @param name
131      * permission name
132      * @param actions permission's actions splitted by a "," :
133      * regexp,scheme(optional),description(optional),http methods(optional)
134      * http methods and schemes (Http or https) are automatically recognized, after the regexp.
135      * @throws IllegalArgumentException
136      * which wraps a
137      * @see URISyntaxException
138      */

139     public URLPermission(String JavaDoc name, String JavaDoc actions) {
140         super(name);
141         this.name = name;
142         String JavaDoc[] actionsArray = actions.split(",");
143
144         if (actionsArray.length > 4)
145             throw new IllegalArgumentException JavaDoc(" 'actions' argument can contain a maximum of three elements separated by ',' ");
146
147         try {
148             setURI(actionsArray[0]);
149         } catch (URISyntaxException JavaDoc e) {
150             throw new IllegalArgumentException JavaDoc(e.getMessage());
151         }
152
153         
154         for(int i =1;i<actionsArray.length;i++){
155             
156             if(URLPermission.HTTPS.equalsIgnoreCase(actionsArray[i])||
157                URLPermission.HTTP.equalsIgnoreCase(actionsArray[i])){
158                 this.scheme = actionsArray[i];
159                 continue;
160             }else if(URLPermission.DELETE.equalsIgnoreCase(actionsArray[i])
161                     ||URLPermission.GET.equalsIgnoreCase(actionsArray[i])
162                     ||URLPermission.HEAD.equalsIgnoreCase(actionsArray[i])
163                     ||URLPermission.OPTIONS.equalsIgnoreCase(actionsArray[i])
164                     ||URLPermission.POST.equalsIgnoreCase(actionsArray[i])
165                     ||URLPermission.PUT.equalsIgnoreCase(actionsArray[i])
166                     ||URLPermission.TRACE.equalsIgnoreCase(actionsArray[i])){
167                 methods.add(actionsArray[i]);
168                 continue;
169                 
170             }else{
171                 this.description = actionsArray[i];
172                 continue;
173             }
174                 
175         }
176
177         //no scheme specified implies any scheme
178
if(scheme==null){
179             scheme = URLPermission.ANY;
180         }
181         
182         //no methods specified implies all methods
183
if(methods.size()==0){
184             methods.add(URLPermission.ANY);
185         }
186         
187         // Mount the string for actions
188

189         // regexp output form
190
this.actions.append(this.prettyPattern);
191
192         // scheme
193
this.actions.append(',');
194         this.actions.append(this.scheme);
195
196         // description
197
if (this.description.length() > 0) {
198             this.actions.append(',');
199             this.actions.append(this.description);
200         }
201
202     }
203
204     /**
205      * 'prettyPattern' is the regexp included in the URI : uri with a 'star'(*) operator, which can be evaluated.
206      *
207      * @param pPattern
208      * @throws URISyntaxException
209      */

210     private void setURI(String JavaDoc pPattern) throws URISyntaxException JavaDoc {
211
212         // build the regexp pattern
213
String JavaDoc regexp = pPattern;
214         regexp = buildRegexpFromString(getPathFromURIString(regexp));
215
216         pattern = Pattern.compile(regexp);
217         if (logger.isLoggable(Level.FINEST)) {
218             logger.log(Level.FINEST, "regexp=" + regexp);
219         }
220         String JavaDoc uriWithoutRegexp = removeRegexpFromURI(pPattern);
221         this.uri = new URI JavaDoc(uriWithoutRegexp);
222
223         if (logger.isLoggable(Level.FINEST)) {
224             logger.finest("uri=" + uri);
225         }
226
227         prettyPattern = pPattern;
228
229         parameters = URLParameterCollection.getURLParameters(getQueryFromURIString(pPattern));
230     }
231
232     /**
233      * replace '*'character (not followed by '*' character, or if it's the last '*') by '' and we replace '**' by '*'.
234      *
235      * @param uriPath
236      * @return URI escaped
237      */

238     static public String JavaDoc removeRegexpFromURI(String JavaDoc uriPath) {
239         // we replace '*'character (not followed by '*' character, or if it's
240
// the last '*') by ''
241
// => '*' in the regexp is replaced
242
uriPath = uriPath.replaceAll("\\*(?!\\*)", "");
243         if (logger.isLoggable(Level.FINEST)) {
244             // logger.log(Level.FINEST,"uriPath="+uriPath);
245
}
246         // we replace '**' by '*' => we convert the escaped(double) '*' in the
247
// simple '*'
248
uriPath = uriPath.replaceAll("\\*{2}", "\\*");
249
250         // --------------- added by VBE
251
// replace '$' by UTF-8 symbol for '$'
252
uriPath = uriPath.replaceAll("\\$\\{", "%24%7B");
253         // replace '}' by UTF-8 symbol for '}'
254
uriPath = uriPath.replaceAll("\\}", "%7D");
255         // --------------- end added by VBE
256

257         return uriPath;
258     }
259
260     public static String JavaDoc getPathFromURIString(String JavaDoc uriString) {
261         String JavaDoc uriPath = uriString;
262         int position = uriString.indexOf("?");
263         if (position != -1) {
264             uriPath = uriString.substring(0, position);
265         }
266         return uriPath;
267     }
268
269     public static String JavaDoc getQueryFromURIString(String JavaDoc uriString) {
270         String JavaDoc uriQuery = "";
271         int position = uriString.indexOf("?");
272         if (position != -1) {
273             uriQuery = uriString.substring(position + 1, uriString.length());
274         }
275         return uriQuery;
276     }
277
278     /**
279      * convenient method to escape regexp special characters, and only use the '*' characters for building the regexp Pattern.
280      *
281      * @param regexp
282      * @return escaped regexp candidate
283      */

284     public static String JavaDoc buildRegexpFromString(String JavaDoc regexp) {
285
286         // replace '\' by '\\'
287
regexp = regexp.replaceAll("\\\\", "\\\\\\\\");
288         // replace '**' by '\*\*'
289
regexp = regexp.replaceAll("\\*\\*", "\\\\*\\\\*");
290         // replace '?' by '\\?'
291
regexp = regexp.replaceAll("\\?", "\\\\\\\\?");
292         // replace '+' by '\\+'
293
regexp = regexp.replaceAll("\\+", "\\\\\\\\+");
294         // replace '{' by '\\{'
295
// regexp = regexp.replaceAll("\\{", "\\\\\\\\{");
296
// replace '}' by '\\}'
297
// regexp = regexp.replaceAll("\\}", "\\\\\\\\}");
298
// replace '[' by '\\['
299
regexp = regexp.replaceAll("\\[", "\\\\\\\\[");
300         // replace ']' by '\\]'
301
regexp = regexp.replaceAll("\\[", "\\\\\\\\]");
302         // replace '^' by '\\^'
303
regexp = regexp.replaceAll("\\^", "\\\\\\\\^");
304         // replace '$' by '\\$'
305
// regexp = regexp.replaceAll("\\$", "\\\\\\\\$");
306

307         // replace '&' by '\\&'
308
regexp = regexp.replaceAll("\\&", "\\\\\\\\&");
309
310         // replace '*' by '\.*'
311
regexp = regexp.replaceAll("\\*", "\\.\\*");
312         return regexp;
313     }
314
315     /**
316      * Determines whether or not to allow access to the guarded object object.
317      * this method comes from the {@link Guard} interface.
318      *
319      * @param perm Permission to check
320      */

321     public void checkGuard(Object JavaDoc perm) {
322         Permission JavaDoc p = (Permission JavaDoc) perm;
323         AccessController.checkPermission(p);
324     }
325
326     /**
327      * override the java.lang.Object 's <i>clone</i> method.
328      *
329      * @return new URLPermission with the <strong>same Domain</strong>.
330      */

331     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
332
333         URLPermission permission = null;
334         permission = new URLPermission(this.name, this.getActions());
335         return permission;
336
337     }
338
339     /**
340      * @param obj
341      * @return true if equals, false otherwise
342      *
343      */

344     public boolean equals(Object JavaDoc obj) {
345         if ((obj instanceof URLPermission) && ((URLPermission) obj).getName().equals(this.getName())) {
346             // we compare two URLPermission with the same name
347
URLPermission tempPerm = (URLPermission) obj;
348             
349             String JavaDoc[] tempActions = tempPerm.getActions().split(",");
350             URI JavaDoc tempUri = null;
351             try {
352                 tempUri = new URI JavaDoc(removeRegexpFromURI(tempActions[0]));
353             } catch (URISyntaxException JavaDoc e) {
354                 logger.log(Level.SEVERE, " URI syntax error: " + removeRegexpFromURI(tempActions[0]));
355             }
356
357             if(!tempPerm.getScheme().equals(this.scheme)){
358                 return false;
359             }
360             
361             if(!tempPerm.getMethods().equals(this.methods)){
362                 return false;
363             }
364             
365             // we should compare paths of these URLPermissions and parameters
366
// but parameter order
367
// doesn't mind
368
if (uri.getPath().equals(tempUri.getPath())){
369                 if(uri.getQuery() == null && tempUri.getQuery() == null){
370                     return true;
371                 }else if(uri.getQuery() == null || tempUri.getQuery() == null){
372                     return false;
373                 }else if(uri.getQuery().equals(tempUri.getQuery())) {
374                     return true;
375                 }
376             }
377             return false;
378         }
379         return false;
380     }
381
382     /**
383      * return actions in a String splitted by comma.
384      *
385      * @return permitted actions.
386      */

387     public String JavaDoc getActions() {
388         return actions.toString();
389     }
390
391     /**
392      * methode used to accelerate the comparation process: useful when hashcode return different int.
393      *
394      * @return hashcode
395      */

396     public int hashCode() {
397         return name.hashCode();
398     }
399
400     /**
401      * verify if this permission implies another URLPermission.
402      *
403      * @param permission
404      * @return true if implies, false otherwise
405      */

406     public boolean implies(java.security.Permission JavaDoc permission) {
407         URLPermission urlpTemp = null;
408         if (!(permission instanceof URLPermission)) {
409             if (logger.isLoggable(Level.FINEST)) {
410                 logger.log(Level.FINEST, " permission is not an URLPermission. type = " + permission.getClass().getName());
411             }
412             return false;
413
414         }
415         
416
417         urlpTemp = (URLPermission) permission;
418         
419         if(this.equals(permission)){
420             return true;
421         }
422         
423         //test ations
424
String JavaDoc urlpTempActions = urlpTemp.getActions();
425         if( urlpTempActions == null ||"".equals(urlpTempActions)){
426             if( actions == null ||"".equals(actions.toString())){
427                 return true;
428             }
429             return false;
430         }
431         
432         //test scheme
433
if(!this.scheme.equals(URLPermission.ANY)&& !this.scheme.equals(urlpTemp.getScheme())){
434             return false;
435         }
436         
437         //test methods
438
if(!this.methods.contains(URLPermission.ANY)){
439             Collection JavaDoc httpMethods = new ArrayList JavaDoc(urlpTemp.getMethods());
440             httpMethods.retainAll(this.methods);
441             if(httpMethods.size()==0){
442             return false;
443             }
444         }
445         
446         boolean b = impliesURI(urlpTemp.getURI());
447         
448         // test the parameters
449
// only if the uri is right
450
if (!b) {
451             return false;
452         }
453         
454         b = impliesParameters(getQueryFromURIString(urlpTemp.getURI()));
455         
456         if (logger.isLoggable(Level.FINEST)) {
457             logger.finest("access decision =" + b);
458         }
459         return b;
460
461     }
462
463     private boolean impliesURI(String JavaDoc uri) {
464         String JavaDoc regexp = getPathFromURIString(uri);
465         Matcher JavaDoc m = pattern.matcher(regexp);
466         if (logger.isLoggable(Level.FINEST)) {
467             logger.log(Level.FINEST, "pattern used to check access =" + pattern.pattern());
468             logger.log(Level.FINEST, " path to be checked =" + regexp);
469         }
470         boolean b = m.matches();
471         if (logger.isLoggable(Level.FINEST)) {
472             logger.log(Level.FINEST, "access decision =" + b);
473         }
474         m.reset();
475         return b;
476     }
477
478     /**
479      * look at the provided parameters by the user permission.
480      *
481      * @param queryFromUserPermission
482      * @return
483      */

484     private boolean impliesParameters(String JavaDoc queryFromUserPermission) {
485
486         if("".equals(queryFromUserPermission)){
487             queryFromUserPermission = null;
488         }
489
490         // if the permission hasn't got any parameters
491
// => the permission implies any parameters
492
if (queryFromUserPermission != null && !parameters.isEmpty()) {
493             String JavaDoc[] params = queryFromUserPermission.split("&");
494
495             // iterate over required parameters keys/values
496
for (int a = 0; a < params.length; a++) {
497                 String JavaDoc[] keyAndValue = params[a].split("=");
498                 URLParameter urlparam = new URLParameter();
499                 urlparam.setKey(keyAndValue[0]);
500                 String JavaDoc[] values = new String JavaDoc[1];
501                 if (keyAndValue.length != 1){
502                     values[0] = keyAndValue[1];
503                 }else{
504                     values[0] = "";
505                 }
506                 urlparam.setValue(values);
507                 // if the evaluated permissionList does not contain the right
508
// URLParameter
509
if (!parameters.implies(urlparam)) {
510                     return false;
511                 }
512
513             }
514         } else if (parameters.isEmpty() && queryFromUserPermission != null) {
515             return true;
516         } else if (parameters.isEmpty() && queryFromUserPermission == null) {
517             return true;
518         } else if (!parameters.isEmpty() && queryFromUserPermission == null) {
519             return false;
520         }
521
522         // we have iterate over the permission collection
523
// and have found each URLParameter in the evaluated permission
524
return true;
525     }
526
527     /**
528      * return an enmpy JGPermissionCollection.
529      *
530      * @return empty JGPermissionCollection
531      */

532     public java.security.PermissionCollection JavaDoc newPermissionCollection() {
533         return new JGPositivePermissionCollection();
534     }
535
536     /**
537      * return a String representation of the permission.
538      *
539      * @return String
540      */

541     public String JavaDoc toString() {
542
543         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
544         sb.append(" name: " + this.name);
545         sb.append("\n scheme: " + this.scheme);
546         sb.append("\n parameters: " + this.parameters.toString());
547         sb.append("\n pattern: " + this.pattern);
548         sb.append("\n uri: " + this.uri);
549         sb.append("\n description: " + this.description);
550         sb.append("\n");
551
552         return sb.toString();
553     }
554
555     /**
556      * method used to compare two objects. this method is used in Collection to <strong>order</strong> items, and MUST be
557      * consistent with the <i>equals</i> method (eache method should return 0/true in the same cases).
558      *
559      * @param o
560      * object to compare
561      * @see java.lang.Comparable#compareTo(java.lang.Object)
562      * @return 0 if both objects are equals, &lt;0 if 0 is lesser than the URLPermission, &gt;0 if 0 is greater than the
563      * URLPermission
564      */

565     public int compareTo(Object JavaDoc o) {
566
567         URLPermission perm = (URLPermission) o;
568         if (this.equals(perm)) {
569             return 0;
570         }
571         return this.name.compareTo(perm.getName());
572     }
573
574     public final String JavaDoc getURI() {
575         return prettyPattern;
576     }
577
578     public Collection JavaDoc getMethods() {
579         return methods;
580     }
581
582     public String JavaDoc getScheme() {
583         return scheme;
584     }
585
586 }
Popular Tags