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