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.ArrayList;
   29   import java.util.List;
   30   import sun.security.util.Debug;
   31   import sun.security.util.SecurityConstants;
   32   import sun.misc.JavaSecurityAccess;
   33   import sun.misc.SharedSecrets;
   34   
   35   
   36   /**
   37    * An AccessControlContext is used to make system resource access decisions
   38    * based on the context it encapsulates.
   39    *
   40    * <p>More specifically, it encapsulates a context and
   41    * has a single method, <code>checkPermission</code>,
   42    * that is equivalent to the <code>checkPermission</code> method
   43    * in the AccessController class, with one difference: The AccessControlContext
   44    * <code>checkPermission</code> method makes access decisions based on the
   45    * context it encapsulates,
   46    * rather than that of the current execution thread.
   47    *
   48    * <p>Thus, the purpose of AccessControlContext is for those situations where
   49    * a security check that should be made within a given context
   50    * actually needs to be done from within a
   51    * <i>different</i> context (for example, from within a worker thread).
   52    *
   53    * <p> An AccessControlContext is created by calling the
   54    * <code>AccessController.getContext</code> method.
   55    * The <code>getContext</code> method takes a "snapshot"
   56    * of the current calling context, and places
   57    * it in an AccessControlContext object, which it returns. A sample call is
   58    * the following:
   59    *
   60    * <pre>
   61    *   AccessControlContext acc = AccessController.getContext()
   62    * </pre>
   63    *
   64    * <p>
   65    * Code within a different context can subsequently call the
   66    * <code>checkPermission</code> method on the
   67    * previously-saved AccessControlContext object. A sample call is the
   68    * following:
   69    *
   70    * <pre>
   71    *   acc.checkPermission(permission)
   72    * </pre>
   73    *
   74    * @see AccessController
   75    *
   76    * @author Roland Schemers
   77    */
   78   
   79   public final class AccessControlContext {
   80   
   81       private ProtectionDomain context[];
   82       private boolean isPrivileged;
   83   
   84       // Note: This field is directly used by the virtual machine
   85       // native codes. Don't touch it.
   86       private AccessControlContext privilegedContext;
   87   
   88       private DomainCombiner combiner = null;
   89   
   90       private static boolean debugInit = false;
   91       private static Debug debug = null;
   92   
   93       static Debug getDebug()
   94       {
   95           if (debugInit)
   96               return debug;
   97           else {
   98               if (Policy.isSet()) {
   99                   debug = Debug.getInstance("access");
  100                   debugInit = true;
  101               }
  102               return debug;
  103           }
  104       }
  105   
  106       /**
  107        * Create an AccessControlContext with the given array of ProtectionDomains.
  108        * Context must not be null. Duplicate domains will be removed from the
  109        * context.
  110        *
  111        * @param context the ProtectionDomains associated with this context.
  112        * The non-duplicate domains are copied from the array. Subsequent
  113        * changes to the array will not affect this AccessControlContext.
  114        * @throws NullPointerException if <code>context</code> is <code>null</code>
  115        */
  116       public AccessControlContext(ProtectionDomain context[])
  117       {
  118           if (context.length == 0) {
  119               this.context = null;
  120           } else if (context.length == 1) {
  121               if (context[0] != null) {
  122                   this.context = context.clone();
  123               } else {
  124                   this.context = null;
  125               }
  126           } else {
  127               List<ProtectionDomain> v = new ArrayList<>(context.length);
  128               for (int i =0; i< context.length; i++) {
  129                   if ((context[i] != null) &&  (!v.contains(context[i])))
  130                       v.add(context[i]);
  131               }
  132               if (!v.isEmpty()) {
  133                   this.context = new ProtectionDomain[v.size()];
  134                   this.context = v.toArray(this.context);
  135               }
  136           }
  137       }
  138   
  139       /**
  140        * Create a new <code>AccessControlContext</code> with the given
  141        * <code>AccessControlContext</code> and <code>DomainCombiner</code>.
  142        * This constructor associates the provided
  143        * <code>DomainCombiner</code> with the provided
  144        * <code>AccessControlContext</code>.
  145        *
  146        * <p>
  147        *
  148        * @param acc the <code>AccessControlContext</code> associated
  149        *          with the provided <code>DomainCombiner</code>.
  150        *
  151        * @param combiner the <code>DomainCombiner</code> to be associated
  152        *          with the provided <code>AccessControlContext</code>.
  153        *
  154        * @exception NullPointerException if the provided
  155        *          <code>context</code> is <code>null</code>.
  156        *
  157        * @exception SecurityException if a security manager is installed and the
  158        *          caller does not have the "createAccessControlContext"
  159        *          {@link SecurityPermission}
  160        * @since 1.3
  161        */
  162       public AccessControlContext(AccessControlContext acc,
  163                                   DomainCombiner combiner) {
  164   
  165           SecurityManager sm = System.getSecurityManager();
  166           if (sm != null) {
  167               sm.checkPermission(SecurityConstants.CREATE_ACC_PERMISSION);
  168           }
  169   
  170           this.context = acc.context;
  171   
  172           // we do not need to run the combine method on the
  173           // provided ACC.  it was already "combined" when the
  174           // context was originally retrieved.
  175           //
  176           // at this point in time, we simply throw away the old
  177           // combiner and use the newly provided one.
  178           this.combiner = combiner;
  179       }
  180   
  181       /**
  182        * package private for AccessController
  183        */
  184       AccessControlContext(ProtectionDomain context[], DomainCombiner combiner) {
  185           if (context != null) {
  186               this.context = context.clone();
  187           }
  188           this.combiner = combiner;
  189       }
  190   
  191       /**
  192        * package private constructor for AccessController.getContext()
  193        */
  194   
  195       AccessControlContext(ProtectionDomain context[],
  196                                    boolean isPrivileged)
  197       {
  198           this.context = context;
  199           this.isPrivileged = isPrivileged;
  200       }
  201   
  202       /**
  203        * Constructor for JavaSecurityAccess.doIntersectionPrivilege()
  204        */
  205       AccessControlContext(ProtectionDomain[] context,
  206                            AccessControlContext privilegedContext)
  207       {
  208           this.context = context;
  209           this.privilegedContext = privilegedContext;
  210           this.isPrivileged = true;
  211       }
  212   
  213       /**
  214        * Returns this context's context.
  215        */
  216       ProtectionDomain[] getContext() {
  217           return context;
  218       }
  219   
  220       /**
  221        * Returns true if this context is privileged.
  222        */
  223       boolean isPrivileged()
  224       {
  225           return isPrivileged;
  226       }
  227   
  228       /**
  229        * get the assigned combiner from the privileged or inherited context
  230        */
  231       DomainCombiner getAssignedCombiner() {
  232           AccessControlContext acc;
  233           if (isPrivileged) {
  234               acc = privilegedContext;
  235           } else {
  236               acc = AccessController.getInheritedAccessControlContext();
  237           }
  238           if (acc != null) {
  239               return acc.combiner;
  240           }
  241           return null;
  242       }
  243   
  244       /**
  245        * Get the <code>DomainCombiner</code> associated with this
  246        * <code>AccessControlContext</code>.
  247        *
  248        * <p>
  249        *
  250        * @return the <code>DomainCombiner</code> associated with this
  251        *          <code>AccessControlContext</code>, or <code>null</code>
  252        *          if there is none.
  253        *
  254        * @exception SecurityException if a security manager is installed and
  255        *          the caller does not have the "getDomainCombiner"
  256        *          {@link SecurityPermission}
  257        * @since 1.3
  258        */
  259       public DomainCombiner getDomainCombiner() {
  260   
  261           SecurityManager sm = System.getSecurityManager();
  262           if (sm != null) {
  263               sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION);
  264           }
  265           return combiner;
  266       }
  267   
  268       /**
  269        * Determines whether the access request indicated by the
  270        * specified permission should be allowed or denied, based on
  271        * the security policy currently in effect, and the context in
  272        * this object. The request is allowed only if every ProtectionDomain
  273        * in the context implies the permission. Otherwise the request is
  274        * denied.
  275        *
  276        * <p>
  277        * This method quietly returns if the access request
  278        * is permitted, or throws a suitable AccessControlException otherwise.
  279        *
  280        * @param perm the requested permission.
  281        *
  282        * @exception AccessControlException if the specified permission
  283        * is not permitted, based on the current security policy and the
  284        * context encapsulated by this object.
  285        * @exception NullPointerException if the permission to check for is null.
  286        */
  287       public void checkPermission(Permission perm)
  288           throws AccessControlException
  289       {
  290           boolean dumpDebug = false;
  291   
  292           if (perm == null) {
  293               throw new NullPointerException("permission can't be null");
  294           }
  295           if (getDebug() != null) {
  296               // If "codebase" is not specified, we dump the info by default.
  297               dumpDebug = !Debug.isOn("codebase=");
  298               if (!dumpDebug) {
  299                   // If "codebase" is specified, only dump if the specified code
  300                   // value is in the stack.
  301                   for (int i = 0; context != null && i < context.length; i++) {
  302                       if (context[i].getCodeSource() != null &&
  303                           context[i].getCodeSource().getLocation() != null &&
  304                           Debug.isOn("codebase=" + context[i].getCodeSource().getLocation().toString())) {
  305                           dumpDebug = true;
  306                           break;
  307                       }
  308                   }
  309               }
  310   
  311               dumpDebug &= !Debug.isOn("permission=") ||
  312                   Debug.isOn("permission=" + perm.getClass().getCanonicalName());
  313   
  314               if (dumpDebug && Debug.isOn("stack")) {
  315                   Thread.currentThread().dumpStack();
  316               }
  317   
  318               if (dumpDebug && Debug.isOn("domain")) {
  319                   if (context == null) {
  320                       debug.println("domain (context is null)");
  321                   } else {
  322                       for (int i=0; i< context.length; i++) {
  323                           debug.println("domain "+i+" "+context[i]);
  324                       }
  325                   }
  326               }
  327           }
  328   
  329           /*
  330            * iterate through the ProtectionDomains in the context.
  331            * Stop at the first one that doesn't allow the
  332            * requested permission (throwing an exception).
  333            *
  334            */
  335   
  336           /* if ctxt is null, all we had on the stack were system domains,
  337              or the first domain was a Privileged system domain. This
  338              is to make the common case for system code very fast */
  339   
  340           if (context == null)
  341               return;
  342   
  343           for (int i=0; i< context.length; i++) {
  344               if (context[i] != null &&  !context[i].implies(perm)) {
  345                   if (dumpDebug) {
  346                       debug.println("access denied " + perm);
  347                   }
  348   
  349                   if (Debug.isOn("failure") && debug != null) {
  350                       // Want to make sure this is always displayed for failure,
  351                       // but do not want to display again if already displayed
  352                       // above.
  353                       if (!dumpDebug) {
  354                           debug.println("access denied " + perm);
  355                       }
  356                       Thread.currentThread().dumpStack();
  357                       final ProtectionDomain pd = context[i];
  358                       final Debug db = debug;
  359                       AccessController.doPrivileged (new PrivilegedAction<Void>() {
  360                           public Void run() {
  361                               db.println("domain that failed "+pd);
  362                               return null;
  363                           }
  364                       });
  365                   }
  366                   throw new AccessControlException("access denied "+perm, perm);
  367               }
  368           }
  369   
  370           // allow if all of them allowed access
  371           if (dumpDebug) {
  372               debug.println("access allowed "+perm);
  373           }
  374   
  375           return;
  376       }
  377   
  378       /**
  379        * Take the stack-based context (this) and combine it with the
  380        * privileged or inherited context, if need be.
  381        */
  382       AccessControlContext optimize() {
  383           // the assigned (privileged or inherited) context
  384           AccessControlContext acc;
  385           if (isPrivileged) {
  386               acc = privilegedContext;
  387           } else {
  388               acc = AccessController.getInheritedAccessControlContext();
  389           }
  390   
  391           // this.context could be null if only system code is on the stack;
  392           // in that case, ignore the stack context
  393           boolean skipStack = (context == null);
  394   
  395           // acc.context could be null if only system code was involved;
  396           // in that case, ignore the assigned context
  397           boolean skipAssigned = (acc == null || acc.context == null);
  398   
  399           if (acc != null && acc.combiner != null) {
  400               // let the assigned acc's combiner do its thing
  401               return goCombiner(context, acc);
  402           }
  403   
  404           // optimization: if neither have contexts; return acc if possible
  405           // rather than this, because acc might have a combiner
  406           if (skipAssigned && skipStack) {
  407               return this;
  408           }
  409   
  410           // optimization: if there is no stack context; there is no reason
  411           // to compress the assigned context, it already is compressed
  412           if (skipStack) {
  413               return acc;
  414           }
  415   
  416           int slen = context.length;
  417   
  418           // optimization: if there is no assigned context and the stack length
  419           // is less then or equal to two; there is no reason to compress the
  420           // stack context, it already is
  421           if (skipAssigned && slen <= 2) {
  422               return this;
  423           }
  424   
  425           // optimization: if there is a single stack domain and that domain
  426           // is already in the assigned context; no need to combine
  427           if ((slen == 1) && (context[0] == acc.context[0])) {
  428               return acc;
  429           }
  430   
  431           int n = (skipAssigned) ? 0 : acc.context.length;
  432   
  433           // now we combine both of them, and create a new context
  434           ProtectionDomain pd[] = new ProtectionDomain[slen + n];
  435   
  436           // first copy in the assigned context domains, no need to compress
  437           if (!skipAssigned) {
  438               System.arraycopy(acc.context, 0, pd, 0, n);
  439           }
  440   
  441           // now add the stack context domains, discarding nulls and duplicates
  442       outer:
  443           for (int i = 0; i < context.length; i++) {
  444               ProtectionDomain sd = context[i];
  445               if (sd != null) {
  446                   for (int j = 0; j < n; j++) {
  447                       if (sd == pd[j]) {
  448                           continue outer;
  449                       }
  450                   }
  451                   pd[n++] = sd;
  452               }
  453           }
  454   
  455           // if length isn't equal, we need to shorten the array
  456           if (n != pd.length) {
  457               // optimization: if we didn't really combine anything
  458               if (!skipAssigned && n == acc.context.length) {
  459                   return acc;
  460               } else if (skipAssigned && n == slen) {
  461                   return this;
  462               }
  463               ProtectionDomain tmp[] = new ProtectionDomain[n];
  464               System.arraycopy(pd, 0, tmp, 0, n);
  465               pd = tmp;
  466           }
  467   
  468           //      return new AccessControlContext(pd, false);
  469   
  470           // Reuse existing ACC
  471   
  472           this.context = pd;
  473           this.combiner = null;
  474           this.isPrivileged = false;
  475   
  476           return this;
  477       }
  478   
  479       private AccessControlContext goCombiner(ProtectionDomain[] current,
  480                                           AccessControlContext assigned) {
  481   
  482           // the assigned ACC's combiner is not null --
  483           // let the combiner do its thing
  484   
  485           // XXX we could add optimizations to 'current' here ...
  486   
  487           if (getDebug() != null) {
  488               debug.println("AccessControlContext invoking the Combiner");
  489           }
  490   
  491           // No need to clone current and assigned.context
  492           // combine() will not update them
  493           ProtectionDomain[] combinedPds = assigned.combiner.combine(
  494               current, assigned.context);
  495   
  496           // return new AccessControlContext(combinedPds, assigned.combiner);
  497   
  498           // Reuse existing ACC
  499           this.context = combinedPds;
  500           this.combiner = assigned.combiner;
  501           this.isPrivileged = false;
  502   
  503           return this;
  504       }
  505   
  506       /**
  507        * Checks two AccessControlContext objects for equality.
  508        * Checks that <i>obj</i> is
  509        * an AccessControlContext and has the same set of ProtectionDomains
  510        * as this context.
  511        * <P>
  512        * @param obj the object we are testing for equality with this object.
  513        * @return true if <i>obj</i> is an AccessControlContext, and has the
  514        * same set of ProtectionDomains as this context, false otherwise.
  515        */
  516       public boolean equals(Object obj) {
  517           if (obj == this)
  518               return true;
  519   
  520           if (! (obj instanceof AccessControlContext))
  521               return false;
  522   
  523           AccessControlContext that = (AccessControlContext) obj;
  524   
  525   
  526           if (context == null) {
  527               return (that.context == null);
  528           }
  529   
  530           if (that.context == null)
  531               return false;
  532   
  533           if (!(this.containsAllPDs(that) && that.containsAllPDs(this)))
  534               return false;
  535   
  536           if (this.combiner == null)
  537               return (that.combiner == null);
  538   
  539           if (that.combiner == null)
  540               return false;
  541   
  542           if (!this.combiner.equals(that.combiner))
  543               return false;
  544   
  545           return true;
  546       }
  547   
  548       private boolean containsAllPDs(AccessControlContext that) {
  549           boolean match = false;
  550           //
  551           // ProtectionDomains within an ACC currently cannot be null
  552           // and this is enforced by the constructor and the various
  553           // optimize methods. However, historically this logic made attempts
  554           // to support the notion of a null PD and therefore this logic continues
  555           // to support that notion.
  556           ProtectionDomain thisPd;
  557           for (int i = 0; i < context.length; i++) {
  558               match = false;
  559               if ((thisPd = context[i]) == null) {
  560                   for (int j = 0; (j < that.context.length) && !match; j++) {
  561                       match = (that.context[j] == null);
  562                   }
  563               } else {
  564                   Class thisPdClass = thisPd.getClass();
  565                   ProtectionDomain thatPd;
  566                   for (int j = 0; (j < that.context.length) && !match; j++) {
  567                       thatPd = that.context[j];
  568   
  569                       // Class check required to avoid PD exposure (4285406)
  570                       match = (thatPd != null &&
  571                           thisPdClass == thatPd.getClass() && thisPd.equals(thatPd));
  572                   }
  573               }
  574               if (!match) return false;
  575           }
  576           return match;
  577       }
  578       /**
  579        * Returns the hash code value for this context. The hash code
  580        * is computed by exclusive or-ing the hash code of all the protection
  581        * domains in the context together.
  582        *
  583        * @return a hash code value for this context.
  584        */
  585   
  586       public int hashCode() {
  587           int hashCode = 0;
  588   
  589           if (context == null)
  590               return hashCode;
  591   
  592           for (int i =0; i < context.length; i++) {
  593               if (context[i] != null)
  594                   hashCode ^= context[i].hashCode();
  595           }
  596           return hashCode;
  597       }
  598   }

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