1 /* 2 * Copyright (c) 1997, 2016, 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 java.security; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.ReferenceQueue; 30 import java.lang.ref.SoftReference; 31 import java.lang.ref.WeakReference; 32 import java.util.ArrayList; 33 import java.util.Enumeration; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.concurrent.ConcurrentHashMap; 37 import jdk.internal.misc.JavaSecurityAccess; 38 import jdk.internal.misc.JavaSecurityProtectionDomainAccess; 39 import static jdk.internal.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; 40 import jdk.internal.misc.SharedSecrets; 41 import sun.security.util.Debug; 42 import sun.security.util.SecurityConstants; 43 44 /** 45 * The ProtectionDomain class encapsulates the characteristics of a domain, 46 * which encloses a set of classes whose instances are granted a set 47 * of permissions when being executed on behalf of a given set of Principals. 48 * <p> 49 * A static set of permissions can be bound to a ProtectionDomain when it is 50 * constructed; such permissions are granted to the domain regardless of the 51 * Policy in force. However, to support dynamic security policies, a 52 * ProtectionDomain can also be constructed such that it is dynamically 53 * mapped to a set of permissions by the current Policy whenever a permission 54 * is checked. 55 * 56 * @author Li Gong 57 * @author Roland Schemers 58 * @author Gary Ellison 59 */ 60 61 public class ProtectionDomain { 62 63 private static class JavaSecurityAccessImpl implements JavaSecurityAccess { 64 65 private JavaSecurityAccessImpl() { 66 } 67 68 @Override 69 public <T> T doIntersectionPrivilege( 70 PrivilegedAction<T> action, 71 final AccessControlContext stack, 72 final AccessControlContext context) { 73 if (action == null) { 74 throw new NullPointerException(); 75 } 76 77 return AccessController.doPrivileged( 78 action, 79 getCombinedACC(context, stack) 80 ); 81 } 82 83 @Override 84 public <T> T doIntersectionPrivilege( 85 PrivilegedAction<T> action, 86 AccessControlContext context) { 87 return doIntersectionPrivilege(action, 88 AccessController.getContext(), context); 89 } 90 91 private static AccessControlContext getCombinedACC( 92 AccessControlContext context, AccessControlContext stack) { 93 AccessControlContext acc = 94 new AccessControlContext(context, stack.getCombiner(), true); 95 96 return new AccessControlContext(stack.getContext(), acc).optimize(); 97 } 98 } 99 100 static { 101 // setup SharedSecrets to allow access to doIntersectionPrivilege 102 // methods and ProtectionDomain cache 103 SharedSecrets.setJavaSecurityAccess(new JavaSecurityAccessImpl()); 104 SharedSecrets.setJavaSecurityProtectionDomainAccess( 105 new JavaSecurityProtectionDomainAccess() { 106 @Override 107 public ProtectionDomainCache getProtectionDomainCache() { 108 return new PDCache(); 109 } 110 }); 111 } 112 113 /** 114 * Used for storing ProtectionDomains as keys in a Map. 115 */ 116 static final class Key {} 117 118 /* CodeSource */ 119 private CodeSource codesource ; 120 121 /* ClassLoader the protection domain was consed from */ 122 private ClassLoader classloader; 123 124 /* Principals running-as within this protection domain */ 125 private Principal[] principals; 126 127 /* the rights this protection domain is granted */ 128 private PermissionCollection permissions; 129 130 /* if the permissions object has AllPermission */ 131 private boolean hasAllPerm = false; 132 133 /* the PermissionCollection is static (pre 1.4 constructor) 134 or dynamic (via a policy refresh) */ 135 private final boolean staticPermissions; 136 137 /* 138 * An object used as a key when the ProtectionDomain is stored in a Map. 139 */ 140 final Key key = new Key(); 141 142 /** 143 * Creates a new ProtectionDomain with the given CodeSource and 144 * Permissions. If the permissions object is not null, then 145 * {@code setReadOnly()} will be called on the passed in 146 * Permissions object. 147 * <p> 148 * The permissions granted to this domain are static, i.e. 149 * invoking the {@link #staticPermissionsOnly()} method returns true. 150 * They contain only the ones passed to this constructor and 151 * the current Policy will not be consulted. 152 * 153 * @param codesource the codesource associated with this domain 154 * @param permissions the permissions granted to this domain 155 */ 156 public ProtectionDomain(CodeSource codesource, 157 PermissionCollection permissions) { 158 this.codesource = codesource; 159 if (permissions != null) { 160 this.permissions = permissions; 161 this.permissions.setReadOnly(); 162 if (permissions instanceof Permissions && 163 ((Permissions)permissions).allPermission != null) { 164 hasAllPerm = true; 165 } 166 } 167 this.classloader = null; 168 this.principals = new Principal[0]; 169 staticPermissions = true; 170 } 171 172 /** 173 * Creates a new ProtectionDomain qualified by the given CodeSource, 174 * Permissions, ClassLoader and array of Principals. If the 175 * permissions object is not null, then {@code setReadOnly()} 176 * will be called on the passed in Permissions object. 177 * <p> 178 * The permissions granted to this domain are dynamic, i.e. 179 * invoking the {@link #staticPermissionsOnly()} method returns false. 180 * They include both the static permissions passed to this constructor, 181 * and any permissions granted to this domain by the current Policy at the 182 * time a permission is checked. 183 * <p> 184 * This constructor is typically used by 185 * {@link SecureClassLoader ClassLoaders} 186 * and {@link DomainCombiner DomainCombiners} which delegate to 187 * {@code Policy} to actively associate the permissions granted to 188 * this domain. This constructor affords the 189 * Policy provider the opportunity to augment the supplied 190 * PermissionCollection to reflect policy changes. 191 * 192 * @param codesource the CodeSource associated with this domain 193 * @param permissions the permissions granted to this domain 194 * @param classloader the ClassLoader associated with this domain 195 * @param principals the array of Principals associated with this 196 * domain. The contents of the array are copied to protect against 197 * subsequent modification. 198 * @see Policy#refresh 199 * @see Policy#getPermissions(ProtectionDomain) 200 * @since 1.4 201 */ 202 public ProtectionDomain(CodeSource codesource, 203 PermissionCollection permissions, 204 ClassLoader classloader, 205 Principal[] principals) { 206 this.codesource = codesource; 207 if (permissions != null) { 208 this.permissions = permissions; 209 this.permissions.setReadOnly(); 210 if (permissions instanceof Permissions && 211 ((Permissions)permissions).allPermission != null) { 212 hasAllPerm = true; 213 } 214 } 215 this.classloader = classloader; 216 this.principals = (principals != null ? principals.clone(): 217 new Principal[0]); 218 staticPermissions = false; 219 } 220 221 /** 222 * Returns the CodeSource of this domain. 223 * @return the CodeSource of this domain which may be null. 224 * @since 1.2 225 */ 226 public final CodeSource getCodeSource() { 227 return this.codesource; 228 } 229 230 231 /** 232 * Returns the ClassLoader of this domain. 233 * @return the ClassLoader of this domain which may be null. 234 * 235 * @since 1.4 236 */ 237 public final ClassLoader getClassLoader() { 238 return this.classloader; 239 } 240 241 242 /** 243 * Returns an array of principals for this domain. 244 * @return a non-null array of principals for this domain. 245 * Returns a new array each time this method is called. 246 * 247 * @since 1.4 248 */ 249 public final Principal[] getPrincipals() { 250 return this.principals.clone(); 251 } 252 253 /** 254 * Returns the static permissions granted to this domain. 255 * 256 * @return the static set of permissions for this domain which may be null. 257 * @see Policy#refresh 258 * @see Policy#getPermissions(ProtectionDomain) 259 */ 260 public final PermissionCollection getPermissions() { 261 return permissions; 262 } 263 264 /** 265 * Returns true if this domain contains only static permissions 266 * and does not check the current {@code Policy} at the time of 267 * permission checking. 268 * 269 * @return true if this domain contains only static permissions. 270 * 271 * @since 9 272 */ 273 public final boolean staticPermissionsOnly() { 274 return this.staticPermissions; 275 } 276 277 /** 278 * Check and see if this ProtectionDomain implies the permissions 279 * expressed in the Permission object. 280 * <p> 281 * The set of permissions evaluated is a function of whether the 282 * ProtectionDomain was constructed with a static set of permissions 283 * or it was bound to a dynamically mapped set of permissions. 284 * <p> 285 * If the {@link #staticPermissionsOnly()} method returns 286 * true, then the permission will only be checked against the 287 * PermissionCollection supplied at construction. 288 * <p> 289 * Otherwise, the permission will be checked against the combination 290 * of the PermissionCollection supplied at construction and 291 * the current Policy binding. 292 * 293 * @param perm the Permission object to check. 294 * 295 * @return true if {@code perm} is implied by this ProtectionDomain. 296 */ 297 public boolean implies(Permission perm) { 298 299 if (hasAllPerm) { 300 // internal permission collection already has AllPermission - 301 // no need to go to policy 302 return true; 303 } 304 305 if (!staticPermissions && 306 Policy.getPolicyNoCheck().implies(this, perm)) 307 return true; 308 if (permissions != null) 309 return permissions.implies(perm); 310 311 return false; 312 } 313 314 // called by the VM -- do not remove 315 boolean impliesCreateAccessControlContext() { 316 return implies(SecurityConstants.CREATE_ACC_PERMISSION); 317 } 318 319 /** 320 * Convert a ProtectionDomain to a String. 321 */ 322 @Override public String toString() { 323 String pals = "<no principals>"; 324 if (principals != null && principals.length > 0) { 325 StringBuilder palBuf = new StringBuilder("(principals "); 326 327 for (int i = 0; i < principals.length; i++) { 328 palBuf.append(principals[i].getClass().getName() + 329 " \"" + principals[i].getName() + 330 "\""); 331 if (i < principals.length-1) 332 palBuf.append(",\n"); 333 else 334 palBuf.append(")\n"); 335 } 336 pals = palBuf.toString(); 337 } 338 339 // Check if policy is set; we don't want to load 340 // the policy prematurely here 341 PermissionCollection pc = Policy.isSet() && seeAllp() ? 342 mergePermissions(): 343 getPermissions(); 344 345 return "ProtectionDomain "+ 346 " "+codesource+"\n"+ 347 " "+classloader+"\n"+ 348 " "+pals+"\n"+ 349 " "+pc+"\n"; 350 } 351 352 /* 353 * holder class for the static field "debug" to delay its initialization 354 */ 355 private static class DebugHolder { 356 private static final Debug debug = Debug.getInstance("domain"); 357 } 358 359 /** 360 * Return true (merge policy permissions) in the following cases: 361 * 362 * . SecurityManager is null 363 * 364 * . SecurityManager is not null, 365 * debug is not null, 366 * SecurityManager impelmentation is in bootclasspath, 367 * Policy implementation is in bootclasspath 368 * (the bootclasspath restrictions avoid recursion) 369 * 370 * . SecurityManager is not null, 371 * debug is null, 372 * caller has Policy.getPolicy permission 373 */ 374 private static boolean seeAllp() { 375 SecurityManager sm = System.getSecurityManager(); 376 377 if (sm == null) { 378 return true; 379 } else { 380 if (DebugHolder.debug != null) { 381 if (sm.getClass().getClassLoader() == null && 382 Policy.getPolicyNoCheck().getClass().getClassLoader() 383 == null) { 384 return true; 385 } 386 } else { 387 try { 388 sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION); 389 return true; 390 } catch (SecurityException se) { 391 // fall thru and return false 392 } 393 } 394 } 395 396 return false; 397 } 398 399 private PermissionCollection mergePermissions() { 400 if (staticPermissions) 401 return permissions; 402 403 PermissionCollection perms = 404 java.security.AccessController.doPrivileged 405 (new java.security.PrivilegedAction<>() { 406 public PermissionCollection run() { 407 Policy p = Policy.getPolicyNoCheck(); 408 return p.getPermissions(ProtectionDomain.this); 409 } 410 }); 411 412 Permissions mergedPerms = new Permissions(); 413 int swag = 32; 414 int vcap = 8; 415 Enumeration<Permission> e; 416 List<Permission> pdVector = new ArrayList<>(vcap); 417 List<Permission> plVector = new ArrayList<>(swag); 418 419 // 420 // Build a vector of domain permissions for subsequent merge 421 if (permissions != null) { 422 synchronized (permissions) { 423 e = permissions.elements(); 424 while (e.hasMoreElements()) { 425 pdVector.add(e.nextElement()); 426 } 427 } 428 } 429 430 // 431 // Build a vector of Policy permissions for subsequent merge 432 if (perms != null) { 433 synchronized (perms) { 434 e = perms.elements(); 435 while (e.hasMoreElements()) { 436 plVector.add(e.nextElement()); 437 vcap++; 438 } 439 } 440 } 441 442 if (perms != null && permissions != null) { 443 // 444 // Weed out the duplicates from the policy. Unless a refresh 445 // has occurred since the pd was consed this should result in 446 // an empty vector. 447 synchronized (permissions) { 448 e = permissions.elements(); // domain vs policy 449 while (e.hasMoreElements()) { 450 Permission pdp = e.nextElement(); 451 Class<?> pdpClass = pdp.getClass(); 452 String pdpActions = pdp.getActions(); 453 String pdpName = pdp.getName(); 454 for (int i = 0; i < plVector.size(); i++) { 455 Permission pp = plVector.get(i); 456 if (pdpClass.isInstance(pp)) { 457 // The equals() method on some permissions 458 // have some side effects so this manual 459 // comparison is sufficient. 460 if (pdpName.equals(pp.getName()) && 461 pdpActions.equals(pp.getActions())) { 462 plVector.remove(i); 463 break; 464 } 465 } 466 } 467 } 468 } 469 } 470 471 if (perms !=null) { 472 // the order of adding to merged perms and permissions 473 // needs to preserve the bugfix 4301064 474 475 for (int i = plVector.size()-1; i >= 0; i--) { 476 mergedPerms.add(plVector.get(i)); 477 } 478 } 479 if (permissions != null) { 480 for (int i = pdVector.size()-1; i >= 0; i--) { 481 mergedPerms.add(pdVector.get(i)); 482 } 483 } 484 485 return mergedPerms; 486 } 487 488 /** 489 * A cache of ProtectionDomains and their Permissions. 490 * 491 * This class stores ProtectionDomains as weak keys in a ConcurrentHashMap 492 * with additional support for checking and removing weak keys that are no 493 * longer in use. There can be cases where the permission collection may 494 * have a chain of strong references back to the ProtectionDomain, which 495 * ordinarily would prevent the entry from being removed from the map. To 496 * address that, we wrap the permission collection in a SoftReference so 497 * that it can be reclaimed by the garbage collector due to memory demand. 498 */ 499 private static class PDCache implements ProtectionDomainCache { 500 private final ConcurrentHashMap<WeakProtectionDomainKey, 501 SoftReference<PermissionCollection>> 502 pdMap = new ConcurrentHashMap<>(); 503 private final ReferenceQueue<Key> queue = new ReferenceQueue<>(); 504 505 @Override 506 public void put(ProtectionDomain pd, PermissionCollection pc) { 507 processQueue(queue, pdMap); 508 WeakProtectionDomainKey weakPd = 509 new WeakProtectionDomainKey(pd, queue); 510 pdMap.put(weakPd, new SoftReference<>(pc)); 511 } 512 513 @Override 514 public PermissionCollection get(ProtectionDomain pd) { 515 processQueue(queue, pdMap); 516 WeakProtectionDomainKey weakPd = new WeakProtectionDomainKey(pd); 517 SoftReference<PermissionCollection> sr = pdMap.get(weakPd); 518 return (sr == null) ? null : sr.get(); 519 } 520 521 /** 522 * Removes weak keys from the map that have been enqueued 523 * on the reference queue and are no longer in use. 524 */ 525 private static void processQueue(ReferenceQueue<Key> queue, 526 ConcurrentHashMap<? extends 527 WeakReference<Key>, ?> pdMap) { 528 Reference<? extends Key> ref; 529 while ((ref = queue.poll()) != null) { 530 pdMap.remove(ref); 531 } 532 } 533 } 534 535 /** 536 * A weak key for a ProtectionDomain. 537 */ 538 private static class WeakProtectionDomainKey extends WeakReference<Key> { 539 /** 540 * Saved value of the referent's identity hash code, to maintain 541 * a consistent hash code after the referent has been cleared 542 */ 543 private final int hash; 544 545 /** 546 * A key representing a null ProtectionDomain. 547 */ 548 private static final Key NULL_KEY = new Key(); 549 550 /** 551 * Create a new WeakProtectionDomain with the specified domain and 552 * registered with a queue. 553 */ 554 WeakProtectionDomainKey(ProtectionDomain pd, ReferenceQueue<Key> rq) { 555 this((pd == null ? NULL_KEY : pd.key), rq); 556 } 557 558 WeakProtectionDomainKey(ProtectionDomain pd) { 559 this(pd == null ? NULL_KEY : pd.key); 560 } 561 562 private WeakProtectionDomainKey(Key key, ReferenceQueue<Key> rq) { 563 super(key, rq); 564 hash = key.hashCode(); 565 } 566 567 private WeakProtectionDomainKey(Key key) { 568 super(key); 569 hash = key.hashCode(); 570 } 571 572 /** 573 * Returns the identity hash code of the original referent. 574 */ 575 @Override 576 public int hashCode() { 577 return hash; 578 } 579 580 /** 581 * Returns true if the given object is an identical 582 * WeakProtectionDomainKey instance, or, if this object's referent 583 * has not been cleared and the given object is another 584 * WeakProtectionDomainKey instance with an identical non-null 585 * referent as this one. 586 */ 587 @Override 588 public boolean equals(Object obj) { 589 if (obj == this) { 590 return true; 591 } 592 593 if (obj instanceof WeakProtectionDomainKey) { 594 Object referent = get(); 595 return (referent != null) && 596 (referent == ((WeakProtectionDomainKey)obj).get()); 597 } else { 598 return false; 599 } 600 } 601 } 602 }