Showing the changes to java/pkg/java/security/ProtectionDomain.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,467 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2011, 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.util.ArrayList; | |
| 29 | +import java.util.Collections; | |
| 30 | +import java.util.Enumeration; | |
| 31 | +import java.util.List; | |
| 32 | +import java.util.Map; | |
| 33 | +import java.util.WeakHashMap; | |
| 34 | +import sun.misc.JavaSecurityProtectionDomainAccess; | |
| 35 | +import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache; | |
| 36 | +import sun.misc.SharedSecrets; | |
| 37 | +import sun.security.util.Debug; | |
| 38 | +import sun.security.util.SecurityConstants; | |
| 39 | +import sun.misc.JavaSecurityAccess; | |
| 40 | +import sun.misc.SharedSecrets; | |
| 41 | + | |
| 42 | +/** | |
| 43 | + * | |
| 44 | + *<p> | |
| 45 | + * This 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 | + * <p> | |
| 56 | + * | |
| 57 | + * @author Li Gong | |
| 58 | + * @author Roland Schemers | |
| 59 | + * @author Gary Ellison | |
| 60 | + */ | |
| 61 | + | |
| 62 | +public class ProtectionDomain { | |
| 63 | + | |
| 64 | + static { | |
| 65 | + // Set up JavaSecurityAccess in SharedSecrets | |
| 66 | + SharedSecrets.setJavaSecurityAccess( | |
| 67 | + new JavaSecurityAccess() { | |
| 68 | + public <T> T doIntersectionPrivilege( | |
| 69 | + PrivilegedAction<T> action, | |
| 70 | + final AccessControlContext stack, | |
| 71 | + final AccessControlContext context) | |
| 72 | + { | |
| 73 | + if (action == null) { | |
| 74 | + throw new NullPointerException(); | |
| 75 | + } | |
| 76 | + return AccessController.doPrivileged( | |
| 77 | + action, | |
| 78 | + new AccessControlContext( | |
| 79 | + stack.getContext(), context).optimize() | |
| 80 | + ); | |
| 81 | + } | |
| 82 | + | |
| 83 | + public <T> T doIntersectionPrivilege( | |
| 84 | + PrivilegedAction<T> action, | |
| 85 | + AccessControlContext context) | |
| 86 | + { | |
| 87 | + return doIntersectionPrivilege(action, | |
| 88 | + AccessController.getContext(), context); | |
| 89 | + } | |
| 90 | + } | |
| 91 | + ); | |
| 92 | + } | |
| 93 | + | |
| 94 | + /* CodeSource */ | |
| 95 | + private CodeSource codesource ; | |
| 96 | + | |
| 97 | + /* ClassLoader the protection domain was consed from */ | |
| 98 | + private ClassLoader classloader; | |
| 99 | + | |
| 100 | + /* Principals running-as within this protection domain */ | |
| 101 | + private Principal[] principals; | |
| 102 | + | |
| 103 | + /* the rights this protection domain is granted */ | |
| 104 | + private PermissionCollection permissions; | |
| 105 | + | |
| 106 | + /* if the permissions object has AllPermission */ | |
| 107 | + private boolean hasAllPerm = false; | |
| 108 | + | |
| 109 | + /* the PermissionCollection is static (pre 1.4 constructor) | |
| 110 | + or dynamic (via a policy refresh) */ | |
| 111 | + private boolean staticPermissions; | |
| 112 | + | |
| 113 | + /* | |
| 114 | + * An object used as a key when the ProtectionDomain is stored in a Map. | |
| 115 | + */ | |
| 116 | + final Key key = new Key(); | |
| 117 | + | |
| 118 | + private static final Debug debug = Debug.getInstance("domain"); | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Creates a new ProtectionDomain with the given CodeSource and | |
| 122 | + * Permissions. If the permissions object is not null, then | |
| 123 | + * <code>setReadOnly())</code> will be called on the passed in | |
| 124 | + * Permissions object. The only permissions granted to this domain | |
| 125 | + * are the ones specified; the current Policy will not be consulted. | |
| 126 | + * | |
| 127 | + * @param codesource the codesource associated with this domain | |
| 128 | + * @param permissions the permissions granted to this domain | |
| 129 | + */ | |
| 130 | + public ProtectionDomain(CodeSource codesource, | |
| 131 | + PermissionCollection permissions) { | |
| 132 | + this.codesource = codesource; | |
| 133 | + if (permissions != null) { | |
| 134 | + this.permissions = permissions; | |
| 135 | + this.permissions.setReadOnly(); | |
| 136 | + if (permissions instanceof Permissions && | |
| 137 | + ((Permissions)permissions).allPermission != null) { | |
| 138 | + hasAllPerm = true; | |
| 139 | + } | |
| 140 | + } | |
| 141 | + this.classloader = null; | |
| 142 | + this.principals = new Principal[0]; | |
| 143 | + staticPermissions = true; | |
| 144 | + } | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * Creates a new ProtectionDomain qualified by the given CodeSource, | |
| 148 | + * Permissions, ClassLoader and array of Principals. If the | |
| 149 | + * permissions object is not null, then <code>setReadOnly()</code> | |
| 150 | + * will be called on the passed in Permissions object. | |
| 151 | + * The permissions granted to this domain are dynamic; they include | |
| 152 | + * both the static permissions passed to this constructor, and any | |
| 153 | + * permissions granted to this domain by the current Policy at the | |
| 154 | + * time a permission is checked. | |
| 155 | + * <p> | |
| 156 | + * This constructor is typically used by | |
| 157 | + * {@link SecureClassLoader ClassLoaders} | |
| 158 | + * and {@link DomainCombiner DomainCombiners} which delegate to | |
| 159 | + * <code>Policy</code> to actively associate the permissions granted to | |
| 160 | + * this domain. This constructor affords the | |
| 161 | + * Policy provider the opportunity to augment the supplied | |
| 162 | + * PermissionCollection to reflect policy changes. | |
| 163 | + * <p> | |
| 164 | + * | |
| 165 | + * @param codesource the CodeSource associated with this domain | |
| 166 | + * @param permissions the permissions granted to this domain | |
| 167 | + * @param classloader the ClassLoader associated with this domain | |
| 168 | + * @param principals the array of Principals associated with this | |
| 169 | + * domain. The contents of the array are copied to protect against | |
| 170 | + * subsequent modification. | |
| 171 | + * @see Policy#refresh | |
| 172 | + * @see Policy#getPermissions(ProtectionDomain) | |
| 173 | + * @since 1.4 | |
| 174 | + */ | |
| 175 | + public ProtectionDomain(CodeSource codesource, | |
| 176 | + PermissionCollection permissions, | |
| 177 | + ClassLoader classloader, | |
| 178 | + Principal[] principals) { | |
| 179 | + this.codesource = codesource; | |
| 180 | + if (permissions != null) { | |
| 181 | + this.permissions = permissions; | |
| 182 | + this.permissions.setReadOnly(); | |
| 183 | + if (permissions instanceof Permissions && | |
| 184 | + ((Permissions)permissions).allPermission != null) { | |
| 185 | + hasAllPerm = true; | |
| 186 | + } | |
| 187 | + } | |
| 188 | + this.classloader = classloader; | |
| 189 | + this.principals = (principals != null ? principals.clone(): | |
| 190 | + new Principal[0]); | |
| 191 | + staticPermissions = false; | |
| 192 | + } | |
| 193 | + | |
| 194 | + /** | |
| 195 | + * Returns the CodeSource of this domain. | |
| 196 | + * @return the CodeSource of this domain which may be null. | |
| 197 | + * @since 1.2 | |
| 198 | + */ | |
| 199 | + public final CodeSource getCodeSource() { | |
| 200 | + return this.codesource; | |
| 201 | + } | |
| 202 | + | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Returns the ClassLoader of this domain. | |
| 206 | + * @return the ClassLoader of this domain which may be null. | |
| 207 | + * | |
| 208 | + * @since 1.4 | |
| 209 | + */ | |
| 210 | + public final ClassLoader getClassLoader() { | |
| 211 | + return this.classloader; | |
| 212 | + } | |
| 213 | + | |
| 214 | + | |
| 215 | + /** | |
| 216 | + * Returns an array of principals for this domain. | |
| 217 | + * @return a non-null array of principals for this domain. | |
| 218 | + * Returns a new array each time this method is called. | |
| 219 | + * | |
| 220 | + * @since 1.4 | |
| 221 | + */ | |
| 222 | + public final Principal[] getPrincipals() { | |
| 223 | + return this.principals.clone(); | |
| 224 | + } | |
| 225 | + | |
| 226 | + /** | |
| 227 | + * Returns the static permissions granted to this domain. | |
| 228 | + * | |
| 229 | + * @return the static set of permissions for this domain which may be null. | |
| 230 | + * @see Policy#refresh | |
| 231 | + * @see Policy#getPermissions(ProtectionDomain) | |
| 232 | + */ | |
| 233 | + public final PermissionCollection getPermissions() { | |
| 234 | + return permissions; | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** | |
| 238 | + * Check and see if this ProtectionDomain implies the permissions | |
| 239 | + * expressed in the Permission object. | |
| 240 | + * <p> | |
| 241 | + * The set of permissions evaluated is a function of whether the | |
| 242 | + * ProtectionDomain was constructed with a static set of permissions | |
| 243 | + * or it was bound to a dynamically mapped set of permissions. | |
| 244 | + * <p> | |
| 245 | + * If the ProtectionDomain was constructed to a | |
| 246 | + * {@link #ProtectionDomain(CodeSource, PermissionCollection) | |
| 247 | + * statically bound} PermissionCollection then the permission will | |
| 248 | + * only be checked against the PermissionCollection supplied at | |
| 249 | + * construction. | |
| 250 | + * <p> | |
| 251 | + * However, if the ProtectionDomain was constructed with | |
| 252 | + * the constructor variant which supports | |
| 253 | + * {@link #ProtectionDomain(CodeSource, PermissionCollection, | |
| 254 | + * ClassLoader, java.security.Principal[]) dynamically binding} | |
| 255 | + * permissions, then the permission will be checked against the | |
| 256 | + * combination of the PermissionCollection supplied at construction and | |
| 257 | + * the current Policy binding. | |
| 258 | + * <p> | |
| 259 | + * | |
| 260 | + * @param permission the Permission object to check. | |
| 261 | + * | |
| 262 | + * @return true if "permission" is implicit to this ProtectionDomain. | |
| 263 | + */ | |
| 264 | + public boolean implies(Permission permission) { | |
| 265 | + | |
| 266 | + if (hasAllPerm) { | |
| 267 | + // internal permission collection already has AllPermission - | |
| 268 | + // no need to go to policy | |
| 269 | + return true; | |
| 270 | + } | |
| 271 | + | |
| 272 | + if (!staticPermissions && | |
| 273 | + Policy.getPolicyNoCheck().implies(this, permission)) | |
| 274 | + return true; | |
| 275 | + if (permissions != null) | |
| 276 | + return permissions.implies(permission); | |
| 277 | + | |
| 278 | + return false; | |
| 279 | + } | |
| 280 | + | |
| 281 | + /** | |
| 282 | + * Convert a ProtectionDomain to a String. | |
| 283 | + */ | |
| 284 | + @Override public String toString() { | |
| 285 | + String pals = "<no principals>"; | |
| 286 | + if (principals != null && principals.length > 0) { | |
| 287 | + StringBuilder palBuf = new StringBuilder("(principals "); | |
| 288 | + | |
| 289 | + for (int i = 0; i < principals.length; i++) { | |
| 290 | + palBuf.append(principals[i].getClass().getName() + | |
| 291 | + " \"" + principals[i].getName() + | |
| 292 | + "\""); | |
| 293 | + if (i < principals.length-1) | |
| 294 | + palBuf.append(",\n"); | |
| 295 | + else | |
| 296 | + palBuf.append(")\n"); | |
| 297 | + } | |
| 298 | + pals = palBuf.toString(); | |
| 299 | + } | |
| 300 | + | |
| 301 | + // Check if policy is set; we don't want to load | |
| 302 | + // the policy prematurely here | |
| 303 | + PermissionCollection pc = Policy.isSet() && seeAllp() ? | |
| 304 | + mergePermissions(): | |
| 305 | + getPermissions(); | |
| 306 | + | |
| 307 | + return "ProtectionDomain "+ | |
| 308 | + " "+codesource+"\n"+ | |
| 309 | + " "+classloader+"\n"+ | |
| 310 | + " "+pals+"\n"+ | |
| 311 | + " "+pc+"\n"; | |
| 312 | + } | |
| 313 | + | |
| 314 | + /** | |
| 315 | + * Return true (merge policy permissions) in the following cases: | |
| 316 | + * | |
| 317 | + * . SecurityManager is null | |
| 318 | + * | |
| 319 | + * . SecurityManager is not null, | |
| 320 | + * debug is not null, | |
| 321 | + * SecurityManager impelmentation is in bootclasspath, | |
| 322 | + * Policy implementation is in bootclasspath | |
| 323 | + * (the bootclasspath restrictions avoid recursion) | |
| 324 | + * | |
| 325 | + * . SecurityManager is not null, | |
| 326 | + * debug is null, | |
| 327 | + * caller has Policy.getPolicy permission | |
| 328 | + */ | |
| 329 | + private static boolean seeAllp() { | |
| 330 | + SecurityManager sm = System.getSecurityManager(); | |
| 331 | + | |
| 332 | + if (sm == null) { | |
| 333 | + return true; | |
| 334 | + } else { | |
| 335 | + if (debug != null) { | |
| 336 | + if (sm.getClass().getClassLoader() == null && | |
| 337 | + Policy.getPolicyNoCheck().getClass().getClassLoader() | |
| 338 | + == null) { | |
| 339 | + return true; | |
| 340 | + } | |
| 341 | + } else { | |
| 342 | + try { | |
| 343 | + sm.checkPermission(SecurityConstants.GET_POLICY_PERMISSION); | |
| 344 | + return true; | |
| 345 | + } catch (SecurityException se) { | |
| 346 | + // fall thru and return false | |
| 347 | + } | |
| 348 | + } | |
| 349 | + } | |
| 350 | + | |
| 351 | + return false; | |
| 352 | + } | |
| 353 | + | |
| 354 | + private PermissionCollection mergePermissions() { | |
| 355 | + if (staticPermissions) | |
| 356 | + return permissions; | |
| 357 | + | |
| 358 | + PermissionCollection perms = | |
| 359 | + java.security.AccessController.doPrivileged | |
| 360 | + (new java.security.PrivilegedAction<PermissionCollection>() { | |
| 361 | + public PermissionCollection run() { | |
| 362 | + Policy p = Policy.getPolicyNoCheck(); | |
| 363 | + return p.getPermissions(ProtectionDomain.this); | |
| 364 | + } | |
| 365 | + }); | |
| 366 | + | |
| 367 | + Permissions mergedPerms = new Permissions(); | |
| 368 | + int swag = 32; | |
| 369 | + int vcap = 8; | |
| 370 | + Enumeration<Permission> e; | |
| 371 | + List<Permission> pdVector = new ArrayList<>(vcap); | |
| 372 | + List<Permission> plVector = new ArrayList<>(swag); | |
| 373 | + | |
| 374 | + // | |
| 375 | + // Build a vector of domain permissions for subsequent merge | |
| 376 | + if (permissions != null) { | |
| 377 | + synchronized (permissions) { | |
| 378 | + e = permissions.elements(); | |
| 379 | + while (e.hasMoreElements()) { | |
| 380 | + pdVector.add(e.nextElement()); | |
| 381 | + } | |
| 382 | + } | |
| 383 | + } | |
| 384 | + | |
| 385 | + // | |
| 386 | + // Build a vector of Policy permissions for subsequent merge | |
| 387 | + if (perms != null) { | |
| 388 | + synchronized (perms) { | |
| 389 | + e = perms.elements(); | |
| 390 | + while (e.hasMoreElements()) { | |
| 391 | + plVector.add(e.nextElement()); | |
| 392 | + vcap++; | |
| 393 | + } | |
| 394 | + } | |
| 395 | + } | |
| 396 | + | |
| 397 | + if (perms != null && permissions != null) { | |
| 398 | + // | |
| 399 | + // Weed out the duplicates from the policy. Unless a refresh | |
| 400 | + // has occured since the pd was consed this should result in | |
| 401 | + // an empty vector. | |
| 402 | + synchronized (permissions) { | |
| 403 | + e = permissions.elements(); // domain vs policy | |
| 404 | + while (e.hasMoreElements()) { | |
| 405 | + Permission pdp = e.nextElement(); | |
| 406 | + Class pdpClass = pdp.getClass(); | |
| 407 | + String pdpActions = pdp.getActions(); | |
| 408 | + String pdpName = pdp.getName(); | |
| 409 | + for (int i = 0; i < plVector.size(); i++) { | |
| 410 | + Permission pp = plVector.get(i); | |
| 411 | + if (pdpClass.isInstance(pp)) { | |
| 412 | + // The equals() method on some permissions | |
| 413 | + // have some side effects so this manual | |
| 414 | + // comparison is sufficient. | |
| 415 | + if (pdpName.equals(pp.getName()) && | |
| 416 | + pdpActions.equals(pp.getActions())) { | |
| 417 | + plVector.remove(i); | |
| 418 | + break; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + } | |
| 422 | + } | |
| 423 | + } | |
| 424 | + } | |
| 425 | + | |
| 426 | + if (perms !=null) { | |
| 427 | + // the order of adding to merged perms and permissions | |
| 428 | + // needs to preserve the bugfix 4301064 | |
| 429 | + | |
| 430 | + for (int i = plVector.size()-1; i >= 0; i--) { | |
| 431 | + mergedPerms.add(plVector.get(i)); | |
| 432 | + } | |
| 433 | + } | |
| 434 | + if (permissions != null) { | |
| 435 | + for (int i = pdVector.size()-1; i >= 0; i--) { | |
| 436 | + mergedPerms.add(pdVector.get(i)); | |
| 437 | + } | |
| 438 | + } | |
| 439 | + | |
| 440 | + return mergedPerms; | |
| 441 | + } | |
| 442 | + | |
| 443 | + /** | |
| 444 | + * Used for storing ProtectionDomains as keys in a Map. | |
| 445 | + */ | |
| 446 | + final class Key {} | |
| 447 | + | |
| 448 | + static { | |
| 449 | + SharedSecrets.setJavaSecurityProtectionDomainAccess( | |
| 450 | + new JavaSecurityProtectionDomainAccess() { | |
| 451 | + public ProtectionDomainCache getProtectionDomainCache() { | |
| 452 | + return new ProtectionDomainCache() { | |
| 453 | + private final Map<Key, PermissionCollection> map = | |
| 454 | + Collections.synchronizedMap | |
| 455 | + (new WeakHashMap<Key, PermissionCollection>()); | |
| 456 | + public void put(ProtectionDomain pd, | |
| 457 | + PermissionCollection pc) { | |
| 458 | + map.put((pd == null ? null : pd.key), pc); | |
| 459 | + } | |
| 460 | + public PermissionCollection get(ProtectionDomain pd) { | |
| 461 | + return pd == null ? map.get(null) : map.get(pd.key); | |
| 462 | + } | |
| 463 | + }; | |
| 464 | + } | |
| 465 | + }); | |
| 466 | + } | |
| 467 | +} | |