home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 23.8 KB | 808 lines |
- /*
- * @(#)PolicyFile.java 1.8 98/03/18
- *
- * Copyright 1997, 1998 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
-
- package java.security;
-
- import java.io.*;
- import java.lang.RuntimePermission;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.Vector;
- import java.util.StringTokenizer;
- import java.util.PropertyPermission;
-
- import java.lang.reflect.*;
-
- import sun.security.tools.*;
- import sun.security.util.PropertyExpander;
-
- /**
- * The policy for a Java runtime (specifying
- * which permissions are available for code from various principals)
- * is represented as one or more separate
- * persistent configurations. Each configuration may be stored as a
- * flat ASCII file, as a serialized binary file of
- * the Policy class, or as a database. <p>
- *
- * Each Java runtime may have multiple policy files.
- * The default policy files are configured in the security
- * properties file to be:
- *
- * <pre>
- * (<i>java.home</i>)/lib/security/java.policy
- * (<i>user.home</i>)/.java.policy
- * </pre>
- *
- * <p>where <i>java.home</i> indicates the JDK installation directory
- * (determined by the value of the "java.home" system property),
- * and
- * <p>where <i>user.home</i> indicates the user's home directory
- * (determined by the value of the "user.home" system property).
- *
- * <p>The Java runtime creates one global Policy object, which is used to
- * represent the permissions granted in the static policy configuration
- * file(s). It is consulted by
- * a ProtectionDomain when the protection domain initializes its set of
- * permissions. <p>
- *
- * <p>The Policy object is agnostic in that
- * it is not involved in making policy decisions. It is merely the
- * Java runtime representation of the persistent policy configuration
- * file(s). <p>
- *
- * <p>When a protection domain needs to initialize its set of
- * permissions, it executes code such as the following
- * to ask the global Policy object to populate a
- * Permissions object with the appropriate permissions:
- * <pre>
- * policy = Policy.getPolicy();
- * Permissions perms = policy.evaluate(MyCodeSource)
- * </pre>
- *
- * <p>The protection domain passes in a CodeSource
- * object, which encapsulates its codebase (URL) and public key attributes.
- * The Policy object evaluates the global policy in light of who the
- * principal is and returns an appropriate Permissions object.
- *
- * @author Roland Schemers
- * @version 1.8, 03/18/98
- * @see java.security.CodeSource
- * @see java.security.Permissions
- * @see java.security.ProtectionDomain
- */
-
- class PolicyFile extends java.security.Policy {
-
- private Vector policyEntries;
- private Hashtable aliasMapping;
- private Vector publicKeys;
- private KeyStore keyStore;
-
- private boolean debug = getDebug();
-
- private boolean initialized = false;
-
- private boolean expandProperties = true;
-
- // for use with the reflection API
-
- private static final Class[] PARAMS = { String.class, String.class};
-
- private static boolean getDebug() {
- try {
- AccessController.beginPrivileged();
- return Boolean.getBoolean("java.security.debug");
- } finally {
- AccessController.endPrivileged();
- }
- }
-
- /**
- * Creates a Policy object.
- */
- public PolicyFile() {
-
- }
-
- /**
- * Initializes the Policy object and reads the default policy
- * configuration file(s) into the Policy object.
- *
- * The algorithm for locating the policy file(s) and reading their
- * information into the Policy object is:
- * <pre>
- * loop through the Security Properties named "policy.url.1",
- * "policy.url.2", etc, until you don't find one. Each of
- * these specify a policy file.
- *
- * if none of these could be loaded, use a builtin static policy
- * equivalent to the default lib/security/java.policy file.
- *
- * if the system property "java.policy" is defined (which is the
- * case when the user uses the -D switch at runtime), and
- * its use is allowed by the security property file,
- * also load it.
- * </pre>
- *
- * Each policy file consists of one or more grant entries, each of
- * which consists of a number of permission entries.
- * <pre>
- * grant signedBy "<i>alias</i>", codeBase "<i>URL</i>" {
- * permission <i>Type</i> "<i>name</i>", "<i>action</i>",
- * signedBy "<i>alias</i>";
- * ....
- * permission <i>Type</i> "<i>name</i>", "<i>action</i>",
- * signedBy "<i>alias</i>";
- * };
- *
- * </pre>
- *
- * All non-italicized items above must appear as is (although case
- * doesn't matter and some are optional, as noted below).
- * Italicized items represent variable values.
- *
- * <p> A grant entry must begin with the word <code>grant</code>.
- * The <code>signedBy</code> and <code>codeBase</code> name/value
- * pairs are optional.
- * If they are not present, then any signer (including unsigned code)
- * will match, and any codeBase will match.
- *
- * <p> A permission entry must begin with the word <code>permission</code>.
- * The word <code><i>Type</i></code> in the template above would actually be
- * a specific permission type, such as <code>java.io.FilePermission</code>
- * or <code>java.lang.RuntimePermission</code>.
- *
- * <p>The "<i>action</i>" is required for
- * many permission types, such as <code>java.io.FilePermission</code>
- * (where it specifies what type of file access is permitted).
- * It is not required for categories such as
- * <code>java.lang.RuntimePermission</code>
- * where it is not necessary - you either have the
- * permission specified by the <code>"<i>name</i>"</code>
- * value following the type name or you don't.
- *
- * <p>The <code>signedBy</code> name/value pair for a permission entry
- * is optional. If present, it indicates a signed permission. That is,
- * the permission class itself must be signed by the given alias in
- * order for it to be granted. For example,
- * suppose you have the following grant entry:
- *
- * <pre>
- * grant {
- * permission Foo "foobar", signedBy "FooSoft";
- * }
- * </pre>
- *
- * <p>Then this permission of type <i>Foo</i> is granted if the
- * <code>Foo.class</code> permission has been signed by the
- * "FooSoft" alias, or if <code>Foo.class</code> is a
- * system class (i.e., is found on the CLASSPATH).
- *
- * <p>Items that appear in an entry must appear in the specified order
- * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
- * "<i>action</i>"). An entry is terminated with a semicolon.
- *
- * <p>Case is unimportant for the identifiers (<code>permission</code>,
- * <code>signedBy</code>, <code>codeBase</code>, etc.) but is
- * significant for the <i>Type</i>
- * or for any string that is passed in as a value. <p>
- *
- * <p>An example of two entries in a policy configuration file is
- * <pre>
- * // if the code is signed by "Duke", grant it read/write to all
- * // files in /tmp.
- *
- * grant signedBy "Duke" {
- * permission java.io.FilePermission "/tmp/*", "read,write";
- * };
- * <p>
- * // grant everyone the following permission
- *
- * grant {
- * permission java.util.PropertyPermission "java.vendor";
- * };
- * </pre>
- */
- private void init() {
-
- policyEntries = new Vector();
- aliasMapping = new Hashtable();
- publicKeys = new Vector();
-
- try {
- AccessController.beginPrivileged();
- initPolicyFile();
- initialized = true;
- } finally {
- AccessController.endPrivileged();
- }
- }
-
- /**
- * Refreshes the policy object.
- *
- */
- public void refresh()
- {
- init();
- }
-
- private KeyStore initKeyStore(URL policyUrl, String keyStoreName) {
- if (keyStoreName != null) {
- try {
- /*
- * location of keystore is specified as absolute URL in policy
- * file, or is relative to URL of policy file
- */
- URL keyStoreUrl = null;
- try {
- keyStoreUrl = new URL(keyStoreName);
- // absolute URL
- } catch (java.net.MalformedURLException e) {
- // relative URL
- keyStoreUrl = new URL(policyUrl, keyStoreName);
- }
- InputStream inStream = keyStoreUrl.openStream();
- KeyStore ks = KeyStore.getInstance();
- ks.load(inStream, null);
- inStream.close();
- return ks;
- } catch (Exception e) {
- // ignore, treat it like we have no keystore
- if (debug) {
- e.printStackTrace();
- }
- return null;
- }
- }
- return null;
- }
-
- private void initPolicyFile() {
-
- // No need to put this into a begin/endPrivileged block, because
- // this is already called from privileged code in Policy.java
- String prop = Security.getProperty("policy.expandProperties");
-
- if (prop != null) expandProperties = prop.equalsIgnoreCase("true");
-
- // No need to put this into a begin/endPrivileged block, because
- // this is already called from privileged code in Policy.java
- String allowSys = Security.getProperty("policy.allowSystemProperty");
-
- if (allowSys.equalsIgnoreCase("true")) {
- // No need to put this into a begin/endPrivileged block, because
- // this is already called from privileged code in Policy.java
- String extra_policy = System.getProperty("java.policy");
- if (extra_policy != null) {
- boolean overrideAll = false;
- if (extra_policy.startsWith("=")) {
- overrideAll = true;
- extra_policy = extra_policy.substring(1);
- }
- try {
- // currently you may only specify a file via -Djava.policy
- extra_policy = PropertyExpander.expand(extra_policy);
- File policyFile = new File(extra_policy);
- URL policyURL = new URL
- ("file:" + policyFile.getCanonicalPath());
- if (debug)
- System.out.println("reading "+policyURL.getFile());
- init(policyURL);
- } catch (Exception e) {
- // ignore.
- }
- if (overrideAll) {
- if (debug) {
- System.err.println("overriding other policies!");
- }
- return;
- }
- }
- }
-
- int n = 1;
- boolean loaded_one = false;
- String policy_url;
- // No need to put this into a begin/endPrivileged block, because
- // this is already called from privileged code in Policy.java
- while ((policy_url = Security.getProperty("policy.url."+n)) != null) {
- try {
- policy_url = PropertyExpander.expand(policy_url).replace
- (File.separatorChar, '/');
- if (debug)
- System.out.println("reading "+policy_url);
- init(new URL(policy_url));
- loaded_one = true;
- } catch (Exception e) {
- if (debug) {
- System.out.println("error reading policy "+e);
- e.printStackTrace();
- }
- // ignore that policy
- }
- n++;
- }
-
- if (loaded_one == false) {
- // use static policy if all else fails
- initStaticPolicy();
- }
- }
-
- private void initStaticPolicy() {
- PolicyEntry pe = new PolicyEntry(new CodeSource(null, null));
- pe.add(new PropertyPermission("java.version","read"));
- pe.add(new PropertyPermission("java.vendor","read"));
- pe.add(new PropertyPermission("java.vendor.url","read"));
- pe.add(new PropertyPermission("java.class.version","read"));
- pe.add(new PropertyPermission("os.name","read"));
- pe.add(new PropertyPermission("os.version","read"));
- pe.add(new PropertyPermission("os.arch","read"));
- pe.add(new PropertyPermission("file.separator","read"));
- pe.add(new PropertyPermission("path.separator","read"));
- pe.add(new PropertyPermission("line.separator","read"));
- policyEntries.addElement(pe);
- try {
- String extdir =
- PropertyExpander.expand("file:${java.home}/lib/ext/");
- pe = new PolicyEntry(new CodeSource(new URL(extdir), null));
- pe.add(new java.security.AllPermission());
- } catch (Exception e) {
- // this is bad. What should we do?
- }
- }
-
- /**
- * Reads a policy configuration into the Policy object using a
- * Reader object.
- *
- * @param policyFile the policy Reader object.
- */
- private void init(URL policy) {
- PolicyParser pp = new PolicyParser(expandProperties);
- try {
- InputStreamReader isr
- = new InputStreamReader(policy.openStream());
- pp.read(isr);
- isr.close();
- keyStore = initKeyStore(policy, pp.getKeyStoreUrl());
- Enumeration enum = pp.grantElements();
- while (enum.hasMoreElements()) {
- PolicyParser.GrantEntry ge =
- (PolicyParser.GrantEntry) enum.nextElement();
- addGrantEntry(ge);
- }
- } catch (Exception e) {
- if (debug) {
- System.err.println(
- "java.security.Policy: error parsing policy " + e);
- e.printStackTrace();
- }
- }
- }
-
- /**
- * Given a PermissionEntry, create a codeSource.
- *
- * @return null if signedBy alias is not recognized
- */
- CodeSource getCodeSource(PolicyParser.GrantEntry ge)
- throws java.net.MalformedURLException
- {
-
- PublicKey[] keys = null;
- if (ge.signedBy != null) {
- keys = getPublicKeys(ge.signedBy);
- if (keys == null) {
- // we don't have a key for this alias,
- // just return
- if (debug) {
- System.out.println(" no publickey for alias " +
- ge.signedBy);
- }
- return null;
- }
- }
-
- URL location;
-
- if (ge.codeBase != null)
- location = new URL(ge.codeBase);
- else
- location = null;
-
- return new CodeSource(location, keys);
- }
-
- /**
- * Add one policy entry to the vector.
- */
- private void addGrantEntry(PolicyParser.GrantEntry ge) {
-
- if (debug) {
- System.out.println("");
- System.out.println("Attempting to add policy entry: ");
- System.out.println(" " + ge.signedBy);
- System.out.println(" " + ge.codeBase);
- System.out.println("");
- }
-
- try {
- CodeSource codesource = getCodeSource(ge);
- // skip if signedBy alias was unknown...
- if (codesource == null) return;
-
- PolicyEntry entry = new PolicyEntry(codesource);
-
- Enumeration enum = ge.permissionElements();
- while (enum.hasMoreElements()) {
- PolicyParser.PermissionEntry pe =
- (PolicyParser.PermissionEntry) enum.nextElement();
- try {
- Permission perm = getInstance(pe.permission,
- pe.name,
- pe.action);
- entry.add(perm);
- if (debug) {
- System.out.println(" add perm "+perm);
- }
- } catch (ClassNotFoundException cnfe) {
- // create an UnresolvedPermission object
- if (debug) {
- System.out.println("creating UnresolvedPerm("+
- pe.permission + ", " +
- pe.name + ", " +
- pe.action + ", " +
- pe.signedBy + ")");
- }
-
- PublicKey keys[];
- if (pe.signedBy != null)
- keys = getPublicKeys(pe.signedBy);
- else
- keys = null;
-
- // only add if we had no signer or we had a
- // a signer and found the keys for it.
- if (keys != null || pe.signedBy == null) {
- Permission perm = new UnresolvedPermission(
- pe.permission,
- pe.name,
- pe.action,
- keys);
- entry.add(perm);
- if (debug) {
- System.out.println(" add perm "+perm);
- }
- }
- } catch (java.lang.reflect.InvocationTargetException ite) {
- System.err.println(
- "java.security.Policy: error adding Permission " +
- pe.permission + " "+ ite.getTargetException());
- } catch (Exception e) {
- System.err.println(
- "java.security.Policy: error adding Permission " +
- pe.permission + " "+ e);
- }
- }
- policyEntries.addElement(entry);
- } catch (Exception e) {
- System.err.println(
- "java.security.Policy: error adding Entry " +
- ge + " " +e);
- }
- }
-
- /**
- * Returns a new Permission object of the given Type. The Permission is
- * created by getting the
- * Class object using the <code>Class.forName</code> method, and using
- * the reflection API to invoke the (String name, String actions)
- * constructor on the
- * object.
- *
- * @param type the type of Permission being created.
- * @param name the name of the Permission being created.
- * @param actions the actions of the Permission being created.
- *
- * @exception ClassNotFoundException if the particular Permission
- * class could not be found.
- *
- * @exception IllegalAccessException if the class or initializer is
- * not accessible.
- *
- * @exception InstantiationException if getInstance tries to
- * instantiate an abstract class or an interface, or if the
- * instantiation fails for some other reason.
- *
- * @exception NoSuchMethodException if the (String, String) constructor
- * is not found.
- *
- * @exception InvocationTargetException if the underlying Permission
- * constructor throws an exception.
- *
- */
-
- private static final Permission getInstance(String type,
- String name,
- String actions)
- throws ClassNotFoundException,
- InstantiationException,
- IllegalAccessException,
- NoSuchMethodException,
- InvocationTargetException
- {
- //XXX we might want to keep a hash of created factories...
- Class pc = Class.forName(type);
- Constructor c = pc.getConstructor(PARAMS);
- return (Permission) c.newInstance(new Object[] { name, actions });
- }
-
- /**
- * Fetch all public keys associated with this alias.
- */
- PublicKey[] getPublicKeys(String aliases) {
-
- Vector vkeys = null;
-
- StringTokenizer st = new StringTokenizer(aliases, ",");
- int n = 0;
-
- while (st.hasMoreTokens()) {
- String alias = st.nextToken().trim();
- n++;
- //See if this alias's public key has already been cached
- PublicKey key = (PublicKey) aliasMapping.get(alias);
- if (key == null && keyStore != null) {
- java.security.cert.Certificate cert
- = keyStore.getCertificate(alias);
- if (cert != null) {
- try {
- key = (PublicKey)cert.getPublicKey();
- if (key != null) {
- aliasMapping.put(alias, key);
- publicKeys.addElement(key);
- }
- } catch (Exception e) {
- // ignore it
- }
- }
- }
-
- if (key != null) {
- if (vkeys == null)
- vkeys = new Vector();
- vkeys.addElement(key);
- }
- }
-
- // make sure n == vkeys.size, since we are doing a logical *and*
- if (vkeys != null && n == vkeys.size()) {
- PublicKey[] keys = new PublicKey [vkeys.size()];
- vkeys.copyInto(keys);
- return keys;
- } else {
- return null;
- }
- }
-
- /**
- * Enumerate all the entries in the global policy object.
- * This method is used by policy admin tools. The tools
- * should use the Enumeration methods on the returned object
- * to fetch the elements sequentially.
- */
- private final synchronized Enumeration elements(){
- return policyEntries.elements();
- }
-
- /**
- * Examines the global policy for the specified CodeSource, and
- * creates a Permissions object with
- * the set of permissions for that principal's protection domain.
- *
- * @param CodeSource the codesource associated with the caller.
- * This encapsulates the original location of the code (where the code
- * came from) and the public key(s) of its signer.
- *
- * @return the set of permissions according to the policy.
- */
- public Permissions evaluate(CodeSource codesource) {
-
- if (!initialized) {
- init();
- }
-
- if (debug) {
- System.out.println("Policy.evaluate("+codesource+")");
- }
-
- Permissions perms = new Permissions();
-
- int i,j;
-
- for (i = 0; i < policyEntries.size(); i++) {
-
- PolicyEntry entry = (PolicyEntry)policyEntries.elementAt(i);
-
- if ( entry.match(codesource)) {
- for (j = 0; j < entry.permissions.size(); j++) {
- Permission p = (Permission) entry.permissions.elementAt(j);
- if (debug) {
- System.out.println(" Policy.evaluate adding " + p);
- }
- perms.add(p);
- }
- }
- }
- return perms;
- }
-
- /**
- * Each entry in the policy configuration file is represented by a
- * PolicyEntry object. <p>
- *
- * A PolicyEntry is a (CodeSource,Permission) pair. The
- * CodeSource contains the (URL, PublicKey) that together identify
- * where the Java bytecodes come from and who (if anyone) signed
- * them. The URL could refer to localhost. The URL could also be
- * null, meaning that this policy entry is given to all comers, as
- * long as they match the signer field. The signer could be null,
- * meaning the code is not signed. <p>
- *
- * The Permission contains the (Type, Name, Action) triplet. <p>
- *
- * For now, the Policy object retrieves the public key from the
- * X.509 certificate on disk that corresponds to the signedBy
- * alias specified in the Policy config file. For reasons of
- * efficiency, the Policy object keeps a hashtable of keys already
- * read in. This could be replaced by a secure internal key
- * store.
- *
- * <p>
- * For example, the entry
- * <pre>
- * permission java.io.File "/tmp", "read,write",
- * signedBy "Duke";
- * </pre>
- * is represented internally
- * <pre>
- *
- * FilePermission f = new FilePermission("/tmp", "read,write");
- * PublicKey p = publickeys.get("Duke");
- * URL u = InetAddress.getLocalHost();
- * CodeBase c = new CodeBase( p, u );
- * pe = new PolicyEntry(f, c);
- * </pre>
- *
- * @author Marianne Mueller
- * @author Roland Schemers
- * @version 1.6, 03/04/97
- * @see java.security.CodeSource
- * @see java.security.Policy
- * @see java.security.Permissions
- * @see java.security.ProtectionDomain */
-
- private static class PolicyEntry {
-
- CodeSource codesource;
- Vector permissions;
-
- /**
- * Given a Permission and a CodeSource, create a policy entry.
- *
- * XXX Decide if/how to add validity fields and "purpose" fields to
- * XXX policy entries
- *
- * @param cs the CodeSource, which encapsulates the URL and the public
- * key
- * attributes from the policy config file. Validity checks are
- * performed on the public key before PolicyEntry is called.
- *
- */
- PolicyEntry(CodeSource cs)
- {
- this.codesource = cs;
- this.permissions = new Vector();
- }
-
- /**
- * add a Permission object to this entry.
- */
- void add(Permission p) {
- permissions.addElement(p);
- }
- /**
- * Returns true if this CodeSource matches this entry
- *
- * @param codesource the CodeSource
- */
- boolean match(CodeSource codesource) {
- return matchKey(codesource) && matchURL(codesource);
- }
-
- /**
- * Returns true if this CodeSource matches this entry
- *
- * @param codesource the CodeSource
- */
- boolean matchURL(CodeSource codesource) {
- // match any URL if this URL is null
- return this.codesource.getLocation() == null ||
- this.codesource.matchLocation(codesource);
- }
-
- /**
- * Returns true if all the PublicKeys in the entry are
- * also in the CodeSource's public key array
- *
- * @param entry entry from the policy
- * @param cs from the CodeSource
- */
- boolean matchKey(CodeSource cs)
- {
- PublicKey[] e = codesource.getKeys();
-
- // match any key
- if (e == null)
- return true;
-
- PublicKey[] c = cs.getKeys();
-
- if (c == null)
- return false;
-
- boolean match;
- for (int i=0; i < e.length; i++) {
- match = false;
- for (int j=0; j < c.length; j++) {
- if (e[i].equals(c[j])) {
- match = true;
- break;
- }
- }
- if (!match) return false;
- }
- return true;
- }
-
- /**
- * Return the CodeSource for this policy entry
- */
- CodeSource getCodeSource() {
- return this.codesource;
- }
-
- public String toString(){
- StringBuffer sb = new StringBuffer();
- sb.append("(");
- sb.append(getCodeSource());
- sb.append("\n");
- for (int j = 0; j < permissions.size(); j++) {
- Permission p = (Permission) permissions.elementAt(j);
- sb.append(" ");
- sb.append(p);
- sb.append("\n");
- }
- sb.append(")\n");
- return sb.toString();
- }
-
- }
- }
-