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 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. The only permissions granted to this domain 147 * are the ones specified; the current Policy will not be consulted. 148 * 149 * @param codesource the codesource associated with this domain 150 * @param permissions the permissions granted to this domain 151 */ 152 public ProtectionDomain(CodeSource codesource, 153 PermissionCollection permissions) { 154 this.codesource = codesource; 155 if (permissions != null) { 156 this.permissions = permissions; 157 this.permissions.setReadOnly(); 158 if (permissions instanceof Permissions && 159 ((Permissions)permissions).allPermission != null) { 160 hasAllPerm = true; 161 } 162 } 163 this.classloader = null; 164 this.principals = new Principal[0]; 165 staticPermissions = true; 166 } 167 168 /** 169 * Creates a new ProtectionDomain qualified by the given CodeSource, 170 * Permissions, ClassLoader and array of Principals. If the 171 * permissions object is not null, then {@code setReadOnly()} 172 * will be called on the passed in Permissions object. 173 * The permissions granted to this domain are dynamic; they include 174 * both the static permissions passed to this constructor, and any 175 * permissions granted to this domain by the current Policy at the 176 * time a permission is checked. 177 * <p> 178 * This constructor is typically used by 179 * {@link SecureClassLoader ClassLoaders} 180 * and {@link DomainCombiner DomainCombiners} which delegate to 181 * {@code Policy} to actively associate the permissions granted to 182 * this domain. This constructor affords the 183 * Policy provider the opportunity to augment the supplied 184 * PermissionCollection to reflect policy changes. 185 * 186 * @param codesource the CodeSource associated with this domain 187 * @param permissions the permissions granted to this domain 188 * @param classloader the ClassLoader associated with this domain 189 * @param principals the array of Principals associated with this 190 * domain. The contents of the array are copied to protect against 191 * subsequent modification. 192 * @see Policy#refresh 193 * @see Policy#getPermissions(ProtectionDomain) 194 * @since 1.4 195 */ 196 public ProtectionDomain(CodeSource codesource, 197 PermissionCollection permissions, 198 ClassLoader classloader, 199 Principal[] principals) { 200 this.codesource = codesource; 201 if (permissions != null) { 202 this.permissions = permissions; 203 this.permissions.setReadOnly(); 204 if (permissions instanceof Permissions && 205 ((Permissions)permissions).allPermission != null) { 206 hasAllPerm = true; 207 } 208 } 209 this.classloader = classloader; 210 this.principals = (principals != null ? principals.clone(): 211 new Principal[0]); 212 staticPermissions = false; 213 } 214 215 /** 216 * Returns the CodeSource of this domain. 217 * @return the CodeSource of this domain which may be null. 218 * @since 1.2 219 */ 220 public final CodeSource getCodeSource() { 221 return this.codesource; 222 } 223 224 225 /** 226 * Returns the ClassLoader of this domain. 227 * @return the ClassLoader of this domain which may be null. 228 * 229 * @since 1.4 230 */ 231 public final ClassLoader getClassLoader() { 232 return this.classloader; 233 } 234 235 236 /** 237 * Returns an array of principals for this domain. 238 * @return a non-null array of principals for this domain. 239 * Returns a new array each time this method is called. 240 * 241 * @since 1.4 242 */ 243 public final Principal[] getPrincipals() { 244 return this.principals.clone(); 245 } 246 247 /** 248 * Returns the static permissions granted to this domain. 249 * 250 * @return the static set of permissions for this domain which may be null. 251 * @see Policy#refresh 252 * @see Policy#getPermissions(ProtectionDomain) 253 */ 254 public final PermissionCollection getPermissions() { 255 return permissions; 256 } 257 258 /** 259 * Check and see if this ProtectionDomain implies the permissions 260 * expressed in the Permission object. 261 * <p> 262 * The set of permissions evaluated is a function of whether the 263 * ProtectionDomain was constructed with a static set of permissions 264 * or it was bound to a dynamically mapped set of permissions. 265 * <p> 266 * If the ProtectionDomain was constructed to a 267 * {@link #ProtectionDomain(CodeSource, PermissionCollection) 268 * statically bound} PermissionCollection then the permission will 269 * only be checked against the PermissionCollection supplied at 270 * construction. 271 * <p> 272 * However, if the ProtectionDomain was constructed with 273 * the constructor variant which supports 274 * {@link #ProtectionDomain(CodeSource, PermissionCollection, 275 * ClassLoader, java.security.Principal[]) dynamically binding} 276 * permissions, then the permission will be checked against the 277 * combination of the PermissionCollection supplied at construction and 278 * the current Policy binding. 279 * 280 * @param permission the Permission object to check. 281 * 282 * @return true if "permission" is implicit to this ProtectionDomain. 283 */ 284 public boolean implies(Permission permission) { 285 286 if (hasAllPerm) { 287 // internal permission collection already has AllPermission - 288 // no need to go to policy 289 return true; 290 } 291 292 if (!staticPermissions && 293 Policy.getPolicyNoCheck().implies(this, permission)) 294 return true; 295 if (permissions != null) 296 return permissions.implies(permission); 297 298 return false; 299 } 300 301 // called by the VM -- do not remove 302 boolean impliesCreateAccessControlContext() { 303 return implies(SecurityConstants.CREATE_ACC_PERMISSION); 304 } 305 306 /** 307 * Convert a ProtectionDomain to a String. 308 */ 309 @Override public String toString() { 310 String pals = "<no principals>"; 311 if (principals != null && principals.length > 0) { 312 StringBuilder palBuf = new StringBuilder("(principals "); 313 314 for (int i = 0; i < principals.length; i++) { 315 palBuf.append(principals[i].getClass().getName() + 316 " \"" + principals[i].getName() + 317 "\""); 318 if (i < principals.length-1) 319 palBuf.append(",\n"); 320 else 321 palBuf.append(")\n"); 322 } 323 pals = palBuf.toString(); 324 } 325 326 // Check if policy is set; we don't want to load 327 // the policy prematurely here 328 PermissionCollection pc = Policy.isSet() && seeAllp() ? 329 mergePermissions(): 330 getPermissions(); 331 332 return "ProtectionDomain "+ 333 " "+codesource+"\n"+ 334 " "+classloader+"\n"+ 335 " "+pals+"\n"+ 336 " "+pc+"\n"; 337 } 338 339 /* 340 * holder class for the static field "debug" to delay its initialization 341 */ 342 private static class DebugHolder { 343 private static final Debug debug = Debug.getInstance("domain"); 344 } 345 346 /** 347 * Return true (merge policy permissions) in the following cases: 348 * 349 * . SecurityManager is null 350 * 351 * . SecurityManager is not null, 352 * debug is not null, 353 * SecurityManager impelmentation is in bootclasspath, 354 * Policy implementation is in bootclasspath 355 * (the bootclasspath restrictions avoid recursion) 356 * 357 * . SecurityManager is not null, 358 * debug is null, 359 * caller has Policy.getPolicy permission 360 */ 361 private static boolean seeAllp() { 362 SecurityManager sm = System.getSecurityManager(); 363 364 if (sm == null) { 365 return true; 366 } else { 367 if (DebugHolder.debug != null) { 368 if (sm.getClass().getClassLoader() == null && 369 Policy.getPolicyNoCheck().getClass().getClassLoader() 370 == null) { 371 return true; 372 } 373 } else { 374 try { 375 sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION); 376 return true; 377 } catch (SecurityException se) { 378 // fall thru and return false 379 } 380 } 381 } 382 383 return false; 384 } 385 386 private PermissionCollection mergePermissions() { 387 if (staticPermissions) 388 return permissions; 389 390 PermissionCollection perms = 391 java.security.AccessController.doPrivileged 392 (new java.security.PrivilegedAction<>() { 393 public PermissionCollection run() { 394 Policy p = Policy.getPolicyNoCheck(); 395 return p.getPermissions(ProtectionDomain.this); 396 } 397 }); 398 399 Permissions mergedPerms = new Permissions(); 400 int swag = 32; 401 int vcap = 8; 402 Enumeration<Permission> e; 403 List<Permission> pdVector = new ArrayList<>(vcap); 404 List<Permission> plVector = new ArrayList<>(swag); 405 406 // 407 // Build a vector of domain permissions for subsequent merge 408 if (permissions != null) { 409 synchronized (permissions) { 410 e = permissions.elements(); 411 while (e.hasMoreElements()) { 412 pdVector.add(e.nextElement()); 413 } 414 } 415 } 416 417 // 418 // Build a vector of Policy permissions for subsequent merge 419 if (perms != null) { 420 synchronized (perms) { 421 e = perms.elements(); 422 while (e.hasMoreElements()) { 423 plVector.add(e.nextElement()); 424 vcap++; 425 } 426 } 427 } 428 429 if (perms != null && permissions != null) { 430 // 431 // Weed out the duplicates from the policy. Unless a refresh 432 // has occurred since the pd was consed this should result in 433 // an empty vector. 434 synchronized (permissions) { 435 e = permissions.elements(); // domain vs policy 436 while (e.hasMoreElements()) { 437 Permission pdp = e.nextElement(); 438 Class<?> pdpClass = pdp.getClass(); 439 String pdpActions = pdp.getActions(); 440 String pdpName = pdp.getName(); 441 for (int i = 0; i < plVector.size(); i++) { 442 Permission pp = plVector.get(i); 443 if (pdpClass.isInstance(pp)) { 444 // The equals() method on some permissions 445 // have some side effects so this manual 446 // comparison is sufficient. 447 if (pdpName.equals(pp.getName()) && 448 pdpActions.equals(pp.getActions())) { 449 plVector.remove(i); 450 break; 451 } 452 } 453 } 454 } 455 } 456 } 457 458 if (perms !=null) { 459 // the order of adding to merged perms and permissions 460 // needs to preserve the bugfix 4301064 461 462 for (int i = plVector.size()-1; i >= 0; i--) { 463 mergedPerms.add(plVector.get(i)); 464 } 465 } 466 if (permissions != null) { 467 for (int i = pdVector.size()-1; i >= 0; i--) { 468 mergedPerms.add(pdVector.get(i)); 469 } 470 } 471 472 return mergedPerms; 473 } 474 475 /** 476 * A cache of ProtectionDomains and their Permissions. 477 * 478 * This class stores ProtectionDomains as weak keys in a ConcurrentHashMap 479 * with additional support for checking and removing weak keys that are no 480 * longer in use. There can be cases where the permission collection may 481 * have a chain of strong references back to the ProtectionDomain, which 482 * ordinarily would prevent the entry from being removed from the map. To 483 * address that, we wrap the permission collection in a SoftReference so 484 * that it can be reclaimed by the garbage collector due to memory demand. 485 */ 486 private static class PDCache implements ProtectionDomainCache { 487 private final ConcurrentHashMap<WeakProtectionDomainKey, 488 SoftReference<PermissionCollection>> 489 pdMap = new ConcurrentHashMap<>(); 490 private final ReferenceQueue<Key> queue = new ReferenceQueue<>(); 491 492 @Override 493 public void put(ProtectionDomain pd, PermissionCollection pc) { 494 processQueue(queue, pdMap); 495 WeakProtectionDomainKey weakPd = 496 new WeakProtectionDomainKey(pd, queue); 497 pdMap.put(weakPd, new SoftReference<>(pc)); 498 } 499 500 @Override 501 public PermissionCollection get(ProtectionDomain pd) { 502 processQueue(queue, pdMap); 503 WeakProtectionDomainKey weakPd = new WeakProtectionDomainKey(pd); 504 SoftReference<PermissionCollection> sr = pdMap.get(weakPd); 505 return (sr == null) ? null : sr.get(); 506 } 507 508 /** 509 * Removes weak keys from the map that have been enqueued 510 * on the reference queue and are no longer in use. 511 */ 512 private static void processQueue(ReferenceQueue<Key> queue, 513 ConcurrentHashMap<? extends 514 WeakReference<Key>, ?> pdMap) { 515 Reference<? extends Key> ref; 516 while ((ref = queue.poll()) != null) { 517 pdMap.remove(ref); 518 } 519 } 520 } 521 522 /** 523 * A weak key for a ProtectionDomain. 524 */ 525 private static class WeakProtectionDomainKey extends WeakReference<Key> { 526 /** 527 * Saved value of the referent's identity hash code, to maintain 528 * a consistent hash code after the referent has been cleared 529 */ 530 private final int hash; 531 532 /** 533 * A key representing a null ProtectionDomain. 534 */ 535 private static final Key NULL_KEY = new Key(); 536 537 /** 538 * Create a new WeakProtectionDomain with the specified domain and 539 * registered with a queue. 540 */ 541 WeakProtectionDomainKey(ProtectionDomain pd, ReferenceQueue<Key> rq) { 542 this((pd == null ? NULL_KEY : pd.key), rq); 543 } 544 545 WeakProtectionDomainKey(ProtectionDomain pd) { 546 this(pd == null ? NULL_KEY : pd.key); 547 } 548 549 private WeakProtectionDomainKey(Key key, ReferenceQueue<Key> rq) { 550 super(key, rq); 551 hash = key.hashCode(); 552 } 553 554 private WeakProtectionDomainKey(Key key) { 555 super(key); 556 hash = key.hashCode(); 557 } 558 559 /** 560 * Returns the identity hash code of the original referent. 561 */ 562 @Override 563 public int hashCode() { 564 return hash; 565 } 566 567 /** 568 * Returns true if the given object is an identical 569 * WeakProtectionDomainKey instance, or, if this object's referent 570 * has not been cleared and the given object is another 571 * WeakProtectionDomainKey instance with an identical non-null 572 * referent as this one. 573 */ 574 @Override 575 public boolean equals(Object obj) { 576 if (obj == this) { 577 return true; 578 } 579 580 if (obj instanceof WeakProtectionDomainKey) { 581 Object referent = get(); 582 return (referent != null) && 583 (referent == ((WeakProtectionDomainKey)obj).get()); 584 } else { 585 return false; 586 } 587 } 588 } 589 } --- EOF ---