1 /* 2 * Copyright (c) 1999, 2012, 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 com.sun.security.auth; 27 28 import java.io.*; 29 import java.lang.reflect.*; 30 import java.net.URL; 31 import java.util.*; 32 33 import java.security.CodeSource; 34 import java.security.KeyStore; 35 import java.security.KeyStoreException; 36 import java.security.Permission; 37 import java.security.Permissions; 38 import java.security.PermissionCollection; 39 import java.security.Principal; 40 import java.security.UnresolvedPermission; 41 import java.security.Security; 42 import java.security.cert.Certificate; 43 import java.security.cert.X509Certificate; 44 45 import javax.security.auth.Subject; 46 import javax.security.auth.PrivateCredentialPermission; 47 48 import sun.security.util.PropertyExpander; 49 50 /** 51 * This class represents a default implementation for 52 * <code>javax.security.auth.Policy</code>. 53 * 54 * <p> This object stores the policy for entire Java runtime, 55 * and is the amalgamation of multiple static policy 56 * configurations that resides in files. 57 * The algorithm for locating the policy file(s) and reading their 58 * information into this <code>Policy</code> object is: 59 * 60 * <ol> 61 * <li> 62 * Loop through the security properties, 63 * <i>auth.policy.url.1</i>, <i>auth.policy.url.2</i>, ..., 64 * <i>auth.policy.url.X</i>". 65 * Each property value specifies a <code>URL</code> pointing to a 66 * policy file to be loaded. Read in and load each policy. 67 * 68 * <li> 69 * The <code>java.lang.System</code> property <i>java.security.auth.policy</i> 70 * may also be set to a <code>URL</code> pointing to another policy file 71 * (which is the case when a user uses the -D switch at runtime). 72 * If this property is defined, and its use is allowed by the 73 * security property file (the Security property, 74 * <i>policy.allowSystemProperty</i> is set to <i>true</i>), 75 * also load that policy. 76 * 77 * <li> 78 * If the <i>java.security.auth.policy</i> property is defined using 79 * "==" (rather than "="), then ignore all other specified 80 * policies and only load this policy. 81 * </ol> 82 * 83 * Each policy file consists of one or more grant entries, each of 84 * which consists of a number of permission entries. 85 * 86 * <pre> 87 * grant signedBy "<b>alias</b>", codeBase "<b>URL</b>", 88 * principal <b>principalClass</b> "<b>principalName</b>", 89 * principal <b>principalClass</b> "<b>principalName</b>", 90 * ... { 91 * 92 * permission <b>Type</b> "<b>name</b> "<b>action</b>", 93 * signedBy "<b>alias</b>"; 94 * permission <b>Type</b> "<b>name</b> "<b>action</b>", 95 * signedBy "<b>alias</b>"; 96 * .... 97 * }; 98 * </pre> 99 * 100 * All non-bold items above must appear as is (although case 101 * doesn't matter and some are optional, as noted below). 102 * Italicized items represent variable values. 103 * 104 * <p> A grant entry must begin with the word <code>grant</code>. 105 * The <code>signedBy</code> and <code>codeBase</code> 106 * name/value pairs are optional. 107 * If they are not present, then any signer (including unsigned code) 108 * will match, and any codeBase will match. Note that the 109 * <code>principal</code> name/value pair is not optional. 110 * This <code>Policy</code> implementation only permits 111 * Principal-based grant entries. Note that the <i>principalClass</i> 112 * may be set to the wildcard value, *, which allows it to match 113 * any <code>Principal</code> class. In addition, the <i>principalName</i> 114 * may also be set to the wildcard value, *, allowing it to match 115 * any <code>Principal</code> name. When setting the <i>principalName</i> 116 * to the *, do not surround the * with quotes. 117 * 118 * <p> A permission entry must begin with the word <code>permission</code>. 119 * The word <code><i>Type</i></code> in the template above is 120 * a specific permission type, such as <code>java.io.FilePermission</code> 121 * or <code>java.lang.RuntimePermission</code>. 122 * 123 * <p> The "<i>action</i>" is required for 124 * many permission types, such as <code>java.io.FilePermission</code> 125 * (where it specifies what type of file access that is permitted). 126 * It is not required for categories such as 127 * <code>java.lang.RuntimePermission</code> 128 * where it is not necessary - you either have the 129 * permission specified by the <code>"<i>name</i>"</code> 130 * value following the type name or you don't. 131 * 132 * <p> The <code>signedBy</code> name/value pair for a permission entry 133 * is optional. If present, it indicates a signed permission. That is, 134 * the permission class itself must be signed by the given alias in 135 * order for it to be granted. For example, 136 * suppose you have the following grant entry: 137 * 138 * <pre> 139 * grant principal foo.com.Principal "Duke" { 140 * permission Foo "foobar", signedBy "FooSoft"; 141 * } 142 * </pre> 143 * 144 * <p> Then this permission of type <i>Foo</i> is granted if the 145 * <code>Foo.class</code> permission has been signed by the 146 * "FooSoft" alias, or if <code>Foo.class</code> is a 147 * system class (i.e., is found on the CLASSPATH). 148 * 149 * <p> Items that appear in an entry must appear in the specified order 150 * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and 151 * "<i>action</i>"). An entry is terminated with a semicolon. 152 * 153 * <p> Case is unimportant for the identifiers (<code>permission</code>, 154 * <code>signedBy</code>, <code>codeBase</code>, etc.) but is 155 * significant for the <i>Type</i> 156 * or for any string that is passed in as a value. <p> 157 * 158 * <p> An example of two entries in a policy configuration file is 159 * <pre> 160 * // if the code is comes from "foo.com" and is running as "Duke", 161 * // grant it read/write to all files in /tmp. 162 * 163 * grant codeBase "foo.com", principal foo.com.Principal "Duke" { 164 * permission java.io.FilePermission "/tmp/*", "read,write"; 165 * }; 166 * 167 * // grant any code running as "Duke" permission to read 168 * // the "java.vendor" Property. 169 * 170 * grant principal foo.com.Principal "Duke" { 171 * permission java.util.PropertyPermission "java.vendor"; 172 * </pre> 173 * 174 * <p> This <code>Policy</code> implementation supports 175 * special handling for PrivateCredentialPermissions. 176 * If a grant entry is configured with a 177 * <code>PrivateCredentialPermission</code>, 178 * and the "Principal Class/Principal Name" for that 179 * <code>PrivateCredentialPermission</code> is "self", 180 * then the entry grants the specified <code>Subject</code> permission to 181 * access its own private Credential. For example, 182 * the following grants the <code>Subject</code> "Duke" 183 * access to its own a.b.Credential. 184 * 185 * <pre> 186 * grant principal foo.com.Principal "Duke" { 187 * permission javax.security.auth.PrivateCredentialPermission 188 * "a.b.Credential self", 189 * "read"; 190 * }; 191 * </pre> 192 * 193 * The following grants the <code>Subject</code> "Duke" 194 * access to all of its own private Credentials: 195 * 196 * <pre> 197 * grant principal foo.com.Principal "Duke" { 198 * permission javax.security.auth.PrivateCredentialPermission 199 * "* self", 200 * "read"; 201 * }; 202 * </pre> 203 * 204 * The following grants all Subjects authenticated as a 205 * <code>SolarisPrincipal</code> (regardless of their respective names) 206 * permission to access their own private Credentials: 207 * 208 * <pre> 209 * grant principal com.sun.security.auth.SolarisPrincipal * { 210 * permission javax.security.auth.PrivateCredentialPermission 211 * "* self", 212 * "read"; 213 * }; 214 * </pre> 215 * 216 * The following grants all Subjects permission to access their own 217 * private Credentials: 218 * 219 * <pre> 220 * grant principal * * { 221 * permission javax.security.auth.PrivateCredentialPermission 222 * "* self", 223 * "read"; 224 * }; 225 * </pre> 226 227 * @deprecated As of JDK 1.4, replaced by 228 * <code>sun.security.provider.PolicyFile</code>. 229 * This class is entirely deprecated. 230 * 231 * @see java.security.CodeSource 232 * @see java.security.Permissions 233 * @see java.security.ProtectionDomain 234 * @see java.security.Security security properties 235 */ 236 @jdk.Supported 237 @Deprecated 238 public class PolicyFile extends javax.security.auth.Policy { 239 240 static final java.util.ResourceBundle rb = 241 java.security.AccessController.doPrivileged 242 (new java.security.PrivilegedAction<java.util.ResourceBundle>() { 243 public java.util.ResourceBundle run() { 244 return (java.util.ResourceBundle.getBundle 245 ("sun.security.util.AuthResources")); 246 } 247 }); 248 // needs to be package private 249 250 private static final sun.security.util.Debug debug = 251 sun.security.util.Debug.getInstance("policy", "\t[Auth Policy]"); 252 253 private static final String AUTH_POLICY = "java.security.auth.policy"; 254 private static final String SECURITY_MANAGER = "java.security.manager"; 255 private static final String AUTH_POLICY_URL = "auth.policy.url."; 256 257 private Vector<PolicyEntry> policyEntries; 258 private Hashtable<Object, Object> aliasMapping; 259 260 private boolean initialized = false; 261 262 private boolean expandProperties = true; 263 private boolean ignoreIdentityScope = true; 264 265 // for use with the reflection API 266 267 private static final Class[] PARAMS = { String.class, String.class}; 268 269 /** 270 * Initializes the Policy object and reads the default policy 271 * configuration file(s) into the Policy object. 272 */ 273 public PolicyFile() { 274 // initialize Policy if either the AUTH_POLICY or 275 // SECURITY_MANAGER properties are set 276 String prop = System.getProperty(AUTH_POLICY); 277 278 if (prop == null) { 279 prop = System.getProperty(SECURITY_MANAGER); 280 } 281 if (prop != null) 282 init(); 283 } 284 285 private synchronized void init() { 286 287 if (initialized) 288 return; 289 290 policyEntries = new Vector<PolicyEntry>(); 291 aliasMapping = new Hashtable<Object, Object>(11); 292 293 initPolicyFile(); 294 initialized = true; 295 } 296 297 /** 298 * Refreshes the policy object by re-reading all the policy files. 299 * 300 * <p> 301 * 302 * @exception SecurityException if the caller doesn't have permission 303 * to refresh the <code>Policy</code>. 304 */ 305 public synchronized void refresh() 306 { 307 308 java.lang.SecurityManager sm = System.getSecurityManager(); 309 if (sm != null) { 310 sm.checkPermission(new javax.security.auth.AuthPermission 311 ("refreshPolicy")); 312 } 313 314 // XXX 315 // 316 // 1) if code instantiates PolicyFile directly, then it will need 317 // all the permissions required for the PolicyFile initialization 318 // 2) if code calls Policy.getPolicy, then it simply needs 319 // AuthPermission(getPolicy), and the javax.security.auth.Policy 320 // implementation instantiates PolicyFile in a doPrivileged block 321 // 3) if after instantiating a Policy (either via #1 or #2), 322 // code calls refresh, it simply needs 323 // AuthPermission(refreshPolicy). then PolicyFile wraps 324 // the refresh in a doPrivileged block. 325 initialized = false; 326 java.security.AccessController.doPrivileged 327 (new java.security.PrivilegedAction<Void>() { 328 public Void run() { 329 init(); 330 return null; 331 } 332 }); 333 } 334 335 private KeyStore initKeyStore(URL policyUrl, String keyStoreName, 336 String keyStoreType) { 337 if (keyStoreName != null) { 338 try { 339 /* 340 * location of keystore is specified as absolute URL in policy 341 * file, or is relative to URL of policy file 342 */ 343 URL keyStoreUrl = null; 344 try { 345 keyStoreUrl = new URL(keyStoreName); 346 // absolute URL 347 } catch (java.net.MalformedURLException e) { 348 // relative URL 349 keyStoreUrl = new URL(policyUrl, keyStoreName); 350 } 351 352 if (debug != null) { 353 debug.println("reading keystore"+keyStoreUrl); 354 } 355 356 InputStream inStream = 357 new BufferedInputStream(getInputStream(keyStoreUrl)); 358 359 KeyStore ks; 360 if (keyStoreType != null) 361 ks = KeyStore.getInstance(keyStoreType); 362 else 363 ks = KeyStore.getInstance(KeyStore.getDefaultType()); 364 ks.load(inStream, null); 365 inStream.close(); 366 return ks; 367 } catch (Exception e) { 368 // ignore, treat it like we have no keystore 369 if (debug != null) { 370 e.printStackTrace(); 371 } 372 return null; 373 } 374 } 375 return null; 376 } 377 378 private void initPolicyFile() { 379 380 String prop = Security.getProperty("policy.expandProperties"); 381 382 if (prop != null) expandProperties = prop.equalsIgnoreCase("true"); 383 384 String iscp = Security.getProperty("policy.ignoreIdentityScope"); 385 386 if (iscp != null) ignoreIdentityScope = iscp.equalsIgnoreCase("true"); 387 388 String allowSys = Security.getProperty("policy.allowSystemProperty"); 389 390 if ((allowSys!=null) && allowSys.equalsIgnoreCase("true")) { 391 392 String extra_policy = System.getProperty(AUTH_POLICY); 393 if (extra_policy != null) { 394 boolean overrideAll = false; 395 if (extra_policy.startsWith("=")) { 396 overrideAll = true; 397 extra_policy = extra_policy.substring(1); 398 } 399 try { 400 extra_policy = PropertyExpander.expand(extra_policy); 401 URL policyURL; 402 File policyFile = new File(extra_policy); 403 if (policyFile.exists()) { 404 policyURL = 405 new URL("file:" + policyFile.getCanonicalPath()); 406 } else { 407 policyURL = new URL(extra_policy); 408 } 409 if (debug != null) 410 debug.println("reading "+policyURL); 411 init(policyURL); 412 } catch (Exception e) { 413 // ignore. 414 if (debug != null) { 415 debug.println("caught exception: "+e); 416 } 417 418 } 419 if (overrideAll) { 420 if (debug != null) { 421 debug.println("overriding other policies!"); 422 } 423 return; 424 } 425 } 426 } 427 428 int n = 1; 429 boolean loaded_one = false; 430 String policy_url; 431 432 while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) { 433 try { 434 policy_url = PropertyExpander.expand(policy_url).replace 435 (File.separatorChar, '/'); 436 if (debug != null) 437 debug.println("reading "+policy_url); 438 init(new URL(policy_url)); 439 loaded_one = true; 440 } catch (Exception e) { 441 if (debug != null) { 442 debug.println("error reading policy "+e); 443 e.printStackTrace(); 444 } 445 // ignore that policy 446 } 447 n++; 448 } 449 450 if (loaded_one == false) { 451 // do not load a static policy 452 } 453 } 454 455 /** 456 * Checks public key. If it is marked as trusted in 457 * the identity database, add it to the policy 458 * with the AllPermission. 459 */ 460 private boolean checkForTrustedIdentity(final Certificate cert) { 461 // XXX JAAS has no way to access the SUN package. 462 // we'll add this back in when JAAS goes into core. 463 return false; 464 } 465 466 /** 467 * Reads a policy configuration into the Policy object using a 468 * Reader object. 469 * 470 * @param policyFile the policy Reader object. 471 */ 472 private void init(URL policy) { 473 PolicyParser pp = new PolicyParser(expandProperties); 474 try { 475 InputStreamReader isr 476 = new InputStreamReader(getInputStream(policy)); 477 pp.read(isr); 478 isr.close(); 479 KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(), 480 pp.getKeyStoreType()); 481 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements(); 482 while (enum_.hasMoreElements()) { 483 PolicyParser.GrantEntry ge = enum_.nextElement(); 484 addGrantEntry(ge, keyStore); 485 } 486 } catch (PolicyParser.ParsingException pe) { 487 System.err.println(AUTH_POLICY + 488 rb.getString(".error.parsing.") + policy); 489 System.err.println(AUTH_POLICY + 490 rb.getString("COLON") + 491 pe.getMessage()); 492 if (debug != null) 493 pe.printStackTrace(); 494 495 } catch (Exception e) { 496 if (debug != null) { 497 debug.println("error parsing "+policy); 498 debug.println(e.toString()); 499 e.printStackTrace(); 500 } 501 } 502 } 503 504 /* 505 * Fast path reading from file urls in order to avoid calling 506 * FileURLConnection.connect() which can be quite slow the first time 507 * it is called. We really should clean up FileURLConnection so that 508 * this is not a problem but in the meantime this fix helps reduce 509 * start up time noticeably for the new launcher. -- DAC 510 */ 511 private InputStream getInputStream(URL url) throws IOException { 512 if ("file".equals(url.getProtocol())) { 513 String path = url.getFile().replace('/', File.separatorChar); 514 return new FileInputStream(path); 515 } else { 516 return url.openStream(); 517 } 518 } 519 520 /** 521 * Given a PermissionEntry, create a codeSource. 522 * 523 * @return null if signedBy alias is not recognized 524 */ 525 CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore) 526 throws java.net.MalformedURLException 527 { 528 Certificate[] certs = null; 529 if (ge.signedBy != null) { 530 certs = getCertificates(keyStore, ge.signedBy); 531 if (certs == null) { 532 // we don't have a key for this alias, 533 // just return 534 if (debug != null) { 535 debug.println(" no certs for alias " + 536 ge.signedBy + ", ignoring."); 537 } 538 return null; 539 } 540 } 541 542 URL location; 543 544 if (ge.codeBase != null) 545 location = new URL(ge.codeBase); 546 else 547 location = null; 548 549 if (ge.principals == null || ge.principals.size() == 0) { 550 return (canonicalizeCodebase 551 (new CodeSource(location, certs), 552 false)); 553 } else { 554 return (canonicalizeCodebase 555 (new SubjectCodeSource(null, ge.principals, location, certs), 556 false)); 557 } 558 } 559 560 /** 561 * Add one policy entry to the vector. 562 */ 563 private void addGrantEntry(PolicyParser.GrantEntry ge, 564 KeyStore keyStore) { 565 566 if (debug != null) { 567 debug.println("Adding policy entry: "); 568 debug.println(" signedBy " + ge.signedBy); 569 debug.println(" codeBase " + ge.codeBase); 570 if (ge.principals != null && ge.principals.size() > 0) { 571 ListIterator<PolicyParser.PrincipalEntry> li = 572 ge.principals.listIterator(); 573 while (li.hasNext()) { 574 PolicyParser.PrincipalEntry pppe = li.next(); 575 debug.println(" " + pppe.principalClass + 576 " " + pppe.principalName); 577 } 578 } 579 debug.println(); 580 } 581 582 try { 583 CodeSource codesource = getCodeSource(ge, keyStore); 584 // skip if signedBy alias was unknown... 585 if (codesource == null) return; 586 587 PolicyEntry entry = new PolicyEntry(codesource); 588 Enumeration<PolicyParser.PermissionEntry> enum_ = 589 ge.permissionElements(); 590 while (enum_.hasMoreElements()) { 591 PolicyParser.PermissionEntry pe = enum_.nextElement(); 592 try { 593 // XXX special case PrivateCredentialPermission-SELF 594 Permission perm; 595 if (pe.permission.equals 596 ("javax.security.auth.PrivateCredentialPermission") && 597 pe.name.endsWith(" self")) { 598 perm = getInstance(pe.permission, 599 pe.name + " \"self\"", 600 pe.action); 601 } else { 602 perm = getInstance(pe.permission, 603 pe.name, 604 pe.action); 605 } 606 entry.add(perm); 607 if (debug != null) { 608 debug.println(" "+perm); 609 } 610 } catch (ClassNotFoundException cnfe) { 611 Certificate certs[]; 612 if (pe.signedBy != null) 613 certs = getCertificates(keyStore, pe.signedBy); 614 else 615 certs = null; 616 617 // only add if we had no signer or we had a 618 // a signer and found the keys for it. 619 if (certs != null || pe.signedBy == null) { 620 Permission perm = new UnresolvedPermission( 621 pe.permission, 622 pe.name, 623 pe.action, 624 certs); 625 entry.add(perm); 626 if (debug != null) { 627 debug.println(" "+perm); 628 } 629 } 630 } catch (java.lang.reflect.InvocationTargetException ite) { 631 System.err.println 632 (AUTH_POLICY + 633 rb.getString(".error.adding.Permission.") + 634 pe.permission + 635 rb.getString("SPACE") + 636 ite.getTargetException()); 637 } catch (Exception e) { 638 System.err.println 639 (AUTH_POLICY + 640 rb.getString(".error.adding.Permission.") + 641 pe.permission + 642 rb.getString("SPACE") + 643 e); 644 } 645 } 646 policyEntries.addElement(entry); 647 } catch (Exception e) { 648 System.err.println 649 (AUTH_POLICY + 650 rb.getString(".error.adding.Entry.") + 651 ge + 652 rb.getString("SPACE") + 653 e); 654 } 655 656 if (debug != null) 657 debug.println(); 658 } 659 660 /** 661 * Returns a new Permission object of the given Type. The Permission is 662 * created by getting the 663 * Class object using the <code>Class.forName</code> method, and using 664 * the reflection API to invoke the (String name, String actions) 665 * constructor on the 666 * object. 667 * 668 * @param type the type of Permission being created. 669 * @param name the name of the Permission being created. 670 * @param actions the actions of the Permission being created. 671 * 672 * @exception ClassNotFoundException if the particular Permission 673 * class could not be found. 674 * 675 * @exception IllegalAccessException if the class or initializer is 676 * not accessible. 677 * 678 * @exception InstantiationException if getInstance tries to 679 * instantiate an abstract class or an interface, or if the 680 * instantiation fails for some other reason. 681 * 682 * @exception NoSuchMethodException if the (String, String) constructor 683 * is not found. 684 * 685 * @exception InvocationTargetException if the underlying Permission 686 * constructor throws an exception. 687 * 688 */ 689 690 private static final Permission getInstance(String type, 691 String name, 692 String actions) 693 throws ClassNotFoundException, 694 InstantiationException, 695 IllegalAccessException, 696 NoSuchMethodException, 697 InvocationTargetException 698 { 699 //XXX we might want to keep a hash of created factories... 700 Class<?> pc = Class.forName(type); 701 Constructor<?> c = pc.getConstructor(PARAMS); 702 return (Permission) c.newInstance(new Object[] { name, actions }); 703 } 704 705 /** 706 * Fetch all certs associated with this alias. 707 */ 708 Certificate[] getCertificates( 709 KeyStore keyStore, String aliases) { 710 711 Vector<Certificate> vcerts = null; 712 713 StringTokenizer st = new StringTokenizer(aliases, ","); 714 int n = 0; 715 716 while (st.hasMoreTokens()) { 717 String alias = st.nextToken().trim(); 718 n++; 719 Certificate cert = null; 720 //See if this alias's cert has already been cached 721 cert = (Certificate) aliasMapping.get(alias); 722 if (cert == null && keyStore != null) { 723 724 try { 725 cert = keyStore.getCertificate(alias); 726 } catch (KeyStoreException kse) { 727 // never happens, because keystore has already been loaded 728 // when we call this 729 } 730 if (cert != null) { 731 aliasMapping.put(alias, cert); 732 aliasMapping.put(cert, alias); 733 } 734 } 735 736 if (cert != null) { 737 if (vcerts == null) 738 vcerts = new Vector<Certificate>(); 739 vcerts.addElement(cert); 740 } 741 } 742 743 // make sure n == vcerts.size, since we are doing a logical *and* 744 if (vcerts != null && n == vcerts.size()) { 745 Certificate[] certs = new Certificate[vcerts.size()]; 746 vcerts.copyInto(certs); 747 return certs; 748 } else { 749 return null; 750 } 751 } 752 753 /** 754 * Enumerate all the entries in the global policy object. 755 * This method is used by policy admin tools. The tools 756 * should use the Enumeration methods on the returned object 757 * to fetch the elements sequentially. 758 */ 759 private final synchronized Enumeration<PolicyEntry> elements(){ 760 return policyEntries.elements(); 761 } 762 763 /** 764 * Examines this <code>Policy</code> and returns the Permissions granted 765 * to the specified <code>Subject</code> and <code>CodeSource</code>. 766 * 767 * <p> Permissions for a particular <i>grant</i> entry are returned 768 * if the <code>CodeSource</code> constructed using the codebase and 769 * signedby values specified in the entry <code>implies</code> 770 * the <code>CodeSource</code> provided to this method, and if the 771 * <code>Subject</code> provided to this method contains all of the 772 * Principals specified in the entry. 773 * 774 * <p> The <code>Subject</code> provided to this method contains all 775 * of the Principals specified in the entry if, for each 776 * <code>Principal</code>, "P1", specified in the <i>grant</i> entry 777 * one of the following two conditions is met: 778 * 779 * <p> 780 * <ol> 781 * <li> the <code>Subject</code> has a 782 * <code>Principal</code>, "P2", where 783 * <code>P2.getClass().getName()</code> equals the 784 * P1's class name, and where 785 * <code>P2.getName()</code> equals the P1's name. 786 * 787 * <li> P1 implements 788 * <code>com.sun.security.auth.PrincipalComparator</code>, 789 * and <code>P1.implies</code> the provided <code>Subject</code>. 790 * </ol> 791 * 792 * <p> Note that this <code>Policy</code> implementation has 793 * special handling for PrivateCredentialPermissions. 794 * When this method encounters a <code>PrivateCredentialPermission</code> 795 * which specifies "self" as the <code>Principal</code> class and name, 796 * it does not add that <code>Permission</code> to the returned 797 * <code>PermissionCollection</code>. Instead, it builds 798 * a new <code>PrivateCredentialPermission</code> 799 * for each <code>Principal</code> associated with the provided 800 * <code>Subject</code>. Each new <code>PrivateCredentialPermission</code> 801 * contains the same Credential class as specified in the 802 * originally granted permission, as well as the Class and name 803 * for the respective <code>Principal</code>. 804 * 805 * <p> 806 * 807 * @param subject the Permissions granted to this <code>Subject</code> 808 * and the additionally provided <code>CodeSource</code> 809 * are returned. <p> 810 * 811 * @param codesource the Permissions granted to this <code>CodeSource</code> 812 * and the additionally provided <code>Subject</code> 813 * are returned. 814 * 815 * @return the Permissions granted to the provided <code>Subject</code> 816 * <code>CodeSource</code>. 817 */ 818 public PermissionCollection getPermissions(final Subject subject, 819 final CodeSource codesource) { 820 821 // XXX when JAAS goes into the JDK core, 822 // we can remove this method and simply 823 // rely on the getPermissions variant that takes a codesource, 824 // which no one can use at this point in time. 825 // at that time, we can also make SubjectCodeSource a public 826 // class. 827 828 // XXX 829 // 830 // 1) if code instantiates PolicyFile directly, then it will need 831 // all the permissions required for the PolicyFile initialization 832 // 2) if code calls Policy.getPolicy, then it simply needs 833 // AuthPermission(getPolicy), and the javax.security.auth.Policy 834 // implementation instantiates PolicyFile in a doPrivileged block 835 // 3) if after instantiating a Policy (either via #1 or #2), 836 // code calls getPermissions, PolicyFile wraps the call 837 // in a doPrivileged block. 838 return java.security.AccessController.doPrivileged 839 (new java.security.PrivilegedAction<PermissionCollection>() { 840 public PermissionCollection run() { 841 SubjectCodeSource scs = new SubjectCodeSource 842 (subject, 843 null, 844 codesource == null ? null : codesource.getLocation(), 845 codesource == null ? null : codesource.getCertificates()); 846 if (initialized) 847 return getPermissions(new Permissions(), scs); 848 else 849 return new PolicyPermissions(PolicyFile.this, scs); 850 } 851 }); 852 } 853 854 /** 855 * Examines the global policy for the specified CodeSource, and 856 * creates a PermissionCollection object with 857 * the set of permissions for that principal's protection domain. 858 * 859 * @param CodeSource the codesource associated with the caller. 860 * This encapsulates the original location of the code (where the code 861 * came from) and the public key(s) of its signer. 862 * 863 * @return the set of permissions according to the policy. 864 */ 865 PermissionCollection getPermissions(CodeSource codesource) { 866 867 if (initialized) 868 return getPermissions(new Permissions(), codesource); 869 else 870 return new PolicyPermissions(this, codesource); 871 } 872 873 /** 874 * Examines the global policy for the specified CodeSource, and 875 * creates a PermissionCollection object with 876 * the set of permissions for that principal's protection domain. 877 * 878 * @param permissions the permissions to populate 879 * @param codesource the codesource associated with the caller. 880 * This encapsulates the original location of the code (where the code 881 * came from) and the public key(s) of its signer. 882 * 883 * @return the set of permissions according to the policy. 884 */ 885 Permissions getPermissions(final Permissions perms, 886 final CodeSource cs) 887 { 888 if (!initialized) { 889 init(); 890 } 891 892 final CodeSource codesource[] = {null}; 893 894 codesource[0] = canonicalizeCodebase(cs, true); 895 896 if (debug != null) { 897 debug.println("evaluate("+codesource[0]+")\n"); 898 } 899 900 // needs to be in a begin/endPrivileged block because 901 // codesource.implies calls URL.equals which does an 902 // InetAddress lookup 903 904 for (int i = 0; i < policyEntries.size(); i++) { 905 906 PolicyEntry entry = policyEntries.elementAt(i); 907 908 if (debug != null) { 909 debug.println("PolicyFile CodeSource implies: " + 910 entry.codesource.toString() + "\n\n" + 911 "\t" + codesource[0].toString() + "\n\n"); 912 } 913 914 if (entry.codesource.implies(codesource[0])) { 915 for (int j = 0; j < entry.permissions.size(); j++) { 916 Permission p = entry.permissions.elementAt(j); 917 if (debug != null) { 918 debug.println(" granting " + p); 919 } 920 if (!addSelfPermissions(p, entry.codesource, 921 codesource[0], perms)) { 922 // we could check for duplicates 923 // before adding new permissions, 924 // but the SubjectDomainCombiner 925 // already checks for duplicates later 926 perms.add(p); 927 } 928 } 929 } 930 } 931 932 // now see if any of the keys are trusted ids. 933 934 if (!ignoreIdentityScope) { 935 Certificate certs[] = codesource[0].getCertificates(); 936 if (certs != null) { 937 for (int k=0; k < certs.length; k++) { 938 if ((aliasMapping.get(certs[k]) == null) && 939 checkForTrustedIdentity(certs[k])) { 940 // checkForTrustedIdentity added it 941 // to the policy for us. next time 942 // around we'll find it. This time 943 // around we need to add it. 944 perms.add(new java.security.AllPermission()); 945 } 946 } 947 } 948 } 949 return perms; 950 } 951 952 /** 953 * Returns true if 'Self' permissions were added to the provided 954 * 'perms', and false otherwise. 955 * 956 * <p> 957 * 958 * @param p check to see if this Permission is a "SELF" 959 * PrivateCredentialPermission. <p> 960 * 961 * @param entryCs the codesource for the Policy entry. 962 * 963 * @param accCs the codesource for from the current AccessControlContext. 964 * 965 * @param perms the PermissionCollection where the individual 966 * PrivateCredentialPermissions will be added. 967 */ 968 private boolean addSelfPermissions(final Permission p, 969 CodeSource entryCs, 970 CodeSource accCs, 971 Permissions perms) { 972 973 if (!(p instanceof PrivateCredentialPermission)) 974 return false; 975 976 if (!(entryCs instanceof SubjectCodeSource)) 977 return false; 978 979 980 PrivateCredentialPermission pcp = (PrivateCredentialPermission)p; 981 SubjectCodeSource scs = (SubjectCodeSource)entryCs; 982 983 // see if it is a SELF permission 984 String[][] pPrincipals = pcp.getPrincipals(); 985 if (pPrincipals.length <= 0 || 986 !pPrincipals[0][0].equalsIgnoreCase("self") || 987 !pPrincipals[0][1].equalsIgnoreCase("self")) { 988 989 // regular PrivateCredentialPermission 990 return false; 991 } else { 992 993 // granted a SELF permission - create a 994 // PrivateCredentialPermission for each 995 // of the Policy entry's CodeSource Principals 996 997 if (scs.getPrincipals() == null) { 998 // XXX SubjectCodeSource has no Subject??? 999 return true; 1000 } 1001 1002 ListIterator<PolicyParser.PrincipalEntry> pli = 1003 scs.getPrincipals().listIterator(); 1004 while (pli.hasNext()) { 1005 1006 PolicyParser.PrincipalEntry principal = pli.next(); 1007 1008 // XXX 1009 // if the Policy entry's Principal does not contain a 1010 // WILDCARD for the Principal name, then a 1011 // new PrivateCredentialPermission is created 1012 // for the Principal listed in the Policy entry. 1013 // if the Policy entry's Principal contains a WILDCARD 1014 // for the Principal name, then a new 1015 // PrivateCredentialPermission is created 1016 // for each Principal associated with the Subject 1017 // in the current ACC. 1018 1019 String[][] principalInfo = getPrincipalInfo 1020 (principal, accCs); 1021 1022 for (int i = 0; i < principalInfo.length; i++) { 1023 1024 // here's the new PrivateCredentialPermission 1025 1026 PrivateCredentialPermission newPcp = 1027 new PrivateCredentialPermission 1028 (pcp.getCredentialClass() + 1029 " " + 1030 principalInfo[i][0] + 1031 " " + 1032 "\"" + principalInfo[i][1] + "\"", 1033 "read"); 1034 1035 if (debug != null) { 1036 debug.println("adding SELF permission: " + 1037 newPcp.toString()); 1038 } 1039 1040 perms.add(newPcp); 1041 } 1042 } 1043 } 1044 return true; 1045 } 1046 1047 /** 1048 * return the principal class/name pair in the 2D array. 1049 * array[x][y]: x corresponds to the array length. 1050 * if (y == 0), it's the principal class. 1051 * if (y == 1), it's the principal name. 1052 */ 1053 private String[][] getPrincipalInfo 1054 (PolicyParser.PrincipalEntry principal, 1055 final CodeSource accCs) { 1056 1057 // there are 3 possibilities: 1058 // 1) the entry's Principal class and name are not wildcarded 1059 // 2) the entry's Principal name is wildcarded only 1060 // 3) the entry's Principal class and name are wildcarded 1061 1062 if (!principal.principalClass.equals 1063 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) && 1064 !principal.principalName.equals 1065 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) { 1066 1067 // build a PrivateCredentialPermission for the principal 1068 // from the Policy entry 1069 String[][] info = new String[1][2]; 1070 info[0][0] = principal.principalClass; 1071 info[0][1] = principal.principalName; 1072 return info; 1073 1074 } else if (!principal.principalClass.equals 1075 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) && 1076 principal.principalName.equals 1077 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) { 1078 1079 // build a PrivateCredentialPermission for all 1080 // the Subject's principals that are instances of principalClass 1081 1082 // the accCs is guaranteed to be a SubjectCodeSource 1083 // because the earlier CodeSource.implies succeeded 1084 SubjectCodeSource scs = (SubjectCodeSource)accCs; 1085 1086 Set<? extends Principal> principalSet = null; 1087 try { 1088 // principal.principalClass should extend Principal 1089 // If it doesn't, we should stop here with a ClassCastException. 1090 @SuppressWarnings("unchecked") 1091 Class<? extends Principal> pClass = (Class<? extends Principal>) 1092 Class.forName(principal.principalClass, false, 1093 ClassLoader.getSystemClassLoader()); 1094 principalSet = scs.getSubject().getPrincipals(pClass); 1095 } catch (Exception e) { 1096 if (debug != null) { 1097 debug.println("problem finding Principal Class " + 1098 "when expanding SELF permission: " + 1099 e.toString()); 1100 } 1101 } 1102 1103 if (principalSet == null) { 1104 // error 1105 return new String[0][0]; 1106 } 1107 1108 String[][] info = new String[principalSet.size()][2]; 1109 1110 int i = 0; 1111 for (Principal p : principalSet) { 1112 info[i][0] = p.getClass().getName(); 1113 info[i][1] = p.getName(); 1114 i++; 1115 } 1116 return info; 1117 1118 } else { 1119 1120 // build a PrivateCredentialPermission for every 1121 // one of the current Subject's principals 1122 1123 // the accCs is guaranteed to be a SubjectCodeSource 1124 // because the earlier CodeSource.implies succeeded 1125 SubjectCodeSource scs = (SubjectCodeSource)accCs; 1126 Set<Principal> principalSet = scs.getSubject().getPrincipals(); 1127 1128 String[][] info = new String[principalSet.size()][2]; 1129 java.util.Iterator<Principal> pIterator = principalSet.iterator(); 1130 1131 int i = 0; 1132 while (pIterator.hasNext()) { 1133 Principal p = pIterator.next(); 1134 info[i][0] = p.getClass().getName(); 1135 info[i][1] = p.getName(); 1136 i++; 1137 } 1138 return info; 1139 } 1140 } 1141 1142 /* 1143 * Returns the signer certificates from the list of certificates associated 1144 * with the given code source. 1145 * 1146 * The signer certificates are those certificates that were used to verify 1147 * signed code originating from the codesource location. 1148 * 1149 * This method assumes that in the given code source, each signer 1150 * certificate is followed by its supporting certificate chain 1151 * (which may be empty), and that the signer certificate and its 1152 * supporting certificate chain are ordered bottom-to-top (i.e., with the 1153 * signer certificate first and the (root) certificate authority last). 1154 */ 1155 Certificate[] getSignerCertificates(CodeSource cs) { 1156 Certificate[] certs = null; 1157 if ((certs = cs.getCertificates()) == null) 1158 return null; 1159 for (int i=0; i<certs.length; i++) { 1160 if (!(certs[i] instanceof X509Certificate)) 1161 return cs.getCertificates(); 1162 } 1163 1164 // Do we have to do anything? 1165 int i = 0; 1166 int count = 0; 1167 while (i < certs.length) { 1168 count++; 1169 while (((i+1) < certs.length) 1170 && ((X509Certificate)certs[i]).getIssuerDN().equals( 1171 ((X509Certificate)certs[i+1]).getSubjectDN())) { 1172 i++; 1173 } 1174 i++; 1175 } 1176 if (count == certs.length) 1177 // Done 1178 return certs; 1179 1180 ArrayList<Certificate> userCertList = new ArrayList<>(); 1181 i = 0; 1182 while (i < certs.length) { 1183 userCertList.add(certs[i]); 1184 while (((i+1) < certs.length) 1185 && ((X509Certificate)certs[i]).getIssuerDN().equals( 1186 ((X509Certificate)certs[i+1]).getSubjectDN())) { 1187 i++; 1188 } 1189 i++; 1190 } 1191 Certificate[] userCerts = new Certificate[userCertList.size()]; 1192 userCertList.toArray(userCerts); 1193 return userCerts; 1194 } 1195 1196 private CodeSource canonicalizeCodebase(CodeSource cs, 1197 boolean extractSignerCerts) { 1198 CodeSource canonCs = cs; 1199 if (cs.getLocation() != null && 1200 cs.getLocation().getProtocol().equalsIgnoreCase("file")) { 1201 try { 1202 String path = cs.getLocation().getFile().replace 1203 ('/', 1204 File.separatorChar); 1205 URL csUrl = null; 1206 if (path.endsWith("*")) { 1207 // remove trailing '*' because it causes canonicalization 1208 // to fail on win32 1209 path = path.substring(0, path.length()-1); 1210 boolean appendFileSep = false; 1211 if (path.endsWith(File.separator)) 1212 appendFileSep = true; 1213 if (path.equals("")) { 1214 path = System.getProperty("user.dir"); 1215 } 1216 File f = new File(path); 1217 path = f.getCanonicalPath(); 1218 StringBuffer sb = new StringBuffer(path); 1219 // reappend '*' to canonicalized filename (note that 1220 // canonicalization may have removed trailing file 1221 // separator, so we have to check for that, too) 1222 if (!path.endsWith(File.separator) && 1223 (appendFileSep || f.isDirectory())) 1224 sb.append(File.separatorChar); 1225 sb.append('*'); 1226 path = sb.toString(); 1227 } else { 1228 path = new File(path).getCanonicalPath(); 1229 } 1230 csUrl = new File(path).toURL(); 1231 1232 if (cs instanceof SubjectCodeSource) { 1233 SubjectCodeSource scs = (SubjectCodeSource)cs; 1234 if (extractSignerCerts) { 1235 canonCs = new SubjectCodeSource 1236 (scs.getSubject(), 1237 scs.getPrincipals(), 1238 csUrl, 1239 getSignerCertificates(scs)); 1240 } else { 1241 canonCs = new SubjectCodeSource 1242 (scs.getSubject(), 1243 scs.getPrincipals(), 1244 csUrl, 1245 scs.getCertificates()); 1246 } 1247 } else { 1248 if (extractSignerCerts) { 1249 canonCs = new CodeSource(csUrl, 1250 getSignerCertificates(cs)); 1251 } else { 1252 canonCs = new CodeSource(csUrl, 1253 cs.getCertificates()); 1254 } 1255 } 1256 } catch (IOException ioe) { 1257 // leave codesource as it is, unless we have to extract its 1258 // signer certificates 1259 if (extractSignerCerts) { 1260 if (!(cs instanceof SubjectCodeSource)) { 1261 canonCs = new CodeSource(cs.getLocation(), 1262 getSignerCertificates(cs)); 1263 } else { 1264 SubjectCodeSource scs = (SubjectCodeSource)cs; 1265 canonCs = new SubjectCodeSource(scs.getSubject(), 1266 scs.getPrincipals(), 1267 scs.getLocation(), 1268 getSignerCertificates(scs)); 1269 } 1270 } 1271 } 1272 } else { 1273 if (extractSignerCerts) { 1274 if (!(cs instanceof SubjectCodeSource)) { 1275 canonCs = new CodeSource(cs.getLocation(), 1276 getSignerCertificates(cs)); 1277 } else { 1278 SubjectCodeSource scs = (SubjectCodeSource)cs; 1279 canonCs = new SubjectCodeSource(scs.getSubject(), 1280 scs.getPrincipals(), 1281 scs.getLocation(), 1282 getSignerCertificates(scs)); 1283 } 1284 } 1285 } 1286 return canonCs; 1287 } 1288 1289 /** 1290 * Each entry in the policy configuration file is represented by a 1291 * PolicyEntry object. <p> 1292 * 1293 * A PolicyEntry is a (CodeSource,Permission) pair. The 1294 * CodeSource contains the (URL, PublicKey) that together identify 1295 * where the Java bytecodes come from and who (if anyone) signed 1296 * them. The URL could refer to localhost. The URL could also be 1297 * null, meaning that this policy entry is given to all comers, as 1298 * long as they match the signer field. The signer could be null, 1299 * meaning the code is not signed. <p> 1300 * 1301 * The Permission contains the (Type, Name, Action) triplet. <p> 1302 * 1303 * For now, the Policy object retrieves the public key from the 1304 * X.509 certificate on disk that corresponds to the signedBy 1305 * alias specified in the Policy config file. For reasons of 1306 * efficiency, the Policy object keeps a hashtable of certs already 1307 * read in. This could be replaced by a secure internal key 1308 * store. 1309 * 1310 * <p> 1311 * For example, the entry 1312 * <pre> 1313 * permission java.io.File "/tmp", "read,write", 1314 * signedBy "Duke"; 1315 * </pre> 1316 * is represented internally 1317 * <pre> 1318 * 1319 * FilePermission f = new FilePermission("/tmp", "read,write"); 1320 * PublicKey p = publickeys.get("Duke"); 1321 * URL u = InetAddress.getLocalHost(); 1322 * CodeBase c = new CodeBase( p, u ); 1323 * pe = new PolicyEntry(f, c); 1324 * </pre> 1325 * 1326 * @author Marianne Mueller 1327 * @author Roland Schemers 1328 * @see java.security.CodeSource 1329 * @see java.security.Policy 1330 * @see java.security.Permissions 1331 * @see java.security.ProtectionDomain 1332 */ 1333 1334 private static class PolicyEntry { 1335 1336 CodeSource codesource; 1337 Vector<Permission> permissions; 1338 1339 /** 1340 * Given a Permission and a CodeSource, create a policy entry. 1341 * 1342 * XXX Decide if/how to add validity fields and "purpose" fields to 1343 * XXX policy entries 1344 * 1345 * @param cs the CodeSource, which encapsulates the URL and the public 1346 * key 1347 * attributes from the policy config file. Validity checks are 1348 * performed on the public key before PolicyEntry is called. 1349 * 1350 */ 1351 PolicyEntry(CodeSource cs) 1352 { 1353 this.codesource = cs; 1354 this.permissions = new Vector<Permission>(); 1355 } 1356 1357 /** 1358 * add a Permission object to this entry. 1359 */ 1360 void add(Permission p) { 1361 permissions.addElement(p); 1362 } 1363 1364 /** 1365 * Return the CodeSource for this policy entry 1366 */ 1367 CodeSource getCodeSource() { 1368 return this.codesource; 1369 } 1370 1371 public String toString(){ 1372 StringBuffer sb = new StringBuffer(); 1373 sb.append(rb.getString("LPARAM")); 1374 sb.append(getCodeSource()); 1375 sb.append("\n"); 1376 for (int j = 0; j < permissions.size(); j++) { 1377 Permission p = permissions.elementAt(j); 1378 sb.append(rb.getString("SPACE")); 1379 sb.append(rb.getString("SPACE")); 1380 sb.append(p); 1381 sb.append(rb.getString("NEWLINE")); 1382 } 1383 sb.append(rb.getString("RPARAM")); 1384 sb.append(rb.getString("NEWLINE")); 1385 return sb.toString(); 1386 } 1387 1388 } 1389 } 1390 1391 class PolicyPermissions extends PermissionCollection { 1392 1393 private static final long serialVersionUID = -1954188373270545523L; 1394 1395 private CodeSource codesource; 1396 private Permissions perms; 1397 private PolicyFile policy; 1398 private boolean notInit; // have we pulled in the policy permissions yet? 1399 private Vector<Permission> additionalPerms; 1400 1401 PolicyPermissions(PolicyFile policy, 1402 CodeSource codesource) 1403 { 1404 this.codesource = codesource; 1405 this.policy = policy; 1406 this.perms = null; 1407 this.notInit = true; 1408 this.additionalPerms = null; 1409 } 1410 1411 public void add(Permission permission) { 1412 if (isReadOnly()) 1413 throw new SecurityException 1414 (PolicyFile.rb.getString 1415 ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection")); 1416 1417 if (perms == null) { 1418 if (additionalPerms == null) 1419 additionalPerms = new Vector<Permission>(); 1420 additionalPerms.add(permission); 1421 } else { 1422 perms.add(permission); 1423 } 1424 } 1425 1426 private synchronized void init() { 1427 if (notInit) { 1428 if (perms == null) 1429 perms = new Permissions(); 1430 1431 if (additionalPerms != null) { 1432 Enumeration<Permission> e = additionalPerms.elements(); 1433 while (e.hasMoreElements()) { 1434 perms.add(e.nextElement()); 1435 } 1436 additionalPerms = null; 1437 } 1438 policy.getPermissions(perms,codesource); 1439 notInit=false; 1440 } 1441 } 1442 1443 public boolean implies(Permission permission) { 1444 if (notInit) 1445 init(); 1446 return perms.implies(permission); 1447 } 1448 1449 public Enumeration<Permission> elements() { 1450 if (notInit) 1451 init(); 1452 return perms.elements(); 1453 } 1454 1455 public String toString() { 1456 if (notInit) 1457 init(); 1458 return perms.toString(); 1459 } 1460 }