home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / security / Permissions.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  13.2 KB  |  438 lines

  1. /*
  2.  * @(#)Permissions.java    1.30 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17. import java.util.Enumeration; 
  18. import java.util.Hashtable;
  19. import java.util.NoSuchElementException;
  20. import java.io.Serializable;
  21. import java.util.ArrayList;
  22.  
  23. /**  
  24.  * This class represents a heterogeneous collection of Permissions. That is,
  25.  * it contains different types of Permission objects, organized into
  26.  * PermissionCollections. For example, if any <code>java.io.FilePermission</code>
  27.  * objects are added to an instance of this class, they are all stored in a single
  28.  * PermissionCollection. It is the PermissionCollection returned by a call to
  29.  * the <code>newPermissionCollection</code> method in the FilePermission class.
  30.  * Similarly, any <code>java.lang.RuntimePermission</code> objects are stored in 
  31.  * the PermissionCollection returned by a call to the 
  32.  * <code>newPermissionCollection</code> method in the
  33.  * RuntimePermission class. Thus, this class represents a collection of
  34.  * PermissionCollections.
  35.  * 
  36.  * <p>When the <code>add</code> method is called to add a Permission, the 
  37.  * Permission is stored in the appropriate PermissionCollection. If no such 
  38.  * collection exists yet, the Permission object's class is determined and the
  39.  * <code>newPermissionCollection</code> method is called on that class to create
  40.  * the PermissionCollection and add it to the Permissions object. If
  41.  * <code>newPermissionCollection</code> returns null, then a default 
  42.  * PermissionCollection that uses a hashtable will be created and used. Each 
  43.  * hashtable entry has a Permission object's name as the key, and the Permission
  44.  * object as the value.
  45.  * 
  46.  * @see Permission
  47.  * @see PermissionCollection
  48.  * @see AllPermission
  49.  * 
  50.  * @version 1.30, 98/03/18
  51.  *
  52.  * @author Marianne Mueller
  53.  * @author Roland Schemers
  54.  */
  55.  
  56. public final class Permissions extends PermissionCollection 
  57. implements Serializable 
  58. {
  59.     /** use serialVersionUID from JDK 1.2 for interoperability */
  60.     private static final long serialVersionUID = -564687543657373888L;
  61.  
  62.  
  63.     private Hashtable perms;
  64.  
  65.     // optimization. keep track of the AllPermission collection
  66.     private PermissionCollection allPermission;
  67.  
  68.     // when set, add will throw an exception.
  69.     private boolean readOnly;
  70.  
  71.     /**
  72.      * Creates a new Permissions object containing no PermissionCollections.
  73.      */
  74.     public Permissions() {
  75.     perms = new Hashtable();
  76.     allPermission = null;
  77.     readOnly = false;
  78.     }
  79.  
  80.     /**
  81.      * Adds a permission object to the PermissionCollection for the class the
  82.      * permission belongs to. For example, if <i>permission</i> is a FilePermission,
  83.      * it is added to the FilePermissionCollection stored in this
  84.      * Permissions object. 
  85.      * 
  86.      * This method creates
  87.      * a new PermissionCollection object (and adds the permission to it)
  88.      * if an appropriate collection does not yet exist. <p>
  89.      *
  90.      * @param permission the Permission object to add.
  91.      * 
  92.      * @exception SecurityException if this Permissions object is
  93.      * marked as readonly.
  94.      * 
  95.      * @see isReadOnly
  96.      */
  97.  
  98.     public void add(Permission permission) {
  99.     if (readOnly)
  100.         throw new SecurityException(
  101.               "attempt to add a Permission to a readonly Permissions object");
  102.     PermissionCollection pc = getPermissionCollection(permission);
  103.     pc.add(permission);
  104.     if (permission instanceof AllPermission) {
  105.         allPermission = pc;
  106.     }
  107.     }
  108.  
  109.     /**
  110.      * Checks to see if this object's PermissionCollection for permissions of the
  111.      * specified permission's type implies the permissions 
  112.      * expressed in the <i>permission</i> object. Returns true if the combination
  113.      * of permissions in the appropriate PermissionCollection (e.g., a
  114.      * FilePermissionCollection for a FilePermission) together imply the
  115.      * specified permission.
  116.      * 
  117.      * <p>For example, suppose there is a FilePermissionCollection in this Permissions
  118.      * object, and it contains one FilePermission that specifies "read" access for
  119.      * all files in all subdirectories of the "/tmp" directory, and another
  120.      * FilePermission that specifies "write" access for all files in the
  121.      * "/tmp/scratch/foo" directory. Then if the <code>implies</code> method
  122.      * is called with a permission specifying both "read" and "write" access
  123.      * to files in the "/tmp/scratch/foo" directory, <code>true</code> is returned.
  124.      * <p>Additionally, if this PermissionCollection contains the
  125.      * AllPermission, this method will always return true.
  126.      * <p>
  127.      * @param permission the Permission object to check.
  128.      *
  129.      * @return true if "permission" is implied by the permissions in the
  130.      * PermissionCollection it
  131.      * belongs to, false if not.
  132.      */
  133.  
  134.     public boolean implies(Permission permission) {
  135.     PermissionCollection pc = getPermissionCollection(permission);
  136.  
  137.     if (allPermission != null && allPermission.implies(permission))
  138.         return true;
  139.     else 
  140.         return pc.implies(permission);
  141.     }
  142.  
  143.     /**
  144.      * Returns an enumeration of all the Permission objects in all the
  145.      * PermissionCollections in this Permissions object.
  146.      *
  147.      * @return an enumeration of all the Permissions.
  148.      */
  149.  
  150.     public Enumeration elements() {
  151.     // go through each Permissions in the hash table 
  152.     // and call their elements() function.
  153.     return new PermissionsEnumerator(perms.elements());
  154.     }
  155.  
  156.     /**
  157.      * Returns an enumeration of all the Permission objects with the same
  158.      * type as <i>p</i>.
  159.      *
  160.      * @param p the prototype Permission object.
  161.      *
  162.      * @return an enumeration of all the Permissions with the same type as <i>p</i>.
  163.      */
  164.  
  165.     // XXX this could be public. Question is, do we want to make it public?
  166.     // it is currently trivial to implement, but that might change...
  167.  
  168.     private Enumeration elements(Permission p) {
  169.     PermissionCollection pc = getPermissionCollection(p);
  170.     return pc.elements();
  171.     }
  172.  
  173.     /** 
  174.      * Gets the PermissionCollection in this Permissions object for
  175.      * permissions whose type is the same as that of <i>p</i>.
  176.      * For example, if <i>p</i> is a FilePermission, the FilePermissionCollection
  177.      * stored in this Permissions object will be returned. 
  178.      * 
  179.      * This method creates a new PermissionCollection object for the specified 
  180.      * type of permission objects if one does not yet exist. 
  181.      * To do so, it first calls the <code>newPermissionCollection</code> method
  182.      * on <i>p</i>.  Subclasses of class Permission 
  183.      * override that method if they need to store their permissions in a particular
  184.      * PermissionCollection object in order to provide the correct semantics
  185.      * when the <code>PermissionCollection.implies</code> method is called.
  186.      * If the call returns a PermissionCollection, that collection is stored
  187.      * in this Permissions object. If the call returns null, then
  188.      * this method instantiates and stores a default PermissionCollection 
  189.      * that uses a hashtable to store its permission objects.
  190.      */
  191.  
  192.     private PermissionCollection getPermissionCollection(Permission p) {
  193.     Class c = p.getClass();
  194.     PermissionCollection pc = (PermissionCollection) perms.get(c);
  195.     if (pc == null) {
  196.         synchronized (perms) {
  197.         // check again, in case someone else created one
  198.         // between the time we checked and the time we
  199.         // got the lock. We do this here to avoid 
  200.         // making this whole method synchronized, because
  201.         // it is called by every public method.
  202.         pc = (PermissionCollection) perms.get(c);
  203.  
  204.         //check for unresolved permissions
  205.         if (pc == null) {
  206.  
  207.             pc = getUnresolvedPermissions(p);
  208.  
  209.             // if still null, create a new collection
  210.             if (pc == null) {
  211.  
  212.             pc = p.newPermissionCollection();
  213.  
  214.             // still no PermissionCollection? 
  215.             // We'll give them a PermissionsHash.
  216.             if (pc == null)
  217.                 pc = new PermissionsHash();
  218.             }
  219.         }
  220.         perms.put(c, pc);
  221.         }
  222.     }
  223.     return pc;
  224.     }
  225.  
  226.     /**
  227.      * Resolves any unresolved permissions of type p.
  228.      *
  229.      * @param p the type of unresolved permission to resolve
  230.      *
  231.      * @return PermissionCollection containing the unresolved permissions,
  232.      *  or null if there were no unresolved permissions of type p.
  233.      *
  234.      */
  235.     private PermissionCollection getUnresolvedPermissions(Permission p)
  236.     {
  237.     UnresolvedPermissionCollection uc = 
  238.     (UnresolvedPermissionCollection) perms.get(UnresolvedPermission.class);
  239.  
  240.     // we have no unresolved permissions if uc is null
  241.     if (uc == null) 
  242.         return null;
  243.  
  244.     java.util.Vector v = uc.removeUnresolvedPermissions(p);
  245.     
  246.     // we have no unresolved permissions of this type if v is null
  247.     if (v == null)
  248.         return null;
  249.  
  250.     PublicKey keys[] = null;
  251.  
  252.     Object signers[] = p.getClass().getSigners();
  253.  
  254.     if (signers != null) {
  255.         ArrayList keysAL = new ArrayList();
  256.         for (int j=0; j < signers.length; j++) {
  257.         if (signers[j] instanceof Identity) {
  258.             PublicKey pk = ((Identity) signers[j]).getPublicKey();
  259.             if (pk != null)
  260.             keysAL.add(pk);
  261.         }
  262.         }
  263.         keys = new PublicKey[keysAL.size()];
  264.         for (int k=0; k< keysAL.size(); k++) {
  265.         keys[k] = (PublicKey) keysAL.get(k);
  266.         }
  267.     }
  268.  
  269.     PermissionCollection pc = null;
  270.     Enumeration e = v.elements();
  271.  
  272.     while(e.hasMoreElements()) {
  273.         UnresolvedPermission up = (UnresolvedPermission) e.nextElement();
  274.         Permission perm = up.resolve(p, keys);
  275.         if (perm != null) {
  276.         if (pc == null) {
  277.             pc = p.newPermissionCollection();
  278.             if (pc == null) 
  279.             pc = new PermissionsHash();
  280.         }
  281.         pc.add(perm);
  282.         }
  283.  
  284.     }
  285.     return pc;
  286.     }
  287.  
  288.     /**
  289.      * Marks this Permissions object as "readonly". After a Permissions object
  290.      * is marked as readonly, no new Permission objects can be added to it
  291.      * using <code>addPermission</code>.
  292.      */
  293.     public void setReadOnly() {
  294.     readOnly = true;
  295.     }
  296.  
  297.     /**
  298.      * Returns true if this Permissions object is marked as readonly. If it
  299.      * is readonly, no new Permission objects can be added to it
  300.      * using <code>addPermission</code>.
  301.      * 
  302.      * <p>By default, the object is <i>not</i> readonly. It can be set to readonly
  303.      * by a call to <code>setReadOnly</code>.
  304.      *
  305.      * @return true if this Permissions object is marked as readonly, false
  306.      * otherwise.
  307.      */
  308.     public boolean isReadOnly() {
  309.     return readOnly;
  310.     }
  311. }
  312.  
  313. final class PermissionsEnumerator implements Enumeration {
  314.  
  315.     // all the perms
  316.     private Enumeration perms;
  317.     // the current set
  318.     private Enumeration permset;
  319.    
  320.     PermissionsEnumerator(Enumeration e) {
  321.     perms = e;
  322.     permset = getNextEnumWithMore();
  323.     }
  324.  
  325.     public synchronized boolean hasMoreElements() {
  326.     // if we enter with permissionimpl null, we know
  327.     // there are no more left.
  328.  
  329.     if (permset == null) 
  330.         return  false;
  331.  
  332.     // try to see if there are any left in the current one
  333.  
  334.     if (permset.hasMoreElements())
  335.         return true;
  336.  
  337.     // get the next one that has something in it...
  338.     permset = getNextEnumWithMore();
  339.  
  340.     // if it is null, we are done!
  341.     return (permset != null);
  342.     }
  343.  
  344.     public synchronized Object nextElement() {
  345.  
  346.     // hasMoreElements will update permset to the next permset
  347.     // with something in it...
  348.  
  349.     if (hasMoreElements()) {
  350.         return permset.nextElement();
  351.     } else {
  352.         throw new NoSuchElementException("PermissionsEnumerator");
  353.     }
  354.  
  355.     }
  356.  
  357.     private Enumeration getNextEnumWithMore() {
  358.     while (perms.hasMoreElements()) {
  359.         PermissionCollection pc = (PermissionCollection) perms.nextElement();
  360.         Enumeration next = (Enumeration) pc.elements();
  361.         if (next.hasMoreElements())
  362.         return next;
  363.     }
  364.     return null;
  365.     }
  366. }
  367.  
  368. /**
  369.  * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
  370.  *
  371.  * @see Permission
  372.  * @see Permissions
  373.  *
  374.  * @version 1.30, 98/03/18
  375.  *
  376.  * @author Roland Schemers
  377.  */
  378.  
  379. final class PermissionsHash extends PermissionCollection
  380. implements Serializable
  381. {
  382.     /** use serialVersionUID from JDK 1.2 for interoperability */
  383.     private static final long serialVersionUID = -8491988220802933440L;
  384.  
  385.     private Hashtable perms;
  386.  
  387.     /**
  388.      * Create an empty PermissionsHash object.
  389.      */
  390.  
  391.     PermissionsHash() {
  392.     perms = new Hashtable();
  393.     }
  394.  
  395.     /**
  396.      * Adds a permission to the PermissionsHash.
  397.      *
  398.      * @param permission the Permission object to add.
  399.      */
  400.  
  401.     public void add(Permission permission)
  402.     {
  403.     // XXX this assumes we replace duplicate Permissions
  404.     perms.put(permission.getName(), permission);
  405.     }
  406.  
  407.     /**
  408.      * Check and see if this set of permissions implies the permissions 
  409.      * expressed in "permission".
  410.      *
  411.      * @param permission the Permission object to compare
  412.      *
  413.      * @return true if "permission" is a proper subset of a permission in 
  414.      * the set, false if not.
  415.      */
  416.  
  417.     public boolean implies(Permission permission) 
  418.     {
  419.     Permission p = (Permission) perms.get(permission.getName());
  420.     if (p == null) 
  421.         return false;
  422.     else 
  423.         return p.implies(permission);
  424.     }
  425.  
  426.     /**
  427.      * Returns an enumeration of all the Permission objects in the container.
  428.      *
  429.      * @return an enumeration of all the Permissions.
  430.      */
  431.  
  432.     public Enumeration elements()
  433.     {
  434.     return perms.elements();
  435.     }
  436. }
  437.  
  438.