1. /*
  2. * @(#)AccessController.java 1.55 04/05/05
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security;
  8. import sun.security.util.Debug;
  9. /**
  10. * <p> The AccessController class is used for access control operations
  11. * and decisions.
  12. *
  13. * <p> More specifically, the AccessController class is used for
  14. * three purposes:
  15. *
  16. * <ul>
  17. * <li> to decide whether an access to a critical system
  18. * resource is to be allowed or denied, based on the security policy
  19. * currently in effect,<p>
  20. * <li>to mark code as being "privileged", thus affecting subsequent
  21. * access determinations, and<p>
  22. * <li>to obtain a "snapshot" of the current calling context so
  23. * access-control decisions from a different context can be made with
  24. * respect to the saved context. </ul>
  25. *
  26. * <p> The {@link #checkPermission(Permission) checkPermission} method
  27. * determines whether the access request indicated by a specified
  28. * permission should be granted or denied. A sample call appears
  29. * below. In this example, <code>checkPermission</code> will determine
  30. * whether or not to grant "read" access to the file named "testFile" in
  31. * the "/temp" directory.
  32. *
  33. * <pre>
  34. *
  35. * FilePermission perm = new FilePermission("/temp/testFile", "read");
  36. * AccessController.checkPermission(perm);
  37. *
  38. * </pre>
  39. *
  40. * <p> If a requested access is allowed,
  41. * <code>checkPermission</code> returns quietly. If denied, an
  42. * AccessControlException is
  43. * thrown. AccessControlException can also be thrown if the requested
  44. * permission is of an incorrect type or contains an invalid value.
  45. * Such information is given whenever possible.
  46. *
  47. * Suppose the current thread traversed m callers, in the order of caller 1
  48. * to caller 2 to caller m. Then caller m invoked the
  49. * <code>checkPermission</code> method.
  50. * The <code>checkPermission </code>method determines whether access
  51. * is granted or denied based on the following algorithm:
  52. *
  53. * <pre>
  54. * i = m;
  55. *
  56. * while (i > 0) {
  57. *
  58. * if (caller i's domain does not have the permission)
  59. * throw AccessControlException
  60. *
  61. * else if (caller i is marked as privileged) {
  62. * if (a context was specified in the call to doPrivileged)
  63. * context.checkPermission(permission)
  64. * return;
  65. * }
  66. * i = i - 1;
  67. * };
  68. *
  69. * // Next, check the context inherited when
  70. * // the thread was created. Whenever a new thread is created, the
  71. * // AccessControlContext at that time is
  72. * // stored and associated with the new thread, as the "inherited"
  73. * // context.
  74. *
  75. * inheritedContext.checkPermission(permission);
  76. * </pre>
  77. *
  78. * <p> A caller can be marked as being "privileged"
  79. * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
  80. * When making access control decisions, the <code>checkPermission</code>
  81. * method stops checking if it reaches a caller that
  82. * was marked as "privileged" via a <code>doPrivileged</code>
  83. * call without a context argument (see below for information about a
  84. * context argument). If that caller's domain has the
  85. * specified permission, no further checking is done and
  86. * <code>checkPermission</code>
  87. * returns quietly, indicating that the requested access is allowed.
  88. * If that domain does not have the specified permission, an exception
  89. * is thrown, as usual.
  90. *
  91. * <p> The normal use of the "privileged" feature is as follows. If you
  92. * don't need to return a value from within the "privileged" block, do
  93. * the following:
  94. *
  95. * <pre>
  96. * somemethod() {
  97. * ...normal code here...
  98. * AccessController.doPrivileged(new PrivilegedAction() {
  99. * public Object run() {
  100. * // privileged code goes here, for example:
  101. * System.loadLibrary("awt");
  102. * return null; // nothing to return
  103. * }
  104. * });
  105. * ...normal code here...
  106. * }
  107. * </pre>
  108. *
  109. * <p>
  110. * PrivilegedAction is an interface with a single method, named
  111. * <code>run</code>, that returns an Object.
  112. * The above example shows creation of an implementation
  113. * of that interface; a concrete implementation of the
  114. * <code>run</code> method is supplied.
  115. * When the call to <code>doPrivileged</code> is made, an
  116. * instance of the PrivilegedAction implementation is passed
  117. * to it. The <code>doPrivileged</code> method calls the
  118. * <code>run</code> method from the PrivilegedAction
  119. * implementation after enabling privileges, and returns the
  120. * <code>run</code> method's return value as the
  121. * <code>doPrivileged</code> return value (which is
  122. * ignored in this example).
  123. *
  124. * <p> If you need to return a value, you can do something like the following:
  125. *
  126. * <pre>
  127. * somemethod() {
  128. * ...normal code here...
  129. * String user = (String) AccessController.doPrivileged(
  130. * new PrivilegedAction() {
  131. * public Object run() {
  132. * return System.getProperty("user.name");
  133. * }
  134. * }
  135. * );
  136. * ...normal code here...
  137. * }
  138. * </pre>
  139. *
  140. * <p>If the action performed in your <code>run</code> method could
  141. * throw a "checked" exception (those listed in the <code>throws</code> clause
  142. * of a method), then you need to use the
  143. * <code>PrivilegedExceptionAction</code> interface instead of the
  144. * <code>PrivilegedAction</code> interface:
  145. *
  146. * <pre>
  147. * somemethod() throws FileNotFoundException {
  148. * ...normal code here...
  149. * try {
  150. * FileInputStream fis = (FileInputStream) AccessController.doPrivileged(
  151. * new PrivilegedExceptionAction() {
  152. * public Object run() throws FileNotFoundException {
  153. * return new FileInputStream("someFile");
  154. * }
  155. * }
  156. * );
  157. * } catch (PrivilegedActionException e) {
  158. * // e.getException() should be an instance of FileNotFoundException,
  159. * // as only "checked" exceptions will be "wrapped" in a
  160. * // <code>PrivilegedActionException</code>.
  161. * throw (FileNotFoundException) e.getException();
  162. * }
  163. * ...normal code here...
  164. * }
  165. * </pre>
  166. *
  167. * <p> Be *very* careful in your use of the "privileged" construct, and
  168. * always remember to make the privileged code section as small as possible.
  169. *
  170. * <p> Note that <code>checkPermission</code> always performs security checks
  171. * within the context of the currently executing thread.
  172. * Sometimes a security check that should be made within a given context
  173. * will actually need to be done from within a
  174. * <i>different</i> context (for example, from within a worker thread).
  175. * The {@link #getContext() getContext} method and
  176. * AccessControlContext class are provided
  177. * for this situation. The <code>getContext</code> method takes a "snapshot"
  178. * of the current calling context, and places
  179. * it in an AccessControlContext object, which it returns. A sample call is
  180. * the following:
  181. *
  182. * <pre>
  183. *
  184. * AccessControlContext acc = AccessController.getContext()
  185. *
  186. * </pre>
  187. *
  188. * <p>
  189. * AccessControlContext itself has a <code>checkPermission</code> method
  190. * that makes access decisions based on the context <i>it</i> encapsulates,
  191. * rather than that of the current execution thread.
  192. * Code within a different context can thus call that method on the
  193. * previously-saved AccessControlContext object. A sample call is the
  194. * following:
  195. *
  196. * <pre>
  197. *
  198. * acc.checkPermission(permission)
  199. *
  200. * </pre>
  201. *
  202. * <p> There are also times where you don't know a priori which permissions
  203. * to check the context against. In these cases you can use the
  204. * doPrivileged method that takes a context:
  205. *
  206. * <pre>
  207. * somemethod() {
  208. * AccessController.doPrivileged(new PrivilegedAction() {
  209. * public Object run() {
  210. * // Code goes here. Any permission checks within this
  211. * // run method will require that the intersection of the
  212. * // callers protection domain and the snapshot's
  213. * // context have the desired permission.
  214. * }
  215. * }, acc);
  216. * ...normal code here...
  217. * }
  218. * </pre>
  219. *
  220. * @see AccessControlContext
  221. *
  222. * @version 1.55 04/05/05
  223. * @author Li Gong
  224. * @author Roland Schemers
  225. */
  226. public final class AccessController {
  227. /**
  228. * Don't allow anyone to instantiate an AccessController
  229. */
  230. private AccessController() { }
  231. /**
  232. * Performs the specified <code>PrivilegedAction</code> with privileges
  233. * enabled. The action is performed with <i>all</i> of the permissions
  234. * possessed by the caller's protection domain.
  235. * <p>
  236. * If the action's <code>run</code> method throws an (unchecked) exception,
  237. * it will propagate through this method.
  238. *
  239. * @param action the action to be performed.
  240. *
  241. * @return the value returned by the action's <code>run</code> method.
  242. *
  243. * @exception NullPointerException if the action is <code>null</code>
  244. *
  245. * @see #doPrivileged(PrivilegedAction,AccessControlContext)
  246. * @see #doPrivileged(PrivilegedExceptionAction)
  247. */
  248. public static native <T> T doPrivileged(PrivilegedAction<T> action);
  249. /**
  250. * Performs the specified <code>PrivilegedAction</code> with privileges
  251. * enabled and restricted by the specified
  252. * <code>AccessControlContext</code>.
  253. * The action is performed with the intersection of the permissions
  254. * possessed by the caller's protection domain, and those possessed
  255. * by the domains represented by the specified
  256. * <code>AccessControlContext</code>.
  257. * <p>
  258. * If the action's <code>run</code> method throws an (unchecked) exception,
  259. * it will propagate through this method.
  260. *
  261. * @param action the action to be performed.
  262. * @param context an <i>access control context</i>
  263. * representing the restriction to be applied to the
  264. * caller's domain's privileges before performing
  265. * the specified action. If the context is
  266. * <code>null</code>,
  267. * then no additional restriction is applied.
  268. *
  269. * @return the value returned by the action's <code>run</code> method.
  270. *
  271. * @exception NullPointerException if the action is <code>null</code>
  272. *
  273. * @see #doPrivileged(PrivilegedAction)
  274. * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  275. */
  276. public static native <T> T doPrivileged(PrivilegedAction<T> action,
  277. AccessControlContext context);
  278. /**
  279. * Performs the specified <code>PrivilegedExceptionAction</code> with
  280. * privileges enabled. The action is performed with <i>all</i> of the
  281. * permissions possessed by the caller's protection domain.
  282. * <p>
  283. * If the action's <code>run</code> method throws an <i>unchecked</i>
  284. * exception, it will propagate through this method.
  285. *
  286. * @param action the action to be performed
  287. *
  288. * @return the value returned by the action's <code>run</code> method
  289. *
  290. * @exception PrivilegedActionException if the specified action's
  291. * <code>run</code> method threw a <i>checked</i> exception
  292. * @exception NullPointerException if the action is <code>null</code>
  293. *
  294. * @see #doPrivileged(PrivilegedAction)
  295. * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  296. */
  297. public static native <T> T
  298. doPrivileged(PrivilegedExceptionAction<T> action)
  299. throws PrivilegedActionException;
  300. /**
  301. * Performs the specified <code>PrivilegedExceptionAction</code> with
  302. * privileges enabled and restricted by the specified
  303. * <code>AccessControlContext</code>. The action is performed with the
  304. * intersection of the the permissions possessed by the caller's
  305. * protection domain, and those possessed by the domains represented by the
  306. * specified <code>AccessControlContext</code>.
  307. * <p>
  308. * If the action's <code>run</code> method throws an <i>unchecked</i>
  309. * exception, it will propagate through this method.
  310. *
  311. * @param action the action to be performed
  312. * @param context an <i>access control context</i>
  313. * representing the restriction to be applied to the
  314. * caller's domain's privileges before performing
  315. * the specified action. If the context is
  316. * <code>null</code>,
  317. * then no additional restriction is applied.
  318. *
  319. * @return the value returned by the action's <code>run</code> method
  320. *
  321. * @exception PrivilegedActionException if the specified action's
  322. * <code>run</code> method
  323. * threw a <i>checked</i> exception
  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
  330. doPrivileged(PrivilegedExceptionAction<T> action,
  331. AccessControlContext context)
  332. throws PrivilegedActionException;
  333. /**
  334. * Returns the AccessControl context. i.e., it gets
  335. * the protection domains of all the callers on the stack,
  336. * starting at the first class with a non-null
  337. * ProtectionDomain.
  338. *
  339. * @return the access control context based on the current stack or
  340. * null if there was only privileged system code.
  341. */
  342. private static native AccessControlContext getStackAccessControlContext();
  343. /**
  344. * Returns the "inherited" AccessControl context. This is the context
  345. * that existed when the thread was created. Package private so
  346. * AccessControlContext can use it.
  347. */
  348. static native AccessControlContext getInheritedAccessControlContext();
  349. /**
  350. * This method takes a "snapshot" of the current calling context, which
  351. * includes the current Thread's inherited AccessControlContext,
  352. * and places it in an AccessControlContext object. This context may then
  353. * be checked at a later point, possibly in another thread.
  354. *
  355. * @see AccessControlContext
  356. *
  357. * @return the AccessControlContext based on the current context.
  358. */
  359. public static AccessControlContext getContext()
  360. {
  361. AccessControlContext acc = getStackAccessControlContext();
  362. if (acc == null) {
  363. // all we had was privileged system code. We don't want
  364. // to return null though, so we construct a real ACC.
  365. return new AccessControlContext(null, true);
  366. } else {
  367. return acc.optimize();
  368. }
  369. }
  370. /**
  371. * Determines whether the access request indicated by the
  372. * specified permission should be allowed or denied, based on
  373. * the security policy currently in effect.
  374. * This method quietly returns if the access request
  375. * is permitted, or throws a suitable AccessControlException otherwise.
  376. *
  377. * @param perm the requested permission.
  378. *
  379. * @exception AccessControlException if the specified permission
  380. * is not permitted, based on the current security policy.
  381. * @exception NullPointerException if the specified permission
  382. * is <code>null</code> and is checked based on the
  383. * security policy currently in effect.
  384. */
  385. public static void checkPermission(Permission perm)
  386. throws AccessControlException
  387. {
  388. //System.err.println("checkPermission "+perm);
  389. //Thread.currentThread().dumpStack();
  390. AccessControlContext stack = getStackAccessControlContext();
  391. // if context is null, we had privileged system code on the stack.
  392. if (stack == null) {
  393. Debug debug = AccessControlContext.getDebug();
  394. if (debug != null) {
  395. if (Debug.isOn("stack"))
  396. Thread.currentThread().dumpStack();
  397. if (Debug.isOn("domain")) {
  398. debug.println("domain (context is null)");
  399. }
  400. debug.println("access allowed "+perm);
  401. }
  402. return;
  403. }
  404. AccessControlContext acc = stack.optimize();
  405. acc.checkPermission(perm);
  406. }
  407. }