KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > osgi > service > useradmin > UserAdminPermission


1 /*
2  * $Header: /cvshome/build/org.osgi.service.useradmin/src/org/osgi/service/useradmin/UserAdminPermission.java,v 1.13 2006/07/12 21:21:33 hargrave Exp $
3  *
4  * Copyright (c) OSGi Alliance (2001, 2006). All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18 package org.osgi.service.useradmin;
19
20 import java.io.IOException JavaDoc;
21 import java.security.*;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Hashtable JavaDoc;
24
25 /**
26  * Permission to configure and access the {@link Role} objects managed by a User
27  * Admin service.
28  *
29  * <p>
30  * This class represents access to the <code>Role</code> objects managed by a User
31  * Admin service and their properties and credentials (in the case of
32  * {@link User} objects).
33  * <p>
34  * The permission name is the name (or name prefix) of a property or credential.
35  * The naming convention follows the hierarchical property naming convention.
36  * Also, an asterisk may appear at the end of the name, following a
37  * &quot;.&quot;, or by itself, to signify a wildcard match. For example:
38  * &quot;org.osgi.security.protocol.*&quot; or &quot;*&quot; is valid, but
39  * &quot;*protocol&quot; or &quot;a*b&quot; are not valid.
40  *
41  * <p>
42  * The <code>UserAdminPermission</code> with the reserved name &quot;admin&quot;
43  * represents the permission required for creating and removing <code>Role</code>
44  * objects in the User Admin service, as well as adding and removing members in
45  * a <code>Group</code> object. This <code>UserAdminPermission</code> does not have
46  * any actions associated with it.
47  *
48  * <p>
49  * The actions to be granted are passed to the constructor in a string
50  * containing a list of one or more comma-separated keywords. The possible
51  * keywords are: <code>changeProperty</code>,<code>changeCredential</code>, and
52  * <code>getCredential</code>. Their meaning is defined as follows:
53  *
54  * <pre>
55  *
56  * action
57  * changeProperty Permission to change (i.e., add and remove)
58  * Role object properties whose names start with
59  * the name argument specified in the constructor.
60  * changeCredential Permission to change (i.e., add and remove)
61  * User object credentials whose names start
62  * with the name argument specified in the constructor.
63  * getCredential Permission to retrieve and check for the
64  * existence of User object credentials whose names
65  * start with the name argument specified in the
66  * constructor.
67  *
68  * </pre>
69  *
70  * The action string is converted to lowercase before processing.
71  *
72  * <p>
73  * Following is a PermissionInfo style policy entry which grants a user
74  * administration bundle a number of <code>UserAdminPermission</code> object:
75  *
76  * <pre>
77  *
78  * (org.osgi.service.useradmin.UserAdminPermission &quot;admin&quot;)
79  * (org.osgi.service.useradmin.UserAdminPermission &quot;com.foo.*&quot; &quot;changeProperty,getCredential,changeCredential&quot;)
80  * (org.osgi.service.useradmin.UserAdminPermission &quot;user.*&quot;, &quot;changeProperty,changeCredential&quot;)
81  *
82  * </pre>
83  *
84  * The first permission statement grants the bundle the permission to perform
85  * any User Admin service operations of type "admin", that is, create and remove
86  * roles and configure <code>Group</code> objects.
87  *
88  * <p>
89  * The second permission statement grants the bundle the permission to change
90  * any properties as well as get and change any credentials whose names start
91  * with <code>com.foo.</code>.
92  *
93  * <p>
94  * The third permission statement grants the bundle the permission to change any
95  * properties and credentials whose names start with <code>user.</code>. This
96  * means that the bundle is allowed to change, but not retrieve any credentials
97  * with the given prefix.
98  *
99  * <p>
100  * The following policy entry empowers the Http Service bundle to perform user
101  * authentication:
102  *
103  * <pre>
104  *
105  * grant codeBase &quot;${jars}http.jar&quot; {
106  * permission org.osgi.service.useradmin.UserAdminPermission
107  * &quot;user.password&quot;, &quot;getCredential&quot;;
108  * };
109  *
110  * </pre>
111  *
112  * <p>
113  * The permission statement grants the Http Service bundle the permission to
114  * validate any password credentials (for authentication purposes), but the
115  * bundle is not allowed to change any properties or credentials.
116  *
117  * @version $Revision: 1.13 $
118  */

119 public final class UserAdminPermission extends BasicPermission {
120     static final long serialVersionUID = -1179971692401603789L;
121     /**
122      * The permission name &quot;admin&quot;.
123      */

124     public static final String JavaDoc ADMIN = "admin";
125     /**
126      * The action string &quot;changeProperty&quot;.
127      */

128     public static final String JavaDoc CHANGE_PROPERTY = "changeProperty";
129     private static final int ACTION_CHANGE_PROPERTY = 0x1;
130     /**
131      * The action string &quot;changeCredential&quot;.
132      */

133     public static final String JavaDoc CHANGE_CREDENTIAL = "changeCredential";
134     private static final int ACTION_CHANGE_CREDENTIAL = 0x2;
135     /**
136      * The action string &quot;getCredential&quot;.
137      */

138     public static final String JavaDoc GET_CREDENTIAL = "getCredential";
139     private static final int ACTION_GET_CREDENTIAL = 0x4;
140     /**
141      * All actions
142      */

143     private static final int ACTION_ALL = ACTION_CHANGE_PROPERTY
144                                                                     | ACTION_CHANGE_CREDENTIAL
145                                                                     | ACTION_GET_CREDENTIAL;
146     /**
147      * No actions.
148      */

149     static final int ACTION_NONE = 0x0;
150     /**
151      * The actions in canonical form.
152      *
153      * @serial
154      */

155     private String JavaDoc actions = null;
156     /**
157      * The actions mask.
158      */

159     private transient int action_mask = ACTION_NONE;
160     /*
161      * Description of this <code> UserAdminPermission </code> (returned by <code>
162      * toString </code> )
163      */

164     private transient String JavaDoc description;
165
166     /**
167      * Creates a new <code>UserAdminPermission</code> with the specified name and
168      * actions. <code>name</code> is either the reserved string &quot;admin&quot;
169      * or the name of a credential or property, and <code>actions</code> contains
170      * a comma-separated list of the actions granted on the specified name.
171      * Valid actions are <code>changeProperty</code>,<code>changeCredential</code>,
172      * and getCredential.
173      *
174      * @param name the name of this <code>UserAdminPermission</code>
175      * @param actions the action string.
176      *
177      * @throws IllegalArgumentException If <code>name</code> equals
178      * &quot;admin&quot; and <code>actions</code> are specified.
179      */

180     public UserAdminPermission(String JavaDoc name, String JavaDoc actions) {
181         this(name, getMask(actions));
182     }
183
184     /**
185      * Package private constructor used by
186      * <code>UserAdminPermissionCollection</code>.
187      *
188      * @param name class name
189      * @param mask action mask
190      */

191     UserAdminPermission(String JavaDoc name, int mask) {
192         super(name);
193         init(mask);
194     }
195
196     /**
197      * Called by constructors and when deserialized.
198      *
199      * @param mask action mask
200      */

201     private void init(int mask) {
202         if (getName().equals(ADMIN)) {
203             if (mask != ACTION_NONE) {
204                 throw new IllegalArgumentException JavaDoc("Actions specified for "
205                         + "no-action " + "UserAdminPermission");
206             }
207         }
208         else {
209             if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
210                 throw new IllegalArgumentException JavaDoc("Invalid action string");
211             }
212         }
213         action_mask = mask;
214     }
215
216     /**
217      * Parses the action string into the action mask.
218      *
219      * @param actions Action string.
220      * @return action mask.
221      */

222     private static int getMask(String JavaDoc actions) {
223         boolean seencomma = false;
224         int mask = ACTION_NONE;
225         if (actions == null) {
226             return (mask);
227         }
228         char[] a = actions.toCharArray();
229         int i = a.length - 1;
230         if (i < 0)
231             return (mask);
232         while (i != -1) {
233             char c;
234             // skip whitespace
235
while ((i != -1)
236                     && ((c = a[i]) == ' ' || c == '\r' || c == '\n'
237                             || c == '\f' || c == '\t'))
238                 i--;
239             // check for the known strings
240
int matchlen;
241             if (i >= 12 && match_get(a, i - 10) && match_credential(a, i)) {
242                 matchlen = 13;
243                 mask |= ACTION_GET_CREDENTIAL;
244             }
245             else
246                 if (i >= 13 && match_change(a, i - 8) && match_property(a, i)) {
247                     matchlen = 14;
248                     mask |= ACTION_CHANGE_PROPERTY;
249                 }
250                 else
251                     if (i >= 15 && match_change(a, i - 10)
252                             && match_credential(a, i)) {
253                         matchlen = 16;
254                         mask |= ACTION_CHANGE_CREDENTIAL;
255                     }
256                     else {
257                         // parse error
258
throw new IllegalArgumentException JavaDoc(
259                                 "invalid permission: " + actions);
260                     }
261             // make sure we didn't just match the tail of a word
262
// like "ackbarfimport". Also, skip to the comma.
263
seencomma = false;
264             while (i >= matchlen && !seencomma) {
265                 switch (a[i - matchlen]) {
266                     case ',' :
267                         seencomma = true;
268                     /* FALLTHROUGH */
269                     case ' ' :
270                     case '\r' :
271                     case '\n' :
272                     case '\f' :
273                     case '\t' :
274                         break;
275                     default :
276                         throw new IllegalArgumentException JavaDoc(
277                                 "invalid permission: " + actions);
278                 }
279                 i--;
280             }
281             // point i at the location of the comma minus one (or -1).
282
i -= matchlen;
283         }
284         if (seencomma) {
285             throw new IllegalArgumentException JavaDoc("invalid permission: " + actions);
286         }
287         return (mask);
288     }
289
290     private static boolean match_change(char[] a, int i) {
291         return ((a[i - 5] == 'c' || a[i - 5] == 'C')
292                 && (a[i - 4] == 'h' || a[i - 4] == 'H')
293                 && (a[i - 3] == 'a' || a[i - 3] == 'A')
294                 && (a[i - 2] == 'n' || a[i - 2] == 'N')
295                 && (a[i - 1] == 'g' || a[i - 1] == 'G') && (a[i - 0] == 'e' || a[i - 0] == 'E'));
296     }
297
298     private static boolean match_get(char[] a, int i) {
299         return ((a[i - 2] == 'g' || a[i - 2] == 'G')
300                 && (a[i - 1] == 'e' || a[i - 1] == 'E') && (a[i - 0] == 't' || a[i - 0] == 'T'));
301     }
302
303     private static boolean match_property(char[] a, int i) {
304         return ((a[i - 7] == 'p' || a[i - 7] == 'P')
305                 && (a[i - 6] == 'r' || a[i - 6] == 'R')
306                 && (a[i - 5] == 'o' || a[i - 5] == 'O')
307                 && (a[i - 4] == 'p' || a[i - 4] == 'P')
308                 && (a[i - 3] == 'e' || a[i - 3] == 'E')
309                 && (a[i - 2] == 'r' || a[i - 2] == 'R')
310                 && (a[i - 1] == 't' || a[i - 1] == 'T') && (a[i - 0] == 'y' || a[i - 0] == 'Y'));
311     }
312
313     private static boolean match_credential(char[] a, int i) {
314         return ((a[i - 9] == 'c' || a[i - 9] == 'C')
315                 && (a[i - 8] == 'r' || a[i - 8] == 'R')
316                 && (a[i - 7] == 'e' || a[i - 7] == 'E')
317                 && (a[i - 6] == 'd' || a[i - 6] == 'D')
318                 && (a[i - 5] == 'e' || a[i - 5] == 'E')
319                 && (a[i - 4] == 'n' || a[i - 4] == 'N')
320                 && (a[i - 3] == 't' || a[i - 3] == 'T')
321                 && (a[i - 2] == 'i' || a[i - 2] == 'I')
322                 && (a[i - 1] == 'a' || a[i - 1] == 'A') && (a[i - 0] == 'l' || a[i - 0] == 'L'));
323     }
324
325     /**
326      * Checks if this <code>UserAdminPermission</code> object &quot;implies&quot;
327      * the specified permission.
328      * <P>
329      * More specifically, this method returns <code>true</code> if:
330      * <p>
331      * <ul>
332      * <li><i>p </i> is an instanceof <code>UserAdminPermission</code>,
333      * <li><i>p </i>'s actions are a proper subset of this object's actions,
334      * and
335      * <li><i>p </i>'s name is implied by this object's name. For example,
336      * &quot;java.*&quot; implies &quot;java.home&quot;.
337      * </ul>
338      *
339      * @param p the permission to check against.
340      *
341      * @return <code>true</code> if the specified permission is implied by this
342      * object; <code>false</code> otherwise.
343      */

344     public boolean implies(Permission p) {
345         if (p instanceof UserAdminPermission) {
346             UserAdminPermission target = (UserAdminPermission) p;
347             return (// Check that the we have the requested action
348
((target.action_mask & action_mask) == target.action_mask)
349                     &&
350                     // If the target action mask is ACTION_NONE, it must be an
351
// admin permission, and then we must be that too
352
(target.action_mask != ACTION_NONE || action_mask == ACTION_NONE) &&
353             // Check that name name matches
354
super.implies(p));
355         }
356         else {
357             return (false);
358         }
359     }
360
361     /**
362      * Returns the canonical string representation of the actions, separated by
363      * comma.
364      *
365      * @return the canonical string representation of the actions.
366      */

367     public String JavaDoc getActions() {
368         if (actions == null) {
369             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
370             boolean comma = false;
371             if ((action_mask & ACTION_CHANGE_CREDENTIAL) == ACTION_CHANGE_CREDENTIAL) {
372                 sb.append(CHANGE_CREDENTIAL);
373                 comma = true;
374             }
375             if ((action_mask & ACTION_CHANGE_PROPERTY) == ACTION_CHANGE_PROPERTY) {
376                 if (comma)
377                     sb.append(',');
378                 sb.append(CHANGE_PROPERTY);
379                 comma = true;
380             }
381             if ((action_mask & ACTION_GET_CREDENTIAL) == ACTION_GET_CREDENTIAL) {
382                 if (comma)
383                     sb.append(',');
384                 sb.append(GET_CREDENTIAL);
385             }
386             actions = sb.toString();
387         }
388         return (actions);
389     }
390
391     /**
392      * Returns a new <code>PermissionCollection</code> object for storing
393      * <code>UserAdminPermission</code> objects.
394      *
395      * @return a new <code>PermissionCollection</code> object suitable for storing
396      * <code>UserAdminPermission</code> objects.
397      */

398     public PermissionCollection newPermissionCollection() {
399         return (new UserAdminPermissionCollection());
400     }
401
402     /**
403      * Checks two <code>UserAdminPermission</code> objects for equality. Checks
404      * that <code>obj</code> is a <code>UserAdminPermission</code>, and has the
405      * same name and actions as this object.
406      *
407      * @param obj the object to be compared for equality with this object.
408      *
409      * @return <code>true</code> if <code>obj</code> is a
410      * <code>UserAdminPermission</code> object, and has the same name and
411      * actions as this <code>UserAdminPermission</code> object.
412      */

413     public boolean equals(Object JavaDoc obj) {
414         if (obj == this) {
415             return (true);
416         }
417         if (obj instanceof UserAdminPermission) {
418             UserAdminPermission uap = (UserAdminPermission) obj;
419             return ((action_mask == uap.action_mask) && getName().equals(
420                     uap.getName()));
421         }
422         else {
423             return (false);
424         }
425     }
426
427     /**
428      * Returns the hash code of this <code>UserAdminPermission</code> object.
429      */

430     public int hashCode() {
431         return (getName().hashCode() ^ getActions().hashCode());
432     }
433
434     /**
435      * Returns the current action mask. Used by the
436      * <code>UserAdminPermissionCollection</code> class.
437      *
438      * @return the actions mask.
439      */

440     int getMask() {
441         return (action_mask);
442     }
443
444     /**
445      * writeObject is called to save the state of this object to a stream. The
446      * actions are serialized, and the superclass takes care of the name.
447      */

448     private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
449             throws IOException JavaDoc {
450         // Write out the actions. The superclass takes care of the name
451
// call getActions to make sure actions field is initialized
452
if (actions == null)
453             getActions();
454         s.defaultWriteObject();
455     }
456
457     /*
458      * Restores this object from a stream (i.e., deserializes it).
459      */

460     private synchronized void readObject(java.io.ObjectInputStream JavaDoc ois)
461             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
462         ois.defaultReadObject();
463         init(getMask(actions));
464     }
465
466     /**
467      * Returns a string describing this <code>UserAdminPermission</code> object.
468      * This string must be in <code>PermissionInfo</code> encoded format.
469      *
470      * @return The <code>PermissionInfo</code> encoded string for this
471      * <code>UserAdminPermission</code> object.
472      * @see "<code>org.osgi.service.permissionadmin.PermissionInfo.getEncoded</code>"
473      */

474     public String JavaDoc toString() {
475         if (description == null) {
476             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
477             sb.append('(');
478             sb.append(getClass().getName());
479             sb.append(" \"");
480             sb.append(getName());
481             String JavaDoc actions = getActions();
482             if (actions.length() > 0) {
483                 sb.append("\" \"");
484                 sb.append(actions);
485             }
486             sb.append("\")");
487             description = sb.toString();
488         }
489         return (description);
490     }
491 }
492 /**
493  * A <code>UserAdminPermissionCollection</code> stores a set of
494  * <code>UserAdminPermission</code> permissions.
495  */

496
497 final class UserAdminPermissionCollection extends PermissionCollection {
498     static final long serialVersionUID = -7222111885230120581L;
499     /**
500      * Table of permissions.
501      *
502      * @serial
503      */

504     private Hashtable JavaDoc permissions;
505     /**
506      * Boolean saying if "*" is in the collection.
507      *
508      * @serial
509      */

510     private boolean all_allowed;
511
512     /**
513      * Creates an empty <code>UserAdminPermissionCollection</code> object.
514      */

515     public UserAdminPermissionCollection() {
516         permissions = new Hashtable JavaDoc();
517         all_allowed = false;
518     }
519
520     /**
521      * Adds the given permission to this <code>UserAdminPermissionCollection</code>.
522      * The key for the hash is the name.
523      *
524      * @param permission the <code>Permission</code> object to add.
525      *
526      * @throws IllegalArgumentException If the given permission is not a
527      * <code>UserAdminPermission</code>
528      * @throws SecurityException If this <code>UserAdminPermissionCollection</code>
529      * object has been marked readonly
530      */

531     public void add(Permission permission) {
532         if (!(permission instanceof UserAdminPermission))
533             throw new IllegalArgumentException JavaDoc("Invalid permission: "
534                     + permission);
535         if (isReadOnly()) {
536             throw new SecurityException JavaDoc("Attempt to add a Permission to a "
537                     + "readonly PermissionCollection");
538         }
539         UserAdminPermission uap = (UserAdminPermission) permission;
540         String JavaDoc name = uap.getName();
541         UserAdminPermission existing = (UserAdminPermission) permissions
542                 .get(name);
543         if (existing != null) {
544             int oldMask = existing.getMask();
545             int newMask = uap.getMask();
546             if (oldMask != newMask) {
547                 permissions.put(name, new UserAdminPermission(name, oldMask
548                         | newMask));
549             }
550         }
551         else {
552             permissions.put(name, permission);
553         }
554         if (!all_allowed) {
555             if (name.equals("*"))
556                 all_allowed = true;
557         }
558     }
559
560     /**
561      * Checks to see if this <code>PermissionCollection</code> implies the given
562      * permission.
563      *
564      * @param permission the <code>Permission</code> object to check against
565      *
566      * @return true if the given permission is implied by this
567      * <code>PermissionCollection</code>, false otherwise.
568      */

569     public boolean implies(Permission permission) {
570         if (!(permission instanceof UserAdminPermission)) {
571             return (false);
572         }
573         UserAdminPermission uap = (UserAdminPermission) permission;
574         UserAdminPermission x;
575         int desired = uap.getMask();
576         int effective = 0;
577         // Short circuit if the "*" Permission was added.
578
// desired can only be ACTION_NONE when name is "admin".
579
if (all_allowed && desired != UserAdminPermission.ACTION_NONE) {
580             x = (UserAdminPermission) permissions.get("*");
581             if (x != null) {
582                 effective |= x.getMask();
583                 if ((effective & desired) == desired) {
584                     return (true);
585                 }
586             }
587         }
588         // strategy:
589
// Check for full match first. Then work our way up the
590
// name looking for matches on a.b.*
591
String JavaDoc name = uap.getName();
592         x = (UserAdminPermission) permissions.get(name);
593         if (x != null) {
594             // we have a direct hit!
595
effective |= x.getMask();
596             if ((effective & desired) == desired) {
597                 return (true);
598             }
599         }
600         // work our way up the tree...
601
int last;
602         int offset = name.length() - 1;
603         while ((last = name.lastIndexOf(".", offset)) != -1) {
604             name = name.substring(0, last + 1) + "*";
605             x = (UserAdminPermission) permissions.get(name);
606             if (x != null) {
607                 effective |= x.getMask();
608                 if ((effective & desired) == desired) {
609                     return (true);
610                 }
611             }
612             offset = last - 1;
613         }
614         // we don't have to check for "*" as it was already checked
615
// at the top (all_allowed), so we just return false
616
return (false);
617     }
618
619     /**
620      * Returns an enumeration of all the <code>UserAdminPermission</code> objects
621      * in the container.
622      *
623      * @return an enumeration of all the <code>UserAdminPermission</code> objects.
624      */

625     public Enumeration JavaDoc elements() {
626         return (permissions.elements());
627     }
628 }
629
Popular Tags