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 }
|