- /*
- * @(#)Permissions.java 1.52 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package java.security;
-
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.NoSuchElementException;
- import java.util.Map;
- import java.util.HashMap;
- import java.util.List;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.Collections;
- import java.io.Serializable;
- import java.io.ObjectStreamField;
- import java.io.ObjectOutputStream;
- import java.io.ObjectInputStream;
- import java.io.IOException;
-
-
- /**
- * This class represents a heterogeneous collection of Permissions. That is,
- * it contains different types of Permission objects, organized into
- * PermissionCollections. For example, if any
- * <code>java.io.FilePermission</code> objects are added to an instance of
- * this class, they are all stored in a single
- * PermissionCollection. It is the PermissionCollection returned by a call to
- * the <code>newPermissionCollection</code> method in the FilePermission class.
- * Similarly, any <code>java.lang.RuntimePermission</code> objects are
- * stored in the PermissionCollection returned by a call to the
- * <code>newPermissionCollection</code> method in the
- * RuntimePermission class. Thus, this class represents a collection of
- * PermissionCollections.
- *
- * <p>When the <code>add</code> method is called to add a Permission, the
- * Permission is stored in the appropriate PermissionCollection. If no such
- * collection exists yet, the Permission object's class is determined and the
- * <code>newPermissionCollection</code> method is called on that class to create
- * the PermissionCollection and add it to the Permissions object. If
- * <code>newPermissionCollection</code> returns null, then a default
- * PermissionCollection that uses a hashtable will be created and used. Each
- * hashtable entry stores a Permission object as both the key and the value.
- *
- * <p> Enumerations returned via the <code>elements</code> method are
- * not <em>fail-fast</em>. Modifications to a collection should not be
- * performed while enumerating over that collection.
- *
- * @see Permission
- * @see PermissionCollection
- * @see AllPermission
- *
- * @version 1.52, 03/01/23
- *
- * @author Marianne Mueller
- * @author Roland Schemers
- *
- * @serial exclude
- */
-
- public final class Permissions extends PermissionCollection
- implements Serializable
- {
- /**
- * Key is permissions Class, value is PermissionCollection for that class.
- * Not serialized; see serialization section at end of class.
- */
- private transient Map permsMap;
-
- // optimization. keep track of whether unresolved permissions need to be checked
- private transient boolean hasUnresolved = false;
-
- // optimization. keep track of the AllPermission collection
- private PermissionCollection allPermission;
-
- /**
- * Creates a new Permissions object containing no PermissionCollections.
- */
- public Permissions() {
- permsMap = new HashMap(11);
- allPermission = null;
- }
-
- /**
- * Adds a permission object to the PermissionCollection for the class the
- * permission belongs to. For example, if <i>permission</i> is a
- * FilePermission, it is added to the FilePermissionCollection stored
- * in this Permissions object.
- *
- * This method creates
- * a new PermissionCollection object (and adds the permission to it)
- * if an appropriate collection does not yet exist. <p>
- *
- * @param permission the Permission object to add.
- *
- * @exception SecurityException if this Permissions object is
- * marked as readonly.
- *
- * @see PermissionCollection#isReadOnly()
- */
-
- public void add(Permission permission) {
- if (isReadOnly())
- throw new SecurityException(
- "attempt to add a Permission to a readonly Permissions object");
- PermissionCollection pc = getPermissionCollection(permission, true);
- pc.add(permission);
-
- // No need to synchronize because all adds are done sequentially
- // and allPermission and hasUnresolved are set only by add()
- if (permission instanceof AllPermission) {
- allPermission = pc;
- }
- if (permission instanceof UnresolvedPermission) {
- hasUnresolved = true;
- }
- }
-
- /**
- * Checks to see if this object's PermissionCollection for permissions of
- * the specified permission's type implies the permissions
- * expressed in the <i>permission</i> object. Returns true if the
- * combination of permissions in the appropriate PermissionCollection
- * (e.g., a FilePermissionCollection for a FilePermission) together
- * imply the specified permission.
- *
- * <p>For example, suppose there is a FilePermissionCollection in this
- * Permissions object, and it contains one FilePermission that specifies
- * "read" access for all files in all subdirectories of the "/tmp"
- * directory, and another FilePermission that specifies "write" access
- * for all files in the "/tmp/scratch/foo" directory.
- * Then if the <code>implies</code> method
- * is called with a permission specifying both "read" and "write" access
- * to files in the "/tmp/scratch/foo" directory, <code>true</code> is
- * returned.
- *
- * <p>Additionally, if this PermissionCollection contains the
- * AllPermission, this method will always return true.
- * <p>
- * @param permission the Permission object to check.
- *
- * @return true if "permission" is implied by the permissions in the
- * PermissionCollection it
- * belongs to, false if not.
- */
-
- public boolean implies(Permission permission) {
- if (allPermission != null) {
- return true; // AllPermission has already been added
- } else {
- PermissionCollection pc = getPermissionCollection(permission, false);
- if (pc != null) {
- return pc.implies(permission);
- } else {
- // none found
- return false;
- }
- }
- }
-
- /**
- * Returns an enumeration of all the Permission objects in all the
- * PermissionCollections in this Permissions object.
- *
- * @return an enumeration of all the Permissions.
- */
-
- public Enumeration elements() {
- // go through each Permissions in the hash table
- // and call their elements() function.
-
- if (hasUnresolved) {
- // Take snapshot of what's in permsMap because permsMap might
- // change during iteration by implies() of other threads;
- // individual PermissionCollections won't change during implies().
-
- List copy = new ArrayList();
- synchronized (permsMap) {
- copy.addAll(permsMap.values());
- }
- return new PermissionsEnumerator(copy.iterator());
- } else {
- // permsMap won't be updated during iteration; sync unnecessary
- return new PermissionsEnumerator(permsMap.values().iterator());
- }
- }
-
- /**
- * Gets the PermissionCollection in this Permissions object for
- * permissions whose type is the same as that of <i>p</i>.
- * For example, if <i>p</i> is a FilePermission,
- * the FilePermissionCollection
- * stored in this Permissions object will be returned.
- *
- * If createEmtpy is true,
- * this method creates a new PermissionCollection object for the specified
- * type of permission objects if one does not yet exist.
- * To do so, it first calls the <code>newPermissionCollection</code> method
- * on <i>p</i>. Subclasses of class Permission
- * override that method if they need to store their permissions in a
- * particular PermissionCollection object in order to provide the
- * correct semantics when the <code>PermissionCollection.implies</code>
- * method is called.
- * If the call returns a PermissionCollection, that collection is stored
- * in this Permissions object. If the call returns null and createEmpty
- * is true, then
- * this method instantiates and stores a default PermissionCollection
- * that uses a hashtable to store its permission objects.
- *
- * createEmtpy is ignored when creating empty PermissionCollection
- * for unresolved permissions because of the overhead of determining the
- * PermissionCollection to use.
- *
- * createEmpty should be set to false when this method is invoked from
- * implies() because it incurs the additional overhead of creating and
- * adding an empty PermissionCollection that will just return false.
- * It should be set to true when invoked from add().
- */
- private PermissionCollection getPermissionCollection(Permission p,
- boolean createEmpty) {
- Class c = p.getClass();
-
- if (!hasUnresolved && !createEmpty) {
- // No need to synchronize because updates have all been done
- return (PermissionCollection) permsMap.get(c);
- } else {
- PermissionCollection pc = null;
-
- // synchronize because permsMap might be updated with a new
- // PermissionCollection
- synchronized (permsMap) {
- pc = (PermissionCollection) permsMap.get(c);
-
- // Check for unresolved permissions
- if (pc == null) {
- pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);
-
- // if still null, create a new collection
- if (pc == null && createEmpty) {
-
- pc = p.newPermissionCollection();
-
- // still no PermissionCollection?
- // We'll give them a PermissionsHash.
- if (pc == null)
- pc = new PermissionsHash();
- }
-
- if (pc != null) {
- permsMap.put(c, pc);
- }
- }
- }
- return pc;
- }
- }
-
- /**
- * Resolves any unresolved permissions of type p.
- *
- * @param p the type of unresolved permission to resolve
- *
- * @return PermissionCollection containing the unresolved permissions,
- * or null if there were no unresolved permissions of type p.
- *
- */
- private PermissionCollection getUnresolvedPermissions(Permission p)
- {
- // Called from within synchronized method so permsMap doesn't need lock
-
- UnresolvedPermissionCollection uc =
- (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
-
- // we have no unresolved permissions if uc is null
- if (uc == null)
- return null;
-
- List unresolvedPerms = uc.getUnresolvedPermissions(p);
-
- // we have no unresolved permissions of this type if unresolvedPerms is null
- if (unresolvedPerms == null)
- return null;
-
- java.security.cert.Certificate certs[] = null;
-
- Object signers[] = p.getClass().getSigners();
-
- int n = 0;
- if (signers != null) {
- for (int j=0; j < signers.length; j++) {
- if (signers[j] instanceof java.security.cert.Certificate) {
- n++;
- }
- }
- certs = new java.security.cert.Certificate[n];
- n = 0;
- for (int j=0; j < signers.length; j++) {
- if (signers[j] instanceof java.security.cert.Certificate) {
- certs[n++] = (java.security.cert.Certificate)signers[j];
- }
- }
- }
-
- PermissionCollection pc = null;
- int len = unresolvedPerms.size();
- for (int i = 0; i < len; i++) {
- UnresolvedPermission up = (UnresolvedPermission)unresolvedPerms.get(i);
- Permission perm = up.resolve(p, certs);
- if (perm != null) {
- if (pc == null) {
- pc = p.newPermissionCollection();
- if (pc == null)
- pc = new PermissionsHash();
- }
- pc.add(perm);
- }
-
- }
- return pc;
- }
-
- private static final long serialVersionUID = 4858622370623524688L;
-
- // Need to maintain serialization interoperability with earlier releases,
- // which had the serializable field:
- // private Hashtable perms;
-
- /**
- * @serialField perms java.util.Hashtable
- * A table of the Permission classes and PermissionCollections.
- * @serialField allPermission java.security.PermissionCollection
- */
- private static final ObjectStreamField[] serialPersistentFields = {
- new ObjectStreamField("perms", Hashtable.class),
- new ObjectStreamField("allPermission", PermissionCollection.class),
- };
-
- /**
- * @serialData Default fields.
- */
- /*
- * Writes the contents of the permsMap field out as a Hashtable for
- * serialization compatibility with earlier releases. allPermission
- * unchanged.
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- // Don't call out.defaultWriteObject()
-
- // Copy perms into a Hashtable
- Hashtable perms = new Hashtable(permsMap.size()*2);
- perms.putAll(permsMap);
-
- // Write out serializable fields
- ObjectOutputStream.PutField pfields = out.putFields();
- pfields.put("allPermission", allPermission);
- pfields.put("perms", perms);
- out.writeFields();
- }
-
- /*
- * Reads in a Hashtable of Class/PermissionCollections and saves them in the
- * permsMap field. Reads in allPermission.
- */
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- // Don't call defaultReadObject()
-
- // Read in serialized fields
- ObjectInputStream.GetField gfields = in.readFields();
-
- // Get allPermission
- allPermission = (PermissionCollection) gfields.get("allPermission", null);
-
- // Get permissions
- Hashtable perms = (Hashtable)gfields.get("perms", null);
- permsMap = new HashMap(perms.size()*2);
- permsMap.putAll(perms);
-
- // Set hasUnresolved
- UnresolvedPermissionCollection uc =
- (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
- hasUnresolved = (uc != null && uc.elements().hasMoreElements());
- }
- }
-
- final class PermissionsEnumerator implements Enumeration {
-
- // all the perms
- private Iterator perms;
- // the current set
- private Enumeration permset;
-
- PermissionsEnumerator(Iterator e) {
- perms = e;
- permset = getNextEnumWithMore();
- }
-
- // No need to synchronize; caller should sync on object as required
- public boolean hasMoreElements() {
- // if we enter with permissionimpl null, we know
- // there are no more left.
-
- if (permset == null)
- return false;
-
- // try to see if there are any left in the current one
-
- if (permset.hasMoreElements())
- return true;
-
- // get the next one that has something in it...
- permset = getNextEnumWithMore();
-
- // if it is null, we are done!
- return (permset != null);
- }
-
- // No need to synchronize; caller should sync on object as required
- public Object nextElement() {
-
- // hasMoreElements will update permset to the next permset
- // with something in it...
-
- if (hasMoreElements()) {
- return permset.nextElement();
- } else {
- throw new NoSuchElementException("PermissionsEnumerator");
- }
-
- }
-
- private Enumeration getNextEnumWithMore() {
- while (perms.hasNext()) {
- PermissionCollection pc = (PermissionCollection)perms.next();
- Enumeration next = (Enumeration) pc.elements();
- if (next.hasMoreElements())
- return next;
- }
- return null;
-
- }
- }
-
- /**
- * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
- *
- * @see Permission
- * @see Permissions
- *
- * @version 1.52, 01/23/03
- *
- * @author Roland Schemers
- *
- * @serial include
- */
-
- final class PermissionsHash extends PermissionCollection
- implements Serializable
- {
- /**
- * Key and value are (same) permissions objects.
- * Not serialized; see serialization section at end of class.
- */
- private transient Map permsMap;
-
- /**
- * Create an empty PermissionsHash object.
- */
-
- PermissionsHash() {
- permsMap = new HashMap(11);
- }
-
- /**
- * Adds a permission to the PermissionsHash.
- *
- * @param permission the Permission object to add.
- */
-
- public void add(Permission permission)
- {
- permsMap.put(permission, permission);
- }
-
- /**
- * Check and see if this set of permissions implies the permissions
- * expressed in "permission".
- *
- * @param permission the Permission object to compare
- *
- * @return true if "permission" is a proper subset of a permission in
- * the set, false if not.
- */
-
- public boolean implies(Permission permission)
- {
- // attempt a fast lookup and implies. If that fails
- // then enumerate through all the permissions.
- Permission p = (Permission) permsMap.get(permission);
-
- // If permission is found, then p.equals(permission)
- if (p == null) {
- Iterator enum = permsMap.values().iterator();
- while (enum.hasNext()) {
- p = (Permission) enum.next();
- if (p.implies(permission))
- return true;
- }
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Returns an enumeration of all the Permission objects in the container.
- *
- * @return an enumeration of all the Permissions.
- */
-
- public Enumeration elements() {
- // Convert Iterator of Map values into an Enumeration
- return Collections.enumeration(permsMap.values());
- }
-
- private static final long serialVersionUID = -8491988220802933440L;
- // Need to maintain serialization interoperability with earlier releases,
- // which had the serializable field:
- // private Hashtable perms;
- /**
- * @serialField perms java.util.Hashtable
- * A table of the Permissions (both key and value are same).
- */
- private static final ObjectStreamField[] serialPersistentFields = {
- new ObjectStreamField("perms", Hashtable.class),
- };
-
- /**
- * @serialData Default fields.
- */
- /*
- * Writes the contents of the permsMap field out as a Hashtable for
- * serialization compatibility with earlier releases.
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- // Don't call out.defaultWriteObject()
-
- // Copy perms into a Hashtable
- Hashtable perms = new Hashtable(permsMap.size()*2);
- perms.putAll(permsMap);
-
- // Write out serializable fields
- ObjectOutputStream.PutField pfields = out.putFields();
- pfields.put("perms", perms);
- out.writeFields();
- }
-
- /*
- * Reads in a Hashtable of Permission/Permission and saves them in the
- * permsMap field.
- */
- private void readObject(ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- // Don't call defaultReadObject()
-
- // Read in serialized fields
- ObjectInputStream.GetField gfields = in.readFields();
-
- // Get permissions
- Hashtable perms = (Hashtable)gfields.get("perms", null);
- permsMap = new HashMap(perms.size()*2);
- permsMap.putAll(perms);
- }
- }