001: /*
002: * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.security;
027:
028: import java.util.Enumeration;
029: import java.util.Hashtable;
030: import java.util.NoSuchElementException;
031: import java.util.Map;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.ArrayList;
035: import java.util.Iterator;
036: import java.util.Collections;
037: import java.io.Serializable;
038: import java.io.ObjectStreamField;
039: import java.io.ObjectOutputStream;
040: import java.io.ObjectInputStream;
041: import java.io.IOException;
042:
043: /**
044: * This class represents a heterogeneous collection of Permissions. That is,
045: * it contains different types of Permission objects, organized into
046: * PermissionCollections. For example, if any
047: * <code>java.io.FilePermission</code> objects are added to an instance of
048: * this class, they are all stored in a single
049: * PermissionCollection. It is the PermissionCollection returned by a call to
050: * the <code>newPermissionCollection</code> method in the FilePermission class.
051: * Similarly, any <code>java.lang.RuntimePermission</code> objects are
052: * stored in the PermissionCollection returned by a call to the
053: * <code>newPermissionCollection</code> method in the
054: * RuntimePermission class. Thus, this class represents a collection of
055: * PermissionCollections.
056: *
057: * <p>When the <code>add</code> method is called to add a Permission, the
058: * Permission is stored in the appropriate PermissionCollection. If no such
059: * collection exists yet, the Permission object's class is determined and the
060: * <code>newPermissionCollection</code> method is called on that class to create
061: * the PermissionCollection and add it to the Permissions object. If
062: * <code>newPermissionCollection</code> returns null, then a default
063: * PermissionCollection that uses a hashtable will be created and used. Each
064: * hashtable entry stores a Permission object as both the key and the value.
065: *
066: * <p> Enumerations returned via the <code>elements</code> method are
067: * not <em>fail-fast</em>. Modifications to a collection should not be
068: * performed while enumerating over that collection.
069: *
070: * @see Permission
071: * @see PermissionCollection
072: * @see AllPermission
073: *
074: * @version 1.68, 07/05/05
075: *
076: * @author Marianne Mueller
077: * @author Roland Schemers
078: *
079: * @serial exclude
080: */
081:
082: public final class Permissions extends PermissionCollection implements
083: Serializable {
084: /**
085: * Key is permissions Class, value is PermissionCollection for that class.
086: * Not serialized; see serialization section at end of class.
087: */
088: private transient Map<Class<?>, PermissionCollection> permsMap;
089:
090: // optimization. keep track of whether unresolved permissions need to be
091: // checked
092: private transient boolean hasUnresolved = false;
093:
094: // optimization. keep track of the AllPermission collection
095: // - package private for ProtectionDomain optimization
096: PermissionCollection allPermission;
097:
098: /**
099: * Creates a new Permissions object containing no PermissionCollections.
100: */
101: public Permissions() {
102: permsMap = new HashMap<Class<?>, PermissionCollection>(11);
103: allPermission = null;
104: }
105:
106: /**
107: * Adds a permission object to the PermissionCollection for the class the
108: * permission belongs to. For example, if <i>permission</i> is a
109: * FilePermission, it is added to the FilePermissionCollection stored
110: * in this Permissions object.
111: *
112: * This method creates
113: * a new PermissionCollection object (and adds the permission to it)
114: * if an appropriate collection does not yet exist. <p>
115: *
116: * @param permission the Permission object to add.
117: *
118: * @exception SecurityException if this Permissions object is
119: * marked as readonly.
120: *
121: * @see PermissionCollection#isReadOnly()
122: */
123:
124: public void add(Permission permission) {
125: if (isReadOnly())
126: throw new SecurityException(
127: "attempt to add a Permission to a readonly Permissions object");
128:
129: PermissionCollection pc;
130:
131: synchronized (this ) {
132: pc = getPermissionCollection(permission, true);
133: pc.add(permission);
134: }
135:
136: // No sync; staleness -> optimizations delayed, which is OK
137: if (permission instanceof AllPermission) {
138: allPermission = pc;
139: }
140: if (permission instanceof UnresolvedPermission) {
141: hasUnresolved = true;
142: }
143: }
144:
145: /**
146: * Checks to see if this object's PermissionCollection for permissions of
147: * the specified permission's class implies the permissions
148: * expressed in the <i>permission</i> object. Returns true if the
149: * combination of permissions in the appropriate PermissionCollection
150: * (e.g., a FilePermissionCollection for a FilePermission) together
151: * imply the specified permission.
152: *
153: * <p>For example, suppose there is a FilePermissionCollection in this
154: * Permissions object, and it contains one FilePermission that specifies
155: * "read" access for all files in all subdirectories of the "/tmp"
156: * directory, and another FilePermission that specifies "write" access
157: * for all files in the "/tmp/scratch/foo" directory.
158: * Then if the <code>implies</code> method
159: * is called with a permission specifying both "read" and "write" access
160: * to files in the "/tmp/scratch/foo" directory, <code>true</code> is
161: * returned.
162: *
163: * <p>Additionally, if this PermissionCollection contains the
164: * AllPermission, this method will always return true.
165: * <p>
166: * @param permission the Permission object to check.
167: *
168: * @return true if "permission" is implied by the permissions in the
169: * PermissionCollection it
170: * belongs to, false if not.
171: */
172:
173: public boolean implies(Permission permission) {
174: // No sync; staleness -> skip optimization, which is OK
175: if (allPermission != null) {
176: return true; // AllPermission has already been added
177: } else {
178: synchronized (this ) {
179: PermissionCollection pc = getPermissionCollection(
180: permission, false);
181: if (pc != null) {
182: return pc.implies(permission);
183: } else {
184: // none found
185: return false;
186: }
187: }
188: }
189: }
190:
191: /**
192: * Returns an enumeration of all the Permission objects in all the
193: * PermissionCollections in this Permissions object.
194: *
195: * @return an enumeration of all the Permissions.
196: */
197:
198: public Enumeration<Permission> elements() {
199: // go through each Permissions in the hash table
200: // and call their elements() function.
201:
202: synchronized (this ) {
203: return new PermissionsEnumerator(permsMap.values()
204: .iterator());
205: }
206: }
207:
208: /**
209: * Gets the PermissionCollection in this Permissions object for
210: * permissions whose type is the same as that of <i>p</i>.
211: * For example, if <i>p</i> is a FilePermission,
212: * the FilePermissionCollection
213: * stored in this Permissions object will be returned.
214: *
215: * If createEmpty is true,
216: * this method creates a new PermissionCollection object for the specified
217: * type of permission objects if one does not yet exist.
218: * To do so, it first calls the <code>newPermissionCollection</code> method
219: * on <i>p</i>. Subclasses of class Permission
220: * override that method if they need to store their permissions in a
221: * particular PermissionCollection object in order to provide the
222: * correct semantics when the <code>PermissionCollection.implies</code>
223: * method is called.
224: * If the call returns a PermissionCollection, that collection is stored
225: * in this Permissions object. If the call returns null and createEmpty
226: * is true, then
227: * this method instantiates and stores a default PermissionCollection
228: * that uses a hashtable to store its permission objects.
229: *
230: * createEmpty is ignored when creating empty PermissionCollection
231: * for unresolved permissions because of the overhead of determining the
232: * PermissionCollection to use.
233: *
234: * createEmpty should be set to false when this method is invoked from
235: * implies() because it incurs the additional overhead of creating and
236: * adding an empty PermissionCollection that will just return false.
237: * It should be set to true when invoked from add().
238: */
239: private PermissionCollection getPermissionCollection(Permission p,
240: boolean createEmpty) {
241: Class c = p.getClass();
242:
243: PermissionCollection pc = permsMap.get(c);
244:
245: if (!hasUnresolved && !createEmpty) {
246: return pc;
247: } else if (pc == null) {
248:
249: // Check for unresolved permissions
250: pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);
251:
252: // if still null, create a new collection
253: if (pc == null && createEmpty) {
254:
255: pc = p.newPermissionCollection();
256:
257: // still no PermissionCollection?
258: // We'll give them a PermissionsHash.
259: if (pc == null)
260: pc = new PermissionsHash();
261: }
262:
263: if (pc != null) {
264: permsMap.put(c, pc);
265: }
266: }
267: return pc;
268: }
269:
270: /**
271: * Resolves any unresolved permissions of type p.
272: *
273: * @param p the type of unresolved permission to resolve
274: *
275: * @return PermissionCollection containing the unresolved permissions,
276: * or null if there were no unresolved permissions of type p.
277: *
278: */
279: private PermissionCollection getUnresolvedPermissions(Permission p) {
280: // Called from within synchronized method so permsMap doesn't need lock
281:
282: UnresolvedPermissionCollection uc = (UnresolvedPermissionCollection) permsMap
283: .get(UnresolvedPermission.class);
284:
285: // we have no unresolved permissions if uc is null
286: if (uc == null)
287: return null;
288:
289: List<UnresolvedPermission> unresolvedPerms = uc
290: .getUnresolvedPermissions(p);
291:
292: // we have no unresolved permissions of this type if unresolvedPerms is null
293: if (unresolvedPerms == null)
294: return null;
295:
296: java.security.cert.Certificate certs[] = null;
297:
298: Object signers[] = p.getClass().getSigners();
299:
300: int n = 0;
301: if (signers != null) {
302: for (int j = 0; j < signers.length; j++) {
303: if (signers[j] instanceof java.security.cert.Certificate) {
304: n++;
305: }
306: }
307: certs = new java.security.cert.Certificate[n];
308: n = 0;
309: for (int j = 0; j < signers.length; j++) {
310: if (signers[j] instanceof java.security.cert.Certificate) {
311: certs[n++] = (java.security.cert.Certificate) signers[j];
312: }
313: }
314: }
315:
316: PermissionCollection pc = null;
317: synchronized (unresolvedPerms) {
318: int len = unresolvedPerms.size();
319: for (int i = 0; i < len; i++) {
320: UnresolvedPermission up = unresolvedPerms.get(i);
321: Permission perm = up.resolve(p, certs);
322: if (perm != null) {
323: if (pc == null) {
324: pc = p.newPermissionCollection();
325: if (pc == null)
326: pc = new PermissionsHash();
327: }
328: pc.add(perm);
329: }
330: }
331: }
332: return pc;
333: }
334:
335: private static final long serialVersionUID = 4858622370623524688L;
336:
337: // Need to maintain serialization interoperability with earlier releases,
338: // which had the serializable field:
339: // private Hashtable perms;
340:
341: /**
342: * @serialField perms java.util.Hashtable
343: * A table of the Permission classes and PermissionCollections.
344: * @serialField allPermission java.security.PermissionCollection
345: */
346: private static final ObjectStreamField[] serialPersistentFields = {
347: new ObjectStreamField("perms", Hashtable.class),
348: new ObjectStreamField("allPermission",
349: PermissionCollection.class), };
350:
351: /**
352: * @serialData Default fields.
353: */
354: /*
355: * Writes the contents of the permsMap field out as a Hashtable for
356: * serialization compatibility with earlier releases. allPermission
357: * unchanged.
358: */
359: private void writeObject(ObjectOutputStream out) throws IOException {
360: // Don't call out.defaultWriteObject()
361:
362: // Copy perms into a Hashtable
363: Hashtable<Class<?>, PermissionCollection> perms = new Hashtable<Class<?>, PermissionCollection>(
364: permsMap.size() * 2); // no sync; estimate
365: synchronized (this ) {
366: perms.putAll(permsMap);
367: }
368:
369: // Write out serializable fields
370: ObjectOutputStream.PutField pfields = out.putFields();
371:
372: pfields.put("allPermission", allPermission); // no sync; staleness OK
373: pfields.put("perms", perms);
374: out.writeFields();
375: }
376:
377: /*
378: * Reads in a Hashtable of Class/PermissionCollections and saves them in the
379: * permsMap field. Reads in allPermission.
380: */
381: private void readObject(ObjectInputStream in) throws IOException,
382: ClassNotFoundException {
383: // Don't call defaultReadObject()
384:
385: // Read in serialized fields
386: ObjectInputStream.GetField gfields = in.readFields();
387:
388: // Get allPermission
389: allPermission = (PermissionCollection) gfields.get(
390: "allPermission", null);
391:
392: // Get permissions
393: Hashtable<Class<?>, PermissionCollection> perms = (Hashtable<Class<?>, PermissionCollection>) gfields
394: .get("perms", null);
395: permsMap = new HashMap<Class<?>, PermissionCollection>(perms
396: .size() * 2);
397: permsMap.putAll(perms);
398:
399: // Set hasUnresolved
400: UnresolvedPermissionCollection uc = (UnresolvedPermissionCollection) permsMap
401: .get(UnresolvedPermission.class);
402: hasUnresolved = (uc != null && uc.elements().hasMoreElements());
403: }
404: }
405:
406: final class PermissionsEnumerator implements Enumeration<Permission> {
407:
408: // all the perms
409: private Iterator<PermissionCollection> perms;
410: // the current set
411: private Enumeration<Permission> permset;
412:
413: PermissionsEnumerator(Iterator<PermissionCollection> e) {
414: perms = e;
415: permset = getNextEnumWithMore();
416: }
417:
418: // No need to synchronize; caller should sync on object as required
419: public boolean hasMoreElements() {
420: // if we enter with permissionimpl null, we know
421: // there are no more left.
422:
423: if (permset == null)
424: return false;
425:
426: // try to see if there are any left in the current one
427:
428: if (permset.hasMoreElements())
429: return true;
430:
431: // get the next one that has something in it...
432: permset = getNextEnumWithMore();
433:
434: // if it is null, we are done!
435: return (permset != null);
436: }
437:
438: // No need to synchronize; caller should sync on object as required
439: public Permission nextElement() {
440:
441: // hasMoreElements will update permset to the next permset
442: // with something in it...
443:
444: if (hasMoreElements()) {
445: return permset.nextElement();
446: } else {
447: throw new NoSuchElementException("PermissionsEnumerator");
448: }
449:
450: }
451:
452: private Enumeration<Permission> getNextEnumWithMore() {
453: while (perms.hasNext()) {
454: PermissionCollection pc = (PermissionCollection) perms
455: .next();
456: Enumeration<Permission> next = pc.elements();
457: if (next.hasMoreElements())
458: return next;
459: }
460: return null;
461:
462: }
463: }
464:
465: /**
466: * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
467: *
468: * @see Permission
469: * @see Permissions
470: *
471: * @version 1.68, 05/05/07
472: *
473: * @author Roland Schemers
474: *
475: * @serial include
476: */
477:
478: final class PermissionsHash extends PermissionCollection implements
479: Serializable {
480: /**
481: * Key and value are (same) permissions objects.
482: * Not serialized; see serialization section at end of class.
483: */
484: private transient Map<Permission, Permission> permsMap;
485:
486: /**
487: * Create an empty PermissionsHash object.
488: */
489:
490: PermissionsHash() {
491: permsMap = new HashMap<Permission, Permission>(11);
492: }
493:
494: /**
495: * Adds a permission to the PermissionsHash.
496: *
497: * @param permission the Permission object to add.
498: */
499:
500: public void add(Permission permission) {
501: synchronized (this ) {
502: permsMap.put(permission, permission);
503: }
504: }
505:
506: /**
507: * Check and see if this set of permissions implies the permissions
508: * expressed in "permission".
509: *
510: * @param permission the Permission object to compare
511: *
512: * @return true if "permission" is a proper subset of a permission in
513: * the set, false if not.
514: */
515:
516: public boolean implies(Permission permission) {
517: // attempt a fast lookup and implies. If that fails
518: // then enumerate through all the permissions.
519: synchronized (this ) {
520: Permission p = permsMap.get(permission);
521:
522: // If permission is found, then p.equals(permission)
523: if (p == null) {
524: for (Permission p_ : permsMap.values()) {
525: if (p_.implies(permission))
526: return true;
527: }
528: return false;
529: } else {
530: return true;
531: }
532: }
533: }
534:
535: /**
536: * Returns an enumeration of all the Permission objects in the container.
537: *
538: * @return an enumeration of all the Permissions.
539: */
540:
541: public Enumeration<Permission> elements() {
542: // Convert Iterator of Map values into an Enumeration
543: synchronized (this ) {
544: return Collections.enumeration(permsMap.values());
545: }
546: }
547:
548: private static final long serialVersionUID = -8491988220802933440L;
549: // Need to maintain serialization interoperability with earlier releases,
550: // which had the serializable field:
551: // private Hashtable perms;
552: /**
553: * @serialField perms java.util.Hashtable
554: * A table of the Permissions (both key and value are same).
555: */
556: private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
557: "perms", Hashtable.class), };
558:
559: /**
560: * @serialData Default fields.
561: */
562: /*
563: * Writes the contents of the permsMap field out as a Hashtable for
564: * serialization compatibility with earlier releases.
565: */
566: private void writeObject(ObjectOutputStream out) throws IOException {
567: // Don't call out.defaultWriteObject()
568:
569: // Copy perms into a Hashtable
570: Hashtable<Permission, Permission> perms = new Hashtable<Permission, Permission>(
571: permsMap.size() * 2);
572: synchronized (this ) {
573: perms.putAll(permsMap);
574: }
575:
576: // Write out serializable fields
577: ObjectOutputStream.PutField pfields = out.putFields();
578: pfields.put("perms", perms);
579: out.writeFields();
580: }
581:
582: /*
583: * Reads in a Hashtable of Permission/Permission and saves them in the
584: * permsMap field.
585: */
586: private void readObject(ObjectInputStream in) throws IOException,
587: ClassNotFoundException {
588: // Don't call defaultReadObject()
589:
590: // Read in serialized fields
591: ObjectInputStream.GetField gfields = in.readFields();
592:
593: // Get permissions
594: Hashtable<Permission, Permission> perms = (Hashtable<Permission, Permission>) gfields
595: .get("perms", null);
596: permsMap = new HashMap<Permission, Permission>(perms.size() * 2);
597: permsMap.putAll(perms);
598: }
599: }
|