Save This Page
Home » openjdk-7 » java » security » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.security;
   27   
   28   import java.util.Enumeration;
   29   import java.util.Hashtable;
   30   import java.util.NoSuchElementException;
   31   import java.util.Map;
   32   import java.util.HashMap;
   33   import java.util.List;
   34   import java.util.ArrayList;
   35   import java.util.Iterator;
   36   import java.util.Collections;
   37   import java.io.Serializable;
   38   import java.io.ObjectStreamField;
   39   import java.io.ObjectOutputStream;
   40   import java.io.ObjectInputStream;
   41   import java.io.IOException;
   42   
   43   
   44   /**
   45    * This class represents a heterogeneous collection of Permissions. That is,
   46    * it contains different types of Permission objects, organized into
   47    * PermissionCollections. For example, if any
   48    * <code>java.io.FilePermission</code> objects are added to an instance of
   49    * this class, they are all stored in a single
   50    * PermissionCollection. It is the PermissionCollection returned by a call to
   51    * the <code>newPermissionCollection</code> method in the FilePermission class.
   52    * Similarly, any <code>java.lang.RuntimePermission</code> objects are
   53    * stored in the PermissionCollection returned by a call to the
   54    * <code>newPermissionCollection</code> method in the
   55    * RuntimePermission class. Thus, this class represents a collection of
   56    * PermissionCollections.
   57    *
   58    * <p>When the <code>add</code> method is called to add a Permission, the
   59    * Permission is stored in the appropriate PermissionCollection. If no such
   60    * collection exists yet, the Permission object's class is determined and the
   61    * <code>newPermissionCollection</code> method is called on that class to create
   62    * the PermissionCollection and add it to the Permissions object. If
   63    * <code>newPermissionCollection</code> returns null, then a default
   64    * PermissionCollection that uses a hashtable will be created and used. Each
   65    * hashtable entry stores a Permission object as both the key and the value.
   66    *
   67    * <p> Enumerations returned via the <code>elements</code> method are
   68    * not <em>fail-fast</em>.  Modifications to a collection should not be
   69    * performed while enumerating over that collection.
   70    *
   71    * @see Permission
   72    * @see PermissionCollection
   73    * @see AllPermission
   74    *
   75    *
   76    * @author Marianne Mueller
   77    * @author Roland Schemers
   78    *
   79    * @serial exclude
   80    */
   81   
   82   public final class Permissions extends PermissionCollection
   83   implements Serializable
   84   {
   85       /**
   86        * Key is permissions Class, value is PermissionCollection for that class.
   87        * Not serialized; see serialization section at end of class.
   88        */
   89       private transient Map<Class<?>, PermissionCollection> permsMap;
   90   
   91       // optimization. keep track of whether unresolved permissions need to be
   92       // checked
   93       private transient boolean hasUnresolved = false;
   94   
   95       // optimization. keep track of the AllPermission collection
   96       // - package private for ProtectionDomain optimization
   97       PermissionCollection allPermission;
   98   
   99       /**
  100        * Creates a new Permissions object containing no PermissionCollections.
  101        */
  102       public Permissions() {
  103           permsMap = new HashMap<Class<?>, PermissionCollection>(11);
  104           allPermission = null;
  105       }
  106   
  107       /**
  108        * Adds a permission object to the PermissionCollection for the class the
  109        * permission belongs to. For example, if <i>permission</i> is a
  110        * FilePermission, it is added to the FilePermissionCollection stored
  111        * in this Permissions object.
  112        *
  113        * This method creates
  114        * a new PermissionCollection object (and adds the permission to it)
  115        * if an appropriate collection does not yet exist. <p>
  116        *
  117        * @param permission the Permission object to add.
  118        *
  119        * @exception SecurityException if this Permissions object is
  120        * marked as readonly.
  121        *
  122        * @see PermissionCollection#isReadOnly()
  123        */
  124   
  125       public void add(Permission permission) {
  126           if (isReadOnly())
  127               throw new SecurityException(
  128                 "attempt to add a Permission to a readonly Permissions object");
  129   
  130           PermissionCollection pc;
  131   
  132           synchronized (this) {
  133               pc = getPermissionCollection(permission, true);
  134               pc.add(permission);
  135           }
  136   
  137           // No sync; staleness -> optimizations delayed, which is OK
  138           if (permission instanceof AllPermission) {
  139               allPermission = pc;
  140           }
  141           if (permission instanceof UnresolvedPermission) {
  142               hasUnresolved = true;
  143           }
  144       }
  145   
  146       /**
  147        * Checks to see if this object's PermissionCollection for permissions of
  148        * the specified permission's class implies the permissions
  149        * expressed in the <i>permission</i> object. Returns true if the
  150        * combination of permissions in the appropriate PermissionCollection
  151        * (e.g., a FilePermissionCollection for a FilePermission) together
  152        * imply the specified permission.
  153        *
  154        * <p>For example, suppose there is a FilePermissionCollection in this
  155        * Permissions object, and it contains one FilePermission that specifies
  156        * "read" access for  all files in all subdirectories of the "/tmp"
  157        * directory, and another FilePermission that specifies "write" access
  158        * for all files in the "/tmp/scratch/foo" directory.
  159        * Then if the <code>implies</code> method
  160        * is called with a permission specifying both "read" and "write" access
  161        * to files in the "/tmp/scratch/foo" directory, <code>true</code> is
  162        * returned.
  163        *
  164        * <p>Additionally, if this PermissionCollection contains the
  165        * AllPermission, this method will always return true.
  166        * <p>
  167        * @param permission the Permission object to check.
  168        *
  169        * @return true if "permission" is implied by the permissions in the
  170        * PermissionCollection it
  171        * belongs to, false if not.
  172        */
  173   
  174       public boolean implies(Permission permission) {
  175           // No sync; staleness -> skip optimization, which is OK
  176           if (allPermission != null) {
  177               return true; // AllPermission has already been added
  178           } else {
  179               synchronized (this) {
  180                   PermissionCollection pc = getPermissionCollection(permission,
  181                       false);
  182                   if (pc != null) {
  183                       return pc.implies(permission);
  184                   } else {
  185                       // none found
  186                       return false;
  187                   }
  188               }
  189           }
  190       }
  191   
  192       /**
  193        * Returns an enumeration of all the Permission objects in all the
  194        * PermissionCollections in this Permissions object.
  195        *
  196        * @return an enumeration of all the Permissions.
  197        */
  198   
  199       public Enumeration<Permission> elements() {
  200           // go through each Permissions in the hash table
  201           // and call their elements() function.
  202   
  203           synchronized (this) {
  204               return new PermissionsEnumerator(permsMap.values().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       {
  281           // Called from within synchronized method so permsMap doesn't need lock
  282   
  283           UnresolvedPermissionCollection uc =
  284           (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
  285   
  286           // we have no unresolved permissions if uc is null
  287           if (uc == null)
  288               return null;
  289   
  290           List<UnresolvedPermission> unresolvedPerms =
  291                                           uc.getUnresolvedPermissions(p);
  292   
  293           // we have no unresolved permissions of this type if unresolvedPerms is null
  294           if (unresolvedPerms == null)
  295               return null;
  296   
  297           java.security.cert.Certificate certs[] = null;
  298   
  299           Object signers[] = p.getClass().getSigners();
  300   
  301           int n = 0;
  302           if (signers != null) {
  303               for (int j=0; j < signers.length; j++) {
  304                   if (signers[j] instanceof java.security.cert.Certificate) {
  305                       n++;
  306                   }
  307               }
  308               certs = new java.security.cert.Certificate[n];
  309               n = 0;
  310               for (int j=0; j < signers.length; j++) {
  311                   if (signers[j] instanceof java.security.cert.Certificate) {
  312                       certs[n++] = (java.security.cert.Certificate)signers[j];
  313                   }
  314               }
  315           }
  316   
  317           PermissionCollection pc = null;
  318           synchronized (unresolvedPerms) {
  319               int len = unresolvedPerms.size();
  320               for (int i = 0; i < len; i++) {
  321                   UnresolvedPermission up = unresolvedPerms.get(i);
  322                   Permission perm = up.resolve(p, certs);
  323                   if (perm != null) {
  324                       if (pc == null) {
  325                           pc = p.newPermissionCollection();
  326                           if (pc == null)
  327                               pc = new PermissionsHash();
  328                       }
  329                       pc.add(perm);
  330                   }
  331               }
  332           }
  333           return pc;
  334       }
  335   
  336       private static final long serialVersionUID = 4858622370623524688L;
  337   
  338       // Need to maintain serialization interoperability with earlier releases,
  339       // which had the serializable field:
  340       // private Hashtable perms;
  341   
  342       /**
  343        * @serialField perms java.util.Hashtable
  344        *     A table of the Permission classes and PermissionCollections.
  345        * @serialField allPermission java.security.PermissionCollection
  346        */
  347       private static final ObjectStreamField[] serialPersistentFields = {
  348           new ObjectStreamField("perms", Hashtable.class),
  349           new ObjectStreamField("allPermission", PermissionCollection.class),
  350       };
  351   
  352       /**
  353        * @serialData Default fields.
  354        */
  355       /*
  356        * Writes the contents of the permsMap field out as a Hashtable for
  357        * serialization compatibility with earlier releases. allPermission
  358        * unchanged.
  359        */
  360       private void writeObject(ObjectOutputStream out) throws IOException {
  361           // Don't call out.defaultWriteObject()
  362   
  363           // Copy perms into a Hashtable
  364           Hashtable<Class<?>, PermissionCollection> perms =
  365               new Hashtable<>(permsMap.size()*2); // no sync; estimate
  366           synchronized (this) {
  367               perms.putAll(permsMap);
  368           }
  369   
  370           // Write out serializable fields
  371           ObjectOutputStream.PutField pfields = out.putFields();
  372   
  373           pfields.put("allPermission", allPermission); // no sync; staleness OK
  374           pfields.put("perms", perms);
  375           out.writeFields();
  376       }
  377   
  378       /*
  379        * Reads in a Hashtable of Class/PermissionCollections and saves them in the
  380        * permsMap field. Reads in allPermission.
  381        */
  382       private void readObject(ObjectInputStream in) throws IOException,
  383       ClassNotFoundException {
  384           // Don't call defaultReadObject()
  385   
  386           // Read in serialized fields
  387           ObjectInputStream.GetField gfields = in.readFields();
  388   
  389           // Get allPermission
  390           allPermission = (PermissionCollection) gfields.get("allPermission", null);
  391   
  392           // Get permissions
  393           Hashtable<Class<?>, PermissionCollection> perms =
  394               (Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
  395           permsMap = new HashMap<Class<?>, PermissionCollection>(perms.size()*2);
  396           permsMap.putAll(perms);
  397   
  398           // Set hasUnresolved
  399           UnresolvedPermissionCollection uc =
  400           (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);
  401           hasUnresolved = (uc != null && uc.elements().hasMoreElements());
  402       }
  403   }
  404   
  405   final class PermissionsEnumerator implements Enumeration<Permission> {
  406   
  407       // all the perms
  408       private Iterator<PermissionCollection> perms;
  409       // the current set
  410       private Enumeration<Permission> permset;
  411   
  412       PermissionsEnumerator(Iterator<PermissionCollection> e) {
  413           perms = e;
  414           permset = getNextEnumWithMore();
  415       }
  416   
  417       // No need to synchronize; caller should sync on object as required
  418       public boolean hasMoreElements() {
  419           // if we enter with permissionimpl null, we know
  420           // there are no more left.
  421   
  422           if (permset == null)
  423               return  false;
  424   
  425           // try to see if there are any left in the current one
  426   
  427           if (permset.hasMoreElements())
  428               return true;
  429   
  430           // get the next one that has something in it...
  431           permset = getNextEnumWithMore();
  432   
  433           // if it is null, we are done!
  434           return (permset != null);
  435       }
  436   
  437       // No need to synchronize; caller should sync on object as required
  438       public Permission nextElement() {
  439   
  440           // hasMoreElements will update permset to the next permset
  441           // with something in it...
  442   
  443           if (hasMoreElements()) {
  444               return permset.nextElement();
  445           } else {
  446               throw new NoSuchElementException("PermissionsEnumerator");
  447           }
  448   
  449       }
  450   
  451       private Enumeration<Permission> getNextEnumWithMore() {
  452           while (perms.hasNext()) {
  453               PermissionCollection pc = perms.next();
  454               Enumeration<Permission> next =pc.elements();
  455               if (next.hasMoreElements())
  456                   return next;
  457           }
  458           return null;
  459   
  460       }
  461   }
  462   
  463   /**
  464    * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
  465    *
  466    * @see Permission
  467    * @see Permissions
  468    *
  469    *
  470    * @author Roland Schemers
  471    *
  472    * @serial include
  473    */
  474   
  475   final class PermissionsHash extends PermissionCollection
  476   implements Serializable
  477   {
  478       /**
  479        * Key and value are (same) permissions objects.
  480        * Not serialized; see serialization section at end of class.
  481        */
  482       private transient Map<Permission, Permission> permsMap;
  483   
  484       /**
  485        * Create an empty PermissionsHash object.
  486        */
  487   
  488       PermissionsHash() {
  489           permsMap = new HashMap<Permission, Permission>(11);
  490       }
  491   
  492       /**
  493        * Adds a permission to the PermissionsHash.
  494        *
  495        * @param permission the Permission object to add.
  496        */
  497   
  498       public void add(Permission permission) {
  499           synchronized (this) {
  500               permsMap.put(permission, permission);
  501           }
  502       }
  503   
  504       /**
  505        * Check and see if this set of permissions implies the permissions
  506        * expressed in "permission".
  507        *
  508        * @param permission the Permission object to compare
  509        *
  510        * @return true if "permission" is a proper subset of a permission in
  511        * the set, false if not.
  512        */
  513   
  514       public boolean implies(Permission permission) {
  515           // attempt a fast lookup and implies. If that fails
  516           // then enumerate through all the permissions.
  517           synchronized (this) {
  518               Permission p = permsMap.get(permission);
  519   
  520               // If permission is found, then p.equals(permission)
  521               if (p == null) {
  522                   for (Permission p_ : permsMap.values()) {
  523                       if (p_.implies(permission))
  524                           return true;
  525                   }
  526                   return false;
  527               } else {
  528                   return true;
  529               }
  530           }
  531       }
  532   
  533       /**
  534        * Returns an enumeration of all the Permission objects in the container.
  535        *
  536        * @return an enumeration of all the Permissions.
  537        */
  538   
  539       public Enumeration<Permission> elements() {
  540           // Convert Iterator of Map values into an Enumeration
  541           synchronized (this) {
  542               return Collections.enumeration(permsMap.values());
  543           }
  544       }
  545   
  546       private static final long serialVersionUID = -8491988220802933440L;
  547       // Need to maintain serialization interoperability with earlier releases,
  548       // which had the serializable field:
  549       // private Hashtable perms;
  550       /**
  551        * @serialField perms java.util.Hashtable
  552        *     A table of the Permissions (both key and value are same).
  553        */
  554       private static final ObjectStreamField[] serialPersistentFields = {
  555           new ObjectStreamField("perms", Hashtable.class),
  556       };
  557   
  558       /**
  559        * @serialData Default fields.
  560        */
  561       /*
  562        * Writes the contents of the permsMap field out as a Hashtable for
  563        * serialization compatibility with earlier releases.
  564        */
  565       private void writeObject(ObjectOutputStream out) throws IOException {
  566           // Don't call out.defaultWriteObject()
  567   
  568           // Copy perms into a Hashtable
  569           Hashtable<Permission, Permission> perms =
  570                   new Hashtable<>(permsMap.size()*2);
  571           synchronized (this) {
  572               perms.putAll(permsMap);
  573           }
  574   
  575           // Write out serializable fields
  576           ObjectOutputStream.PutField pfields = out.putFields();
  577           pfields.put("perms", perms);
  578           out.writeFields();
  579       }
  580   
  581       /*
  582        * Reads in a Hashtable of Permission/Permission and saves them in the
  583        * permsMap field.
  584        */
  585       private void readObject(ObjectInputStream in) throws IOException,
  586       ClassNotFoundException {
  587           // Don't call defaultReadObject()
  588   
  589           // Read in serialized fields
  590           ObjectInputStream.GetField gfields = in.readFields();
  591   
  592           // Get permissions
  593           Hashtable<Permission, Permission> perms =
  594                   (Hashtable<Permission, Permission>)gfields.get("perms", null);
  595           permsMap = new HashMap<Permission, Permission>(perms.size()*2);
  596           permsMap.putAll(perms);
  597       }
  598   }

Save This Page
Home » openjdk-7 » java » security » [javadoc | source]