001: /*
002: * @(#)Policy.java 1.76 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.security;
029:
030: import java.io.*;
031: import java.lang.RuntimePermission;
032: import java.net.MalformedURLException;
033: import java.net.URL;
034: import java.util.Enumeration;
035: import java.util.Hashtable;
036: import java.util.Vector;
037: import java.util.StringTokenizer;
038: import java.util.PropertyPermission;
039:
040: import java.lang.reflect.*;
041:
042: import java.util.WeakHashMap;
043: import sun.security.util.Debug;
044: import sun.security.util.SecurityConstants;
045:
046: /**
047: * This is an abstract class for representing the system security
048: * policy for a Java application environment (specifying
049: * which permissions are available for code from various sources).
050: * That is, the security policy is represented by a Policy subclass
051: * providing an implementation of the abstract methods
052: * in this Policy class.
053: *
054: * <p>There is only one Policy object in effect at any given time.
055: *
056: * <p>The source location for the policy information utilized by the
057: * Policy object is up to the Policy implementation.
058: * The policy configuration may be stored, for example, as a
059: * flat ASCII file, as a serialized binary file of
060: * the Policy class, or as a database.
061: *
062: * <p>The currently-installed Policy object can be obtained by
063: * calling the <code>getPolicy</code> method, and it can be
064: * changed by a call to the <code>setPolicy</code> method (by
065: * code with permission to reset the Policy).
066: *
067: * <p>The <code>refresh</code> method causes the policy
068: * object to refresh/reload its current configuration.
069: *
070: * <p>This is implementation-dependent. For example, if the policy
071: * object stores its policy in configuration files, calling
072: * <code>refresh</code> will cause it to re-read the configuration
073: * policy files. The refreshed policy may not have an effect on classes
074: * in a particular ProtectionDomain. This is dependent on the Policy
075: * provider's implementation of the
076: * {@link #implies(ProtectionDomain,Permission) implies}
077: * method and the PermissionCollection caching strategy.
078: *
079: * <p>The default Policy implementation can be changed by setting the
080: * value of the "policy.provider" security property (in the Java
081: * security properties file) to the fully qualified name of
082: * the desired Policy implementation class.
083: * The Java security properties file is located in the file named
084: * <JAVA_HOME>/lib/security/java.security, where <JAVA_HOME>
085: * refers to the directory where the SDK was installed.
086: *
087: * @author Roland Schemers
088: * @author Gary Ellison
089: * @version 1.76, 10/10/06
090: * @see java.security.CodeSource
091: * @see java.security.PermissionCollection
092: * @see java.security.SecureClassLoader
093: */
094:
095: public abstract class Policy {
096:
097: /** the system-wide policy. */
098: private static Policy policy; // package private for AccessControlContext
099: private static final Debug debug = Debug.getInstance("policy");
100:
101: // Cache mapping ProtectionDomain to PermissionCollection
102: private WeakHashMap pdMapping;
103:
104: /** package private for AccessControlContext */
105: static boolean isSet() {
106: return policy != null;
107: }
108:
109: /**
110: * Returns the installed Policy object. This value should not be cached,
111: * as it may be changed by a call to <code>setPolicy</code>.
112: * This method first calls
113: * <code>SecurityManager.checkPermission</code> with a
114: * <code>SecurityPermission("getPolicy")</code> permission
115: * to ensure it's ok to get the Policy object..
116: *
117: * @return the installed Policy.
118: *
119: * @throws SecurityException
120: * if a security manager exists and its
121: * <code>checkPermission</code> method doesn't allow
122: * getting the Policy object.
123: *
124: * @see SecurityManager#checkPermission(Permission)
125: * @see #setPolicy(java.security.Policy)
126: */
127: public static Policy getPolicy() {
128: SecurityManager sm = System.getSecurityManager();
129: if (sm != null)
130: sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION);
131: return getPolicyNoCheck();
132: }
133:
134: /**
135: * Returns the installed Policy object, skipping the security check.
136: * Used by SecureClassLoader and getPolicy.
137: *
138: * @return the installed Policy.
139: *
140: */
141: static synchronized Policy getPolicyNoCheck() {
142: if (policy == null) {
143: String policy_class = null;
144: policy_class = (String) AccessController
145: .doPrivileged(new PrivilegedAction() {
146: public Object run() {
147: return Security
148: .getProperty("policy.provider");
149: }
150: });
151: if (policy_class == null) {
152: policy_class = "sun.security.provider.PolicyFile";
153: }
154:
155: try {
156: policy = (Policy) Class.forName(policy_class)
157: .newInstance();
158: } catch (Exception e) {
159: /*
160: * The policy_class seems to be an extension
161: * so we have to bootstrap loading it via a policy
162: * provider that is on the bootclasspath
163: * If it loads then shift gears to using the configured
164: * provider.
165: */
166:
167: // install the bootstrap provider to avoid recursion
168: policy = new sun.security.provider.PolicyFile();
169:
170: final String pc = policy_class;
171: Policy p = (Policy) AccessController
172: .doPrivileged(new PrivilegedAction() {
173: public Object run() {
174: try {
175: ClassLoader cl = ClassLoader
176: .getSystemClassLoader();
177: // we want the extension loader
178: ClassLoader extcl = null;
179: while (cl != null) {
180: extcl = cl;
181: cl = cl.getParent();
182: }
183: return (extcl != null ? Class
184: .forName(pc, true, extcl)
185: .newInstance() : null);
186: } catch (Exception e) {
187: return null;
188: }
189: }
190: });
191: /*
192: * if it loaded install it as the policy provider. Otherwise
193: * continue to use the system default implementation
194: */
195: if (p != null)
196: policy = p;
197:
198: if (p == null && debug != null) {
199: debug.println("policy provider " + policy_class
200: + " not available;using "
201: + "sun.security.provider.PolicyFile");
202: e.printStackTrace();
203: }
204: }
205: }
206: return policy;
207: }
208:
209: /**
210: * Sets the system-wide Policy object. This method first calls
211: * <code>SecurityManager.checkPermission</code> with a
212: * <code>SecurityPermission("setPolicy")</code>
213: * permission to ensure it's ok to set the Policy.
214: *
215: * @param policy the new system Policy object.
216: *
217: * @throws SecurityException
218: * if a security manager exists and its
219: * <code>checkPermission</code> method doesn't allow
220: * setting the Policy.
221: *
222: * @see SecurityManager#checkPermission(Permission)
223: * @see #getPolicy()
224: *
225: */
226: public static void setPolicy(Policy policy) {
227: SecurityManager sm = System.getSecurityManager();
228: if (sm != null)
229: sm.checkPermission(new SecurityPermission("setPolicy"));
230: if (policy != null) {
231: initPolicy(policy);
232: }
233: Policy.policy = policy;
234: }
235:
236: /**
237: * Initialize superclass state such that a legacy provider can
238: * handle queries for itself.
239: *
240: * @since 1.4
241: */
242: private static void initPolicy(final Policy p) {
243: /*
244: * A policy provider not on the bootclasspath could trigger
245: * security checks fulfilling a call to either Policy.implies
246: * or Policy.getPermissions. If this does occur the provider
247: * must be able to answer for it's own ProtectionDomain
248: * without triggering additional security checks, otherwise
249: * the policy implementation will end up in an infinite
250: * recursion.
251: *
252: * To mitigate this, the provider can collect it's own
253: * ProtectionDomain and associate a PermissionCollection while
254: * it is being installed. The currently installed policy
255: * provider (if there is one) will handle calls to
256: * Policy.implies or Policy.getPermissions during this
257: * process.
258: *
259: * This Policy superclass caches away the ProtectionDomain and
260: * statically binds permissions so that legacy Policy
261: * implementations will continue to function.
262: */
263:
264: ProtectionDomain policyDomain = (ProtectionDomain) AccessController
265: .doPrivileged(new PrivilegedAction() {
266: public Object run() {
267: return p.getClass().getProtectionDomain();
268: }
269: });
270:
271: /*
272: * Collect the permissions granted to this protection domain
273: * so that the provider can be security checked while processing
274: * calls to Policy.implies or Policy.getPermissions.
275: */
276: PermissionCollection policyPerms = null;
277: synchronized (p) {
278: if (p.pdMapping == null) {
279: p.pdMapping = new WeakHashMap();
280: }
281: }
282:
283: if (policyDomain.getCodeSource() != null) {
284: if (Policy.isSet()) {
285: policyPerms = policy.getPermissions(policyDomain);
286: }
287:
288: if (policyPerms == null) { // assume it has all
289: policyPerms = new Permissions();
290: policyPerms.add(SecurityConstants.ALL_PERMISSION);
291: }
292:
293: synchronized (p) {
294: // cache of pd to permissions
295: p.pdMapping.put(policyDomain, policyPerms);
296: }
297: }
298: return;
299: }
300:
301: /**
302: * Evaluates the global policy and returns a
303: * PermissionCollection object specifying the set of
304: * permissions allowed for code from the specified
305: * code source.
306: *
307: * @param codesource the CodeSource associated with the caller.
308: * This encapsulates the original location of the code (where the code
309: * came from) and the public key(s) of its signer.
310: *
311: * @return the set of permissions allowed for code from <i>codesource</i>
312: * according to the policy.The returned set of permissions must be
313: * a new mutable instance and it must support heterogeneous
314: * Permission types.
315: *
316: */
317: public abstract PermissionCollection getPermissions(
318: CodeSource codesource);
319:
320: /**
321: * Evaluates the global policy and returns a
322: * PermissionCollection object specifying the set of
323: * permissions allowed given the characteristics of the
324: * protection domain.
325: *
326: * @param domain the ProtectionDomain associated with the caller.
327: *
328: * @return the set of permissions allowed for the <i>domain</i>
329: * according to the policy.The returned set of permissions must be
330: * a new mutable instance and it must support heterogeneous
331: * Permission types.
332: *
333: * @see java.security.ProtectionDomain
334: * @see java.security.SecureClassLoader
335: * @since 1.4
336: */
337: public PermissionCollection getPermissions(ProtectionDomain domain) {
338: PermissionCollection pc = null;
339:
340: if (domain == null)
341: return new Permissions();
342:
343: if (pdMapping == null) {
344: initPolicy(this );
345: }
346:
347: synchronized (pdMapping) {
348: pc = (PermissionCollection) pdMapping.get(domain);
349: }
350:
351: if (pc != null) {
352: Permissions perms = new Permissions();
353: for (Enumeration e = pc.elements(); e.hasMoreElements();) {
354: perms.add((Permission) e.nextElement());
355: }
356: return perms;
357: }
358:
359: pc = getPermissions(domain.getCodeSource());
360: if (pc == null) {
361: pc = new Permissions();
362: }
363:
364: addStaticPerms(pc, domain.getPermissions());
365: return pc;
366: }
367:
368: /**
369: * add static permissions to provided permission collection
370: */
371: private void addStaticPerms(PermissionCollection perms,
372: PermissionCollection statics) {
373: if (statics != null) {
374: Enumeration e = statics.elements();
375: while (e.hasMoreElements()) {
376: perms.add((Permission) e.nextElement());
377: }
378: }
379: }
380:
381: /**
382: * Evaluates the global policy for the permissions granted to
383: * the ProtectionDomain and tests whether the permission is
384: * granted.
385: *
386: * @param domain the ProtectionDomain to test
387: * @param permission the Permission object to be tested for implication.
388: *
389: * @return true if "permission" is a proper subset of a permission
390: * granted to this ProtectionDomain.
391: *
392: * @see java.security.ProtectionDomain
393: * @since 1.4
394: */
395: public boolean implies(ProtectionDomain domain,
396: Permission permission) {
397: PermissionCollection pc;
398: WeakHashMap policyCache;
399:
400: if (pdMapping == null) {
401: initPolicy(this );
402: }
403:
404: policyCache = pdMapping;
405:
406: synchronized (policyCache) {
407: pc = (PermissionCollection) policyCache.get(domain);
408: }
409:
410: if (pc != null) {
411: return pc.implies(permission);
412: }
413:
414: pc = getPermissions(domain);
415: if (pc == null) {
416: return false;
417: }
418:
419: synchronized (policyCache) {
420: // cache it
421: policyCache.put(domain, pc);
422: }
423:
424: return pc.implies(permission);
425: }
426:
427: /**
428: * Refreshes/reloads the policy configuration. The behavior of this method
429: * depends on the implementation. For example, calling <code>refresh</code>
430: * on a file-based policy will cause the file to be re-read.
431: *
432: */
433: public abstract void refresh();
434: }
|