Save This Page
Home » openjdk-7 » javax.security » auth » [javadoc | source]
    1   /*
    2    * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.security.auth;
   27   
   28   import java.security.AccessController;
   29   import java.security.AccessControlContext;
   30   import java.security.AllPermission;
   31   import java.security.Permission;
   32   import java.security.Permissions;
   33   import java.security.PermissionCollection;
   34   import java.security.Policy;
   35   import java.security.Principal;
   36   import java.security.PrivilegedAction;
   37   import java.security.ProtectionDomain;
   38   import java.lang.ClassLoader;
   39   import java.security.Security;
   40   import java.util.Set;
   41   import java.util.Iterator;
   42   import java.util.WeakHashMap;
   43   import java.lang.ref.WeakReference;
   44   
   45   /**
   46    * A <code>SubjectDomainCombiner</code> updates ProtectionDomains
   47    * with Principals from the <code>Subject</code> associated with this
   48    * <code>SubjectDomainCombiner</code>.
   49    *
   50    */
   51   public class SubjectDomainCombiner implements java.security.DomainCombiner {
   52   
   53       private Subject subject;
   54       private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =
   55                   new WeakKeyValueMap<ProtectionDomain, ProtectionDomain>();
   56       private Set<Principal> principalSet;
   57       private Principal[] principals;
   58   
   59       private static final sun.security.util.Debug debug =
   60           sun.security.util.Debug.getInstance("combiner",
   61                                           "\t[SubjectDomainCombiner]");
   62   
   63       // Note: check only at classloading time, not dynamically during combine()
   64       private static final boolean useJavaxPolicy = compatPolicy();
   65   
   66       // Relevant only when useJavaxPolicy is true
   67       private static final boolean allowCaching =
   68                                           (useJavaxPolicy && cachePolicy());
   69   
   70       /**
   71        * Associate the provided <code>Subject</code> with this
   72        * <code>SubjectDomainCombiner</code>.
   73        *
   74        * <p>
   75        *
   76        * @param subject the <code>Subject</code> to be associated with
   77        *          with this <code>SubjectDomainCombiner</code>.
   78        */
   79       public SubjectDomainCombiner(Subject subject) {
   80           this.subject = subject;
   81   
   82           if (subject.isReadOnly()) {
   83               principalSet = subject.getPrincipals();
   84               principals = principalSet.toArray
   85                           (new Principal[principalSet.size()]);
   86           }
   87       }
   88   
   89       /**
   90        * Get the <code>Subject</code> associated with this
   91        * <code>SubjectDomainCombiner</code>.
   92        *
   93        * <p>
   94        *
   95        * @return the <code>Subject</code> associated with this
   96        *          <code>SubjectDomainCombiner</code>, or <code>null</code>
   97        *          if no <code>Subject</code> is associated with this
   98        *          <code>SubjectDomainCombiner</code>.
   99        *
  100        * @exception SecurityException if the caller does not have permission
  101        *          to get the <code>Subject</code> associated with this
  102        *          <code>SubjectDomainCombiner</code>.
  103        */
  104       public Subject getSubject() {
  105           java.lang.SecurityManager sm = System.getSecurityManager();
  106           if (sm != null) {
  107               sm.checkPermission(new AuthPermission
  108                   ("getSubjectFromDomainCombiner"));
  109           }
  110           return subject;
  111       }
  112   
  113       /**
  114        * Update the relevant ProtectionDomains with the Principals
  115        * from the <code>Subject</code> associated with this
  116        * <code>SubjectDomainCombiner</code>.
  117        *
  118        * <p> A new <code>ProtectionDomain</code> instance is created
  119        * for each <code>ProtectionDomain</code> in the
  120        * <i>currentDomains</i> array.  Each new <code>ProtectionDomain</code>
  121        * instance is created using the <code>CodeSource</code>,
  122        * <code>Permission</code>s and <code>ClassLoader</code>
  123        * from the corresponding <code>ProtectionDomain</code> in
  124        * <i>currentDomains</i>, as well as with the Principals from
  125        * the <code>Subject</code> associated with this
  126        * <code>SubjectDomainCombiner</code>.
  127        *
  128        * <p> All of the newly instantiated ProtectionDomains are
  129        * combined into a new array.  The ProtectionDomains from the
  130        * <i>assignedDomains</i> array are appended to this new array,
  131        * and the result is returned.
  132        *
  133        * <p> Note that optimizations such as the removal of duplicate
  134        * ProtectionDomains may have occurred.
  135        * In addition, caching of ProtectionDomains may be permitted.
  136        *
  137        * <p>
  138        *
  139        * @param currentDomains the ProtectionDomains associated with the
  140        *          current execution Thread, up to the most recent
  141        *          privileged <code>ProtectionDomain</code>.
  142        *          The ProtectionDomains are are listed in order of execution,
  143        *          with the most recently executing <code>ProtectionDomain</code>
  144        *          residing at the beginning of the array. This parameter may
  145        *          be <code>null</code> if the current execution Thread
  146        *          has no associated ProtectionDomains.<p>
  147        *
  148        * @param assignedDomains the ProtectionDomains inherited from the
  149        *          parent Thread, or the ProtectionDomains from the
  150        *          privileged <i>context</i>, if a call to
  151        *          AccessController.doPrivileged(..., <i>context</i>)
  152        *          had occurred  This parameter may be <code>null</code>
  153        *          if there were no ProtectionDomains inherited from the
  154        *          parent Thread, or from the privileged <i>context</i>.
  155        *
  156        * @return a new array consisting of the updated ProtectionDomains,
  157        *          or <code>null</code>.
  158        */
  159       public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
  160                                   ProtectionDomain[] assignedDomains) {
  161           if (debug != null) {
  162               if (subject == null) {
  163                   debug.println("null subject");
  164               } else {
  165                   final Subject s = subject;
  166                   AccessController.doPrivileged
  167                       (new java.security.PrivilegedAction<Void>() {
  168                       public Void run() {
  169                           debug.println(s.toString());
  170                           return null;
  171                       }
  172                   });
  173               }
  174               printInputDomains(currentDomains, assignedDomains);
  175           }
  176   
  177           if (currentDomains == null || currentDomains.length == 0) {
  178               // No need to optimize assignedDomains because it should
  179               // have been previously optimized (when it was set).
  180   
  181               // Note that we are returning a direct reference
  182               // to the input array - since ACC does not clone
  183               // the arrays when it calls combiner.combine,
  184               // multiple ACC instances may share the same
  185               // array instance in this case
  186   
  187               return assignedDomains;
  188           }
  189   
  190           // optimize currentDomains
  191           //
  192           // No need to optimize assignedDomains because it should
  193           // have been previously optimized (when it was set).
  194   
  195           currentDomains = optimize(currentDomains);
  196           if (debug != null) {
  197               debug.println("after optimize");
  198               printInputDomains(currentDomains, assignedDomains);
  199           }
  200   
  201           if (currentDomains == null && assignedDomains == null) {
  202               return null;
  203           }
  204   
  205           // maintain backwards compatibility for people who provide
  206           // their own javax.security.auth.Policy implementations
  207           if (useJavaxPolicy) {
  208               return combineJavaxPolicy(currentDomains, assignedDomains);
  209           }
  210   
  211           int cLen = (currentDomains == null ? 0 : currentDomains.length);
  212           int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
  213   
  214           // the ProtectionDomains for the new AccessControlContext
  215           // that we will return
  216           ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
  217   
  218           boolean allNew = true;
  219           synchronized(cachedPDs) {
  220               if (!subject.isReadOnly() &&
  221                   !subject.getPrincipals().equals(principalSet)) {
  222   
  223                   // if the Subject was mutated, clear the PD cache
  224                   Set<Principal> newSet = subject.getPrincipals();
  225                   synchronized(newSet) {
  226                       principalSet = new java.util.HashSet<Principal>(newSet);
  227                   }
  228                   principals = principalSet.toArray
  229                           (new Principal[principalSet.size()]);
  230                   cachedPDs.clear();
  231   
  232                   if (debug != null) {
  233                       debug.println("Subject mutated - clearing cache");
  234                   }
  235               }
  236   
  237               ProtectionDomain subjectPd;
  238               for (int i = 0; i < cLen; i++) {
  239                   ProtectionDomain pd = currentDomains[i];
  240   
  241                   subjectPd = cachedPDs.getValue(pd);
  242   
  243                   if (subjectPd == null) {
  244                       subjectPd = new ProtectionDomain(pd.getCodeSource(),
  245                                                   pd.getPermissions(),
  246                                                   pd.getClassLoader(),
  247                                                   principals);
  248                       cachedPDs.putValue(pd, subjectPd);
  249                   } else {
  250                       allNew = false;
  251                   }
  252                   newDomains[i] = subjectPd;
  253               }
  254           }
  255   
  256           if (debug != null) {
  257               debug.println("updated current: ");
  258               for (int i = 0; i < cLen; i++) {
  259                   debug.println("\tupdated[" + i + "] = " +
  260                                   printDomain(newDomains[i]));
  261               }
  262           }
  263   
  264           // now add on the assigned domains
  265           if (aLen > 0) {
  266               System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
  267   
  268               // optimize the result (cached PDs might exist in assignedDomains)
  269               if (!allNew) {
  270                   newDomains = optimize(newDomains);
  271               }
  272           }
  273   
  274           // if aLen == 0 || allNew, no need to further optimize newDomains
  275   
  276           if (debug != null) {
  277               if (newDomains == null || newDomains.length == 0) {
  278                   debug.println("returning null");
  279               } else {
  280                   debug.println("combinedDomains: ");
  281                   for (int i = 0; i < newDomains.length; i++) {
  282                       debug.println("newDomain " + i + ": " +
  283                                     printDomain(newDomains[i]));
  284                   }
  285               }
  286           }
  287   
  288           // return the new ProtectionDomains
  289           if (newDomains == null || newDomains.length == 0) {
  290               return null;
  291           } else {
  292               return newDomains;
  293           }
  294       }
  295   
  296       /**
  297        * Use the javax.security.auth.Policy implementation
  298        */
  299       private ProtectionDomain[] combineJavaxPolicy(
  300           ProtectionDomain[] currentDomains,
  301           ProtectionDomain[] assignedDomains) {
  302   
  303           if (!allowCaching) {
  304               java.security.AccessController.doPrivileged
  305                   (new PrivilegedAction<Void>() {
  306                       public Void run() {
  307                           // Call refresh only caching is disallowed
  308                           javax.security.auth.Policy.getPolicy().refresh();
  309                           return null;
  310                       }
  311                   });
  312           }
  313   
  314           int cLen = (currentDomains == null ? 0 : currentDomains.length);
  315           int aLen = (assignedDomains == null ? 0 : assignedDomains.length);
  316   
  317           // the ProtectionDomains for the new AccessControlContext
  318           // that we will return
  319           ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];
  320   
  321           synchronized(cachedPDs) {
  322               if (!subject.isReadOnly() &&
  323                   !subject.getPrincipals().equals(principalSet)) {
  324   
  325                   // if the Subject was mutated, clear the PD cache
  326                   Set<Principal> newSet = subject.getPrincipals();
  327                   synchronized(newSet) {
  328                       principalSet = new java.util.HashSet<Principal>(newSet);
  329                   }
  330                   principals = principalSet.toArray
  331                           (new Principal[principalSet.size()]);
  332                   cachedPDs.clear();
  333   
  334                   if (debug != null) {
  335                       debug.println("Subject mutated - clearing cache");
  336                   }
  337               }
  338   
  339               for (int i = 0; i < cLen; i++) {
  340                   ProtectionDomain pd = currentDomains[i];
  341                   ProtectionDomain subjectPd = cachedPDs.getValue(pd);
  342   
  343                   if (subjectPd == null) {
  344   
  345                       // XXX
  346                       // we must first add the original permissions.
  347                       // that way when we later add the new JAAS permissions,
  348                       // any unresolved JAAS-related permissions will
  349                       // automatically get resolved.
  350   
  351                       // get the original perms
  352                       Permissions perms = new Permissions();
  353                       PermissionCollection coll = pd.getPermissions();
  354                       java.util.Enumeration e;
  355                       if (coll != null) {
  356                           synchronized (coll) {
  357                               e = coll.elements();
  358                               while (e.hasMoreElements()) {
  359                                   Permission newPerm =
  360                                           (Permission)e.nextElement();
  361                                    perms.add(newPerm);
  362                               }
  363                           }
  364                       }
  365   
  366                       // get perms from the policy
  367   
  368                       final java.security.CodeSource finalCs = pd.getCodeSource();
  369                       final Subject finalS = subject;
  370                       PermissionCollection newPerms =
  371                           java.security.AccessController.doPrivileged
  372                           (new PrivilegedAction<PermissionCollection>() {
  373                           public PermissionCollection run() {
  374                             return
  375                             javax.security.auth.Policy.getPolicy().getPermissions
  376                                   (finalS, finalCs);
  377                           }
  378                       });
  379   
  380                       // add the newly granted perms,
  381                       // avoiding duplicates
  382                       synchronized (newPerms) {
  383                           e = newPerms.elements();
  384                           while (e.hasMoreElements()) {
  385                               Permission newPerm = (Permission)e.nextElement();
  386                               if (!perms.implies(newPerm)) {
  387                                   perms.add(newPerm);
  388                                   if (debug != null)
  389                                       debug.println (
  390                                           "Adding perm " + newPerm + "\n");
  391                               }
  392                           }
  393                       }
  394                       subjectPd = new ProtectionDomain
  395                           (finalCs, perms, pd.getClassLoader(), principals);
  396   
  397                       if (allowCaching)
  398                           cachedPDs.putValue(pd, subjectPd);
  399                   }
  400                   newDomains[i] = subjectPd;
  401               }
  402           }
  403   
  404           if (debug != null) {
  405               debug.println("updated current: ");
  406               for (int i = 0; i < cLen; i++) {
  407                   debug.println("\tupdated[" + i + "] = " + newDomains[i]);
  408               }
  409           }
  410   
  411           // now add on the assigned domains
  412           if (aLen > 0) {
  413               System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);
  414           }
  415   
  416           if (debug != null) {
  417               if (newDomains == null || newDomains.length == 0) {
  418                   debug.println("returning null");
  419               } else {
  420                   debug.println("combinedDomains: ");
  421                   for (int i = 0; i < newDomains.length; i++) {
  422                       debug.println("newDomain " + i + ": " +
  423                           newDomains[i].toString());
  424                   }
  425               }
  426           }
  427   
  428           // return the new ProtectionDomains
  429           if (newDomains == null || newDomains.length == 0) {
  430               return null;
  431           } else {
  432               return newDomains;
  433           }
  434       }
  435   
  436       private static ProtectionDomain[] optimize(ProtectionDomain[] domains) {
  437           if (domains == null || domains.length == 0)
  438               return null;
  439   
  440           ProtectionDomain[] optimized = new ProtectionDomain[domains.length];
  441           ProtectionDomain pd;
  442           int num = 0;
  443           for (int i = 0; i < domains.length; i++) {
  444   
  445               // skip domains with AllPermission
  446               // XXX
  447               //
  448               //  if (domains[i].implies(ALL_PERMISSION))
  449               //  continue;
  450   
  451               // skip System Domains
  452               if ((pd = domains[i]) != null) {
  453   
  454                   // remove duplicates
  455                   boolean found = false;
  456                   for (int j = 0; j < num && !found; j++) {
  457                       found = (optimized[j] == pd);
  458                   }
  459                   if (!found) {
  460                       optimized[num++] = pd;
  461                   }
  462               }
  463           }
  464   
  465           // resize the array if necessary
  466           if (num > 0 && num < domains.length) {
  467               ProtectionDomain[] downSize = new ProtectionDomain[num];
  468               System.arraycopy(optimized, 0, downSize, 0, downSize.length);
  469               optimized = downSize;
  470           }
  471   
  472           return ((num == 0 || optimized.length == 0) ? null : optimized);
  473       }
  474   
  475       private static boolean cachePolicy() {
  476           String s = AccessController.doPrivileged
  477               (new PrivilegedAction<String>() {
  478               public String run() {
  479                   return java.security.Security.getProperty
  480                                           ("cache.auth.policy");
  481               }
  482           });
  483           if (s != null) {
  484               return Boolean.parseBoolean(s);
  485           }
  486   
  487           // cache by default
  488           return true;
  489       }
  490   
  491       // maintain backwards compatibility for people who provide
  492       // their own javax.security.auth.Policy implementations
  493       private static boolean compatPolicy() {
  494           javax.security.auth.Policy javaxPolicy = AccessController.doPrivileged
  495               (new PrivilegedAction<javax.security.auth.Policy>() {
  496               public javax.security.auth.Policy run() {
  497                   return javax.security.auth.Policy.getPolicy();
  498               }
  499           });
  500   
  501           if (!(javaxPolicy instanceof com.sun.security.auth.PolicyFile)) {
  502               if (debug != null) {
  503                   debug.println("Providing backwards compatibility for " +
  504                           "javax.security.auth.policy implementation: " +
  505                           javaxPolicy.toString());
  506               }
  507   
  508               return true;
  509           } else {
  510               return false;
  511           }
  512       }
  513   
  514       private static void printInputDomains(ProtectionDomain[] currentDomains,
  515                                   ProtectionDomain[] assignedDomains) {
  516           if (currentDomains == null || currentDomains.length == 0) {
  517               debug.println("currentDomains null or 0 length");
  518           } else {
  519               for (int i = 0; currentDomains != null &&
  520                           i < currentDomains.length; i++) {
  521                   if (currentDomains[i] == null) {
  522                       debug.println("currentDomain " + i + ": SystemDomain");
  523                   } else {
  524                       debug.println("currentDomain " + i + ": " +
  525                                   printDomain(currentDomains[i]));
  526                   }
  527               }
  528           }
  529   
  530           if (assignedDomains == null || assignedDomains.length == 0) {
  531               debug.println("assignedDomains null or 0 length");
  532           } else {
  533               debug.println("assignedDomains = ");
  534               for (int i = 0; assignedDomains != null &&
  535                           i < assignedDomains.length; i++) {
  536                   if (assignedDomains[i] == null) {
  537                       debug.println("assignedDomain " + i + ": SystemDomain");
  538                   } else {
  539                       debug.println("assignedDomain " + i + ": " +
  540                                   printDomain(assignedDomains[i]));
  541                   }
  542               }
  543           }
  544       }
  545   
  546       private static String printDomain(final ProtectionDomain pd) {
  547           if (pd == null) {
  548               return "null";
  549           }
  550           return AccessController.doPrivileged(new PrivilegedAction<String>() {
  551               public String run() {
  552                   return pd.toString();
  553               }
  554           });
  555       }
  556   
  557       /**
  558        * A HashMap that has weak keys and values.
  559        *
  560        * Key objects in this map are the "current" ProtectionDomain instances
  561        * received via the combine method.  Each "current" PD is mapped to a
  562        * new PD instance that holds both the contents of the "current" PD,
  563        * as well as the principals from the Subject associated with this combiner.
  564        *
  565        * The newly created "principal-based" PD values must be stored as
  566        * WeakReferences since they contain strong references to the
  567        * corresponding key object (the "current" non-principal-based PD),
  568        * which will prevent the key from being GC'd.  Specifically,
  569        * a "principal-based" PD contains strong references to the CodeSource,
  570        * signer certs, PermissionCollection and ClassLoader objects
  571        * in the "current PD".
  572        */
  573       private static class WeakKeyValueMap<K,V> extends
  574                                           WeakHashMap<K,WeakReference<V>> {
  575   
  576           public V getValue(K key) {
  577               WeakReference<V> wr = super.get(key);
  578               if (wr != null) {
  579                   return wr.get();
  580               }
  581               return null;
  582           }
  583   
  584           public V putValue(K key, V value) {
  585               WeakReference<V> wr = super.put(key, new WeakReference<V>(value));
  586               if (wr != null) {
  587                   return wr.get();
  588               }
  589               return null;
  590           }
  591       }
  592   }

Save This Page
Home » openjdk-7 » javax.security » auth » [javadoc | source]