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

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

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