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