001: /*
002: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.security;
027:
028: import sun.security.util.Debug;
029:
030: /**
031: * <p> The AccessController class is used for access control operations
032: * and decisions.
033: *
034: * <p> More specifically, the AccessController class is used for
035: * three purposes:
036: *
037: * <ul>
038: * <li> to decide whether an access to a critical system
039: * resource is to be allowed or denied, based on the security policy
040: * currently in effect,<p>
041: * <li>to mark code as being "privileged", thus affecting subsequent
042: * access determinations, and<p>
043: * <li>to obtain a "snapshot" of the current calling context so
044: * access-control decisions from a different context can be made with
045: * respect to the saved context. </ul>
046: *
047: * <p> The {@link #checkPermission(Permission) checkPermission} method
048: * determines whether the access request indicated by a specified
049: * permission should be granted or denied. A sample call appears
050: * below. In this example, <code>checkPermission</code> will determine
051: * whether or not to grant "read" access to the file named "testFile" in
052: * the "/temp" directory.
053: *
054: * <pre>
055: *
056: * FilePermission perm = new FilePermission("/temp/testFile", "read");
057: * AccessController.checkPermission(perm);
058: *
059: * </pre>
060: *
061: * <p> If a requested access is allowed,
062: * <code>checkPermission</code> returns quietly. If denied, an
063: * AccessControlException is
064: * thrown. AccessControlException can also be thrown if the requested
065: * permission is of an incorrect type or contains an invalid value.
066: * Such information is given whenever possible.
067: *
068: * Suppose the current thread traversed m callers, in the order of caller 1
069: * to caller 2 to caller m. Then caller m invoked the
070: * <code>checkPermission</code> method.
071: * The <code>checkPermission </code>method determines whether access
072: * is granted or denied based on the following algorithm:
073: *
074: * <pre> {@code
075: * for (int i = m; i > 0; i--) {
076: *
077: * if (caller i's domain does not have the permission)
078: * throw AccessControlException
079: *
080: * else if (caller i is marked as privileged) {
081: * if (a context was specified in the call to doPrivileged)
082: * context.checkPermission(permission)
083: * return;
084: * }
085: * };
086: *
087: * // Next, check the context inherited when the thread was created.
088: * // Whenever a new thread is created, the AccessControlContext at
089: * // that time is stored and associated with the new thread, as the
090: * // "inherited" context.
091: *
092: * inheritedContext.checkPermission(permission);
093: * }</pre>
094: *
095: * <p> A caller can be marked as being "privileged"
096: * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
097: * When making access control decisions, the <code>checkPermission</code>
098: * method stops checking if it reaches a caller that
099: * 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: * @version 1.68 07/05/17
234: * @author Li Gong
235: * @author Roland Schemers
236: */
237:
238: public final class AccessController {
239:
240: /**
241: * Don't allow anyone to instantiate an AccessController
242: */
243: private AccessController() {
244: }
245:
246: /**
247: * Performs the specified <code>PrivilegedAction</code> with privileges
248: * enabled. The action is performed with <i>all</i> of the permissions
249: * possessed by the caller's protection domain.
250: *
251: * <p> If the action's <code>run</code> method throws an (unchecked)
252: * exception, it will propagate through this method.
253: *
254: * <p> Note that any DomainCombiner associated with the current
255: * AccessControlContext will be ignored while the action is performed.
256: *
257: * @param action the action to be performed.
258: *
259: * @return the value returned by the action's <code>run</code> method.
260: *
261: * @exception NullPointerException if the action is <code>null</code>
262: *
263: * @see #doPrivileged(PrivilegedAction,AccessControlContext)
264: * @see #doPrivileged(PrivilegedExceptionAction)
265: * @see #doPrivilegedWithCombiner(PrivilegedAction)
266: * @see java.security.DomainCombiner
267: */
268:
269: public static native <T> T doPrivileged(PrivilegedAction<T> action);
270:
271: /**
272: * Performs the specified <code>PrivilegedAction</code> with privileges
273: * enabled. The action is performed with <i>all</i> of the permissions
274: * possessed by the caller's protection domain.
275: *
276: * <p> If the action's <code>run</code> method throws an (unchecked)
277: * exception, it will propagate through this method.
278: *
279: * <p> This method preserves the current AccessControlContext's
280: * DomainCombiner (which may be null) while the action is performed.
281: *
282: * @param action the action to be performed.
283: *
284: * @return the value returned by the action's <code>run</code> method.
285: *
286: * @exception NullPointerException if the action is <code>null</code>
287: *
288: * @see #doPrivileged(PrivilegedAction)
289: * @see java.security.DomainCombiner
290: *
291: * @since 1.6
292: */
293: public static <T> T doPrivilegedWithCombiner(
294: PrivilegedAction<T> action) {
295:
296: DomainCombiner dc = null;
297: AccessControlContext acc = getStackAccessControlContext();
298: if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
299: return AccessController.doPrivileged(action);
300: }
301: return AccessController.doPrivileged(action,
302: preserveCombiner(dc));
303: }
304:
305: /**
306: * Performs the specified <code>PrivilegedAction</code> with privileges
307: * enabled and restricted by the specified
308: * <code>AccessControlContext</code>.
309: * The action is performed with the intersection of the permissions
310: * possessed by the caller's protection domain, and those possessed
311: * by the domains represented by the specified
312: * <code>AccessControlContext</code>.
313: * <p>
314: * If the action's <code>run</code> method throws an (unchecked) exception,
315: * it will propagate through this method.
316: *
317: * @param action the action to be performed.
318: * @param context an <i>access control context</i>
319: * representing the restriction to be applied to the
320: * caller's domain's privileges before performing
321: * the specified action. If the context is
322: * <code>null</code>,
323: * then no additional restriction is applied.
324: *
325: * @return the value returned by the action's <code>run</code> method.
326: *
327: * @exception NullPointerException if the action is <code>null</code>
328: *
329: * @see #doPrivileged(PrivilegedAction)
330: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
331: */
332: public static native <T> T doPrivileged(PrivilegedAction<T> action,
333: AccessControlContext context);
334:
335: /**
336: * Performs the specified <code>PrivilegedExceptionAction</code> with
337: * privileges enabled. The action is performed with <i>all</i> of the
338: * permissions possessed by the caller's protection domain.
339: *
340: * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
341: * exception, it will propagate through this method.
342: *
343: * <p> Note that any DomainCombiner associated with the current
344: * AccessControlContext will be ignored while the action is performed.
345: *
346: * @param action the action to be performed
347: *
348: * @return the value returned by the action's <code>run</code> method
349: *
350: * @exception PrivilegedActionException if the specified action's
351: * <code>run</code> method threw a <i>checked</i> exception
352: * @exception NullPointerException if the action is <code>null</code>
353: *
354: * @see #doPrivileged(PrivilegedAction)
355: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
356: * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
357: * @see java.security.DomainCombiner
358: */
359: public static native <T> T doPrivileged(
360: PrivilegedExceptionAction<T> action)
361: throws PrivilegedActionException;
362:
363: /**
364: * Performs the specified <code>PrivilegedExceptionAction</code> with
365: * privileges enabled. The action is performed with <i>all</i> of the
366: * permissions possessed by the caller's protection domain.
367: *
368: * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
369: * exception, it will propagate through this method.
370: *
371: * <p> This method preserves the current AccessControlContext's
372: * DomainCombiner (which may be null) while the action is performed.
373: *
374: * @param action the action to be performed.
375: *
376: * @return the value returned by the action's <code>run</code> method
377: *
378: * @exception PrivilegedActionException if the specified action's
379: * <code>run</code> method threw a <i>checked</i> exception
380: * @exception NullPointerException if the action is <code>null</code>
381: *
382: * @see #doPrivileged(PrivilegedAction)
383: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
384: * @see java.security.DomainCombiner
385: *
386: * @since 1.6
387: */
388: public static <T> T doPrivilegedWithCombiner(
389: PrivilegedExceptionAction<T> action)
390: throws PrivilegedActionException {
391:
392: DomainCombiner dc = null;
393: AccessControlContext acc = getStackAccessControlContext();
394: if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
395: return AccessController.doPrivileged(action);
396: }
397: return AccessController.doPrivileged(action,
398: preserveCombiner(dc));
399: }
400:
401: /**
402: * preserve the combiner across the doPrivileged call
403: */
404: private static AccessControlContext preserveCombiner(
405: DomainCombiner combiner) {
406:
407: /**
408: * callerClass[0] = Reflection.getCallerClass
409: * callerClass[1] = AccessController.preserveCombiner
410: * callerClass[2] = AccessController.doPrivileged
411: * callerClass[3] = caller
412: */
413: final Class callerClass = sun.reflect.Reflection
414: .getCallerClass(3);
415: ProtectionDomain callerPd = doPrivileged(new PrivilegedAction<ProtectionDomain>() {
416: public ProtectionDomain run() {
417: return callerClass.getProtectionDomain();
418: }
419: });
420:
421: // perform 'combine' on the caller of doPrivileged,
422: // even if the caller is from the bootclasspath
423: ProtectionDomain[] pds = new ProtectionDomain[] { callerPd };
424: return new AccessControlContext(combiner.combine(pds, null),
425: combiner);
426: }
427:
428: /**
429: * Performs the specified <code>PrivilegedExceptionAction</code> with
430: * privileges enabled and restricted by the specified
431: * <code>AccessControlContext</code>. The action is performed with the
432: * intersection of the the permissions possessed by the caller's
433: * protection domain, and those possessed by the domains represented by the
434: * specified <code>AccessControlContext</code>.
435: * <p>
436: * If the action's <code>run</code> method throws an <i>unchecked</i>
437: * exception, it will propagate through this method.
438: *
439: * @param action the action to be performed
440: * @param context an <i>access control context</i>
441: * representing the restriction to be applied to the
442: * caller's domain's privileges before performing
443: * the specified action. If the context is
444: * <code>null</code>,
445: * then no additional restriction is applied.
446: *
447: * @return the value returned by the action's <code>run</code> method
448: *
449: * @exception PrivilegedActionException if the specified action's
450: * <code>run</code> method
451: * threw a <i>checked</i> exception
452: * @exception NullPointerException if the action is <code>null</code>
453: *
454: * @see #doPrivileged(PrivilegedAction)
455: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
456: */
457: public static native <T> T doPrivileged(
458: PrivilegedExceptionAction<T> action,
459: AccessControlContext context)
460: throws PrivilegedActionException;
461:
462: /**
463: * Returns the AccessControl context. i.e., it gets
464: * the protection domains of all the callers on the stack,
465: * starting at the first class with a non-null
466: * ProtectionDomain.
467: *
468: * @return the access control context based on the current stack or
469: * null if there was only privileged system code.
470: */
471:
472: private static native AccessControlContext getStackAccessControlContext();
473:
474: /**
475: * Returns the "inherited" AccessControl context. This is the context
476: * that existed when the thread was created. Package private so
477: * AccessControlContext can use it.
478: */
479:
480: static native AccessControlContext getInheritedAccessControlContext();
481:
482: /**
483: * This method takes a "snapshot" of the current calling context, which
484: * includes the current Thread's inherited AccessControlContext,
485: * and places it in an AccessControlContext object. This context may then
486: * be checked at a later point, possibly in another thread.
487: *
488: * @see AccessControlContext
489: *
490: * @return the AccessControlContext based on the current context.
491: */
492:
493: public static AccessControlContext getContext() {
494: AccessControlContext acc = getStackAccessControlContext();
495: if (acc == null) {
496: // all we had was privileged system code. We don't want
497: // to return null though, so we construct a real ACC.
498: return new AccessControlContext(null, true);
499: } else {
500: return acc.optimize();
501: }
502: }
503:
504: /**
505: * Determines whether the access request indicated by the
506: * specified permission should be allowed or denied, based on
507: * the current AccessControlContext and security policy.
508: * This method quietly returns if the access request
509: * is permitted, or throws a suitable AccessControlException otherwise.
510: *
511: * @param perm the requested permission.
512: *
513: * @exception AccessControlException if the specified permission
514: * is not permitted, based on the current security policy.
515: * @exception NullPointerException if the specified permission
516: * is <code>null</code> and is checked based on the
517: * security policy currently in effect.
518: */
519:
520: public static void checkPermission(Permission perm)
521: throws AccessControlException {
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="
538: + perm.getClass().getCanonicalName());
539: }
540:
541: if (dumpDebug && Debug.isOn("stack")) {
542: Thread.currentThread().dumpStack();
543: }
544:
545: if (dumpDebug && Debug.isOn("domain")) {
546: debug.println("domain (context is null)");
547: }
548:
549: if (dumpDebug) {
550: debug.println("access allowed " + perm);
551: }
552: return;
553: }
554:
555: AccessControlContext acc = stack.optimize();
556: acc.checkPermission(perm);
557: }
558: }
|