KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > PropertyPermission


1 /*
2  * @(#)PropertyPermission.java 1.33 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.util;
9
10 import java.io.Serializable JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.security.*;
13 import java.util.Map JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Enumeration JavaDoc;
16 import java.util.Hashtable JavaDoc;
17 import java.util.Collections JavaDoc;
18 import java.io.ObjectStreamField JavaDoc;
19 import java.io.ObjectOutputStream JavaDoc;
20 import java.io.ObjectInputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import sun.security.util.SecurityConstants;
23
24 /**
25  * This class is for property permissions.
26  *
27  * <P>
28  * The name is the name of the property ("java.home",
29  * "os.name", etc). The naming
30  * convention follows the hierarchical property naming convention.
31  * Also, an asterisk
32  * may appear at the end of the name, following a ".", or by itself, to
33  * signify a wildcard match. For example: "java.*" or "*" is valid,
34  * "*java" or "a*b" is not valid.
35  * <P>
36  * <P>
37  * The actions to be granted are passed to the constructor in a string containing
38  * a list of zero or more comma-separated keywords. The possible keywords are
39  * "read" and "write". Their meaning is defined as follows:
40  * <P>
41  * <DL>
42  * <DT> read
43  * <DD> read permission. Allows <code>System.getProperty</code> to
44  * be called.
45  * <DT> write
46  * <DD> write permission. Allows <code>System.setProperty</code> to
47  * be called.
48  * </DL>
49  * <P>
50  * The actions string is converted to lowercase before processing.
51  * <P>
52  * Care should be taken before granting code permission to access
53  * certain system properties. For example, granting permission to
54  * access the "java.home" system property gives potentially malevolent
55  * code sensitive information about the system environment (the Java
56  * installation directory). Also, granting permission to access
57  * the "user.name" and "user.home" system properties gives potentially
58  * malevolent code sensitive information about the user environment
59  * (the user's account name and home directory).
60  *
61  * @see java.security.BasicPermission
62  * @see java.security.Permission
63  * @see java.security.Permissions
64  * @see java.security.PermissionCollection
65  * @see java.lang.SecurityManager
66  *
67  * @version 1.33 03/12/19
68  *
69  * @author Roland Schemers
70  * @since 1.2
71  *
72  * @serial exclude
73  */

74
75 public final class PropertyPermission extends BasicPermission {
76
77     /**
78      * Read action.
79      */

80     private final static int READ = 0x1;
81
82     /**
83      * Write action.
84      */

85     private final static int WRITE = 0x2;
86     /**
87      * All actions (read,write);
88      */

89     private final static int ALL = READ|WRITE;
90     /**
91      * No actions.
92      */

93     private final static int NONE = 0x0;
94
95     /**
96      * The actions mask.
97      *
98      */

99     private transient int mask;
100
101     /**
102      * The actions string.
103      *
104      * @serial
105      */

106     private String JavaDoc actions; // Left null as long as possible, then
107
// created and re-used in the getAction function.
108

109     /**
110      * initialize a PropertyPermission object. Common to all constructors.
111      * Also called during de-serialization.
112      *
113      * @param mask the actions mask to use.
114      *
115      */

116
117     private void init(int mask)
118     {
119
120     if ((mask & ALL) != mask)
121         throw new IllegalArgumentException JavaDoc("invalid actions mask");
122
123     if (mask == NONE)
124         throw new IllegalArgumentException JavaDoc("invalid actions mask");
125
126     if (getName() == null)
127         throw new NullPointerException JavaDoc("name can't be null");
128
129     this.mask = mask;
130     }
131
132     /**
133      * Creates a new PropertyPermission object with the specified name.
134      * The name is the name of the system property, and
135      * <i>actions</i> contains a comma-separated list of the
136      * desired actions granted on the property. Possible actions are
137      * "read" and "write".
138      *
139      * @param name the name of the PropertyPermission.
140      * @param actions the actions string.
141      */

142
143     public PropertyPermission(String JavaDoc name, String JavaDoc actions)
144     {
145     super(name,actions);
146     init(getMask(actions));
147     }
148
149     /**
150      * Checks if this PropertyPermission object "implies" the specified
151      * permission.
152      * <P>
153      * More specifically, this method returns true if:<p>
154      * <ul>
155      * <li> <i>p</i> is an instanceof PropertyPermission,<p>
156      * <li> <i>p</i>'s actions are a subset of this
157      * object's actions, and <p>
158      * <li> <i>p</i>'s name is implied by this object's
159      * name. For example, "java.*" implies "java.home".
160      * </ul>
161      * @param p the permission to check against.
162      *
163      * @return true if the specified permission is implied by this object,
164      * false if not.
165      */

166     public boolean implies(Permission p) {
167     if (!(p instanceof PropertyPermission JavaDoc))
168         return false;
169
170     PropertyPermission JavaDoc that = (PropertyPermission JavaDoc) p;
171
172     // we get the effective mask. i.e., the "and" of this and that.
173
// They must be equal to that.mask for implies to return true.
174

175     return ((this.mask & that.mask) == that.mask) && super.implies(that);
176     }
177
178
179     /**
180      * Checks two PropertyPermission objects for equality. Checks that <i>obj</i> is
181      * a PropertyPermission, and has the same name and actions as this object.
182      * <P>
183      * @param obj the object we are testing for equality with this object.
184      * @return true if obj is a PropertyPermission, and has the same name and
185      * actions as this PropertyPermission object.
186      */

187     public boolean equals(Object JavaDoc obj) {
188     if (obj == this)
189         return true;
190
191     if (! (obj instanceof PropertyPermission JavaDoc))
192         return false;
193
194     PropertyPermission JavaDoc that = (PropertyPermission JavaDoc) obj;
195
196     return (this.mask == that.mask) &&
197         (this.getName().equals(that.getName()));
198     }
199
200     /**
201      * Returns the hash code value for this object.
202      * The hash code used is the hash code of this permissions name, that is,
203      * <code>getName().hashCode()</code>, where <code>getName</code> is
204      * from the Permission superclass.
205      *
206      * @return a hash code value for this object.
207      */

208
209     public int hashCode() {
210     return this.getName().hashCode();
211     }
212
213
214     /**
215      * Converts an actions String to an actions mask.
216      *
217      * @param action the action string.
218      * @return the actions mask.
219      */

220     private static int getMask(String JavaDoc actions) {
221
222     int mask = NONE;
223
224     if (actions == null) {
225         return mask;
226     }
227
228     // Check against use of constants (used heavily within the JDK)
229
if (actions == SecurityConstants.PROPERTY_READ_ACTION) {
230         return READ;
231     } if (actions == SecurityConstants.PROPERTY_WRITE_ACTION) {
232         return WRITE;
233     } else if (actions == SecurityConstants.PROPERTY_RW_ACTION) {
234         return READ|WRITE;
235     }
236
237     char[] a = actions.toCharArray();
238
239     int i = a.length - 1;
240     if (i < 0)
241         return mask;
242
243     while (i != -1) {
244         char c;
245
246         // skip whitespace
247
while ((i!=-1) && ((c = a[i]) == ' ' ||
248                    c == '\r' ||
249                    c == '\n' ||
250                    c == '\f' ||
251                    c == '\t'))
252         i--;
253
254         // check for the known strings
255
int matchlen;
256
257         if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') &&
258               (a[i-2] == 'e' || a[i-2] == 'E') &&
259               (a[i-1] == 'a' || a[i-1] == 'A') &&
260               (a[i] == 'd' || a[i] == 'D'))
261         {
262         matchlen = 4;
263         mask |= READ;
264
265         } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') &&
266                  (a[i-3] == 'r' || a[i-3] == 'R') &&
267                  (a[i-2] == 'i' || a[i-2] == 'I') &&
268                  (a[i-1] == 't' || a[i-1] == 'T') &&
269                  (a[i] == 'e' || a[i] == 'E'))
270         {
271         matchlen = 5;
272         mask |= WRITE;
273
274         } else {
275         // parse error
276
throw new IllegalArgumentException JavaDoc(
277             "invalid permission: " + actions);
278         }
279
280         // make sure we didn't just match the tail of a word
281
// like "ackbarfaccept". Also, skip to the comma.
282
boolean seencomma = false;
283         while (i >= matchlen && !seencomma) {
284         switch(a[i-matchlen]) {
285         case ',':
286             seencomma = true;
287             /*FALLTHROUGH*/
288         case ' ': case '\r': case '\n':
289         case '\f': case '\t':
290             break;
291         default:
292             throw new IllegalArgumentException JavaDoc(
293                 "invalid permission: " + actions);
294         }
295         i--;
296         }
297
298         // point i at the location of the comma minus one (or -1).
299
i -= matchlen;
300     }
301
302     return mask;
303     }
304
305
306     /**
307      * Return the canonical string representation of the actions.
308      * Always returns present actions in the following order:
309      * read, write.
310      *
311      * @return the canonical string representation of the actions.
312      */

313     static String JavaDoc getActions(int mask)
314     {
315     StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
316         boolean comma = false;
317
318     if ((mask & READ) == READ) {
319         comma = true;
320         sb.append("read");
321     }
322
323     if ((mask & WRITE) == WRITE) {
324         if (comma) sb.append(',');
325             else comma = true;
326         sb.append("write");
327     }
328     return sb.toString();
329     }
330
331     /**
332      * Returns the "canonical string representation" of the actions.
333      * That is, this method always returns present actions in the following order:
334      * read, write. For example, if this PropertyPermission object
335      * allows both write and read actions, a call to <code>getActions</code>
336      * will return the string "read,write".
337      *
338      * @return the canonical string representation of the actions.
339      */

340     public String JavaDoc getActions()
341     {
342     if (actions == null)
343         actions = getActions(this.mask);
344
345     return actions;
346     }
347
348     /**
349      * Return the current action mask.
350      * Used by the PropertyPermissionCollection
351      *
352      * @return the actions mask.
353      */

354
355     int getMask() {
356     return mask;
357     }
358
359     /**
360      * Returns a new PermissionCollection object for storing
361      * PropertyPermission objects.
362      * <p>
363      *
364      * @return a new PermissionCollection object suitable for storing
365      * PropertyPermissions.
366      */

367
368     public PermissionCollection newPermissionCollection() {
369     return new PropertyPermissionCollection();
370     }
371
372
373     private static final long serialVersionUID = 885438825399942851L;
374
375     /**
376      * WriteObject is called to save the state of the PropertyPermission
377      * to a stream. The actions are serialized, and the superclass
378      * takes care of the name.
379      */

380     private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
381         throws IOException JavaDoc
382     {
383     // Write out the actions. The superclass takes care of the name
384
// call getActions to make sure actions field is initialized
385
if (actions == null)
386         getActions();
387     s.defaultWriteObject();
388     }
389
390     /**
391      * readObject is called to restore the state of the PropertyPermission from
392      * a stream.
393      */

394     private synchronized void readObject(java.io.ObjectInputStream JavaDoc s)
395          throws IOException JavaDoc, ClassNotFoundException JavaDoc
396     {
397     // Read in the action, then initialize the rest
398
s.defaultReadObject();
399     init(getMask(actions));
400     }
401 }
402
403 /**
404  * A PropertyPermissionCollection stores a set of PropertyPermission
405  * permissions.
406  *
407  * @see java.security.Permission
408  * @see java.security.Permissions
409  * @see java.security.PermissionCollection
410  *
411  * @version 1.33, 12/19/03
412  *
413  * @author Roland Schemers
414  *
415  * @serial include
416  */

417 final class PropertyPermissionCollection extends PermissionCollection
418 implements Serializable JavaDoc
419 {
420
421     /**
422      * Key is property name; value is PropertyPermission.
423      * Not serialized; see serialization section at end of class.
424      */

425     private transient Map JavaDoc perms;
426
427     /**
428      * Boolean saying if "*" is in the collection.
429      *
430      * @see #serialPersistentFields
431      */

432     // No sync access; OK for this to be stale.
433
private boolean all_allowed;
434
435     /**
436      * Create an empty PropertyPermissions object.
437      *
438      */

439
440     public PropertyPermissionCollection() {
441     perms = new HashMap JavaDoc(32); // Capacity for default policy
442
all_allowed = false;
443     }
444
445     /**
446      * Adds a permission to the PropertyPermissions. The key for the hash is
447      * the name.
448      *
449      * @param permission the Permission object to add.
450      *
451      * @exception IllegalArgumentException - if the permission is not a
452      * PropertyPermission
453      *
454      * @exception SecurityException - if this PropertyPermissionCollection
455      * object has been marked readonly
456      */

457
458     public void add(Permission permission)
459     {
460     if (! (permission instanceof PropertyPermission JavaDoc))
461         throw new IllegalArgumentException JavaDoc("invalid permission: "+
462                            permission);
463     if (isReadOnly())
464         throw new SecurityException JavaDoc(
465         "attempt to add a Permission to a readonly PermissionCollection");
466
467     PropertyPermission JavaDoc pp = (PropertyPermission JavaDoc) permission;
468     String JavaDoc propName = pp.getName();
469
470     synchronized (this) {
471         PropertyPermission JavaDoc existing = (PropertyPermission JavaDoc) perms.get(propName);
472
473         if (existing != null) {
474         int oldMask = existing.getMask();
475         int newMask = pp.getMask();
476         if (oldMask != newMask) {
477             int effective = oldMask | newMask;
478             String JavaDoc actions = PropertyPermission.getActions(effective);
479             perms.put(propName, new PropertyPermission JavaDoc(propName, actions));
480         }
481         } else {
482         perms.put(propName, permission);
483         }
484     }
485
486         if (!all_allowed) {
487         if (propName.equals("*"))
488         all_allowed = true;
489     }
490     }
491
492     /**
493      * Check and see if this set of permissions implies the permissions
494      * expressed in "permission".
495      *
496      * @param p the Permission object to compare
497      *
498      * @return true if "permission" is a proper subset of a permission in
499      * the set, false if not.
500      */

501
502     public boolean implies(Permission permission)
503     {
504     if (! (permission instanceof PropertyPermission JavaDoc))
505         return false;
506
507     PropertyPermission JavaDoc pp = (PropertyPermission JavaDoc) permission;
508     PropertyPermission JavaDoc x;
509
510     int desired = pp.getMask();
511     int effective = 0;
512
513     // short circuit if the "*" Permission was added
514
if (all_allowed) {
515         synchronized (this) {
516         x = (PropertyPermission JavaDoc) perms.get("*");
517         }
518         if (x != null) {
519         effective |= x.getMask();
520         if ((effective & desired) == desired)
521             return true;
522         }
523     }
524
525     // strategy:
526
// Check for full match first. Then work our way up the
527
// name looking for matches on a.b.*
528

529     String JavaDoc name = pp.getName();
530     //System.out.println("check "+name);
531

532     synchronized (this) {
533         x = (PropertyPermission JavaDoc) perms.get(name);
534     }
535
536     if (x != null) {
537         // we have a direct hit!
538
effective |= x.getMask();
539         if ((effective & desired) == desired)
540         return true;
541     }
542
543     // work our way up the tree...
544
int last, offset;
545
546     offset = name.length()-1;
547
548     while ((last = name.lastIndexOf(".", offset)) != -1) {
549
550         name = name.substring(0, last+1) + "*";
551         //System.out.println("check "+name);
552
synchronized (this) {
553         x = (PropertyPermission JavaDoc) perms.get(name);
554         }
555
556         if (x != null) {
557         effective |= x.getMask();
558         if ((effective & desired) == desired)
559             return true;
560         }
561         offset = last -1;
562     }
563
564     // we don't have to check for "*" as it was already checked
565
// at the top (all_allowed), so we just return false
566
return false;
567     }
568
569     /**
570      * Returns an enumeration of all the PropertyPermission objects in the
571      * container.
572      *
573      * @return an enumeration of all the PropertyPermission objects.
574      */

575
576     public Enumeration JavaDoc elements() {
577         // Convert Iterator of Map values into an Enumeration
578
synchronized (this) {
579         return Collections.enumeration(perms.values());
580     }
581     }
582
583     private static final long serialVersionUID = 7015263904581634791L;
584
585     // Need to maintain serialization interoperability with earlier releases,
586
// which had the serializable field:
587
//
588
// Table of permissions.
589
//
590
// @serial
591
//
592
// private Hashtable permissions;
593
/**
594      * @serialField permissions java.util.Hashtable
595      * A table of the PropertyPermissions.
596      * @serialField all_allowed boolean
597      * boolean saying if "*" is in the collection.
598      */

599     private static final ObjectStreamField JavaDoc[] serialPersistentFields = {
600         new ObjectStreamField JavaDoc("permissions", Hashtable JavaDoc.class),
601     new ObjectStreamField JavaDoc("all_allowed", Boolean.TYPE),
602     };
603
604     /**
605      * @serialData Default fields.
606      */

607     /*
608      * Writes the contents of the perms field out as a Hashtable for
609      * serialization compatibility with earlier releases. all_allowed
610      * unchanged.
611      */

612     private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
613     // Don't call out.defaultWriteObject()
614

615     // Copy perms into a Hashtable
616
Hashtable JavaDoc permissions = new Hashtable JavaDoc(perms.size()*2);
617     synchronized (this) {
618         permissions.putAll(perms);
619     }
620
621     // Write out serializable fields
622
ObjectOutputStream.PutField JavaDoc pfields = out.putFields();
623     pfields.put("all_allowed", all_allowed);
624         pfields.put("permissions", permissions);
625         out.writeFields();
626     }
627
628     /*
629      * Reads in a Hashtable of PropertyPermissions and saves them in the
630      * perms field. Reads in all_allowed.
631      */

632     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
633     ClassNotFoundException JavaDoc {
634     // Don't call defaultReadObject()
635

636     // Read in serialized fields
637
ObjectInputStream.GetField JavaDoc gfields = in.readFields();
638
639     // Get all_allowed
640
all_allowed = gfields.get("all_allowed", false);
641
642     // Get permissions
643
Hashtable JavaDoc permissions = (Hashtable JavaDoc)gfields.get("permissions", null);
644     perms = new HashMap JavaDoc(permissions.size()*2);
645     perms.putAll(permissions);
646     }
647 }
648
Popular Tags