home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / security / PolicyFile.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  23.8 KB  |  808 lines

  1. /*
  2.  * @(#)PolicyFile.java    1.8 98/03/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15.  
  16. package java.security;
  17.  
  18. import java.io.*;
  19. import java.lang.RuntimePermission;
  20. import java.net.MalformedURLException;
  21. import java.net.URL;
  22. import java.util.Enumeration;
  23. import java.util.Hashtable;
  24. import java.util.Vector;
  25. import java.util.StringTokenizer;
  26. import java.util.PropertyPermission;
  27.  
  28. import java.lang.reflect.*;
  29.  
  30. import sun.security.tools.*;
  31. import sun.security.util.PropertyExpander;
  32.  
  33. /**
  34.  * The policy for a Java runtime (specifying 
  35.  * which permissions are available for code from various principals)
  36.  * is represented as one or more separate
  37.  * persistent configurations.  Each configuration may be stored as a
  38.  * flat ASCII file, as a serialized binary file of
  39.  * the Policy class, or as a database. <p>
  40.  * 
  41.  * Each Java runtime may have multiple policy files.
  42.  * The default policy files are configured in the security
  43.  * properties file to be:
  44.  * 
  45.  * <pre>
  46.  *   (<i>java.home</i>)/lib/security/java.policy
  47.  *   (<i>user.home</i>)/.java.policy
  48.  * </pre>
  49.  * 
  50.  * <p>where <i>java.home</i> indicates the JDK installation directory 
  51.  * (determined by the value of the "java.home" system property),
  52.  * and
  53.  * <p>where <i>user.home</i> indicates the user's home directory
  54.  * (determined by the value of the "user.home" system property).
  55.  * 
  56.  * <p>The Java runtime creates one global Policy object, which is used to
  57.  * represent the permissions granted in the static policy configuration 
  58.  * file(s).  It is consulted by
  59.  * a ProtectionDomain when the protection domain initializes its set of
  60.  * permissions. <p>
  61.  * 
  62.  * <p>The Policy object is agnostic in that
  63.  * it is not involved in making policy decisions.  It is merely the
  64.  * Java runtime representation of the persistent policy configuration
  65.  * file(s). <p>
  66.  * 
  67.  * <p>When a protection domain needs to initialize its set of
  68.  * permissions, it executes code such as the following
  69.  * to ask the global Policy object to populate a
  70.  * Permissions object with the appropriate permissions:
  71.  * <pre>
  72.  *  policy = Policy.getPolicy();
  73.  *  Permissions perms = policy.evaluate(MyCodeSource)
  74.  * </pre>
  75.  * 
  76.  * <p>The protection domain passes in a CodeSource
  77.  * object, which encapsulates its codebase (URL) and public key attributes.
  78.  * The Policy object evaluates the global policy in light of who the
  79.  * principal is and returns an appropriate Permissions object. 
  80.  * 
  81.  * @author Roland Schemers
  82.  * @version 1.8, 03/18/98
  83.  * @see java.security.CodeSource
  84.  * @see java.security.Permissions
  85.  * @see java.security.ProtectionDomain 
  86.  */
  87.  
  88. class PolicyFile extends java.security.Policy {
  89.  
  90.     private Vector policyEntries;
  91.     private Hashtable aliasMapping;
  92.     private Vector publicKeys;
  93.     private KeyStore keyStore;
  94.  
  95.     private boolean debug = getDebug();
  96.  
  97.     private boolean initialized = false;
  98.  
  99.     private boolean expandProperties = true;
  100.  
  101.     // for use with the reflection API
  102.  
  103.     private static final Class[] PARAMS = { String.class, String.class};
  104.  
  105.     private static boolean getDebug() {
  106.     try {
  107.         AccessController.beginPrivileged();
  108.         return Boolean.getBoolean("java.security.debug");
  109.     } finally {
  110.         AccessController.endPrivileged();
  111.     }
  112.     }
  113.  
  114.     /** 
  115.      * Creates a Policy object.
  116.      */
  117.     public PolicyFile() {
  118.  
  119.     }
  120.  
  121.     /** 
  122.      * Initializes the Policy object and reads the default policy 
  123.      * configuration file(s) into the Policy object.
  124.      * 
  125.      * The algorithm for locating the policy file(s) and reading their
  126.      * information into the Policy object is:
  127.      * <pre>
  128.      *   loop through the Security Properties named "policy.url.1", 
  129.      *   "policy.url.2", etc, until you don't find one. Each of 
  130.      *   these specify a policy file.
  131.      *   
  132.      *   if none of these could be loaded, use a builtin static policy
  133.      *      equivalent to the default lib/security/java.policy file.
  134.      * 
  135.      *   if the system property "java.policy" is defined (which is the
  136.      *      case when the user uses the -D switch at runtime), and
  137.      *     its use is allowed by the security property file,
  138.      *     also load it.
  139.      * </pre>
  140.      * 
  141.      * Each policy file consists of one or more grant entries, each of
  142.      * which consists of a number of permission entries.
  143.      * <pre>
  144.      *   grant signedBy "<i>alias</i>", codeBase "<i>URL</i>" {
  145.      *     permission <i>Type</i> "<i>name</i>", "<i>action</i>", 
  146.      *         signedBy "<i>alias</i>";
  147.      *     ....
  148.      *     permission <i>Type</i> "<i>name</i>", "<i>action</i>", 
  149.      *         signedBy "<i>alias</i>";
  150.      *   };
  151.      *      
  152.      * </pre>
  153.      * 
  154.      * All non-italicized items above must appear as is (although case 
  155.      * doesn't matter and some are optional, as noted below).
  156.      * Italicized items represent variable values.
  157.      *
  158.      * <p> A grant entry must begin with the word <code>grant</code>.
  159.      * The <code>signedBy</code> and <code>codeBase</code> name/value 
  160.      * pairs are optional.
  161.      * If they are not present, then any signer (including unsigned code)
  162.      * will match, and any codeBase will match.
  163.      *
  164.      * <p> A permission entry must begin with the word <code>permission</code>. 
  165.      * The word <code><i>Type</i></code> in the template above would actually be
  166.      * a specific permission type, such as <code>java.io.FilePermission</code>
  167.      * or <code>java.lang.RuntimePermission</code>.
  168.      * 
  169.      * <p>The "<i>action</i>" is required for
  170.      * many permission types, such as <code>java.io.FilePermission</code>
  171.      * (where it specifies what type of file access is permitted).
  172.      * It is not required for categories such as 
  173.      * <code>java.lang.RuntimePermission</code>
  174.      * where it is not necessary - you either have the 
  175.      * permission specified by the <code>"<i>name</i>"</code> 
  176.      * value following the type name or you don't.
  177.      * 
  178.      * <p>The <code>signedBy</code> name/value pair for a permission entry 
  179.      * is optional. If present, it indicates a signed permission. That is,
  180.      * the permission class itself must be signed by the given alias in
  181.      * order for it to be granted. For example,
  182.      * suppose you have the following grant entry:
  183.      * 
  184.      * <pre>
  185.      *   grant {
  186.      *     permission Foo "foobar", signedBy "FooSoft";
  187.      *   }
  188.      * </pre>
  189.      * 
  190.      * <p>Then this permission of type <i>Foo</i> is granted if the 
  191.      * <code>Foo.class</code> permission has been signed by the 
  192.      * "FooSoft" alias, or if <code>Foo.class</code> is a 
  193.      * system class (i.e., is found on the CLASSPATH).
  194.      * 
  195.      * <p>Items that appear in an entry must appear in the specified order
  196.      * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and 
  197.      * "<i>action</i>"). An entry is terminated with a semicolon.
  198.      * 
  199.      * <p>Case is unimportant for the identifiers (<code>permission</code>, 
  200.      * <code>signedBy</code>, <code>codeBase</code>, etc.) but is 
  201.      * significant for the <i>Type</i>
  202.      * or for any string that is passed in as a value. <p>
  203.      * 
  204.      * <p>An example of two entries in a policy configuration file is
  205.      * <pre>
  206.      *   //  if the code is signed by "Duke", grant it read/write to all 
  207.      *   // files in /tmp.
  208.      *
  209.      *   grant signedBy "Duke" {
  210.      *         permission java.io.FilePermission "/tmp/*", "read,write";
  211.      *   };
  212.      * <p>    
  213.      *   // grant everyone the following permission
  214.      *
  215.      *   grant { 
  216.      *        permission java.util.PropertyPermission "java.vendor";
  217.      *   };
  218.      *  </pre>
  219.      */
  220.     private void init() {
  221.  
  222.     policyEntries = new Vector();
  223.     aliasMapping = new Hashtable();
  224.     publicKeys = new Vector();
  225.     
  226.     try {
  227.         AccessController.beginPrivileged();
  228.         initPolicyFile();
  229.         initialized = true;
  230.     } finally {
  231.         AccessController.endPrivileged();
  232.     }
  233.     }
  234.  
  235.     /**
  236.      * Refreshes the policy object. 
  237.      *
  238.      */
  239.     public void refresh()
  240.     {
  241.     init();
  242.     }
  243.  
  244.     private KeyStore initKeyStore(URL policyUrl, String keyStoreName) {
  245.     if (keyStoreName != null) {
  246.         try {
  247.         /*
  248.          * location of keystore is specified as absolute URL in policy
  249.          * file, or is relative to URL of policy file
  250.          */
  251.         URL keyStoreUrl = null;
  252.         try {
  253.             keyStoreUrl = new URL(keyStoreName);
  254.             // absolute URL
  255.         } catch (java.net.MalformedURLException e) {
  256.             // relative URL
  257.             keyStoreUrl = new URL(policyUrl, keyStoreName);
  258.         }
  259.         InputStream inStream = keyStoreUrl.openStream();
  260.         KeyStore ks = KeyStore.getInstance();
  261.         ks.load(inStream, null);
  262.         inStream.close();
  263.         return ks;
  264.         } catch (Exception e) {
  265.         // ignore, treat it like we have no keystore
  266.         if (debug) {
  267.             e.printStackTrace();
  268.         }
  269.         return null;
  270.         }        
  271.     }
  272.     return null;
  273.     }
  274.  
  275.     private void initPolicyFile() {
  276.  
  277.     // No need to put this into a begin/endPrivileged block, because
  278.     // this is already called from privileged code in Policy.java
  279.     String prop = Security.getProperty("policy.expandProperties");
  280.  
  281.     if (prop != null) expandProperties = prop.equalsIgnoreCase("true");
  282.  
  283.     // No need to put this into a begin/endPrivileged block, because
  284.     // this is already called from privileged code in Policy.java
  285.     String allowSys  = Security.getProperty("policy.allowSystemProperty");
  286.  
  287.     if (allowSys.equalsIgnoreCase("true")) {
  288.         // No need to put this into a begin/endPrivileged block, because
  289.         // this is already called from privileged code in Policy.java
  290.         String extra_policy = System.getProperty("java.policy");
  291.         if (extra_policy != null) {
  292.         boolean overrideAll = false;
  293.         if (extra_policy.startsWith("=")) {
  294.             overrideAll = true;
  295.             extra_policy = extra_policy.substring(1);
  296.         }
  297.         try {
  298.             // currently you may only specify a file via -Djava.policy
  299.             extra_policy = PropertyExpander.expand(extra_policy);
  300.             File policyFile = new File(extra_policy);
  301.             URL policyURL = new URL
  302.                 ("file:" + policyFile.getCanonicalPath());
  303.             if (debug)
  304.             System.out.println("reading "+policyURL.getFile());
  305.             init(policyURL);
  306.         } catch (Exception e) {
  307.             // ignore. 
  308.         }
  309.         if (overrideAll) {
  310.             if (debug) {
  311.             System.err.println("overriding other policies!");
  312.             }
  313.             return;
  314.         }
  315.         }
  316.     }
  317.  
  318.     int n = 1;
  319.     boolean loaded_one = false;
  320.     String policy_url;
  321.     // No need to put this into a begin/endPrivileged block, because
  322.     // this is already called from privileged code in Policy.java
  323.     while ((policy_url = Security.getProperty("policy.url."+n)) != null) {
  324.         try {
  325.         policy_url = PropertyExpander.expand(policy_url).replace
  326.                         (File.separatorChar, '/');
  327.         if (debug)
  328.             System.out.println("reading "+policy_url);
  329.         init(new URL(policy_url));
  330.         loaded_one = true;
  331.         } catch (Exception e) {
  332.         if (debug) {
  333.             System.out.println("error reading policy "+e);
  334.             e.printStackTrace();
  335.         }
  336.         // ignore that policy
  337.         }
  338.         n++;
  339.     }
  340.  
  341.     if (loaded_one == false) {
  342.         // use static policy if all else fails
  343.         initStaticPolicy();
  344.     }
  345.     }
  346.  
  347.     private void initStaticPolicy() {
  348.     PolicyEntry pe = new PolicyEntry(new CodeSource(null, null));
  349.     pe.add(new PropertyPermission("java.version","read"));
  350.     pe.add(new PropertyPermission("java.vendor","read"));
  351.     pe.add(new PropertyPermission("java.vendor.url","read"));
  352.     pe.add(new PropertyPermission("java.class.version","read"));
  353.     pe.add(new PropertyPermission("os.name","read"));
  354.     pe.add(new PropertyPermission("os.version","read"));
  355.     pe.add(new PropertyPermission("os.arch","read"));
  356.     pe.add(new PropertyPermission("file.separator","read"));
  357.     pe.add(new PropertyPermission("path.separator","read"));
  358.     pe.add(new PropertyPermission("line.separator","read"));
  359.     policyEntries.addElement(pe);
  360.     try {
  361.         String extdir = 
  362.         PropertyExpander.expand("file:${java.home}/lib/ext/");
  363.         pe = new PolicyEntry(new CodeSource(new URL(extdir), null));
  364.         pe.add(new java.security.AllPermission());
  365.     } catch (Exception e) {
  366.         // this is bad. What should we do?
  367.     }
  368.     }
  369.  
  370.     /** 
  371.      * Reads a policy configuration into the Policy object using a
  372.      * Reader object.
  373.      * 
  374.      * @param policyFile the policy Reader object.
  375.      */
  376.     private void init(URL policy) {
  377.     PolicyParser pp = new PolicyParser(expandProperties);
  378.     try {
  379.         InputStreamReader isr
  380.         = new InputStreamReader(policy.openStream()); 
  381.         pp.read(isr);
  382.         isr.close();
  383.         keyStore = initKeyStore(policy, pp.getKeyStoreUrl());
  384.         Enumeration enum = pp.grantElements();
  385.         while (enum.hasMoreElements()) {
  386.         PolicyParser.GrantEntry ge =
  387.             (PolicyParser.GrantEntry) enum.nextElement();
  388.         addGrantEntry(ge);
  389.         }
  390.     } catch (Exception e) {
  391.         if (debug) {
  392.         System.err.println(
  393.              "java.security.Policy: error parsing policy " + e);
  394.         e.printStackTrace();
  395.         }
  396.     }
  397.     }
  398.  
  399.     /**
  400.      * Given a PermissionEntry, create a codeSource.
  401.      *
  402.      * @return null if signedBy alias is not recognized
  403.      */
  404.     CodeSource getCodeSource(PolicyParser.GrantEntry ge) 
  405.     throws java.net.MalformedURLException
  406.     {
  407.     
  408.     PublicKey[] keys = null;
  409.     if (ge.signedBy != null) {
  410.         keys = getPublicKeys(ge.signedBy);
  411.         if (keys == null) {
  412.         // we don't have a key for this alias,
  413.         // just return
  414.         if (debug) {
  415.             System.out.println(" no publickey for alias " +
  416.                        ge.signedBy);
  417.         }
  418.         return null;
  419.         }
  420.     }
  421.     
  422.     URL location;
  423.  
  424.     if (ge.codeBase != null)
  425.         location = new URL(ge.codeBase);
  426.     else
  427.         location = null;
  428.     
  429.     return new CodeSource(location, keys);
  430.     }
  431.  
  432.     /**
  433.      * Add one policy entry to the vector. 
  434.      */
  435.     private void addGrantEntry(PolicyParser.GrantEntry ge) {
  436.  
  437.     if (debug) {
  438.         System.out.println("");
  439.         System.out.println("Attempting to add policy entry: ");
  440.         System.out.println("     " + ge.signedBy);
  441.         System.out.println("     " + ge.codeBase);
  442.         System.out.println("");
  443.     }
  444.  
  445.     try {
  446.         CodeSource codesource = getCodeSource(ge);
  447.         // skip if signedBy alias was unknown...
  448.         if (codesource == null) return;
  449.  
  450.         PolicyEntry entry = new PolicyEntry(codesource);
  451.  
  452.         Enumeration enum = ge.permissionElements();
  453.         while (enum.hasMoreElements()) {
  454.         PolicyParser.PermissionEntry pe =
  455.             (PolicyParser.PermissionEntry) enum.nextElement();
  456.         try { 
  457.             Permission perm = getInstance(pe.permission,
  458.                              pe.name,
  459.                              pe.action);
  460.             entry.add(perm);
  461.             if (debug) {
  462.             System.out.println("   add perm "+perm);
  463.             }
  464.         } catch (ClassNotFoundException cnfe) {
  465.             // create an UnresolvedPermission object
  466.             if (debug) {
  467.             System.out.println("creating UnresolvedPerm("+
  468.                        pe.permission + ", " +
  469.                        pe.name + ", " +
  470.                        pe.action + ", " +
  471.                        pe.signedBy + ")");
  472.             }
  473.             
  474.             PublicKey keys[];
  475.             if (pe.signedBy != null) 
  476.             keys = getPublicKeys(pe.signedBy);
  477.             else 
  478.             keys = null;
  479.  
  480.             // only add if we had no signer or we had a
  481.             // a signer and found the keys for it.
  482.             if (keys != null || pe.signedBy == null) {
  483.                 Permission perm = new UnresolvedPermission(
  484.                          pe.permission,
  485.                          pe.name,
  486.                          pe.action,
  487.                          keys);
  488.                 entry.add(perm);
  489.                 if (debug) {
  490.                 System.out.println("   add perm "+perm);
  491.                 }
  492.             }
  493.         } catch (java.lang.reflect.InvocationTargetException ite) {
  494.             System.err.println(
  495.                "java.security.Policy: error adding Permission " +
  496.                    pe.permission + " "+ ite.getTargetException());
  497.         } catch (Exception e) {
  498.             System.err.println(
  499.                "java.security.Policy: error adding Permission " +
  500.                        pe.permission + " "+ e);
  501.         }
  502.         }
  503.         policyEntries.addElement(entry);
  504.     } catch (Exception e) {
  505.         System.err.println(
  506.               "java.security.Policy: error adding Entry " +
  507.               ge + " " +e);
  508.     }
  509.     }
  510.  
  511.     /**
  512.      * Returns a new Permission object of the given Type. The Permission is
  513.      * created by getting the 
  514.      * Class object using the <code>Class.forName</code> method, and using 
  515.      * the reflection API to invoke the (String name, String actions) 
  516.      * constructor on the
  517.      * object.
  518.      *
  519.      * @param type the type of Permission being created.
  520.      * @param name the name of the Permission being created.
  521.      * @param actions the actions of the Permission being created.
  522.      *
  523.      * @exception  ClassNotFoundException  if the particular Permission
  524.      *             class could not be found.
  525.      *
  526.      * @exception  IllegalAccessException  if the class or initializer is
  527.      *               not accessible.
  528.      *
  529.      * @exception  InstantiationException  if getInstance tries to
  530.      *               instantiate an abstract class or an interface, or if the
  531.      *               instantiation fails for some other reason.
  532.      *
  533.      * @exception  NoSuchMethodException if the (String, String) constructor
  534.      *               is not found.
  535.      *
  536.      * @exception  InvocationTargetException if the underlying Permission 
  537.      *               constructor throws an exception.
  538.      *               
  539.      */
  540.  
  541.     private static final Permission getInstance(String type,
  542.                     String name,
  543.                     String actions)
  544.     throws ClassNotFoundException,
  545.            InstantiationException,
  546.            IllegalAccessException,
  547.            NoSuchMethodException,
  548.            InvocationTargetException
  549.     {
  550.     //XXX we might want to keep a hash of created factories...
  551.     Class pc = Class.forName(type);
  552.     Constructor c = pc.getConstructor(PARAMS);
  553.     return (Permission) c.newInstance(new Object[] { name, actions });
  554.     }
  555.  
  556.     /**
  557.      * Fetch all public keys associated with this alias. 
  558.      */
  559.     PublicKey[] getPublicKeys(String aliases) {
  560.  
  561.     Vector vkeys = null;
  562.  
  563.     StringTokenizer st = new StringTokenizer(aliases, ",");
  564.     int n = 0;
  565.  
  566.     while (st.hasMoreTokens()) {
  567.         String alias = st.nextToken().trim();
  568.         n++;
  569.         //See if this alias's public key has already been cached
  570.         PublicKey key = (PublicKey) aliasMapping.get(alias);
  571.         if (key == null && keyStore != null) {
  572.         java.security.cert.Certificate cert 
  573.             = keyStore.getCertificate(alias);
  574.         if (cert != null) {
  575.             try {
  576.             key = (PublicKey)cert.getPublicKey();
  577.             if (key != null) {
  578.                 aliasMapping.put(alias, key);
  579.                 publicKeys.addElement(key);
  580.             }
  581.             } catch (Exception e) {
  582.             // ignore it
  583.             }
  584.         } 
  585.         }
  586.  
  587.         if (key != null) {
  588.         if (vkeys == null)
  589.             vkeys = new Vector();
  590.         vkeys.addElement(key);
  591.         }
  592.     }
  593.  
  594.     // make sure n == vkeys.size, since we are doing a logical *and*
  595.     if (vkeys != null && n == vkeys.size()) {
  596.         PublicKey[] keys = new PublicKey [vkeys.size()];
  597.         vkeys.copyInto(keys);
  598.         return keys;
  599.     } else {
  600.         return null;
  601.     }
  602.     }
  603.  
  604.     /**
  605.      * Enumerate all the entries in the global policy object. 
  606.      * This method is used by policy admin tools.   The tools
  607.      * should use the Enumeration methods on the returned object
  608.      * to fetch the elements sequentially. 
  609.      */
  610.     private final synchronized Enumeration elements(){
  611.     return policyEntries.elements();
  612.     }
  613.  
  614.     /**
  615.      * Examines the global policy for the specified CodeSource, and
  616.      * creates a Permissions object with
  617.      * the set of permissions for that principal's protection domain.
  618.      *
  619.      * @param CodeSource the codesource associated with the caller.
  620.      * This encapsulates the original location of the code (where the code
  621.      * came from) and the public key(s) of its signer.
  622.      *
  623.      * @return the set of permissions according to the policy.  
  624.      */
  625.     public Permissions evaluate(CodeSource codesource) {
  626.  
  627.     if (!initialized) {
  628.         init();
  629.     }
  630.  
  631.     if (debug) {
  632.         System.out.println("Policy.evaluate("+codesource+")");
  633.     }
  634.  
  635.     Permissions perms = new Permissions();
  636.  
  637.     int i,j; 
  638.  
  639.     for (i = 0; i < policyEntries.size(); i++) {
  640.  
  641.         PolicyEntry entry = (PolicyEntry)policyEntries.elementAt(i);
  642.  
  643.         if ( entry.match(codesource)) {
  644.         for (j = 0; j < entry.permissions.size(); j++) {
  645.             Permission p = (Permission) entry.permissions.elementAt(j);
  646.             if (debug) {
  647.             System.out.println("  Policy.evaluate adding " + p);
  648.             }
  649.             perms.add(p);
  650.         }
  651.         }
  652.     }
  653.     return perms;
  654.     }
  655.  
  656.     /**
  657.      * Each entry in the policy configuration file is represented by a
  658.      * PolicyEntry object.  <p>
  659.      *
  660.      * A PolicyEntry is a (CodeSource,Permission) pair.  The
  661.      * CodeSource contains the (URL, PublicKey) that together identify
  662.      * where the Java bytecodes come from and who (if anyone) signed
  663.      * them.  The URL could refer to localhost.  The URL could also be
  664.      * null, meaning that this policy entry is given to all comers, as
  665.      * long as they match the signer field.  The signer could be null,
  666.      * meaning the code is not signed. <p>
  667.      * 
  668.      * The Permission contains the (Type, Name, Action) triplet. <p>
  669.      * 
  670.      * For now, the Policy object retrieves the public key from the
  671.      * X.509 certificate on disk that corresponds to the signedBy
  672.      * alias specified in the Policy config file.  For reasons of
  673.      * efficiency, the Policy object keeps a hashtable of keys already
  674.      * read in.  This could be replaced by a secure internal key
  675.      * store.
  676.      * 
  677.      * <p>
  678.      * For example, the entry
  679.      * <pre>
  680.      *         permission java.io.File "/tmp", "read,write",
  681.      *        signedBy "Duke";    
  682.      * </pre>
  683.      * is represented internally 
  684.      * <pre>
  685.      * 
  686.      * FilePermission f = new FilePermission("/tmp", "read,write");
  687.      * PublicKey p = publickeys.get("Duke");
  688.      * URL u = InetAddress.getLocalHost();
  689.      * CodeBase c = new CodeBase( p, u );
  690.      * pe = new PolicyEntry(f, c);
  691.      * </pre>
  692.      * 
  693.      * @author Marianne Mueller
  694.      * @author Roland Schemers
  695.      * @version 1.6, 03/04/97
  696.      * @see java.security.CodeSource
  697.      * @see java.security.Policy
  698.      * @see java.security.Permissions
  699.      * @see java.security.ProtectionDomain */
  700.  
  701.     private static class PolicyEntry {
  702.  
  703.     CodeSource codesource;
  704.     Vector permissions;
  705.  
  706.     /**
  707.      * Given a Permission and a CodeSource, create a policy entry.
  708.      * 
  709.      * XXX Decide if/how to add validity fields and "purpose" fields to
  710.      * XXX policy entries 
  711.      * 
  712.      * @param cs the CodeSource, which encapsulates the URL and the public
  713.      *        key
  714.      *        attributes from the policy config file.   Validity checks are
  715.      *        performed on the public key before PolicyEntry is called. 
  716.      * 
  717.      */
  718.     PolicyEntry(CodeSource cs)
  719.     {
  720.         this.codesource = cs;
  721.         this.permissions = new Vector();
  722.     }
  723.  
  724.     /**
  725.      * add a Permission object to this entry.
  726.      */
  727.     void add(Permission p) {
  728.         permissions.addElement(p);
  729.     }
  730.     /**
  731.      * Returns true if this CodeSource matches this entry
  732.      * 
  733.      * @param codesource the CodeSource
  734.      */
  735.     boolean match(CodeSource codesource) {
  736.         return matchKey(codesource) && matchURL(codesource);
  737.     }
  738.  
  739.     /**
  740.      * Returns true if this CodeSource matches this entry
  741.      * 
  742.      * @param codesource the CodeSource
  743.      */
  744.     boolean matchURL(CodeSource codesource) {
  745.         // match any URL if this URL is null
  746.         return this.codesource.getLocation() == null ||
  747.            this.codesource.matchLocation(codesource);
  748.     }
  749.  
  750.     /**
  751.      * Returns true if all the PublicKeys in the entry are
  752.      * also in the CodeSource's public key array
  753.      * 
  754.      * @param entry entry from the policy
  755.      * @param cs from the CodeSource
  756.      */
  757.     boolean matchKey(CodeSource cs)
  758.     {
  759.         PublicKey[] e = codesource.getKeys();
  760.         
  761.         // match any key
  762.         if (e == null) 
  763.         return true;
  764.  
  765.         PublicKey[] c = cs.getKeys();
  766.  
  767.         if (c == null)
  768.         return false;
  769.  
  770.         boolean match;
  771.         for (int i=0; i < e.length; i++) {
  772.         match = false;
  773.         for (int j=0; j < c.length; j++) {
  774.             if (e[i].equals(c[j])) {
  775.             match = true;
  776.             break;
  777.             }
  778.         }
  779.         if (!match) return false;
  780.         }
  781.         return true;
  782.     }
  783.  
  784.     /**
  785.      * Return the CodeSource for this policy entry
  786.      */
  787.     CodeSource getCodeSource() {
  788.         return this.codesource;
  789.     }
  790.  
  791.     public String toString(){
  792.         StringBuffer sb = new StringBuffer();
  793.         sb.append("(");
  794.         sb.append(getCodeSource());
  795.         sb.append("\n");
  796.         for (int j = 0; j < permissions.size(); j++) {
  797.         Permission p = (Permission) permissions.elementAt(j);
  798.         sb.append("  ");
  799.         sb.append(p);
  800.         sb.append("\n");
  801.         }
  802.         sb.append(")\n");
  803.         return sb.toString();
  804.     }
  805.  
  806.     }
  807. }
  808.