001: /*
002: * @(#)AccessController.java 1.58 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.security;
029:
030: import sun.security.util.Debug;
031: import sun.misc.CVM;
032:
033: /**
034: * <p> The AccessController class is used for access control operations
035: * and decisions.
036: *
037: * <p> More specifically, the AccessController class is used for
038: * three purposes:
039: *
040: * <ul>
041: * <li> to decide whether an access to a critical system
042: * resource is to be allowed or denied, based on the security policy
043: * currently in effect,<p>
044: * <li>to mark code as being "privileged", thus affecting subsequent
045: * access determinations, and<p>
046: * <li>to obtain a "snapshot" of the current calling context so
047: * access-control decisions from a different context can be made with
048: * respect to the saved context. </ul>
049: *
050: * <p> The {@link #checkPermission(Permission) checkPermission} method
051: * determines whether the access request indicated by a specified
052: * permission should be granted or denied. A sample call appears
053: * below. In this example, <code>checkPermission</code> will determine
054: * whether or not to grant "read" access to the file named "testFile" in
055: * the "/temp" directory.
056: *
057: * <pre>
058: *
059: * FilePermission perm = new FilePermission("/temp/testFile", "read");
060: * AccessController.checkPermission(perm);
061: *
062: * </pre>
063: *
064: * <p> If a requested access is allowed,
065: * <code>checkPermission</code> returns quietly. If denied, an
066: * AccessControlException is
067: * thrown. AccessControlException can also be thrown if the requested
068: * permission is of an incorrect type or contains an invalid value.
069: * Such information is given whenever possible.
070: *
071: * Suppose the current thread traversed m callers, in the order of caller 1
072: * to caller 2 to caller m. Then caller m invoked the
073: * <code>checkPermission</code> method.
074: * The <code>checkPermission </code>method determines whether access
075: * is granted or denied based on the following algorithm:
076: *
077: * <pre>
078: * i = m;
079: *
080: * while (i > 0) {
081: *
082: * if (caller i's domain does not have the permission)
083: * throw AccessControlException
084: *
085: * else if (caller i is marked as privileged) {
086: * if (a context was specified in the call to doPrivileged)
087: * context.checkPermission(permission)
088: * return;
089: * }
090: * i = i - 1;
091: * };
092: *
093: * // Next, check the context inherited when
094: * // the thread was created. Whenever a new thread is created, the
095: * // AccessControlContext at that time is
096: * // stored and associated with the new thread, as the "inherited"
097: * // context.
098: *
099: * inheritedContext.checkPermission(permission);
100: * </pre>
101: *
102: * <p> A caller can be marked as being "privileged"
103: * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
104: * When making access control decisions, the <code>checkPermission</code>
105: * method stops checking if it reaches a caller that
106: * was marked as "privileged" via a <code>doPrivileged</code>
107: * call without a context argument (see below for information about a
108: * context argument). If that caller's domain has the
109: * specified permission, no further checking is done and
110: * <code>checkPermission</code>
111: * returns quietly, indicating that the requested access is allowed.
112: * If that domain does not have the specified permission, an exception
113: * is thrown, as usual.
114: *
115: * <p> The normal use of the "privileged" feature is as follows. If you
116: * don't need to return a value from within the "privileged" block, do
117: * the following:
118: *
119: * <pre>
120: * somemethod() {
121: * ...normal code here...
122: * AccessController.doPrivileged(new PrivilegedAction() {
123: * public Object run() {
124: * // privileged code goes here, for example:
125: * System.loadLibrary("awt");
126: * return null; // nothing to return
127: * }
128: * });
129: * ...normal code here...
130: * }
131: * </pre>
132: *
133: * <p>
134: * PrivilegedAction is an interface with a single method, named
135: * <code>run</code>, that returns an Object.
136: * The above example shows creation of an implementation
137: * of that interface; a concrete implementation of the
138: * <code>run</code> method is supplied.
139: * When the call to <code>doPrivileged</code> is made, an
140: * instance of the PrivilegedAction implementation is passed
141: * to it. The <code>doPrivileged</code> method calls the
142: * <code>run</code> method from the PrivilegedAction
143: * implementation after enabling privileges, and returns the
144: * <code>run</code> method's return value as the
145: * <code>doPrivileged</code> return value (which is
146: * ignored in this example).
147: *
148: * <p> If you need to return a value, you can do something like the following:
149: *
150: * <pre>
151: * somemethod() {
152: * ...normal code here...
153: * String user = (String) AccessController.doPrivileged(
154: * new PrivilegedAction() {
155: * public Object run() {
156: * return System.getProperty("user.name");
157: * }
158: * }
159: * );
160: * ...normal code here...
161: * }
162: * </pre>
163: *
164: * <p>If the action performed in your <code>run</code> method could
165: * throw a "checked" exception (those listed in the <code>throws</code> clause
166: * of a method), then you need to use the
167: * <code>PrivilegedExceptionAction</code> interface instead of the
168: * <code>PrivilegedAction</code> interface:
169: *
170: * <pre>
171: * somemethod() throws FileNotFoundException {
172: * ...normal code here...
173: * try {
174: * FileInputStream fis = (FileInputStream) AccessController.doPrivileged(
175: * new PrivilegedExceptionAction() {
176: * public Object run() throws FileNotFoundException {
177: * return new FileInputStream("someFile");
178: * }
179: * }
180: * );
181: * } catch (PrivilegedActionException e) {
182: * // e.getException() should be an instance of FileNotFoundException,
183: * // as only "checked" exceptions will be "wrapped" in a
184: * // <code>PrivilegedActionException</code>.
185: * throw (FileNotFoundException) e.getException();
186: * }
187: * ...normal code here...
188: * }
189: * </pre>
190: *
191: * <p> Be *very* careful in your use of the "privileged" construct, and
192: * always remember to make the privileged code section as small as possible.
193: *
194: * <p> Note that <code>checkPermission</code> always performs security checks
195: * within the context of the currently executing thread.
196: * Sometimes a security check that should be made within a given context
197: * will actually need to be done from within a
198: * <i>different</i> context (for example, from within a worker thread).
199: * The {@link #getContext() getContext} method and
200: * AccessControlContext class are provided
201: * for this situation. The <code>getContext</code> method takes a "snapshot"
202: * of the current calling context, and places
203: * it in an AccessControlContext object, which it returns. A sample call is
204: * the following:
205: *
206: * <pre>
207: *
208: * AccessControlContext acc = AccessController.getContext()
209: *
210: * </pre>
211: *
212: * <p>
213: * AccessControlContext itself has a <code>checkPermission</code> method
214: * that makes access decisions based on the context <i>it</i> encapsulates,
215: * rather than that of the current execution thread.
216: * Code within a different context can thus call that method on the
217: * previously-saved AccessControlContext object. A sample call is the
218: * following:
219: *
220: * <pre>
221: *
222: * acc.checkPermission(permission)
223: *
224: * </pre>
225: *
226: * <p> There are also times where you don't know a priori which permissions
227: * to check the context against. In these cases you can use the
228: * doPrivileged method that takes a context:
229: *
230: * <pre>
231: * somemethod() {
232: * AccessController.doPrivileged(new PrivilegedAction() {
233: * public Object run() {
234: * // Code goes here. Any permission checks within this
235: * // run method will require that the intersection of the
236: * // callers protection domain and the snapshot's
237: * // context have the desired permission.
238: * }
239: * }, acc);
240: * ...normal code here...
241: * }
242: * </pre>
243: *
244: * @see AccessControlContext
245: *
246: * @version 1.48 00/05/03
247: * @author Li Gong
248: * @author Roland Schemers
249: */
250:
251: public final class AccessController {
252:
253: /**
254: * Don't allow anyone to instantiate an AccessController
255: */
256: private AccessController() {
257: }
258:
259: /**
260: * Performs the specified <code>PrivilegedAction</code> with privileges
261: * enabled. The action is performed with <i>all</i> of the permissions
262: * possessed by the caller's protection domain.
263: * <p>
264: * If the action's <code>run</code> method throws an (unchecked) exception,
265: * it will propagate through this method.
266: *
267: * @param action the action to be performed.
268: * @return the value returned by the action's <code>run</code> method.
269: * @see #doPrivileged(PrivilegedAction,AccessControlContext)
270: * @see #doPrivileged(PrivilegedExceptionAction)
271: */
272:
273: public static Object doPrivileged(PrivilegedAction action) {
274: return doPrivileged(action, null);
275: }
276:
277: /**
278: * Performs the specified <code>PrivilegedAction</code> with privileges
279: * enabled and restricted by the specified <code>AccessControlContext</code>.
280: * The action is performed with the intersection of the permissions
281: * possessed by the caller's protection domain, and those possessed
282: * by the domains represented by the specified
283: * <code>AccessControlContext</code>.
284: * <p>
285: * If the action's <code>run</code> method throws an (unchecked) exception,
286: * it will propagate through this method.
287: *
288: * @param action the action to be performed.
289: * @param context an <i>access control context</i> representing the
290: * restriction to be applied to the caller's domain's
291: * privileges before performing the specified action.
292: * @return the value returned by the action's <code>run</code> method.
293: * @see #doPrivileged(PrivilegedAction)
294: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
295: */
296: public static Object doPrivileged(PrivilegedAction action,
297: AccessControlContext context) {
298: return action.run();
299: }
300:
301: /**
302: * Performs the specified <code>PrivilegedExceptionAction</code> with
303: * privileges enabled. The action is performed with <i>all</i> of the
304: * permissions possessed by the caller's protection domain.
305: * <p>
306: * If the action's <code>run</code> method throws an <i>unchecked</i>
307: * exception, it will propagate through this method.
308: *
309: * @param action the action to be performed
310: * @return the value returned by the action's <code>run</code> method
311: * @throws PrivilegedActionException if the specified action's
312: * <code>run</code> method threw a <i>checked</i> exception
313: * @see #doPrivileged(PrivilegedAction)
314: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
315: */
316: public static Object doPrivileged(PrivilegedExceptionAction action)
317: throws PrivilegedActionException {
318: return doPrivileged(action, null);
319: }
320:
321: /**
322: * Performs the specified <code>PrivilegedExceptionAction</code> with
323: * privileges enabled and restricted by the specified
324: * <code>AccessControlContext</code>. The action is performed with the
325: * intersection of the the permissions possessed by the caller's
326: * protection domain, and those possessed by the domains represented by the
327: * specified <code>AccessControlContext</code>.
328: * <p>
329: * If the action's <code>run</code> method throws an <i>unchecked</i>
330: * exception, it will propagate through this method.
331: *
332: * @param action the action to be performed
333: * @param context an <i>access control context</i> representing the
334: * restriction to be applied to the caller's domain's
335: * privileges before performing the specified action
336: * @return the value returned by the action's <code>run</code> method
337: * @throws PrivilegedActionException if the specified action's
338: * <code>run</code> method
339: * threw a <i>checked</i> exception
340: * @see #doPrivileged(PrivilegedAction)
341: * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
342: */
343: public static Object doPrivileged(PrivilegedExceptionAction action,
344: AccessControlContext context)
345: throws PrivilegedActionException {
346: try {
347: return action.run();
348: } catch (RuntimeException e) {
349: // mimic JDK behavior
350: throw e;
351: } catch (Exception e) {
352: // slight deviation from JDK behavior, but not spec
353: // They always wrap, for some reason (bug?)
354: throw new PrivilegedActionException(e);
355: } catch (Throwable e) {
356: throw CVM.throwLocalException(e);
357: }
358: }
359:
360: /**
361: * Returns the AccessControl context. i.e., it gets
362: * the protection domains of all the callers on the stack,
363: * starting at the first class with a non-null
364: * ProtectionDomain.
365: *
366: * @return the access control context based on the current stack or
367: * null if there was only privileged system code.
368: *
369: *
370: */
371:
372: private static AccessControlContext sysACC = new AccessControlContext(
373: null, false, null);
374:
375: private static AccessControlContext privACC = new AccessControlContext(
376: null, true, null);
377:
378: private static native void fillInContext(ProtectionDomain[] ctx,
379: int n);
380:
381: private static native int computeContext(boolean[] isPrivilegedRef,
382: AccessControlContext[] ctxRef);
383:
384: private static AccessControlContext getStackAccessControlContext() {
385: AccessControlContext[] privilegedContextRef = new AccessControlContext[1];
386: boolean[] isPrivilegedRef = new boolean[1];
387:
388: int count = computeContext(isPrivilegedRef,
389: privilegedContextRef);
390:
391: boolean isPrivileged = isPrivilegedRef[0];
392: AccessControlContext privilegedContext = privilegedContextRef[0];
393:
394: // either all the domains on the stack were system domains, or
395: // we had a privileged system domain
396: if (count == 0) {
397: if (isPrivileged && privilegedContext == null) {
398: return null;
399: } else if (privilegedContext != null) {
400: return new AccessControlContext(null, isPrivileged,
401: privilegedContext);
402: } else if (!isPrivileged) {
403: return sysACC;
404: } else {
405: throw new InternalError();
406: }
407: }
408:
409: ProtectionDomain[] ctx = new ProtectionDomain[count];
410:
411: fillInContext(ctx, count);
412:
413: return new AccessControlContext(ctx, isPrivileged,
414: privilegedContext);
415: }
416:
417: /**
418: * Returns the "inherited" AccessControl context. This is the context
419: * that existed when the thread was created. Package private so
420: * AccessControlContext can use it.
421: */
422:
423: static native AccessControlContext getInheritedAccessControlContext();
424:
425: /**
426: * This method takes a "snapshot" of the current calling context, which
427: * includes the current Thread's inherited AccessControlContext,
428: * and places it in an AccessControlContext object. This context may then
429: * be checked at a later point, possibly in another thread.
430: *
431: * @see AccessControlContext
432: *
433: * @return the AccessControlContext based on the current context.
434: */
435:
436: public static AccessControlContext getContext() {
437: AccessControlContext acc = getStackAccessControlContext();
438: if (acc == null) {
439: // all we had was privileged system code. We don't want
440: // to return null though, so we construct a real ACC.
441: return privACC;
442: } else {
443: return acc.optimize();
444: }
445: }
446:
447: /**
448: * Determines whether the access request indicated by the
449: * specified permission should be allowed or denied, based on
450: * the security policy currently in effect.
451: * This method quietly returns if the access request
452: * is permitted, or throws a suitable AccessControlException otherwise.
453: *
454: * @param perm the requested permission.
455: *
456: * @exception AccessControlException if the specified permission
457: * is not permitted, based on the current security policy.
458: */
459:
460: public static void checkPermission(Permission perm)
461: throws AccessControlException {
462: //System.err.println("checkPermission "+perm);
463: //Thread.currentThread().dumpStack();
464:
465: AccessControlContext stack = getStackAccessControlContext();
466: // if context is null, we had privileged system code on the stack.
467: if (stack == null) {
468: Debug debug = AccessControlContext.getDebug();
469: if (debug != null) {
470: if (Debug.isOn("stack"))
471: Thread.currentThread().dumpStack();
472: if (Debug.isOn("domain")) {
473: debug.println("domain (context is null)");
474: }
475: debug.println("access allowed " + perm);
476: }
477: return;
478: }
479:
480: AccessControlContext acc = stack.optimize();
481: acc.checkPermission(perm);
482:
483: }
484: }
|