1. /*
  2. * @(#)Policy.java 1.89 03/01/23
  3. *
  4. * Copyright 2003 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 SDK was installed.
  61. *
  62. * @author Roland Schemers
  63. * @author Gary Ellison
  64. * @version 1.89, 01/23/03
  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 policy 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 policy)
  193. {
  194. SecurityManager sm = System.getSecurityManager();
  195. if (sm != null) sm.checkPermission(
  196. new SecurityPermission("setPolicy"));
  197. if (policy != null) {
  198. initPolicy(policy);
  199. }
  200. Policy.policy = policy;
  201. }
  202. /**
  203. * Initialize superclass state such that a legacy provider can
  204. * handle queries for itself.
  205. *
  206. * @since 1.4
  207. */
  208. private static void initPolicy (final Policy p) {
  209. /*
  210. * A policy provider not on the bootclasspath could trigger
  211. * security checks fulfilling a call to either Policy.implies
  212. * or Policy.getPermissions. If this does occur the provider
  213. * must be able to answer for it's own ProtectionDomain
  214. * without triggering additional security checks, otherwise
  215. * the policy implementation will end up in an infinite
  216. * recursion.
  217. *
  218. * To mitigate this, the provider can collect it's own
  219. * ProtectionDomain and associate a PermissionCollection while
  220. * it is being installed. The currently installed policy
  221. * provider (if there is one) will handle calls to
  222. * Policy.implies or Policy.getPermissions during this
  223. * process.
  224. *
  225. * This Policy superclass caches away the ProtectionDomain and
  226. * statically binds permissions so that legacy Policy
  227. * implementations will continue to function.
  228. */
  229. ProtectionDomain policyDomain = (ProtectionDomain)
  230. AccessController.doPrivileged(new PrivilegedAction() {
  231. public Object run() {
  232. return p.getClass().getProtectionDomain();
  233. }
  234. });
  235. /*
  236. * Collect the permissions granted to this protection domain
  237. * so that the provider can be security checked while processing
  238. * calls to Policy.implies or Policy.getPermissions.
  239. */
  240. PermissionCollection policyPerms = null;
  241. synchronized (p) {
  242. if (p.pdMapping == null) {
  243. p.pdMapping = new WeakHashMap();
  244. }
  245. }
  246. if (policyDomain.getCodeSource() != null) {
  247. if (Policy.isSet()) {
  248. policyPerms = policy.getPermissions(policyDomain);
  249. }
  250. if (policyPerms == null) { // assume it has all
  251. policyPerms = new Permissions();
  252. policyPerms.add(SecurityConstants.ALL_PERMISSION);
  253. }
  254. synchronized (p) {
  255. // cache of pd to permissions
  256. p.pdMapping.put(policyDomain, policyPerms);
  257. }
  258. }
  259. return;
  260. }
  261. /**
  262. * Evaluates the global policy and returns a
  263. * PermissionCollection object specifying the set of
  264. * permissions allowed for code from the specified
  265. * code source.
  266. *
  267. * @param codesource the CodeSource associated with the caller.
  268. * This encapsulates the original location of the code (where the code
  269. * came from) and the public key(s) of its signer.
  270. *
  271. * @return the set of permissions allowed for code from <i>codesource</i>
  272. * according to the policy.The returned set of permissions must be
  273. * a new mutable instance and it must support heterogeneous
  274. * Permission types.
  275. *
  276. */
  277. public abstract PermissionCollection getPermissions(CodeSource codesource);
  278. /**
  279. * Evaluates the global policy and returns a
  280. * PermissionCollection object specifying the set of
  281. * permissions allowed given the characteristics of the
  282. * protection domain.
  283. *
  284. * @param domain the ProtectionDomain associated with the caller.
  285. *
  286. * @return the set of permissions allowed for the <i>domain</i>
  287. * according to the policy.The returned set of permissions must be
  288. * a new mutable instance and it must support heterogeneous
  289. * Permission types.
  290. *
  291. * @see java.security.ProtectionDomain
  292. * @see java.security.SecureClassLoader
  293. * @since 1.4
  294. */
  295. public PermissionCollection getPermissions(ProtectionDomain domain) {
  296. PermissionCollection pc = null;
  297. if (domain == null)
  298. return new Permissions();
  299. if (pdMapping == null) {
  300. initPolicy(this);
  301. }
  302. synchronized (pdMapping) {
  303. pc = (PermissionCollection)pdMapping.get(domain);
  304. }
  305. if (pc != null) {
  306. Permissions perms = new Permissions();
  307. for (Enumeration e = pc.elements() ; e.hasMoreElements() ;) {
  308. perms.add((Permission)e.nextElement());
  309. }
  310. return perms;
  311. }
  312. pc = getPermissions(domain.getCodeSource());
  313. if (pc == null) {
  314. pc = new Permissions();
  315. }
  316. addStaticPerms(pc, domain.getPermissions());
  317. return pc;
  318. }
  319. /**
  320. * add static permissions to provided permission collection
  321. */
  322. private void addStaticPerms(PermissionCollection perms,
  323. PermissionCollection statics) {
  324. if (statics != null) {
  325. Enumeration e = statics.elements();
  326. while (e.hasMoreElements()) {
  327. perms.add((Permission)e.nextElement());
  328. }
  329. }
  330. }
  331. /**
  332. * Evaluates the global policy for the permissions granted to
  333. * the ProtectionDomain and tests whether the permission is
  334. * granted.
  335. *
  336. * @param domain the ProtectionDomain to test
  337. * @param permission the Permission object to be tested for implication.
  338. *
  339. * @return true if "permission" is a proper subset of a permission
  340. * granted to this ProtectionDomain.
  341. *
  342. * @see java.security.ProtectionDomain
  343. * @since 1.4
  344. */
  345. public boolean implies(ProtectionDomain domain, Permission permission) {
  346. PermissionCollection pc;
  347. WeakHashMap policyCache;
  348. if (pdMapping == null) {
  349. initPolicy(this);
  350. }
  351. policyCache = pdMapping;
  352. synchronized (policyCache) {
  353. pc = (PermissionCollection)policyCache.get(domain);
  354. }
  355. if (pc != null) {
  356. return pc.implies(permission);
  357. }
  358. pc = getPermissions(domain);
  359. if (pc == null) {
  360. return false;
  361. }
  362. synchronized (policyCache) {
  363. // cache it
  364. policyCache.put(domain, pc);
  365. }
  366. return pc.implies(permission);
  367. }
  368. /**
  369. * Refreshes/reloads the policy configuration. The behavior of this method
  370. * depends on the implementation. For example, calling <code>refresh</code>
  371. * on a file-based policy will cause the file to be re-read.
  372. *
  373. */
  374. public abstract void refresh();
  375. }