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