jdk/src/share/classes/sun/security/provider/AuthPolicyFile.java
changeset 19439 57876ed3c426
child 20754 3d7b2fafc34b
equal deleted inserted replaced
19438:7de6ae3cecad 19439:57876ed3c426
       
     1 /*
       
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.provider;
       
    27 
       
    28 import java.io.*;
       
    29 import java.lang.reflect.*;
       
    30 import java.net.URL;
       
    31 import java.util.*;
       
    32 
       
    33 import java.security.AccessController;
       
    34 import java.security.CodeSource;
       
    35 import java.security.KeyStore;
       
    36 import java.security.KeyStoreException;
       
    37 import java.security.Permission;
       
    38 import java.security.Permissions;
       
    39 import java.security.PermissionCollection;
       
    40 import java.security.Principal;
       
    41 import java.security.PrivilegedAction;
       
    42 import java.security.UnresolvedPermission;
       
    43 import java.security.Security;
       
    44 import java.security.cert.Certificate;
       
    45 import java.security.cert.X509Certificate;
       
    46 
       
    47 import javax.security.auth.Subject;
       
    48 import javax.security.auth.PrivateCredentialPermission;
       
    49 
       
    50 import sun.security.provider.PolicyParser.GrantEntry;
       
    51 import sun.security.provider.PolicyParser.PermissionEntry;
       
    52 import sun.security.provider.PolicyParser.PrincipalEntry;
       
    53 import sun.security.util.Debug;
       
    54 import sun.security.util.PolicyUtil;
       
    55 import sun.security.util.PropertyExpander;
       
    56 
       
    57 /**
       
    58  * See {@code com.sun.security.auth.PolicyFile} for the class description.
       
    59  * This class is necessary in order to support a default
       
    60  * {@code javax.security.auth.Policy} implementation on the compact1 and
       
    61  * compact2 profiles.
       
    62  *
       
    63  * @deprecated As of JDK 1.4, replaced by
       
    64  *             {@code sun.security.provider.PolicyFile}.
       
    65  *             This class is entirely deprecated.
       
    66  */
       
    67 @Deprecated
       
    68 public class AuthPolicyFile extends javax.security.auth.Policy {
       
    69 
       
    70     static final ResourceBundle rb =
       
    71         AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
       
    72             @Override public ResourceBundle run() {
       
    73                 return (ResourceBundle.getBundle
       
    74                         ("sun.security.util.AuthResources"));
       
    75             }
       
    76         });
       
    77 
       
    78     private static final Debug debug = Debug.getInstance("policy",
       
    79                                                          "\t[Auth Policy]");
       
    80 
       
    81     private static final String AUTH_POLICY = "java.security.auth.policy";
       
    82     private static final String SECURITY_MANAGER = "java.security.manager";
       
    83     private static final String AUTH_POLICY_URL = "auth.policy.url.";
       
    84 
       
    85     private Vector<PolicyEntry> policyEntries;
       
    86     private Hashtable<Object, Object> aliasMapping;
       
    87 
       
    88     private boolean initialized = false;
       
    89 
       
    90     private boolean expandProperties = true;
       
    91     private boolean ignoreIdentityScope = true;
       
    92 
       
    93     // for use with the reflection API
       
    94     private static final Class[] PARAMS = { String.class, String.class};
       
    95 
       
    96     /**
       
    97      * Initializes the Policy object and reads the default policy
       
    98      * configuration file(s) into the Policy object.
       
    99      */
       
   100     public AuthPolicyFile() {
       
   101         // initialize Policy if either the AUTH_POLICY or
       
   102         // SECURITY_MANAGER properties are set
       
   103         String prop = System.getProperty(AUTH_POLICY);
       
   104 
       
   105         if (prop == null) {
       
   106             prop = System.getProperty(SECURITY_MANAGER);
       
   107         }
       
   108         if (prop != null) {
       
   109             init();
       
   110         }
       
   111     }
       
   112 
       
   113     private synchronized void init() {
       
   114         if (initialized) {
       
   115             return;
       
   116         }
       
   117 
       
   118         policyEntries = new Vector<PolicyEntry>();
       
   119         aliasMapping = new Hashtable<Object, Object>(11);
       
   120 
       
   121         initPolicyFile();
       
   122         initialized = true;
       
   123     }
       
   124 
       
   125     @Override
       
   126     public synchronized void refresh() {
       
   127 
       
   128         java.lang.SecurityManager sm = System.getSecurityManager();
       
   129         if (sm != null) {
       
   130             sm.checkPermission(new javax.security.auth.AuthPermission
       
   131                                 ("refreshPolicy"));
       
   132         }
       
   133 
       
   134         // XXX
       
   135         //
       
   136         // 1)   if code instantiates PolicyFile directly, then it will need
       
   137         //      all the permissions required for the PolicyFile initialization
       
   138         // 2)   if code calls Policy.getPolicy, then it simply needs
       
   139         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
       
   140         //      implementation instantiates PolicyFile in a doPrivileged block
       
   141         // 3)   if after instantiating a Policy (either via #1 or #2),
       
   142         //      code calls refresh, it simply needs
       
   143         //      AuthPermission(refreshPolicy).  then PolicyFile wraps
       
   144         //      the refresh in a doPrivileged block.
       
   145         initialized = false;
       
   146         AccessController.doPrivileged(new PrivilegedAction<Void>() {
       
   147             @Override public Void run() {
       
   148                 init();
       
   149                 return null;
       
   150             }
       
   151         });
       
   152     }
       
   153 
       
   154     private KeyStore initKeyStore(URL policyUrl, String keyStoreName,
       
   155                                   String keyStoreType) {
       
   156         if (keyStoreName != null) {
       
   157             try {
       
   158                 /*
       
   159                  * location of keystore is specified as absolute URL in policy
       
   160                  * file, or is relative to URL of policy file
       
   161                  */
       
   162                 URL keyStoreUrl = null;
       
   163                 try {
       
   164                     keyStoreUrl = new URL(keyStoreName);
       
   165                     // absolute URL
       
   166                 } catch (java.net.MalformedURLException e) {
       
   167                     // relative URL
       
   168                     keyStoreUrl = new URL(policyUrl, keyStoreName);
       
   169                 }
       
   170 
       
   171                 if (debug != null) {
       
   172                     debug.println("reading keystore"+keyStoreUrl);
       
   173                 }
       
   174 
       
   175                 InputStream inStream = new BufferedInputStream(
       
   176                     PolicyUtil.getInputStream(keyStoreUrl));
       
   177 
       
   178                 KeyStore ks;
       
   179                 if (keyStoreType != null)
       
   180                     ks = KeyStore.getInstance(keyStoreType);
       
   181                 else
       
   182                     ks = KeyStore.getInstance(KeyStore.getDefaultType());
       
   183                 ks.load(inStream, null);
       
   184                 inStream.close();
       
   185                 return ks;
       
   186             } catch (Exception e) {
       
   187                 // ignore, treat it like we have no keystore
       
   188                 if (debug != null) {
       
   189                     e.printStackTrace();
       
   190                 }
       
   191                 return null;
       
   192             }
       
   193         }
       
   194         return null;
       
   195     }
       
   196 
       
   197     private void initPolicyFile() {
       
   198 
       
   199         String prop = Security.getProperty("policy.expandProperties");
       
   200         if (prop != null) {
       
   201             expandProperties = prop.equalsIgnoreCase("true");
       
   202         }
       
   203 
       
   204         String iscp = Security.getProperty("policy.ignoreIdentityScope");
       
   205         if (iscp != null) {
       
   206             ignoreIdentityScope = iscp.equalsIgnoreCase("true");
       
   207         }
       
   208 
       
   209         String allowSys = Security.getProperty("policy.allowSystemProperty");
       
   210         if (allowSys != null && allowSys.equalsIgnoreCase("true")) {
       
   211             String extra_policy = System.getProperty(AUTH_POLICY);
       
   212             if (extra_policy != null) {
       
   213                 boolean overrideAll = false;
       
   214                 if (extra_policy.startsWith("=")) {
       
   215                     overrideAll = true;
       
   216                     extra_policy = extra_policy.substring(1);
       
   217                 }
       
   218                 try {
       
   219                     extra_policy = PropertyExpander.expand(extra_policy);
       
   220                     URL policyURL;
       
   221                     File policyFile = new File(extra_policy);
       
   222                     if (policyFile.exists()) {
       
   223                         policyURL =
       
   224                             new URL("file:" + policyFile.getCanonicalPath());
       
   225                     } else {
       
   226                         policyURL = new URL(extra_policy);
       
   227                     }
       
   228                     if (debug != null) {
       
   229                         debug.println("reading " + policyURL);
       
   230                     }
       
   231                     init(policyURL);
       
   232                 } catch (Exception e) {
       
   233                     // ignore.
       
   234                     if (debug != null) {
       
   235                         debug.println("caught exception: " + e);
       
   236                     }
       
   237 
       
   238                 }
       
   239                 if (overrideAll) {
       
   240                     if (debug != null) {
       
   241                         debug.println("overriding other policies!");
       
   242                     }
       
   243                     return;
       
   244                 }
       
   245             }
       
   246         }
       
   247 
       
   248         int n = 1;
       
   249         boolean loaded_one = false;
       
   250         String policy_url;
       
   251 
       
   252         while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) {
       
   253             try {
       
   254                 policy_url = PropertyExpander.expand(policy_url).replace
       
   255                                                 (File.separatorChar, '/');
       
   256                 if (debug != null) {
       
   257                     debug.println("reading " + policy_url);
       
   258                 }
       
   259                 init(new URL(policy_url));
       
   260                 loaded_one = true;
       
   261             } catch (Exception e) {
       
   262                 if (debug != null) {
       
   263                     debug.println("error reading policy " + e);
       
   264                     e.printStackTrace();
       
   265                 }
       
   266                 // ignore that policy
       
   267             }
       
   268             n++;
       
   269         }
       
   270 
       
   271         if (loaded_one == false) {
       
   272             // do not load a static policy
       
   273         }
       
   274     }
       
   275 
       
   276     /**
       
   277      * Checks public key. If it is marked as trusted in
       
   278      * the identity database, add it to the policy
       
   279      * with the AllPermission.
       
   280      */
       
   281     private boolean checkForTrustedIdentity(final Certificate cert) {
       
   282         return false;
       
   283     }
       
   284 
       
   285     /**
       
   286      * Reads a policy configuration into the Policy object using a
       
   287      * Reader object.
       
   288      *
       
   289      * @param policyFile the policy Reader object.
       
   290      */
       
   291     private void init(URL policy) {
       
   292         PolicyParser pp = new PolicyParser(expandProperties);
       
   293         try (InputStreamReader isr
       
   294                 = new InputStreamReader(PolicyUtil.getInputStream(policy))) {
       
   295             pp.read(isr);
       
   296             KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(),
       
   297                                              pp.getKeyStoreType());
       
   298             Enumeration<GrantEntry> enum_ = pp.grantElements();
       
   299             while (enum_.hasMoreElements()) {
       
   300                 GrantEntry ge = enum_.nextElement();
       
   301                 addGrantEntry(ge, keyStore);
       
   302             }
       
   303         } catch (PolicyParser.ParsingException pe) {
       
   304             System.err.println(AUTH_POLICY +
       
   305                                rb.getString(".error.parsing.") + policy);
       
   306             System.err.println(AUTH_POLICY + rb.getString("COLON") +
       
   307                                pe.getMessage());
       
   308             if (debug != null) {
       
   309                 pe.printStackTrace();
       
   310             }
       
   311         } catch (Exception e) {
       
   312             if (debug != null) {
       
   313                 debug.println("error parsing " + policy);
       
   314                 debug.println(e.toString());
       
   315                 e.printStackTrace();
       
   316             }
       
   317         }
       
   318     }
       
   319 
       
   320     /**
       
   321      * Given a PermissionEntry, create a codeSource.
       
   322      *
       
   323      * @return null if signedBy alias is not recognized
       
   324      */
       
   325     CodeSource getCodeSource(GrantEntry ge, KeyStore keyStore)
       
   326             throws java.net.MalformedURLException
       
   327     {
       
   328         Certificate[] certs = null;
       
   329         if (ge.signedBy != null) {
       
   330             certs = getCertificates(keyStore, ge.signedBy);
       
   331             if (certs == null) {
       
   332                 // we don't have a key for this alias,
       
   333                 // just return
       
   334                 if (debug != null) {
       
   335                     debug.println(" no certs for alias " +
       
   336                                        ge.signedBy + ", ignoring.");
       
   337                 }
       
   338                 return null;
       
   339             }
       
   340         }
       
   341 
       
   342         URL location;
       
   343         if (ge.codeBase != null) {
       
   344             location = new URL(ge.codeBase);
       
   345         } else {
       
   346             location = null;
       
   347         }
       
   348 
       
   349         if (ge.principals == null || ge.principals.size() == 0) {
       
   350             return (canonicalizeCodebase
       
   351                         (new CodeSource(location, certs),
       
   352                         false));
       
   353         } else {
       
   354             return (canonicalizeCodebase
       
   355                 (new SubjectCodeSource(null, ge.principals, location, certs),
       
   356                 false));
       
   357         }
       
   358     }
       
   359 
       
   360     /**
       
   361      * Add one policy entry to the vector.
       
   362      */
       
   363     private void addGrantEntry(GrantEntry ge, KeyStore keyStore) {
       
   364 
       
   365         if (debug != null) {
       
   366             debug.println("Adding policy entry: ");
       
   367             debug.println("  signedBy " + ge.signedBy);
       
   368             debug.println("  codeBase " + ge.codeBase);
       
   369             if (ge.principals != null) {
       
   370                 for (PrincipalEntry pppe : ge.principals) {
       
   371                     debug.println("  " + pppe.getPrincipalClass() +
       
   372                                         " " + pppe.getPrincipalName());
       
   373                 }
       
   374             }
       
   375             debug.println();
       
   376         }
       
   377 
       
   378         try {
       
   379             CodeSource codesource = getCodeSource(ge, keyStore);
       
   380             // skip if signedBy alias was unknown...
       
   381             if (codesource == null) return;
       
   382 
       
   383             PolicyEntry entry = new PolicyEntry(codesource);
       
   384             Enumeration<PermissionEntry> enum_ = ge.permissionElements();
       
   385             while (enum_.hasMoreElements()) {
       
   386                 PermissionEntry pe = enum_.nextElement();
       
   387                 try {
       
   388                     // XXX special case PrivateCredentialPermission-SELF
       
   389                     Permission perm;
       
   390                     if (pe.permission.equals
       
   391                         ("javax.security.auth.PrivateCredentialPermission") &&
       
   392                         pe.name.endsWith(" self")) {
       
   393                         perm = getInstance(pe.permission,
       
   394                                          pe.name + " \"self\"",
       
   395                                          pe.action);
       
   396                     } else {
       
   397                         perm = getInstance(pe.permission,
       
   398                                          pe.name,
       
   399                                          pe.action);
       
   400                     }
       
   401                     entry.add(perm);
       
   402                     if (debug != null) {
       
   403                         debug.println("  "+perm);
       
   404                     }
       
   405                 } catch (ClassNotFoundException cnfe) {
       
   406                     Certificate certs[];
       
   407                     if (pe.signedBy != null) {
       
   408                         certs = getCertificates(keyStore, pe.signedBy);
       
   409                     } else {
       
   410                         certs = null;
       
   411                     }
       
   412 
       
   413                     // only add if we had no signer or we had a
       
   414                     // a signer and found the keys for it.
       
   415                     if (certs != null || pe.signedBy == null) {
       
   416                             Permission perm = new UnresolvedPermission(
       
   417                                              pe.permission,
       
   418                                              pe.name,
       
   419                                              pe.action,
       
   420                                              certs);
       
   421                             entry.add(perm);
       
   422                             if (debug != null) {
       
   423                                 debug.println("  "+perm);
       
   424                             }
       
   425                     }
       
   426                 } catch (java.lang.reflect.InvocationTargetException ite) {
       
   427                     System.err.println
       
   428                         (AUTH_POLICY +
       
   429                         rb.getString(".error.adding.Permission.") +
       
   430                         pe.permission +
       
   431                         rb.getString("SPACE") +
       
   432                         ite.getTargetException());
       
   433                 } catch (Exception e) {
       
   434                     System.err.println
       
   435                         (AUTH_POLICY +
       
   436                         rb.getString(".error.adding.Permission.") +
       
   437                         pe.permission +
       
   438                         rb.getString("SPACE") +
       
   439                         e);
       
   440                 }
       
   441             }
       
   442             policyEntries.addElement(entry);
       
   443         } catch (Exception e) {
       
   444             System.err.println
       
   445                 (AUTH_POLICY +
       
   446                 rb.getString(".error.adding.Entry.") +
       
   447                 ge +
       
   448                 rb.getString("SPACE") +
       
   449                 e);
       
   450         }
       
   451 
       
   452         if (debug != null) {
       
   453             debug.println();
       
   454         }
       
   455     }
       
   456 
       
   457     /**
       
   458      * Returns a new Permission object of the given Type. The Permission is
       
   459      * created by getting the
       
   460      * Class object using the <code>Class.forName</code> method, and using
       
   461      * the reflection API to invoke the (String name, String actions)
       
   462      * constructor on the
       
   463      * object.
       
   464      *
       
   465      * @param type the type of Permission being created.
       
   466      * @param name the name of the Permission being created.
       
   467      * @param actions the actions of the Permission being created.
       
   468      *
       
   469      * @exception  ClassNotFoundException  if the particular Permission
       
   470      *             class could not be found.
       
   471      *
       
   472      * @exception  IllegalAccessException  if the class or initializer is
       
   473      *               not accessible.
       
   474      *
       
   475      * @exception  InstantiationException  if getInstance tries to
       
   476      *               instantiate an abstract class or an interface, or if the
       
   477      *               instantiation fails for some other reason.
       
   478      *
       
   479      * @exception  NoSuchMethodException if the (String, String) constructor
       
   480      *               is not found.
       
   481      *
       
   482      * @exception  InvocationTargetException if the underlying Permission
       
   483      *               constructor throws an exception.
       
   484      *
       
   485      */
       
   486     private static final Permission getInstance(String type,
       
   487                                     String name,
       
   488                                     String actions)
       
   489         throws ClassNotFoundException,
       
   490                InstantiationException,
       
   491                IllegalAccessException,
       
   492                NoSuchMethodException,
       
   493                InvocationTargetException
       
   494     {
       
   495         //XXX we might want to keep a hash of created factories...
       
   496         Class<?> pc = Class.forName(type);
       
   497         Constructor<?> c = pc.getConstructor(PARAMS);
       
   498         return (Permission) c.newInstance(new Object[] { name, actions });
       
   499     }
       
   500 
       
   501     /**
       
   502      * Fetch all certs associated with this alias.
       
   503      */
       
   504     Certificate[] getCertificates(KeyStore keyStore, String aliases) {
       
   505 
       
   506         Vector<Certificate> vcerts = null;
       
   507 
       
   508         StringTokenizer st = new StringTokenizer(aliases, ",");
       
   509         int n = 0;
       
   510 
       
   511         while (st.hasMoreTokens()) {
       
   512             String alias = st.nextToken().trim();
       
   513             n++;
       
   514             Certificate cert = null;
       
   515             // See if this alias's cert has already been cached
       
   516             cert = (Certificate) aliasMapping.get(alias);
       
   517             if (cert == null && keyStore != null) {
       
   518 
       
   519                 try {
       
   520                     cert = keyStore.getCertificate(alias);
       
   521                 } catch (KeyStoreException kse) {
       
   522                     // never happens, because keystore has already been loaded
       
   523                     // when we call this
       
   524                 }
       
   525                 if (cert != null) {
       
   526                     aliasMapping.put(alias, cert);
       
   527                     aliasMapping.put(cert, alias);
       
   528                 }
       
   529             }
       
   530 
       
   531             if (cert != null) {
       
   532                 if (vcerts == null) {
       
   533                     vcerts = new Vector<Certificate>();
       
   534                 }
       
   535                 vcerts.addElement(cert);
       
   536             }
       
   537         }
       
   538 
       
   539         // make sure n == vcerts.size, since we are doing a logical *and*
       
   540         if (vcerts != null && n == vcerts.size()) {
       
   541             Certificate[] certs = new Certificate[vcerts.size()];
       
   542             vcerts.copyInto(certs);
       
   543             return certs;
       
   544         } else {
       
   545             return null;
       
   546         }
       
   547     }
       
   548 
       
   549     /**
       
   550      * Enumerate all the entries in the global policy object.
       
   551      * This method is used by policy admin tools.   The tools
       
   552      * should use the Enumeration methods on the returned object
       
   553      * to fetch the elements sequentially.
       
   554      */
       
   555     private final synchronized Enumeration<PolicyEntry> elements() {
       
   556         return policyEntries.elements();
       
   557     }
       
   558 
       
   559     @Override
       
   560     public PermissionCollection getPermissions(final Subject subject,
       
   561                                                final CodeSource codesource) {
       
   562 
       
   563         // 1)   if code instantiates PolicyFile directly, then it will need
       
   564         //      all the permissions required for the PolicyFile initialization
       
   565         // 2)   if code calls Policy.getPolicy, then it simply needs
       
   566         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
       
   567         //      implementation instantiates PolicyFile in a doPrivileged block
       
   568         // 3)   if after instantiating a Policy (either via #1 or #2),
       
   569         //      code calls getPermissions, PolicyFile wraps the call
       
   570         //      in a doPrivileged block.
       
   571         return AccessController.doPrivileged
       
   572             (new PrivilegedAction<PermissionCollection>() {
       
   573             @Override public PermissionCollection run() {
       
   574                 SubjectCodeSource scs = new SubjectCodeSource(
       
   575                     subject, null,
       
   576                     codesource == null ? null : codesource.getLocation(),
       
   577                     codesource == null ? null : codesource.getCertificates());
       
   578                 if (initialized) {
       
   579                     return getPermissions(new Permissions(), scs);
       
   580                 } else {
       
   581                     return new PolicyPermissions(AuthPolicyFile.this, scs);
       
   582                 }
       
   583             }
       
   584         });
       
   585     }
       
   586 
       
   587     /**
       
   588      * Examines the global policy for the specified CodeSource, and
       
   589      * creates a PermissionCollection object with
       
   590      * the set of permissions for that principal's protection domain.
       
   591      *
       
   592      * @param CodeSource the codesource associated with the caller.
       
   593      * This encapsulates the original location of the code (where the code
       
   594      * came from) and the public key(s) of its signer.
       
   595      *
       
   596      * @return the set of permissions according to the policy.
       
   597      */
       
   598     PermissionCollection getPermissions(CodeSource codesource) {
       
   599 
       
   600         if (initialized) {
       
   601             return getPermissions(new Permissions(), codesource);
       
   602         } else {
       
   603             return new PolicyPermissions(this, codesource);
       
   604         }
       
   605     }
       
   606 
       
   607     /**
       
   608      * Examines the global policy for the specified CodeSource, and
       
   609      * creates a PermissionCollection object with
       
   610      * the set of permissions for that principal's protection domain.
       
   611      *
       
   612      * @param permissions the permissions to populate
       
   613      * @param codesource the codesource associated with the caller.
       
   614      * This encapsulates the original location of the code (where the code
       
   615      * came from) and the public key(s) of its signer.
       
   616      *
       
   617      * @return the set of permissions according to the policy.
       
   618      */
       
   619     Permissions getPermissions(final Permissions perms,
       
   620                                final CodeSource cs)
       
   621     {
       
   622         if (!initialized) {
       
   623             init();
       
   624         }
       
   625 
       
   626         final CodeSource codesource[] = {null};
       
   627 
       
   628         codesource[0] = canonicalizeCodebase(cs, true);
       
   629 
       
   630         if (debug != null) {
       
   631             debug.println("evaluate(" + codesource[0] + ")\n");
       
   632         }
       
   633 
       
   634         // needs to be in a begin/endPrivileged block because
       
   635         // codesource.implies calls URL.equals which does an
       
   636         // InetAddress lookup
       
   637 
       
   638         for (int i = 0; i < policyEntries.size(); i++) {
       
   639 
       
   640            PolicyEntry entry = policyEntries.elementAt(i);
       
   641 
       
   642            if (debug != null) {
       
   643                 debug.println("PolicyFile CodeSource implies: " +
       
   644                               entry.codesource.toString() + "\n\n" +
       
   645                               "\t" + codesource[0].toString() + "\n\n");
       
   646            }
       
   647 
       
   648            if (entry.codesource.implies(codesource[0])) {
       
   649                for (int j = 0; j < entry.permissions.size(); j++) {
       
   650                     Permission p = entry.permissions.elementAt(j);
       
   651                     if (debug != null) {
       
   652                         debug.println("  granting " + p);
       
   653                     }
       
   654                     if (!addSelfPermissions(p, entry.codesource,
       
   655                                             codesource[0], perms)) {
       
   656                         // we could check for duplicates
       
   657                         // before adding new permissions,
       
   658                         // but the SubjectDomainCombiner
       
   659                         // already checks for duplicates later
       
   660                         perms.add(p);
       
   661                     }
       
   662                 }
       
   663             }
       
   664         }
       
   665 
       
   666         // now see if any of the keys are trusted ids.
       
   667 
       
   668         if (!ignoreIdentityScope) {
       
   669             Certificate certs[] = codesource[0].getCertificates();
       
   670             if (certs != null) {
       
   671                 for (int k=0; k < certs.length; k++) {
       
   672                     if (aliasMapping.get(certs[k]) == null &&
       
   673                         checkForTrustedIdentity(certs[k])) {
       
   674                         // checkForTrustedIdentity added it
       
   675                         // to the policy for us. next time
       
   676                         // around we'll find it. This time
       
   677                         // around we need to add it.
       
   678                         perms.add(new java.security.AllPermission());
       
   679                     }
       
   680                 }
       
   681             }
       
   682         }
       
   683         return perms;
       
   684     }
       
   685 
       
   686     /**
       
   687      * Returns true if 'Self' permissions were added to the provided
       
   688      * 'perms', and false otherwise.
       
   689      *
       
   690      * <p>
       
   691      *
       
   692      * @param p check to see if this Permission is a "SELF"
       
   693      *                  PrivateCredentialPermission. <p>
       
   694      *
       
   695      * @param entryCs the codesource for the Policy entry.
       
   696      *
       
   697      * @param accCs the codesource for from the current AccessControlContext.
       
   698      *
       
   699      * @param perms the PermissionCollection where the individual
       
   700      *                  PrivateCredentialPermissions will be added.
       
   701      */
       
   702     private boolean addSelfPermissions(final Permission p,
       
   703                                        CodeSource entryCs,
       
   704                                        CodeSource accCs,
       
   705                                        Permissions perms) {
       
   706 
       
   707         if (!(p instanceof PrivateCredentialPermission)) {
       
   708             return false;
       
   709         }
       
   710 
       
   711         if (!(entryCs instanceof SubjectCodeSource)) {
       
   712             return false;
       
   713         }
       
   714 
       
   715         PrivateCredentialPermission pcp = (PrivateCredentialPermission)p;
       
   716         SubjectCodeSource scs = (SubjectCodeSource)entryCs;
       
   717 
       
   718         // see if it is a SELF permission
       
   719         String[][] pPrincipals = pcp.getPrincipals();
       
   720         if (pPrincipals.length <= 0 ||
       
   721             !pPrincipals[0][0].equalsIgnoreCase("self") ||
       
   722             !pPrincipals[0][1].equalsIgnoreCase("self")) {
       
   723 
       
   724             // regular PrivateCredentialPermission
       
   725             return false;
       
   726         } else {
       
   727 
       
   728             // granted a SELF permission - create a
       
   729             // PrivateCredentialPermission for each
       
   730             // of the Policy entry's CodeSource Principals
       
   731 
       
   732             if (scs.getPrincipals() == null) {
       
   733                 // XXX SubjectCodeSource has no Subject???
       
   734                 return true;
       
   735             }
       
   736 
       
   737             for (PrincipalEntry principal : scs.getPrincipals()) {
       
   738 
       
   739                 //      if the Policy entry's Principal does not contain a
       
   740                 //              WILDCARD for the Principal name, then a
       
   741                 //              new PrivateCredentialPermission is created
       
   742                 //              for the Principal listed in the Policy entry.
       
   743                 //      if the Policy entry's Principal contains a WILDCARD
       
   744                 //              for the Principal name, then a new
       
   745                 //              PrivateCredentialPermission is created
       
   746                 //              for each Principal associated with the Subject
       
   747                 //              in the current ACC.
       
   748 
       
   749                 String[][] principalInfo = getPrincipalInfo(principal, accCs);
       
   750 
       
   751                 for (int i = 0; i < principalInfo.length; i++) {
       
   752 
       
   753                     // here's the new PrivateCredentialPermission
       
   754 
       
   755                     PrivateCredentialPermission newPcp =
       
   756                         new PrivateCredentialPermission
       
   757                                 (pcp.getCredentialClass() +
       
   758                                         " " +
       
   759                                         principalInfo[i][0] +
       
   760                                         " " +
       
   761                                         "\"" + principalInfo[i][1] + "\"",
       
   762                                 "read");
       
   763 
       
   764                     if (debug != null) {
       
   765                         debug.println("adding SELF permission: " +
       
   766                                         newPcp.toString());
       
   767                     }
       
   768 
       
   769                     perms.add(newPcp);
       
   770                 }
       
   771             }
       
   772         }
       
   773         return true;
       
   774     }
       
   775 
       
   776     /**
       
   777      * return the principal class/name pair in the 2D array.
       
   778      * array[x][y]:     x corresponds to the array length.
       
   779      *                  if (y == 0), it's the principal class.
       
   780      *                  if (y == 1), it's the principal name.
       
   781      */
       
   782     private String[][] getPrincipalInfo(PrincipalEntry principal,
       
   783                                         final CodeSource accCs) {
       
   784 
       
   785         // there are 3 possibilities:
       
   786         // 1) the entry's Principal class and name are not wildcarded
       
   787         // 2) the entry's Principal name is wildcarded only
       
   788         // 3) the entry's Principal class and name are wildcarded
       
   789 
       
   790         if (!principal.getPrincipalClass().equals
       
   791                 (PrincipalEntry.WILDCARD_CLASS) &&
       
   792             !principal.getPrincipalName().equals
       
   793                 (PrincipalEntry.WILDCARD_NAME)) {
       
   794 
       
   795             // build a PrivateCredentialPermission for the principal
       
   796             // from the Policy entry
       
   797             String[][] info = new String[1][2];
       
   798             info[0][0] = principal.getPrincipalClass();
       
   799             info[0][1] = principal.getPrincipalName();
       
   800             return info;
       
   801 
       
   802         } else if (!principal.getPrincipalClass().equals
       
   803                 (PrincipalEntry.WILDCARD_CLASS) &&
       
   804             principal.getPrincipalName().equals
       
   805                 (PrincipalEntry.WILDCARD_NAME)) {
       
   806 
       
   807             // build a PrivateCredentialPermission for all
       
   808             // the Subject's principals that are instances of principalClass
       
   809 
       
   810             // the accCs is guaranteed to be a SubjectCodeSource
       
   811             // because the earlier CodeSource.implies succeeded
       
   812             SubjectCodeSource scs = (SubjectCodeSource)accCs;
       
   813 
       
   814             Set<? extends Principal> principalSet = null;
       
   815             try {
       
   816                 // principal.principalClass should extend Principal
       
   817                 // If it doesn't, we should stop here with a ClassCastException.
       
   818                 @SuppressWarnings("unchecked")
       
   819                 Class<? extends Principal> pClass = (Class<? extends Principal>)
       
   820                         Class.forName(principal.getPrincipalClass(), false,
       
   821                                       ClassLoader.getSystemClassLoader());
       
   822                 principalSet = scs.getSubject().getPrincipals(pClass);
       
   823             } catch (Exception e) {
       
   824                 if (debug != null) {
       
   825                     debug.println("problem finding Principal Class " +
       
   826                                   "when expanding SELF permission: " +
       
   827                                   e.toString());
       
   828                 }
       
   829             }
       
   830 
       
   831             if (principalSet == null) {
       
   832                 // error
       
   833                 return new String[0][0];
       
   834             }
       
   835 
       
   836             String[][] info = new String[principalSet.size()][2];
       
   837 
       
   838             int i = 0;
       
   839             for (Principal p : principalSet) {
       
   840                 info[i][0] = p.getClass().getName();
       
   841                 info[i][1] = p.getName();
       
   842                 i++;
       
   843             }
       
   844             return info;
       
   845 
       
   846         } else {
       
   847 
       
   848             // build a PrivateCredentialPermission for every
       
   849             // one of the current Subject's principals
       
   850 
       
   851             // the accCs is guaranteed to be a SubjectCodeSource
       
   852             // because the earlier CodeSource.implies succeeded
       
   853             SubjectCodeSource scs = (SubjectCodeSource)accCs;
       
   854             Set<Principal> principalSet = scs.getSubject().getPrincipals();
       
   855 
       
   856             String[][] info = new String[principalSet.size()][2];
       
   857 
       
   858             int i = 0;
       
   859             for (Principal p : principalSet) {
       
   860                 info[i][0] = p.getClass().getName();
       
   861                 info[i][1] = p.getName();
       
   862                 i++;
       
   863             }
       
   864             return info;
       
   865         }
       
   866     }
       
   867 
       
   868     /*
       
   869      * Returns the signer certificates from the list of certificates associated
       
   870      * with the given code source.
       
   871      *
       
   872      * The signer certificates are those certificates that were used to verify
       
   873      * signed code originating from the codesource location.
       
   874      *
       
   875      * This method assumes that in the given code source, each signer
       
   876      * certificate is followed by its supporting certificate chain
       
   877      * (which may be empty), and that the signer certificate and its
       
   878      * supporting certificate chain are ordered bottom-to-top (i.e., with the
       
   879      * signer certificate first and the (root) certificate authority last).
       
   880      */
       
   881     Certificate[] getSignerCertificates(CodeSource cs) {
       
   882         Certificate[] certs = null;
       
   883         if ((certs = cs.getCertificates()) == null) {
       
   884             return null;
       
   885         }
       
   886         for (int i = 0; i < certs.length; i++) {
       
   887             if (!(certs[i] instanceof X509Certificate))
       
   888                 return cs.getCertificates();
       
   889         }
       
   890 
       
   891         // Do we have to do anything?
       
   892         int i = 0;
       
   893         int count = 0;
       
   894         while (i < certs.length) {
       
   895             count++;
       
   896             while (((i+1) < certs.length)
       
   897                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
       
   898                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
       
   899                 i++;
       
   900             }
       
   901             i++;
       
   902         }
       
   903         if (count == certs.length) {
       
   904             // Done
       
   905             return certs;
       
   906         }
       
   907 
       
   908         ArrayList<Certificate> userCertList = new ArrayList<>();
       
   909         i = 0;
       
   910         while (i < certs.length) {
       
   911             userCertList.add(certs[i]);
       
   912             while (((i+1) < certs.length)
       
   913                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
       
   914                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
       
   915                 i++;
       
   916             }
       
   917             i++;
       
   918         }
       
   919         Certificate[] userCerts = new Certificate[userCertList.size()];
       
   920         userCertList.toArray(userCerts);
       
   921         return userCerts;
       
   922     }
       
   923 
       
   924     private CodeSource canonicalizeCodebase(CodeSource cs,
       
   925                                             boolean extractSignerCerts) {
       
   926         CodeSource canonCs = cs;
       
   927         if (cs.getLocation() != null &&
       
   928             cs.getLocation().getProtocol().equalsIgnoreCase("file")) {
       
   929             try {
       
   930                 String path = cs.getLocation().getFile().replace
       
   931                                                         ('/',
       
   932                                                         File.separatorChar);
       
   933                 URL csUrl = null;
       
   934                 if (path.endsWith("*")) {
       
   935                     // remove trailing '*' because it causes canonicalization
       
   936                     // to fail on win32
       
   937                     path = path.substring(0, path.length()-1);
       
   938                     boolean appendFileSep = false;
       
   939                     if (path.endsWith(File.separator)) {
       
   940                         appendFileSep = true;
       
   941                     }
       
   942                     if (path.equals("")) {
       
   943                         path = System.getProperty("user.dir");
       
   944                     }
       
   945                     File f = new File(path);
       
   946                     path = f.getCanonicalPath();
       
   947                     StringBuffer sb = new StringBuffer(path);
       
   948                     // reappend '*' to canonicalized filename (note that
       
   949                     // canonicalization may have removed trailing file
       
   950                     // separator, so we have to check for that, too)
       
   951                     if (!path.endsWith(File.separator) &&
       
   952                         (appendFileSep || f.isDirectory())) {
       
   953                         sb.append(File.separatorChar);
       
   954                     }
       
   955                     sb.append('*');
       
   956                     path = sb.toString();
       
   957                 } else {
       
   958                     path = new File(path).getCanonicalPath();
       
   959                 }
       
   960                 csUrl = new File(path).toURL();
       
   961 
       
   962                 if (cs instanceof SubjectCodeSource) {
       
   963                     SubjectCodeSource scs = (SubjectCodeSource)cs;
       
   964                     if (extractSignerCerts) {
       
   965                         canonCs = new SubjectCodeSource(scs.getSubject(),
       
   966                                                         scs.getPrincipals(),
       
   967                                                         csUrl,
       
   968                                                         getSignerCertificates(scs));
       
   969                     } else {
       
   970                         canonCs = new SubjectCodeSource(scs.getSubject(),
       
   971                                                         scs.getPrincipals(),
       
   972                                                         csUrl,
       
   973                                                         scs.getCertificates());
       
   974                     }
       
   975                 } else {
       
   976                     if (extractSignerCerts) {
       
   977                         canonCs = new CodeSource(csUrl,
       
   978                                                  getSignerCertificates(cs));
       
   979                     } else {
       
   980                         canonCs = new CodeSource(csUrl,
       
   981                                                  cs.getCertificates());
       
   982                     }
       
   983                 }
       
   984             } catch (IOException ioe) {
       
   985                 // leave codesource as it is, unless we have to extract its
       
   986                 // signer certificates
       
   987                 if (extractSignerCerts) {
       
   988                     if (!(cs instanceof SubjectCodeSource)) {
       
   989                         canonCs = new CodeSource(cs.getLocation(),
       
   990                                                 getSignerCertificates(cs));
       
   991                     } else {
       
   992                         SubjectCodeSource scs = (SubjectCodeSource)cs;
       
   993                         canonCs = new SubjectCodeSource(scs.getSubject(),
       
   994                                                 scs.getPrincipals(),
       
   995                                                 scs.getLocation(),
       
   996                                                 getSignerCertificates(scs));
       
   997                     }
       
   998                 }
       
   999             }
       
  1000         } else {
       
  1001             if (extractSignerCerts) {
       
  1002                 if (!(cs instanceof SubjectCodeSource)) {
       
  1003                     canonCs = new CodeSource(cs.getLocation(),
       
  1004                                         getSignerCertificates(cs));
       
  1005                 } else {
       
  1006                     SubjectCodeSource scs = (SubjectCodeSource)cs;
       
  1007                     canonCs = new SubjectCodeSource(scs.getSubject(),
       
  1008                                         scs.getPrincipals(),
       
  1009                                         scs.getLocation(),
       
  1010                                         getSignerCertificates(scs));
       
  1011                 }
       
  1012             }
       
  1013         }
       
  1014         return canonCs;
       
  1015     }
       
  1016 
       
  1017     /**
       
  1018      * Each entry in the policy configuration file is represented by a
       
  1019      * PolicyEntry object.  <p>
       
  1020      *
       
  1021      * A PolicyEntry is a (CodeSource,Permission) pair.  The
       
  1022      * CodeSource contains the (URL, PublicKey) that together identify
       
  1023      * where the Java bytecodes come from and who (if anyone) signed
       
  1024      * them.  The URL could refer to localhost.  The URL could also be
       
  1025      * null, meaning that this policy entry is given to all comers, as
       
  1026      * long as they match the signer field.  The signer could be null,
       
  1027      * meaning the code is not signed. <p>
       
  1028      *
       
  1029      * The Permission contains the (Type, Name, Action) triplet. <p>
       
  1030      *
       
  1031      * For now, the Policy object retrieves the public key from the
       
  1032      * X.509 certificate on disk that corresponds to the signedBy
       
  1033      * alias specified in the Policy config file.  For reasons of
       
  1034      * efficiency, the Policy object keeps a hashtable of certs already
       
  1035      * read in.  This could be replaced by a secure internal key
       
  1036      * store.
       
  1037      *
       
  1038      * <p>
       
  1039      * For example, the entry
       
  1040      * <pre>
       
  1041      *          permission java.io.File "/tmp", "read,write",
       
  1042      *          signedBy "Duke";
       
  1043      * </pre>
       
  1044      * is represented internally
       
  1045      * <pre>
       
  1046      *
       
  1047      * FilePermission f = new FilePermission("/tmp", "read,write");
       
  1048      * PublicKey p = publickeys.get("Duke");
       
  1049      * URL u = InetAddress.getLocalHost();
       
  1050      * CodeBase c = new CodeBase( p, u );
       
  1051      * pe = new PolicyEntry(f, c);
       
  1052      * </pre>
       
  1053      *
       
  1054      * @author Marianne Mueller
       
  1055      * @author Roland Schemers
       
  1056      * @see java.security.CodeSource
       
  1057      * @see java.security.Policy
       
  1058      * @see java.security.Permissions
       
  1059      * @see java.security.ProtectionDomain
       
  1060      */
       
  1061     private static class PolicyEntry {
       
  1062 
       
  1063         CodeSource codesource;
       
  1064         Vector<Permission> permissions;
       
  1065 
       
  1066         /**
       
  1067          * Given a Permission and a CodeSource, create a policy entry.
       
  1068          *
       
  1069          * XXX Decide if/how to add validity fields and "purpose" fields to
       
  1070          * XXX policy entries
       
  1071          *
       
  1072          * @param cs the CodeSource, which encapsulates the URL and the public
       
  1073          *        key attributes from the policy config file. Validity checks
       
  1074          *        are performed on the public key before PolicyEntry is called.
       
  1075          *
       
  1076          */
       
  1077         PolicyEntry(CodeSource cs) {
       
  1078             this.codesource = cs;
       
  1079             this.permissions = new Vector<Permission>();
       
  1080         }
       
  1081 
       
  1082         /**
       
  1083          * add a Permission object to this entry.
       
  1084          */
       
  1085         void add(Permission p) {
       
  1086             permissions.addElement(p);
       
  1087         }
       
  1088 
       
  1089         /**
       
  1090          * Return the CodeSource for this policy entry
       
  1091          */
       
  1092         CodeSource getCodeSource() {
       
  1093             return this.codesource;
       
  1094         }
       
  1095 
       
  1096         @Override
       
  1097         public String toString(){
       
  1098             StringBuffer sb = new StringBuffer();
       
  1099             sb.append(rb.getString("LPARAM"));
       
  1100             sb.append(getCodeSource());
       
  1101             sb.append("\n");
       
  1102             for (int j = 0; j < permissions.size(); j++) {
       
  1103                 Permission p = permissions.elementAt(j);
       
  1104                 sb.append(rb.getString("SPACE"));
       
  1105                 sb.append(rb.getString("SPACE"));
       
  1106                 sb.append(p);
       
  1107                 sb.append(rb.getString("NEWLINE"));
       
  1108             }
       
  1109             sb.append(rb.getString("RPARAM"));
       
  1110             sb.append(rb.getString("NEWLINE"));
       
  1111             return sb.toString();
       
  1112         }
       
  1113 
       
  1114     }
       
  1115 }
       
  1116 
       
  1117 @SuppressWarnings("deprecation")
       
  1118 class PolicyPermissions extends PermissionCollection {
       
  1119 
       
  1120     private static final long serialVersionUID = -1954188373270545523L;
       
  1121 
       
  1122     private CodeSource codesource;
       
  1123     private Permissions perms;
       
  1124     private AuthPolicyFile policy;
       
  1125     private boolean notInit; // have we pulled in the policy permissions yet?
       
  1126     private Vector<Permission> additionalPerms;
       
  1127 
       
  1128     PolicyPermissions(AuthPolicyFile policy,
       
  1129                       CodeSource codesource)
       
  1130     {
       
  1131         this.codesource = codesource;
       
  1132         this.policy = policy;
       
  1133         this.perms = null;
       
  1134         this.notInit = true;
       
  1135         this.additionalPerms = null;
       
  1136     }
       
  1137 
       
  1138     @Override
       
  1139     public void add(Permission permission) {
       
  1140         if (isReadOnly())
       
  1141             throw new SecurityException
       
  1142             (AuthPolicyFile.rb.getString
       
  1143             ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection"));
       
  1144 
       
  1145         if (perms == null) {
       
  1146             if (additionalPerms == null) {
       
  1147                 additionalPerms = new Vector<Permission>();
       
  1148             }
       
  1149             additionalPerms.add(permission);
       
  1150         } else {
       
  1151             perms.add(permission);
       
  1152         }
       
  1153     }
       
  1154 
       
  1155     private synchronized void init() {
       
  1156         if (notInit) {
       
  1157             if (perms == null) {
       
  1158                 perms = new Permissions();
       
  1159             }
       
  1160             if (additionalPerms != null) {
       
  1161                 Enumeration<Permission> e = additionalPerms.elements();
       
  1162                 while (e.hasMoreElements()) {
       
  1163                     perms.add(e.nextElement());
       
  1164                 }
       
  1165                 additionalPerms = null;
       
  1166             }
       
  1167             policy.getPermissions(perms, codesource);
       
  1168             notInit = false;
       
  1169         }
       
  1170     }
       
  1171 
       
  1172     @Override
       
  1173     public boolean implies(Permission permission) {
       
  1174         if (notInit) {
       
  1175             init();
       
  1176         }
       
  1177         return perms.implies(permission);
       
  1178     }
       
  1179 
       
  1180     @Override
       
  1181     public Enumeration<Permission> elements() {
       
  1182         if (notInit) {
       
  1183             init();
       
  1184         }
       
  1185         return perms.elements();
       
  1186     }
       
  1187 
       
  1188     @Override
       
  1189     public String toString() {
       
  1190         if (notInit) {
       
  1191             init();
       
  1192         }
       
  1193         return perms.toString();
       
  1194     }
       
  1195 }