2
* Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
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).
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.
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
26
package java.security;
28
import ikvm.internal.CallerID;
29
import sun.misc.Unsafe;
30
import sun.security.util.Debug;
33
* <p> The AccessController class is used for access control operations
36
* <p> More specifically, the AccessController class is used for
40
* <li> to decide whether an access to a critical system
41
* resource is to be allowed or denied, based on the security policy
42
* currently in effect,<p>
43
* <li>to mark code as being "privileged", thus affecting subsequent
44
* access determinations, and<p>
45
* <li>to obtain a "snapshot" of the current calling context so
46
* access-control decisions from a different context can be made with
47
* respect to the saved context. </ul>
49
* <p> The {@link #checkPermission(Permission) checkPermission} method
50
* determines whether the access request indicated by a specified
51
* permission should be granted or denied. A sample call appears
52
* below. In this example, <code>checkPermission</code> will determine
53
* whether or not to grant "read" access to the file named "testFile" in
54
* the "/temp" directory.
58
* FilePermission perm = new FilePermission("/temp/testFile", "read");
59
* AccessController.checkPermission(perm);
63
* <p> If a requested access is allowed,
64
* <code>checkPermission</code> returns quietly. If denied, an
65
* AccessControlException is
66
* thrown. AccessControlException can also be thrown if the requested
67
* permission is of an incorrect type or contains an invalid value.
68
* Such information is given whenever possible.
70
* Suppose the current thread traversed m callers, in the order of caller 1
71
* to caller 2 to caller m. Then caller m invoked the
72
* <code>checkPermission</code> method.
73
* The <code>checkPermission </code>method determines whether access
74
* is granted or denied based on the following algorithm:
77
* for (int i = m; i > 0; i--) {
79
* if (caller i's domain does not have the permission)
80
* throw AccessControlException
82
* else if (caller i is marked as privileged) {
83
* if (a context was specified in the call to doPrivileged)
84
* context.checkPermission(permission)
89
* // Next, check the context inherited when the thread was created.
90
* // Whenever a new thread is created, the AccessControlContext at
91
* // that time is stored and associated with the new thread, as the
92
* // "inherited" context.
94
* inheritedContext.checkPermission(permission);
97
* <p> A caller can be marked as being "privileged"
98
* (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
99
* When making access control decisions, the <code>checkPermission</code>
100
* method stops checking if it reaches a caller that
101
* was marked as "privileged" via a <code>doPrivileged</code>
102
* call without a context argument (see below for information about a
103
* context argument). If that caller's domain has the
104
* specified permission, no further checking is done and
105
* <code>checkPermission</code>
106
* returns quietly, indicating that the requested access is allowed.
107
* If that domain does not have the specified permission, an exception
108
* is thrown, as usual.
110
* <p> The normal use of the "privileged" feature is as follows. If you
111
* don't need to return a value from within the "privileged" block, do
116
* ...normal code here...
117
* AccessController.doPrivileged(new PrivilegedAction<Void>() {
118
* public Void run() {
119
* // privileged code goes here, for example:
120
* System.loadLibrary("awt");
121
* return null; // nothing to return
124
* ...normal code here...
128
* PrivilegedAction is an interface with a single method, named
130
* The above example shows creation of an implementation
131
* of that interface; a concrete implementation of the
132
* <code>run</code> method is supplied.
133
* When the call to <code>doPrivileged</code> is made, an
134
* instance of the PrivilegedAction implementation is passed
135
* to it. The <code>doPrivileged</code> method calls the
136
* <code>run</code> method from the PrivilegedAction
137
* implementation after enabling privileges, and returns the
138
* <code>run</code> method's return value as the
139
* <code>doPrivileged</code> return value (which is
140
* ignored in this example).
142
* <p> If you need to return a value, you can do something like the following:
146
* ...normal code here...
147
* String user = AccessController.doPrivileged(
148
* new PrivilegedAction<String>() {
149
* public String run() {
150
* return System.getProperty("user.name");
153
* ...normal code here...
156
* <p>If the action performed in your <code>run</code> method could
157
* throw a "checked" exception (those listed in the <code>throws</code> clause
158
* of a method), then you need to use the
159
* <code>PrivilegedExceptionAction</code> interface instead of the
160
* <code>PrivilegedAction</code> interface:
163
* somemethod() throws FileNotFoundException {
164
* ...normal code here...
166
* FileInputStream fis = AccessController.doPrivileged(
167
* new PrivilegedExceptionAction<FileInputStream>() {
168
* public FileInputStream run() throws FileNotFoundException {
169
* return new FileInputStream("someFile");
172
* } catch (PrivilegedActionException e) {
173
* // e.getException() should be an instance of FileNotFoundException,
174
* // as only "checked" exceptions will be "wrapped" in a
175
* // PrivilegedActionException.
176
* throw (FileNotFoundException) e.getException();
178
* ...normal code here...
181
* <p> Be *very* careful in your use of the "privileged" construct, and
182
* always remember to make the privileged code section as small as possible.
184
* <p> Note that <code>checkPermission</code> always performs security checks
185
* within the context of the currently executing thread.
186
* Sometimes a security check that should be made within a given context
187
* will actually need to be done from within a
188
* <i>different</i> context (for example, from within a worker thread).
189
* The {@link #getContext() getContext} method and
190
* AccessControlContext class are provided
191
* for this situation. The <code>getContext</code> method takes a "snapshot"
192
* of the current calling context, and places
193
* it in an AccessControlContext object, which it returns. A sample call is
198
* AccessControlContext acc = AccessController.getContext()
203
* AccessControlContext itself has a <code>checkPermission</code> method
204
* that makes access decisions based on the context <i>it</i> encapsulates,
205
* rather than that of the current execution thread.
206
* Code within a different context can thus call that method on the
207
* previously-saved AccessControlContext object. A sample call is the
212
* acc.checkPermission(permission)
216
* <p> There are also times where you don't know a priori which permissions
217
* to check the context against. In these cases you can use the
218
* doPrivileged method that takes a context:
222
* AccessController.doPrivileged(new PrivilegedAction<Object>() {
223
* public Object run() {
224
* // Code goes here. Any permission checks within this
225
* // run method will require that the intersection of the
226
* // callers protection domain and the snapshot's
227
* // context have the desired permission.
230
* ...normal code here...
233
* @see AccessControlContext
236
* @author Roland Schemers
239
public final class AccessController {
241
@cli.System.ThreadStaticAttribute.Annotation
242
private static PrivilegedElement privileged_stack_top;
245
public static final class LazyContext {
248
AccessControlContext context;
249
final cli.System.Diagnostics.StackTrace stackTrace = new cli.System.Diagnostics.StackTrace(1);
253
public static LazyContext getLazyContext(LazyContext parent) {
254
LazyContext lc = new LazyContext();
256
if (privileged_stack_top != null) {
257
lc.callerID = privileged_stack_top.callerID;
258
lc.context = privileged_stack_top.context;
263
private static final class PrivilegedElement {
265
AccessControlContext context;
268
private static Object doPrivileged(Object action, AccessControlContext context, CallerID callerID) {
269
PrivilegedElement savedPrivilegedElement = privileged_stack_top;
271
PrivilegedElement pi = new PrivilegedElement();
272
pi.callerID = callerID;
273
pi.context = context;
274
privileged_stack_top = pi;
276
if (action instanceof PrivilegedAction) {
277
return ((PrivilegedAction)action).run();
279
return ((PrivilegedExceptionAction)action).run();
281
} catch (Exception x) {
282
if (!(x instanceof RuntimeException)) {
283
Unsafe.getUnsafe().throwException(new PrivilegedActionException(x));
285
throw (RuntimeException)x;
288
privileged_stack_top = savedPrivilegedElement;
293
* Don't allow anyone to instantiate an AccessController
295
private AccessController() { }
298
* Performs the specified <code>PrivilegedAction</code> with privileges
299
* enabled. The action is performed with <i>all</i> of the permissions
300
* possessed by the caller's protection domain.
302
* <p> If the action's <code>run</code> method throws an (unchecked)
303
* exception, it will propagate through this method.
305
* <p> Note that any DomainCombiner associated with the current
306
* AccessControlContext will be ignored while the action is performed.
308
* @param action the action to be performed.
310
* @return the value returned by the action's <code>run</code> method.
312
* @exception NullPointerException if the action is <code>null</code>
314
* @see #doPrivileged(PrivilegedAction,AccessControlContext)
315
* @see #doPrivileged(PrivilegedExceptionAction)
316
* @see #doPrivilegedWithCombiner(PrivilegedAction)
317
* @see java.security.DomainCombiner
320
@ikvm.internal.HasCallerID
321
public static <T> T doPrivileged(PrivilegedAction<T> action) {
322
return (T)doPrivileged(action, null, CallerID.getCallerID());
326
* Performs the specified <code>PrivilegedAction</code> with privileges
327
* enabled. The action is performed with <i>all</i> of the permissions
328
* possessed by the caller's protection domain.
330
* <p> If the action's <code>run</code> method throws an (unchecked)
331
* exception, it will propagate through this method.
333
* <p> This method preserves the current AccessControlContext's
334
* DomainCombiner (which may be null) while the action is performed.
336
* @param action the action to be performed.
338
* @return the value returned by the action's <code>run</code> method.
340
* @exception NullPointerException if the action is <code>null</code>
342
* @see #doPrivileged(PrivilegedAction)
343
* @see java.security.DomainCombiner
347
public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
349
DomainCombiner dc = null;
350
AccessControlContext acc = getStackAccessControlContext();
351
if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
352
return AccessController.doPrivileged(action);
354
return AccessController.doPrivileged(action, preserveCombiner(dc));
359
* Performs the specified <code>PrivilegedAction</code> with privileges
360
* enabled and restricted by the specified
361
* <code>AccessControlContext</code>.
362
* The action is performed with the intersection of the permissions
363
* possessed by the caller's protection domain, and those possessed
364
* by the domains represented by the specified
365
* <code>AccessControlContext</code>.
367
* If the action's <code>run</code> method throws an (unchecked) exception,
368
* it will propagate through this method.
370
* @param action the action to be performed.
371
* @param context an <i>access control context</i>
372
* representing the restriction to be applied to the
373
* caller's domain's privileges before performing
374
* the specified action. If the context is
376
* then no additional restriction is applied.
378
* @return the value returned by the action's <code>run</code> method.
380
* @exception NullPointerException if the action is <code>null</code>
382
* @see #doPrivileged(PrivilegedAction)
383
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
385
@ikvm.internal.HasCallerID
386
public static <T> T doPrivileged(PrivilegedAction<T> action,
387
AccessControlContext context) {
388
return (T)doPrivileged(action, context, CallerID.getCallerID());
392
* Performs the specified <code>PrivilegedExceptionAction</code> with
393
* privileges enabled. The action is performed with <i>all</i> of the
394
* permissions possessed by the caller's protection domain.
396
* <p> If the action's <code>run</code> method throws an <i>unchecked</i>
397
* exception, it will propagate through this method.
399
* <p> Note that any DomainCombiner associated with the current
400
* AccessControlContext will be ignored while the action is performed.
402
* @param action the action to be performed
404
* @return the value returned by the action's <code>run</code> method
406
* @exception PrivilegedActionException if the specified action's
407
* <code>run</code> method threw a <i>checked</i> exception
408
* @exception NullPointerException if the action is <code>null</code>
410
* @see #doPrivileged(PrivilegedAction)
411
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
412
* @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
413
* @see java.security.DomainCombiner
415
@ikvm.internal.HasCallerID
417
doPrivileged(PrivilegedExceptionAction<T> action)
418
throws PrivilegedActionException {
419
return (T)doPrivileged(action, null, CallerID.getCallerID());
424
* Performs the specified <code>PrivilegedExceptionAction</code> with
425
* privileges enabled. The action is performed with <i>all</i> of the
426
* permissions possessed by the caller's protection domain.
428
* <p> If the action's <code>run</code> method throws an <i>unchecked</i>
429
* exception, it will propagate through this method.
431
* <p> This method preserves the current AccessControlContext's
432
* DomainCombiner (which may be null) while the action is performed.
434
* @param action the action to be performed.
436
* @return the value returned by the action's <code>run</code> method
438
* @exception PrivilegedActionException if the specified action's
439
* <code>run</code> method threw a <i>checked</i> exception
440
* @exception NullPointerException if the action is <code>null</code>
442
* @see #doPrivileged(PrivilegedAction)
443
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
444
* @see java.security.DomainCombiner
448
public static <T> T doPrivilegedWithCombiner
449
(PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
451
DomainCombiner dc = null;
452
AccessControlContext acc = getStackAccessControlContext();
453
if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
454
return AccessController.doPrivileged(action);
456
return AccessController.doPrivileged(action, preserveCombiner(dc));
460
* preserve the combiner across the doPrivileged call
462
private static AccessControlContext preserveCombiner
463
(DomainCombiner combiner) {
466
* callerClass[0] = Reflection.getCallerClass
467
* callerClass[1] = AccessController.preserveCombiner
468
* callerClass[2] = AccessController.doPrivileged
469
* callerClass[3] = caller
471
final Class callerClass = sun.reflect.Reflection.getCallerClass(3);
472
ProtectionDomain callerPd = doPrivileged
473
(new PrivilegedAction<ProtectionDomain>() {
474
public ProtectionDomain run() {
475
return callerClass.getProtectionDomain();
479
// perform 'combine' on the caller of doPrivileged,
480
// even if the caller is from the bootclasspath
481
ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
482
return new AccessControlContext(combiner.combine(pds, null), combiner);
487
* Performs the specified <code>PrivilegedExceptionAction</code> with
488
* privileges enabled and restricted by the specified
489
* <code>AccessControlContext</code>. The action is performed with the
490
* intersection of the permissions possessed by the caller's
491
* protection domain, and those possessed by the domains represented by the
492
* specified <code>AccessControlContext</code>.
494
* If the action's <code>run</code> method throws an <i>unchecked</i>
495
* exception, it will propagate through this method.
497
* @param action the action to be performed
498
* @param context an <i>access control context</i>
499
* representing the restriction to be applied to the
500
* caller's domain's privileges before performing
501
* the specified action. If the context is
503
* then no additional restriction is applied.
505
* @return the value returned by the action's <code>run</code> method
507
* @exception PrivilegedActionException if the specified action's
508
* <code>run</code> method
509
* threw a <i>checked</i> exception
510
* @exception NullPointerException if the action is <code>null</code>
512
* @see #doPrivileged(PrivilegedAction)
513
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
515
@ikvm.internal.HasCallerID
517
doPrivileged(PrivilegedExceptionAction<T> action,
518
AccessControlContext context)
519
throws PrivilegedActionException {
520
return (T)doPrivileged(action, context, CallerID.getCallerID());
524
* Returns the AccessControl context. i.e., it gets
525
* the protection domains of all the callers on the stack,
526
* starting at the first class with a non-null
529
* @return the access control context based on the current stack or
530
* null if there was only privileged system code.
533
private static AccessControlContext getStackAccessControlContext() {
534
AccessControlContext context = null;
535
CallerID callerID = null;
536
PrivilegedElement pi = privileged_stack_top;
538
context = pi.context;
539
callerID = pi.callerID;
541
return getStackAccessControlContext(context, callerID);
544
private static native AccessControlContext getStackAccessControlContext(AccessControlContext context, CallerID callerID);
547
* Returns the "inherited" AccessControl context. This is the context
548
* that existed when the thread was created. Package private so
549
* AccessControlContext can use it.
552
static native AccessControlContext getInheritedAccessControlContext();
555
* This method takes a "snapshot" of the current calling context, which
556
* includes the current Thread's inherited AccessControlContext,
557
* and places it in an AccessControlContext object. This context may then
558
* be checked at a later point, possibly in another thread.
560
* @see AccessControlContext
562
* @return the AccessControlContext based on the current context.
565
public static AccessControlContext getContext()
567
AccessControlContext acc = getStackAccessControlContext();
569
// all we had was privileged system code. We don't want
570
// to return null though, so we construct a real ACC.
571
return new AccessControlContext(null, true);
573
return acc.optimize();
578
* Determines whether the access request indicated by the
579
* specified permission should be allowed or denied, based on
580
* the current AccessControlContext and security policy.
581
* This method quietly returns if the access request
582
* is permitted, or throws an AccessControlException otherwise. The
583
* getPermission method of the AccessControlException returns the
584
* <code>perm</code> Permission object instance.
586
* @param perm the requested permission.
588
* @exception AccessControlException if the specified permission
589
* is not permitted, based on the current security policy.
590
* @exception NullPointerException if the specified permission
591
* is <code>null</code> and is checked based on the
592
* security policy currently in effect.
595
public static void checkPermission(Permission perm)
596
throws AccessControlException
598
//System.err.println("checkPermission "+perm);
599
//Thread.currentThread().dumpStack();
602
throw new NullPointerException("permission can't be null");
605
AccessControlContext stack = getStackAccessControlContext();
606
// if context is null, we had privileged system code on the stack.
608
Debug debug = AccessControlContext.getDebug();
609
boolean dumpDebug = false;
611
dumpDebug = !Debug.isOn("codebase=");
612
dumpDebug &= !Debug.isOn("permission=") ||
613
Debug.isOn("permission=" + perm.getClass().getCanonicalName());
616
if (dumpDebug && Debug.isOn("stack")) {
617
Thread.currentThread().dumpStack();
620
if (dumpDebug && Debug.isOn("domain")) {
621
debug.println("domain (context is null)");
625
debug.println("access allowed "+perm);
630
AccessControlContext acc = stack.optimize();
631
acc.checkPermission(perm);