1. /*
  2. * @(#)Policy.java 1.94 04/06/28
  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 java.io.*;
  9. import java.lang.RuntimePermission;
  10. import java.net.MalformedURLException;
  11. import java.net.URL;
  12. import java.util.Enumeration;
  13. import java.util.Hashtable;
  14. import java.util.Vector;
  15. import java.util.StringTokenizer;
  16. import java.util.PropertyPermission;
  17. import java.lang.reflect.*;
  18. import java.util.WeakHashMap;
  19. import sun.security.util.Debug;
  20. import sun.security.util.SecurityConstants;
  21. /**
  22. * This is an abstract class for representing the system security
  23. * policy for a Java application environment (specifying
  24. * which permissions are available for code from various sources).
  25. * That is, the security policy is represented by a Policy subclass
  26. * providing an implementation of the abstract methods
  27. * in this Policy class.
  28. *
  29. * <p>There is only one Policy object in effect at any given time.
  30. *
  31. * <p>The source location for the policy information utilized by the
  32. * Policy object is up to the Policy implementation.
  33. * The policy configuration may be stored, for example, as a
  34. * flat ASCII file, as a serialized binary file of
  35. * the Policy class, or as a database.
  36. *
  37. * <p>The currently-installed Policy object can be obtained by
  38. * calling the <code>getPolicy</code> method, and it can be
  39. * changed by a call to the <code>setPolicy</code> method (by
  40. * code with permission to reset the Policy).
  41. *
  42. * <p>The <code>refresh</code> method causes the policy
  43. * object to refresh/reload its current configuration.
  44. *
  45. * <p>This is implementation-dependent. For example, if the policy
  46. * object stores its policy in configuration files, calling
  47. * <code>refresh</code> will cause it to re-read the configuration
  48. * policy files. The refreshed policy may not have an effect on classes
  49. * in a particular ProtectionDomain. This is dependent on the Policy
  50. * provider's implementation of the
  51. * {@link #implies(ProtectionDomain,Permission) implies}
  52. * method and the PermissionCollection caching strategy.
  53. *
  54. * <p>The default Policy implementation can be changed by setting the
  55. * value of the "policy.provider" security property (in the Java
  56. * security properties file) to the fully qualified name of
  57. * the desired Policy implementation class.
  58. * The Java security properties file is located in the file named
  59. * <JAVA_HOME>/lib/security/java.security, where <JAVA_HOME>
  60. * refers to the directory where the JDK was installed.
  61. *
  62. * @author Roland Schemers
  63. * @author Gary Ellison
  64. * @version 1.94, 06/28/04
  65. * @see java.security.CodeSource
  66. * @see java.security.PermissionCollection
  67. * @see java.security.SecureClassLoader
  68. */
  69. public abstract class Policy {
  70. /** the system-wide policy. */
  71. private static Policy policy; // package private for AccessControlContext
  72. private static final Debug debug = Debug.getInstance("policy");
  73. // Cache mapping ProtectionDomain to PermissionCollection
  74. private WeakHashMap pdMapping;
  75. /** package private for AccessControlContext */
  76. static boolean isSet()
  77. {
  78. return policy != null;
  79. }
  80. /**
  81. * Returns the installed Policy object. This value should not be cached,
  82. * as it may be changed by a call to <code>setPolicy</code>.
  83. * This method first calls
  84. * <code>SecurityManager.checkPermission</code> with a
  85. * <code>SecurityPermission("getPolicy")</code> permission
  86. * to ensure it's ok to get the Policy object..
  87. *
  88. * @return the installed Policy.
  89. *
  90. * @throws SecurityException
  91. * if a security manager exists and its
  92. * <code>checkPermission</code> method doesn't allow
  93. * getting the Policy object.
  94. *
  95. * @see SecurityManager#checkPermission(Permission)
  96. * @see #setPolicy(java.security.Policy)
  97. */
  98. public static Policy getPolicy()
  99. {
  100. SecurityManager sm = System.getSecurityManager();
  101. if (sm != null)
  102. sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
  103. return getPolicyNoCheck();
  104. }
  105. /**
  106. * Returns the installed Policy object, skipping the security check.
  107. * Used by SecureClassLoader and getPolicy.
  108. *
  109. * @return the installed Policy.
  110. *
  111. */
  112. static synchronized Policy getPolicyNoCheck()
  113. {
  114. if (policy == null) {
  115. String policy_class = null;
  116. policy_class = (String)AccessController.doPrivileged(
  117. new PrivilegedAction() {
  118. public Object run() {
  119. return Security.getProperty("policy.provider");
  120. }
  121. });
  122. if (policy_class == null) {
  123. policy_class = "sun.security.provider.PolicyFile";
  124. }
  125. try {
  126. policy = (Policy)
  127. Class.forName(policy_class).newInstance();
  128. } catch (Exception e) {
  129. /*
  130. * The policy_class seems to be an extension
  131. * so we have to bootstrap loading it via a policy
  132. * provider that is on the bootclasspath
  133. * If it loads then shift gears to using the configured
  134. * provider.
  135. */
  136. // install the bootstrap provider to avoid recursion
  137. policy = new sun.security.provider.PolicyFile();
  138. final String pc = policy_class;
  139. Policy p = (Policy)
  140. AccessController.doPrivileged(new PrivilegedAction() {
  141. public Object run() {
  142. try {
  143. ClassLoader cl =
  144. ClassLoader.getSystemClassLoader();
  145. // we want the extension loader
  146. ClassLoader extcl = null;
  147. while (cl != null) {
  148. extcl = cl;
  149. cl = cl.getParent();
  150. }
  151. return (extcl != null? Class.forName
  152. (pc, true, extcl).newInstance():
  153. null);
  154. } catch (Exception e) {
  155. return null;
  156. }
  157. }
  158. });
  159. /*
  160. * if it loaded install it as the policy provider. Otherwise
  161. * continue to use the system default implementation
  162. */
  163. if (p != null)
  164. policy = p;
  165. if (p == null && debug != null) {
  166. debug.println("policy provider " +
  167. policy_class + " not available;using " +
  168. "sun.security.provider.PolicyFile");
  169. e.printStackTrace();
  170. }
  171. }
  172. }
  173. return policy;
  174. }
  175. /**
  176. * Sets the system-wide Policy object. This method first calls
  177. * <code>SecurityManager.checkPermission</code> with a
  178. * <code>SecurityPermission("setPolicy")</code>
  179. * permission to ensure it's ok to set the Policy.
  180. *
  181. * @param p the new system Policy object.
  182. *
  183. * @throws SecurityException
  184. * if a security manager exists and its
  185. * <code>checkPermission</code> method doesn't allow
  186. * setting the Policy.
  187. *
  188. * @see SecurityManager#checkPermission(Permission)
  189. * @see #getPolicy()
  190. *
  191. */
  192. public static void setPolicy(Policy p)
  193. {
  194. SecurityManager sm = System.getSecurityManager();
  195. if (sm != null) sm.checkPermission(
  196. new SecurityPermission("setPolicy"));
  197. if (p != null) {
  198. initPolicy(p);
  199. }
  200. synchronized (Policy.class) {
  201. Policy.policy = p;
  202. }
  203. }
  204. /**
  205. * Initialize superclass state such that a legacy provider can
  206. * handle queries for itself.
  207. *
  208. * @since 1.4
  209. */
  210. private static void initPolicy (final Policy p) {
  211. /*
  212. * A policy provider not on the bootclasspath could trigger
  213. * security checks fulfilling a call to either Policy.implies
  214. * or Policy.getPermissions. If this does occur the provider
  215. * must be able to answer for it's own ProtectionDomain
  216. * without triggering additional security checks, otherwise
  217. * the policy implementation will end up in an infinite
  218. * recursion.
  219. *
  220. * To mitigate this, the provider can collect it's own
  221. * ProtectionDomain and associate a PermissionCollection while
  222. * it is being installed. The currently installed policy
  223. * provider (if there is one) will handle calls to
  224. * Policy.implies or Policy.getPermissions during this
  225. * process.
  226. *
  227. * This Policy superclass caches away the ProtectionDomain and
  228. * statically binds permissions so that legacy Policy
  229. * implementations will continue to function.
  230. */
  231. ProtectionDomain policyDomain = (ProtectionDomain)
  232. AccessController.doPrivileged(new PrivilegedAction() {
  233. public Object run() {
  234. return p.getClass().getProtectionDomain();
  235. }
  236. });
  237. /*
  238. * Collect the permissions granted to this protection domain
  239. * so that the provider can be security checked while processing
  240. * calls to Policy.implies or Policy.getPermissions.
  241. */
  242. PermissionCollection policyPerms = null;
  243. synchronized (p) {
  244. if (p.pdMapping == null) {
  245. p.pdMapping = new WeakHashMap();
  246. }
  247. }
  248. if (policyDomain.getCodeSource() != null) {
  249. if (Policy.isSet()) {
  250. policyPerms = policy.getPermissions(policyDomain);
  251. }
  252. if (policyPerms == null) { // assume it has all
  253. policyPerms = new Permissions();
  254. policyPerms.add(SecurityConstants.ALL_PERMISSION);
  255. }
  256. synchronized (p.pdMapping) {
  257. // cache of pd to permissions
  258. p.pdMapping.put(policyDomain, policyPerms);
  259. }
  260. }
  261. return;
  262. }
  263. /**
  264. * Evaluates the global policy and returns a
  265. * PermissionCollection object specifying the set of
  266. * permissions allowed for code from the specified
  267. * code source.
  268. *
  269. * @param codesource the CodeSource associated with the caller.
  270. * This encapsulates the original location of the code (where the code
  271. * came from) and the public key(s) of its signer.
  272. *
  273. * @return the set of permissions allowed for code from <i>codesource</i>
  274. * according to the policy.The returned set of permissions must be
  275. * a new mutable instance and it must support heterogeneous
  276. * Permission types.
  277. *
  278. */
  279. public abstract PermissionCollection getPermissions(CodeSource codesource);
  280. /**
  281. * Evaluates the global policy and returns a
  282. * PermissionCollection object specifying the set of
  283. * permissions allowed given the characteristics of the
  284. * protection domain.
  285. *
  286. * @param domain the ProtectionDomain associated with the caller.
  287. *
  288. * @return the set of permissions allowed for the <i>domain</i>
  289. * according to the policy.The returned set of permissions must be
  290. * a new mutable instance and it must support heterogeneous
  291. * Permission types.
  292. *
  293. * @see java.security.ProtectionDomain
  294. * @see java.security.SecureClassLoader
  295. * @since 1.4
  296. */
  297. public PermissionCollection getPermissions(ProtectionDomain domain) {
  298. PermissionCollection pc = null;
  299. if (domain == null)
  300. return new Permissions();
  301. if (pdMapping == null) {
  302. initPolicy(this);
  303. }
  304. synchronized (pdMapping) {
  305. pc = (PermissionCollection)pdMapping.get(domain);
  306. }
  307. if (pc != null) {
  308. Permissions perms = new Permissions();
  309. synchronized (pc) {
  310. for (Enumeration e = pc.elements() ; e.hasMoreElements() ;) {
  311. perms.add((Permission)e.nextElement());
  312. }
  313. }
  314. return perms;
  315. }
  316. pc = getPermissions(domain.getCodeSource());
  317. if (pc == null) {
  318. pc = new Permissions();
  319. }
  320. addStaticPerms(pc, domain.getPermissions());
  321. return pc;
  322. }
  323. /**
  324. * add static permissions to provided permission collection
  325. */
  326. private void addStaticPerms(PermissionCollection perms,
  327. PermissionCollection statics) {
  328. if (statics != null) {
  329. synchronized (statics) {
  330. Enumeration e = statics.elements();
  331. while (e.hasMoreElements()) {
  332. perms.add((Permission)e.nextElement());
  333. }
  334. }
  335. }
  336. }
  337. /**
  338. * Evaluates the global policy for the permissions granted to
  339. * the ProtectionDomain and tests whether the permission is
  340. * granted.
  341. *
  342. * @param domain the ProtectionDomain to test
  343. * @param permission the Permission object to be tested for implication.
  344. *
  345. * @return true if "permission" is a proper subset of a permission
  346. * granted to this ProtectionDomain.
  347. *
  348. * @see java.security.ProtectionDomain
  349. * @since 1.4
  350. */
  351. public boolean implies(ProtectionDomain domain, Permission permission) {
  352. PermissionCollection pc;
  353. if (pdMapping == null) {
  354. initPolicy(this);
  355. }
  356. synchronized (pdMapping) {
  357. pc = (PermissionCollection)pdMapping.get(domain);
  358. }
  359. if (pc != null) {
  360. return pc.implies(permission);
  361. }
  362. pc = getPermissions(domain);
  363. if (pc == null) {
  364. return false;
  365. }
  366. synchronized (pdMapping) {
  367. // cache it
  368. pdMapping.put(domain, pc);
  369. }
  370. return pc.implies(permission);
  371. }
  372. /**
  373. * Refreshes/reloads the policy configuration. The behavior of this method
  374. * depends on the implementation. For example, calling <code>refresh</code>
  375. * on a file-based policy will cause the file to be re-read.
  376. *
  377. */
  378. public abstract void refresh();
  379. }