jdk/src/share/classes/java/security/AccessController.java
changeset 2 90ce3da70b43
child 2589 af4853bc7e87
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-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 java.security;
       
    27 
       
    28 import sun.security.util.Debug;
       
    29 
       
    30 /**
       
    31  * <p> The AccessController class is used for access control operations
       
    32  * and decisions.
       
    33  *
       
    34  * <p> More specifically, the AccessController class is used for
       
    35  * three purposes:
       
    36  *
       
    37  * <ul>
       
    38  * <li> to decide whether an access to a critical system
       
    39  * resource is to be allowed or denied, based on the security policy
       
    40  * currently in effect,<p>
       
    41  * <li>to mark code as being "privileged", thus affecting subsequent
       
    42  * access determinations, and<p>
       
    43  * <li>to obtain a "snapshot" of the current calling context so
       
    44  * access-control decisions from a different context can be made with
       
    45  * respect to the saved context. </ul>
       
    46  *
       
    47  * <p> The {@link #checkPermission(Permission) checkPermission} method
       
    48  * determines whether the access request indicated by a specified
       
    49  * permission should be granted or denied. A sample call appears
       
    50  * below. In this example, <code>checkPermission</code> will determine
       
    51  * whether or not to grant "read" access to the file named "testFile" in
       
    52  * the "/temp" directory.
       
    53  *
       
    54  * <pre>
       
    55  *
       
    56  * FilePermission perm = new FilePermission("/temp/testFile", "read");
       
    57  * AccessController.checkPermission(perm);
       
    58  *
       
    59  * </pre>
       
    60  *
       
    61  * <p> If a requested access is allowed,
       
    62  * <code>checkPermission</code> returns quietly. If denied, an
       
    63  * AccessControlException is
       
    64  * thrown. AccessControlException can also be thrown if the requested
       
    65  * permission is of an incorrect type or contains an invalid value.
       
    66  * Such information is given whenever possible.
       
    67  *
       
    68  * Suppose the current thread traversed m callers, in the order of caller 1
       
    69  * to caller 2 to caller m. Then caller m invoked the
       
    70  * <code>checkPermission</code> method.
       
    71  * The <code>checkPermission </code>method determines whether access
       
    72  * is granted or denied based on the following algorithm:
       
    73  *
       
    74  *  <pre> {@code
       
    75  * for (int i = m; i > 0; i--) {
       
    76  *
       
    77  *     if (caller i's domain does not have the permission)
       
    78  *         throw AccessControlException
       
    79  *
       
    80  *     else if (caller i is marked as privileged) {
       
    81  *         if (a context was specified in the call to doPrivileged)
       
    82  *             context.checkPermission(permission)
       
    83  *         return;
       
    84  *     }
       
    85  * };
       
    86  *
       
    87  * // Next, check the context inherited when the thread was created.
       
    88  * // Whenever a new thread is created, the AccessControlContext at
       
    89  * // that time is stored and associated with the new thread, as the
       
    90  * // "inherited" context.
       
    91  *
       
    92  * inheritedContext.checkPermission(permission);
       
    93  * }</pre>
       
    94  *
       
    95  * <p> A caller can be marked as being "privileged"
       
    96  * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
       
    97  * When making access control decisions, the <code>checkPermission</code>
       
    98  * method stops checking if it reaches a caller that
       
    99  * was marked as "privileged" via a <code>doPrivileged</code>
       
   100  * call without a context argument (see below for information about a
       
   101  * context argument). If that caller's domain has the
       
   102  * specified permission, no further checking is done and
       
   103  * <code>checkPermission</code>
       
   104  * returns quietly, indicating that the requested access is allowed.
       
   105  * If that domain does not have the specified permission, an exception
       
   106  * is thrown, as usual.
       
   107  *
       
   108  * <p> The normal use of the "privileged" feature is as follows. If you
       
   109  * don't need to return a value from within the "privileged" block, do
       
   110  * the following:
       
   111  *
       
   112  *  <pre> {@code
       
   113  * somemethod() {
       
   114  *     ...normal code here...
       
   115  *     AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   116  *         public Void run() {
       
   117  *             // privileged code goes here, for example:
       
   118  *             System.loadLibrary("awt");
       
   119  *             return null; // nothing to return
       
   120  *         }
       
   121  *     });
       
   122  *     ...normal code here...
       
   123  * }}</pre>
       
   124  *
       
   125  * <p>
       
   126  * PrivilegedAction is an interface with a single method, named
       
   127  * <code>run</code>.
       
   128  * The above example shows creation of an implementation
       
   129  * of that interface; a concrete implementation of the
       
   130  * <code>run</code> method is supplied.
       
   131  * When the call to <code>doPrivileged</code> is made, an
       
   132  * instance of the PrivilegedAction implementation is passed
       
   133  * to it. The <code>doPrivileged</code> method calls the
       
   134  * <code>run</code> method from the PrivilegedAction
       
   135  * implementation after enabling privileges, and returns the
       
   136  * <code>run</code> method's return value as the
       
   137  * <code>doPrivileged</code> return value (which is
       
   138  * ignored in this example).
       
   139  *
       
   140  * <p> If you need to return a value, you can do something like the following:
       
   141  *
       
   142  *  <pre> {@code
       
   143  * somemethod() {
       
   144  *     ...normal code here...
       
   145  *     String user = AccessController.doPrivileged(
       
   146  *         new PrivilegedAction<String>() {
       
   147  *         public String run() {
       
   148  *             return System.getProperty("user.name");
       
   149  *             }
       
   150  *         });
       
   151  *     ...normal code here...
       
   152  * }}</pre>
       
   153  *
       
   154  * <p>If the action performed in your <code>run</code> method could
       
   155  * throw a "checked" exception (those listed in the <code>throws</code> clause
       
   156  * of a method), then you need to use the
       
   157  * <code>PrivilegedExceptionAction</code> interface instead of the
       
   158  * <code>PrivilegedAction</code> interface:
       
   159  *
       
   160  *  <pre> {@code
       
   161  * somemethod() throws FileNotFoundException {
       
   162  *     ...normal code here...
       
   163  *     try {
       
   164  *         FileInputStream fis = AccessController.doPrivileged(
       
   165  *         new PrivilegedExceptionAction<FileInputStream>() {
       
   166  *             public FileInputStream run() throws FileNotFoundException {
       
   167  *                 return new FileInputStream("someFile");
       
   168  *             }
       
   169  *         });
       
   170  *     } catch (PrivilegedActionException e) {
       
   171  *         // e.getException() should be an instance of FileNotFoundException,
       
   172  *         // as only "checked" exceptions will be "wrapped" in a
       
   173  *         // PrivilegedActionException.
       
   174  *         throw (FileNotFoundException) e.getException();
       
   175  *     }
       
   176  *     ...normal code here...
       
   177  *  }}</pre>
       
   178  *
       
   179  * <p> Be *very* careful in your use of the "privileged" construct, and
       
   180  * always remember to make the privileged code section as small as possible.
       
   181  *
       
   182  * <p> Note that <code>checkPermission</code> always performs security checks
       
   183  * within the context of the currently executing thread.
       
   184  * Sometimes a security check that should be made within a given context
       
   185  * will actually need to be done from within a
       
   186  * <i>different</i> context (for example, from within a worker thread).
       
   187  * The {@link #getContext() getContext} method and
       
   188  * AccessControlContext class are provided
       
   189  * for this situation. The <code>getContext</code> method takes a "snapshot"
       
   190  * of the current calling context, and places
       
   191  * it in an AccessControlContext object, which it returns. A sample call is
       
   192  * the following:
       
   193  *
       
   194  * <pre>
       
   195  *
       
   196  * AccessControlContext acc = AccessController.getContext()
       
   197  *
       
   198  * </pre>
       
   199  *
       
   200  * <p>
       
   201  * AccessControlContext itself has a <code>checkPermission</code> method
       
   202  * that makes access decisions based on the context <i>it</i> encapsulates,
       
   203  * rather than that of the current execution thread.
       
   204  * Code within a different context can thus call that method on the
       
   205  * previously-saved AccessControlContext object. A sample call is the
       
   206  * following:
       
   207  *
       
   208  * <pre>
       
   209  *
       
   210  * acc.checkPermission(permission)
       
   211  *
       
   212  * </pre>
       
   213  *
       
   214  * <p> There are also times where you don't know a priori which permissions
       
   215  * to check the context against. In these cases you can use the
       
   216  * doPrivileged method that takes a context:
       
   217  *
       
   218  *  <pre> {@code
       
   219  * somemethod() {
       
   220  *     AccessController.doPrivileged(new PrivilegedAction<Object>() {
       
   221  *         public Object run() {
       
   222  *             // Code goes here. Any permission checks within this
       
   223  *             // run method will require that the intersection of the
       
   224  *             // callers protection domain and the snapshot's
       
   225  *             // context have the desired permission.
       
   226  *         }
       
   227  *     }, acc);
       
   228  *     ...normal code here...
       
   229  * }}</pre>
       
   230  *
       
   231  * @see AccessControlContext
       
   232  *
       
   233  * @author Li Gong
       
   234  * @author Roland Schemers
       
   235  */
       
   236 
       
   237 public final class AccessController {
       
   238 
       
   239     /**
       
   240      * Don't allow anyone to instantiate an AccessController
       
   241      */
       
   242     private AccessController() { }
       
   243 
       
   244     /**
       
   245      * Performs the specified <code>PrivilegedAction</code> with privileges
       
   246      * enabled. The action is performed with <i>all</i> of the permissions
       
   247      * possessed by the caller's protection domain.
       
   248      *
       
   249      * <p> If the action's <code>run</code> method throws an (unchecked)
       
   250      * exception, it will propagate through this method.
       
   251      *
       
   252      * <p> Note that any DomainCombiner associated with the current
       
   253      * AccessControlContext will be ignored while the action is performed.
       
   254      *
       
   255      * @param action the action to be performed.
       
   256      *
       
   257      * @return the value returned by the action's <code>run</code> method.
       
   258      *
       
   259      * @exception NullPointerException if the action is <code>null</code>
       
   260      *
       
   261      * @see #doPrivileged(PrivilegedAction,AccessControlContext)
       
   262      * @see #doPrivileged(PrivilegedExceptionAction)
       
   263      * @see #doPrivilegedWithCombiner(PrivilegedAction)
       
   264      * @see java.security.DomainCombiner
       
   265      */
       
   266 
       
   267     public static native <T> T doPrivileged(PrivilegedAction<T> action);
       
   268 
       
   269     /**
       
   270      * Performs the specified <code>PrivilegedAction</code> with privileges
       
   271      * enabled. The action is performed with <i>all</i> of the permissions
       
   272      * possessed by the caller's protection domain.
       
   273      *
       
   274      * <p> If the action's <code>run</code> method throws an (unchecked)
       
   275      * exception, it will propagate through this method.
       
   276      *
       
   277      * <p> This method preserves the current AccessControlContext's
       
   278      * DomainCombiner (which may be null) while the action is performed.
       
   279      *
       
   280      * @param action the action to be performed.
       
   281      *
       
   282      * @return the value returned by the action's <code>run</code> method.
       
   283      *
       
   284      * @exception NullPointerException if the action is <code>null</code>
       
   285      *
       
   286      * @see #doPrivileged(PrivilegedAction)
       
   287      * @see java.security.DomainCombiner
       
   288      *
       
   289      * @since 1.6
       
   290      */
       
   291     public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
       
   292 
       
   293         DomainCombiner dc = null;
       
   294         AccessControlContext acc = getStackAccessControlContext();
       
   295         if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
       
   296             return AccessController.doPrivileged(action);
       
   297         }
       
   298         return AccessController.doPrivileged(action, preserveCombiner(dc));
       
   299     }
       
   300 
       
   301 
       
   302     /**
       
   303      * Performs the specified <code>PrivilegedAction</code> with privileges
       
   304      * enabled and restricted by the specified
       
   305      * <code>AccessControlContext</code>.
       
   306      * The action is performed with the intersection of the permissions
       
   307      * possessed by the caller's protection domain, and those possessed
       
   308      * by the domains represented by the specified
       
   309      * <code>AccessControlContext</code>.
       
   310      * <p>
       
   311      * If the action's <code>run</code> method throws an (unchecked) exception,
       
   312      * it will propagate through this method.
       
   313      *
       
   314      * @param action the action to be performed.
       
   315      * @param context an <i>access control context</i>
       
   316      *                representing the restriction to be applied to the
       
   317      *                caller's domain's privileges before performing
       
   318      *                the specified action.  If the context is
       
   319      *                <code>null</code>,
       
   320      *                then no additional restriction is applied.
       
   321      *
       
   322      * @return the value returned by the action's <code>run</code> method.
       
   323      *
       
   324      * @exception NullPointerException if the action is <code>null</code>
       
   325      *
       
   326      * @see #doPrivileged(PrivilegedAction)
       
   327      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
       
   328      */
       
   329     public static native <T> T doPrivileged(PrivilegedAction<T> action,
       
   330                                             AccessControlContext context);
       
   331 
       
   332     /**
       
   333      * Performs the specified <code>PrivilegedExceptionAction</code> with
       
   334      * privileges enabled.  The action is performed with <i>all</i> of the
       
   335      * permissions possessed by the caller's protection domain.
       
   336      *
       
   337      * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
       
   338      * exception, it will propagate through this method.
       
   339      *
       
   340      * <p> Note that any DomainCombiner associated with the current
       
   341      * AccessControlContext will be ignored while the action is performed.
       
   342      *
       
   343      * @param action the action to be performed
       
   344      *
       
   345      * @return the value returned by the action's <code>run</code> method
       
   346      *
       
   347      * @exception PrivilegedActionException if the specified action's
       
   348      *         <code>run</code> method threw a <i>checked</i> exception
       
   349      * @exception NullPointerException if the action is <code>null</code>
       
   350      *
       
   351      * @see #doPrivileged(PrivilegedAction)
       
   352      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
       
   353      * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
       
   354      * @see java.security.DomainCombiner
       
   355      */
       
   356     public static native <T> T
       
   357         doPrivileged(PrivilegedExceptionAction<T> action)
       
   358         throws PrivilegedActionException;
       
   359 
       
   360 
       
   361     /**
       
   362      * Performs the specified <code>PrivilegedExceptionAction</code> with
       
   363      * privileges enabled.  The action is performed with <i>all</i> of the
       
   364      * permissions possessed by the caller's protection domain.
       
   365      *
       
   366      * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
       
   367      * exception, it will propagate through this method.
       
   368      *
       
   369      * <p> This method preserves the current AccessControlContext's
       
   370      * DomainCombiner (which may be null) while the action is performed.
       
   371      *
       
   372      * @param action the action to be performed.
       
   373      *
       
   374      * @return the value returned by the action's <code>run</code> method
       
   375      *
       
   376      * @exception PrivilegedActionException if the specified action's
       
   377      *         <code>run</code> method threw a <i>checked</i> exception
       
   378      * @exception NullPointerException if the action is <code>null</code>
       
   379      *
       
   380      * @see #doPrivileged(PrivilegedAction)
       
   381      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
       
   382      * @see java.security.DomainCombiner
       
   383      *
       
   384      * @since 1.6
       
   385      */
       
   386     public static <T> T doPrivilegedWithCombiner
       
   387         (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
       
   388 
       
   389         DomainCombiner dc = null;
       
   390         AccessControlContext acc = getStackAccessControlContext();
       
   391         if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
       
   392             return AccessController.doPrivileged(action);
       
   393         }
       
   394         return AccessController.doPrivileged(action, preserveCombiner(dc));
       
   395     }
       
   396 
       
   397     /**
       
   398      * preserve the combiner across the doPrivileged call
       
   399      */
       
   400     private static AccessControlContext preserveCombiner
       
   401                                         (DomainCombiner combiner) {
       
   402 
       
   403         /**
       
   404          * callerClass[0] = Reflection.getCallerClass
       
   405          * callerClass[1] = AccessController.preserveCombiner
       
   406          * callerClass[2] = AccessController.doPrivileged
       
   407          * callerClass[3] = caller
       
   408          */
       
   409         final Class callerClass = sun.reflect.Reflection.getCallerClass(3);
       
   410         ProtectionDomain callerPd = doPrivileged
       
   411             (new PrivilegedAction<ProtectionDomain>() {
       
   412             public ProtectionDomain run() {
       
   413                 return callerClass.getProtectionDomain();
       
   414             }
       
   415         });
       
   416 
       
   417         // perform 'combine' on the caller of doPrivileged,
       
   418         // even if the caller is from the bootclasspath
       
   419         ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
       
   420         return new AccessControlContext(combiner.combine(pds, null), combiner);
       
   421     }
       
   422 
       
   423 
       
   424     /**
       
   425      * Performs the specified <code>PrivilegedExceptionAction</code> with
       
   426      * privileges enabled and restricted by the specified
       
   427      * <code>AccessControlContext</code>.  The action is performed with the
       
   428      * intersection of the the permissions possessed by the caller's
       
   429      * protection domain, and those possessed by the domains represented by the
       
   430      * specified <code>AccessControlContext</code>.
       
   431      * <p>
       
   432      * If the action's <code>run</code> method throws an <i>unchecked</i>
       
   433      * exception, it will propagate through this method.
       
   434      *
       
   435      * @param action the action to be performed
       
   436      * @param context an <i>access control context</i>
       
   437      *                representing the restriction to be applied to the
       
   438      *                caller's domain's privileges before performing
       
   439      *                the specified action.  If the context is
       
   440      *                <code>null</code>,
       
   441      *                then no additional restriction is applied.
       
   442      *
       
   443      * @return the value returned by the action's <code>run</code> method
       
   444      *
       
   445      * @exception PrivilegedActionException if the specified action's
       
   446      *         <code>run</code> method
       
   447      *         threw a <i>checked</i> exception
       
   448      * @exception NullPointerException if the action is <code>null</code>
       
   449      *
       
   450      * @see #doPrivileged(PrivilegedAction)
       
   451      * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
       
   452      */
       
   453     public static native <T> T
       
   454         doPrivileged(PrivilegedExceptionAction<T> action,
       
   455                      AccessControlContext context)
       
   456         throws PrivilegedActionException;
       
   457 
       
   458     /**
       
   459      * Returns the AccessControl context. i.e., it gets
       
   460      * the protection domains of all the callers on the stack,
       
   461      * starting at the first class with a non-null
       
   462      * ProtectionDomain.
       
   463      *
       
   464      * @return the access control context based on the current stack or
       
   465      *         null if there was only privileged system code.
       
   466      */
       
   467 
       
   468     private static native AccessControlContext getStackAccessControlContext();
       
   469 
       
   470     /**
       
   471      * Returns the "inherited" AccessControl context. This is the context
       
   472      * that existed when the thread was created. Package private so
       
   473      * AccessControlContext can use it.
       
   474      */
       
   475 
       
   476     static native AccessControlContext getInheritedAccessControlContext();
       
   477 
       
   478     /**
       
   479      * This method takes a "snapshot" of the current calling context, which
       
   480      * includes the current Thread's inherited AccessControlContext,
       
   481      * and places it in an AccessControlContext object. This context may then
       
   482      * be checked at a later point, possibly in another thread.
       
   483      *
       
   484      * @see AccessControlContext
       
   485      *
       
   486      * @return the AccessControlContext based on the current context.
       
   487      */
       
   488 
       
   489     public static AccessControlContext getContext()
       
   490     {
       
   491         AccessControlContext acc = getStackAccessControlContext();
       
   492         if (acc == null) {
       
   493             // all we had was privileged system code. We don't want
       
   494             // to return null though, so we construct a real ACC.
       
   495             return new AccessControlContext(null, true);
       
   496         } else {
       
   497             return acc.optimize();
       
   498         }
       
   499     }
       
   500 
       
   501     /**
       
   502      * Determines whether the access request indicated by the
       
   503      * specified permission should be allowed or denied, based on
       
   504      * the current AccessControlContext and security policy.
       
   505      * This method quietly returns if the access request
       
   506      * is permitted, or throws an AccessControlException otherwise. The
       
   507      * getPermission method of the AccessControlException returns the
       
   508      * <code>perm</code> Permission object instance.
       
   509      *
       
   510      * @param perm the requested permission.
       
   511      *
       
   512      * @exception AccessControlException if the specified permission
       
   513      *            is not permitted, based on the current security policy.
       
   514      * @exception NullPointerException if the specified permission
       
   515      *            is <code>null</code> and is checked based on the
       
   516      *            security policy currently in effect.
       
   517      */
       
   518 
       
   519     public static void checkPermission(Permission perm)
       
   520                  throws AccessControlException
       
   521     {
       
   522         //System.err.println("checkPermission "+perm);
       
   523         //Thread.currentThread().dumpStack();
       
   524 
       
   525         if (perm == null) {
       
   526             throw new NullPointerException("permission can't be null");
       
   527         }
       
   528 
       
   529         AccessControlContext stack = getStackAccessControlContext();
       
   530         // if context is null, we had privileged system code on the stack.
       
   531         if (stack == null) {
       
   532             Debug debug = AccessControlContext.getDebug();
       
   533             boolean dumpDebug = false;
       
   534             if (debug != null) {
       
   535                 dumpDebug = !Debug.isOn("codebase=");
       
   536                 dumpDebug &= !Debug.isOn("permission=") ||
       
   537                     Debug.isOn("permission=" + perm.getClass().getCanonicalName());
       
   538             }
       
   539 
       
   540             if (dumpDebug && Debug.isOn("stack")) {
       
   541                 Thread.currentThread().dumpStack();
       
   542             }
       
   543 
       
   544             if (dumpDebug && Debug.isOn("domain")) {
       
   545                 debug.println("domain (context is null)");
       
   546             }
       
   547 
       
   548             if (dumpDebug) {
       
   549                 debug.println("access allowed "+perm);
       
   550             }
       
   551             return;
       
   552         }
       
   553 
       
   554         AccessControlContext acc = stack.optimize();
       
   555         acc.checkPermission(perm);
       
   556     }
       
   557 }