1 /* 2 * Copyright (c) 1998, 2024, 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 javax.security.auth; 27 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.io.ObjectOutputStream; 31 import java.io.ObjectStreamField; 32 import java.security.*; 33 import java.text.MessageFormat; 34 import java.util.*; 35 import java.util.concurrent.Callable; 36 import java.util.concurrent.CompletionException; 37 38 import jdk.internal.access.SharedSecrets; 39 import sun.security.util.ResourcesMgr; 40 41 /** 42 * <p> A {@code Subject} represents a grouping of related information 43 * for a single entity, such as a person. 44 * Such information includes the Subject's identities as well as 45 * its security-related attributes 46 * (passwords and cryptographic keys, for example). 47 * 48 * <p> Subjects may potentially have multiple identities. 49 * Each identity is represented as a {@code Principal} 50 * within the {@code Subject}. Principals simply bind names to a 51 * {@code Subject}. For example, a {@code Subject} that happens 52 * to be a person, Alice, might have two Principals: 53 * one which binds "Alice Bar", the name on her driver license, 54 * to the {@code Subject}, and another which binds, 55 * "999-99-9999", the number on her student identification card, 56 * to the {@code Subject}. Both Principals refer to the same 57 * {@code Subject} even though each has a different name. 58 * 59 * <p> A {@code Subject} may also own security-related attributes, 60 * which are referred to as credentials. 61 * Sensitive credentials that require special protection, such as 62 * private cryptographic keys, are stored within a private credential 63 * {@code Set}. Credentials intended to be shared, such as 64 * public key certificates or Kerberos server tickets are stored 65 * within a public credential {@code Set}. Different permissions 66 * are required to access and modify the different credential Sets. 67 * 68 * <p> To retrieve all the Principals associated with a {@code Subject}, 69 * invoke the {@code getPrincipals} method. To retrieve 70 * all the public or private credentials belonging to a {@code Subject}, 71 * invoke the {@code getPublicCredentials} method or 72 * {@code getPrivateCredentials} method, respectively. 73 * To modify the returned {@code Set} of Principals and credentials, 74 * use the methods defined in the {@code Set} class. 75 * For example: 76 * <pre> 77 * Subject subject; 78 * Principal principal; 79 * Object credential; 80 * 81 * // add a Principal and credential to the Subject 82 * subject.getPrincipals().add(principal); 83 * subject.getPublicCredentials().add(credential); 84 * </pre> 85 * 86 * <p> This {@code Subject} class implements {@code Serializable}. 87 * While the Principals associated with the {@code Subject} are serialized, 88 * the credentials associated with the {@code Subject} are not. 89 * Note that the {@code java.security.Principal} class 90 * does not implement {@code Serializable}. Therefore, all concrete 91 * {@code Principal} implementations associated with Subjects 92 * must implement {@code Serializable}. 93 * 94 * <h2>Deprecated Methods and Replacements</h2> 95 * 96 * <p> The following methods in this class for user-based authorization 97 * that are dependent on Security Manager APIs are deprecated for removal: 98 * <ul> 99 * <li>{@link #getSubject(AccessControlContext)} 100 * <li>{@link #doAs(Subject, PrivilegedAction)} 101 * <li>{@link #doAs(Subject, PrivilegedExceptionAction)} 102 * <li>{@link #doAsPrivileged(Subject, PrivilegedAction, AccessControlContext)} 103 * <li>{@link #doAsPrivileged(Subject, PrivilegedExceptionAction, AccessControlContext)} 104 * </ul> 105 * Methods {@link #current()} and {@link #callAs(Subject, Callable)} 106 * are replacements for these methods, where {@code current} 107 * is mostly equivalent to {@code getSubject(AccessController.getContext())} 108 * and {@code callAs} is similar to {@code doAs} except that the 109 * input type and exceptions thrown are slightly different. 110 * 111 * <p id="sm-allowed"><b>These methods behave differently depending on 112 * whether a security manager is 113 * {@linkplain SecurityManager##set-security-manager allowed or disallowed}</b>: 114 * <ul> 115 * <li>If a security manager is allowed, which means it is either already set 116 * or allowed to be set dynamically, a {@code Subject} object is associated 117 * with an {@code AccessControlContext} through a {@code doAs} or 118 * {@code callAs} call, and the subject can then be retrieved using the 119 * {@code getSubject(AccessControlContext)} or {@code current} method. 120 * <li>If a security manager is not allowed, which means it is not set and 121 * not allowed to be set dynamically, a {@code doAs} or {@code callAs} call 122 * binds a {@code Subject} object to the period of execution of an action, 123 * and the subject can be retrieved using the {@code current} method inside 124 * the action. This subject can be inherited by child threads if they are 125 * started and terminate within the execution of its parent thread using 126 * structured concurrency. 127 * </ul> 128 * 129 * @since 1.4 130 * @see java.security.Principal 131 * @see java.security.DomainCombiner 132 */ 133 public final class Subject implements java.io.Serializable { 134 135 @java.io.Serial 136 private static final long serialVersionUID = -8308522755600156056L; 137 138 /** 139 * A {@code Set} that provides a view of all of this 140 * Subject's Principals 141 * 142 * @serial Each element in this set is a 143 * {@code java.security.Principal}. 144 * The set is a {@code Subject.SecureSet}. 145 */ 146 @SuppressWarnings("serial") // Not statically typed as Serializable 147 Set<Principal> principals; 148 149 /** 150 * Sets that provide a view of all of this 151 * Subject's Credentials 152 */ 153 transient Set<Object> pubCredentials; 154 transient Set<Object> privCredentials; 155 156 /** 157 * Whether this Subject is read-only 158 * 159 * @serial 160 */ 161 private volatile boolean readOnly; 162 163 private static final int PRINCIPAL_SET = 1; 164 private static final int PUB_CREDENTIAL_SET = 2; 165 private static final int PRIV_CREDENTIAL_SET = 3; 166 167 private static final ProtectionDomain[] NULL_PD_ARRAY 168 = new ProtectionDomain[0]; 169 170 /** 171 * Create an instance of a {@code Subject} 172 * with an empty {@code Set} of Principals and empty 173 * Sets of public and private credentials. 174 * 175 * <p> The newly constructed Sets check whether this {@code Subject} 176 * has been set read-only before permitting subsequent modifications. 177 * The newly created Sets also prevent illegal modifications 178 * by ensuring that callers have sufficient permissions. These Sets 179 * also prohibit null elements, and attempts to add, query, or remove 180 * a null element will result in a {@code NullPointerException}. 181 * 182 * <p> To modify the Principals Set, the caller must have 183 * {@code AuthPermission("modifyPrincipals")}. 184 * To modify the public credential Set, the caller must have 185 * {@code AuthPermission("modifyPublicCredentials")}. 186 * To modify the private credential Set, the caller must have 187 * {@code AuthPermission("modifyPrivateCredentials")}. 188 */ 189 public Subject() { 190 191 this.principals = Collections.synchronizedSet 192 (new SecureSet<>(this, PRINCIPAL_SET)); 193 this.pubCredentials = Collections.synchronizedSet 194 (new SecureSet<>(this, PUB_CREDENTIAL_SET)); 195 this.privCredentials = Collections.synchronizedSet 196 (new SecureSet<>(this, PRIV_CREDENTIAL_SET)); 197 } 198 199 /** 200 * Create an instance of a {@code Subject} with 201 * Principals and credentials. 202 * 203 * <p> The Principals and credentials from the specified Sets 204 * are copied into newly constructed Sets. 205 * These newly created Sets check whether this {@code Subject} 206 * has been set read-only before permitting subsequent modifications. 207 * The newly created Sets also prevent illegal modifications 208 * by ensuring that callers have sufficient permissions. These Sets 209 * also prohibit null elements, and attempts to add, query, or remove 210 * a null element will result in a {@code NullPointerException}. 211 * 212 * <p> To modify the Principals Set, the caller must have 213 * {@code AuthPermission("modifyPrincipals")}. 214 * To modify the public credential Set, the caller must have 215 * {@code AuthPermission("modifyPublicCredentials")}. 216 * To modify the private credential Set, the caller must have 217 * {@code AuthPermission("modifyPrivateCredentials")}. 218 * 219 * @param readOnly true if the {@code Subject} is to be read-only, 220 * and false otherwise. 221 * 222 * @param principals the {@code Set} of Principals 223 * to be associated with this {@code Subject}. 224 * 225 * @param pubCredentials the {@code Set} of public credentials 226 * to be associated with this {@code Subject}. 227 * 228 * @param privCredentials the {@code Set} of private credentials 229 * to be associated with this {@code Subject}. 230 * 231 * @throws NullPointerException if the specified 232 * {@code principals}, {@code pubCredentials}, 233 * or {@code privCredentials} are {@code null}, 234 * or a null value exists within any of these three 235 * Sets. 236 */ 237 public Subject(boolean readOnly, Set<? extends Principal> principals, 238 Set<?> pubCredentials, Set<?> privCredentials) { 239 LinkedList<Principal> principalList 240 = collectionNullClean(principals); 241 LinkedList<Object> pubCredsList 242 = collectionNullClean(pubCredentials); 243 LinkedList<Object> privCredsList 244 = collectionNullClean(privCredentials); 245 246 this.principals = Collections.synchronizedSet( 247 new SecureSet<>(this, PRINCIPAL_SET, principalList)); 248 this.pubCredentials = Collections.synchronizedSet( 249 new SecureSet<>(this, PUB_CREDENTIAL_SET, pubCredsList)); 250 this.privCredentials = Collections.synchronizedSet( 251 new SecureSet<>(this, PRIV_CREDENTIAL_SET, privCredsList)); 252 this.readOnly = readOnly; 253 } 254 255 /** 256 * Set this {@code Subject} to be read-only. 257 * 258 * <p> Modifications (additions and removals) to this Subject's 259 * {@code Principal} {@code Set} and 260 * credential Sets will be disallowed. 261 * The {@code destroy} operation on this Subject's credentials will 262 * still be permitted. 263 * 264 * <p> Subsequent attempts to modify the Subject's {@code Principal} 265 * and credential Sets will result in an 266 * {@code IllegalStateException} being thrown. 267 * Also, once a {@code Subject} is read-only, 268 * it can not be reset to being writable again. 269 * 270 * @throws SecurityException if a security manager is installed and the 271 * caller does not have an 272 * {@link AuthPermission#AuthPermission(String) 273 * AuthPermission("setReadOnly")} permission to set this 274 * {@code Subject} to be read-only. 275 */ 276 public void setReadOnly() { 277 @SuppressWarnings("removal") 278 java.lang.SecurityManager sm = System.getSecurityManager(); 279 if (sm != null) { 280 sm.checkPermission(AuthPermissionHolder.SET_READ_ONLY_PERMISSION); 281 } 282 283 this.readOnly = true; 284 } 285 286 /** 287 * Query whether this {@code Subject} is read-only. 288 * 289 * @return true if this {@code Subject} is read-only, false otherwise. 290 */ 291 public boolean isReadOnly() { 292 return this.readOnly; 293 } 294 295 /** 296 * Get the {@code Subject} associated with the provided 297 * {@code AccessControlContext}. This method is intended to be used with 298 * a security manager. It throws an {@code UnsupportedOperationException} 299 * if a security manager is not allowed. 300 * 301 * <p> The {@code AccessControlContext} may contain many 302 * Subjects (from nested {@code doAs} calls). 303 * In this situation, the most recent {@code Subject} associated 304 * with the {@code AccessControlContext} is returned. 305 * 306 * @param acc the {@code AccessControlContext} from which to retrieve 307 * the {@code Subject}. 308 * 309 * @return the {@code Subject} associated with the provided 310 * {@code AccessControlContext}, or {@code null} 311 * if no {@code Subject} is associated 312 * with the provided {@code AccessControlContext}. 313 * 314 * @throws UnsupportedOperationException if a security manager is 315 * not allowed 316 * 317 * @throws SecurityException if a security manager is installed and the 318 * caller does not have an 319 * {@link AuthPermission#AuthPermission(String) 320 * AuthPermission("getSubject")} permission to get the 321 * {@code Subject}. 322 * 323 * @throws NullPointerException if the provided 324 * {@code AccessControlContext} is {@code null}. 325 * 326 * @deprecated This method depends on {@link AccessControlContext} 327 * which, in conjunction with 328 * {@linkplain SecurityManager the Security Manager}, is deprecated 329 * and subject to removal in a future release. However, 330 * obtaining a Subject is useful independent of the Security Manager. 331 * Thus, a replacement API named {@link #current()} has been added 332 * which can be used to obtain the current subject. 333 */ 334 @SuppressWarnings("removal") 335 @Deprecated(since="17", forRemoval=true) 336 public static Subject getSubject(final AccessControlContext acc) { 337 338 java.lang.SecurityManager sm = System.getSecurityManager(); 339 if (sm != null) { 340 sm.checkPermission(AuthPermissionHolder.GET_SUBJECT_PERMISSION); 341 } 342 343 Objects.requireNonNull(acc, ResourcesMgr.getString 344 ("invalid.null.AccessControlContext.provided")); 345 346 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 347 throw new UnsupportedOperationException( 348 "getSubject is supported only if a security manager is allowed"); 349 } else { 350 // return the Subject from the DomainCombiner of the provided context 351 return AccessController.doPrivileged 352 (new java.security.PrivilegedAction<>() { 353 public Subject run() { 354 DomainCombiner dc = acc.getDomainCombiner(); 355 if (!(dc instanceof SubjectDomainCombiner)) { 356 return null; 357 } 358 SubjectDomainCombiner sdc = (SubjectDomainCombiner) dc; 359 return sdc.getSubject(); 360 } 361 }); 362 } 363 } 364 365 private static final ScopedValue<Subject> SCOPED_SUBJECT = 366 ScopedValue.newInstance(); 367 368 /** 369 * Returns the current subject. 370 * 371 * <p> The current subject is installed by the {@link #callAs} method. 372 * When {@code callAs(subject, action)} is called, {@code action} is 373 * executed with {@code subject} as its current subject which can be 374 * retrieved by this method. After {@code action} is finished, the current 375 * subject is reset to its previous value. The current 376 * subject is {@code null} before the first call of {@code callAs()}. 377 * 378 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, this 379 * method is equivalent to calling {@link #getSubject} with the current 380 * {@code AccessControlContext}. 381 * 382 * <p> If a security manager is not allowed, this method returns the 383 * {@code Subject} bound to the period of the execution of the current 384 * thread. 385 * 386 * @return the current subject, or {@code null} if a current subject is 387 * not installed or the current subject is set to {@code null}. 388 * @see #callAs(Subject, Callable) 389 * @since 18 390 */ 391 @SuppressWarnings("removal") 392 public static Subject current() { 393 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 394 return SCOPED_SUBJECT.orElse(null); 395 } else { 396 return getSubject(AccessController.getContext()); 397 } 398 } 399 400 /** 401 * Executes a {@code Callable} with {@code subject} as the 402 * current subject. 403 * 404 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, 405 * this method first retrieves the current Thread's 406 * {@code AccessControlContext} via 407 * {@code AccessController.getContext}, 408 * and then instantiates a new {@code AccessControlContext} 409 * using the retrieved context along with a new 410 * {@code SubjectDomainCombiner} (constructed using 411 * the provided {@code Subject}). 412 * Finally, this method invokes {@code AccessController.doPrivileged}, 413 * passing it the provided {@code PrivilegedAction}, 414 * as well as the newly constructed {@code AccessControlContext}. 415 * 416 * <p> If a security manager is not allowed, 417 * this method launches {@code action} and binds {@code subject} to the 418 * period of its execution. 419 * 420 * @param subject the {@code Subject} that the specified {@code action} 421 * will run as. This parameter may be {@code null}. 422 * @param action the code to be run with {@code subject} as its current 423 * subject. Must not be {@code null}. 424 * @param <T> the type of value returned by the {@code call} method 425 * of {@code action} 426 * @return the value returned by the {@code call} method of {@code action} 427 * @throws NullPointerException if {@code action} is {@code null} 428 * @throws CompletionException if {@code action.call()} throws an exception. 429 * The cause of the {@code CompletionException} is set to the exception 430 * thrown by {@code action.call()}. 431 * @see #current() 432 * @since 18 433 */ 434 public static <T> T callAs(final Subject subject, 435 final Callable<T> action) throws CompletionException { 436 Objects.requireNonNull(action); 437 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 438 try { 439 return ScopedValue.where(SCOPED_SUBJECT, subject).call(action::call); 440 } catch (Exception e) { 441 throw new CompletionException(e); 442 } 443 } else { 444 try { 445 PrivilegedExceptionAction<T> pa = () -> action.call(); 446 @SuppressWarnings("removal") 447 var result = doAs(subject, pa); 448 return result; 449 } catch (PrivilegedActionException e) { 450 throw new CompletionException(e.getCause()); 451 } catch (Exception e) { 452 throw new CompletionException(e); 453 } 454 } 455 } 456 457 /** 458 * Perform work as a particular {@code Subject}. 459 * 460 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, 461 * this method first retrieves the current Thread's 462 * {@code AccessControlContext} via 463 * {@code AccessController.getContext}, 464 * and then instantiates a new {@code AccessControlContext} 465 * using the retrieved context along with a new 466 * {@code SubjectDomainCombiner} (constructed using 467 * the provided {@code Subject}). 468 * Finally, this method invokes {@code AccessController.doPrivileged}, 469 * passing it the provided {@code PrivilegedAction}, 470 * as well as the newly constructed {@code AccessControlContext}. 471 * 472 * <p> If a security manager is not allowed, 473 * this method launches {@code action} and binds {@code subject} to the 474 * period of its execution. 475 * 476 * @param subject the {@code Subject} that the specified 477 * {@code action} will run as. This parameter 478 * may be {@code null}. 479 * 480 * @param <T> the type of the value returned by the PrivilegedAction's 481 * {@code run} method. 482 * 483 * @param action the code to be run as the specified 484 * {@code Subject}. 485 * 486 * @return the value returned by the PrivilegedAction's 487 * {@code run} method. 488 * 489 * @throws NullPointerException if the {@code PrivilegedAction} 490 * is {@code null}. 491 * 492 * @throws SecurityException if a security manager is installed and the 493 * caller does not have an 494 * {@link AuthPermission#AuthPermission(String) 495 * AuthPermission("doAs")} permission to invoke this 496 * method. 497 * 498 * @deprecated This method depends on {@link AccessControlContext} 499 * which, in conjunction with 500 * {@linkplain SecurityManager the Security Manager}, is deprecated 501 * and subject to removal in a future release. However, performing 502 * work as a Subject is useful independent of the Security Manager. 503 * Thus, a replacement API named {@link #callAs} has been added 504 * which can be used to perform the same work. 505 */ 506 @SuppressWarnings("removal") 507 @Deprecated(since="18", forRemoval=true) 508 public static <T> T doAs(final Subject subject, 509 final java.security.PrivilegedAction<T> action) { 510 511 java.lang.SecurityManager sm = System.getSecurityManager(); 512 if (sm != null) { 513 sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION); 514 } 515 516 Objects.requireNonNull(action, 517 ResourcesMgr.getString("invalid.null.action.provided")); 518 519 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 520 try { 521 return callAs(subject, action::run); 522 } catch (CompletionException ce) { 523 var cause = ce.getCause(); 524 if (cause instanceof RuntimeException re) { 525 throw re; 526 } else if (cause instanceof Error er) { 527 throw er; 528 } else { 529 throw new AssertionError(ce); 530 } 531 } 532 } else { 533 // set up the new Subject-based AccessControlContext 534 // for doPrivileged 535 final AccessControlContext currentAcc = AccessController.getContext(); 536 537 // call doPrivileged and push this new context on the stack 538 return java.security.AccessController.doPrivileged 539 (action, 540 createContext(subject, currentAcc)); 541 } 542 } 543 544 /** 545 * Perform work as a particular {@code Subject}. 546 * 547 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, 548 * this method first retrieves the current Thread's 549 * {@code AccessControlContext} via 550 * {@code AccessController.getContext}, 551 * and then instantiates a new {@code AccessControlContext} 552 * using the retrieved context along with a new 553 * {@code SubjectDomainCombiner} (constructed using 554 * the provided {@code Subject}). 555 * Finally, this method invokes {@code AccessController.doPrivileged}, 556 * passing it the provided {@code PrivilegedExceptionAction}, 557 * as well as the newly constructed {@code AccessControlContext}. 558 * 559 * <p> If a security manager is not allowed, 560 * this method launches {@code action} and binds {@code subject} to the 561 * period of its execution. 562 563 * @param subject the {@code Subject} that the specified 564 * {@code action} will run as. This parameter 565 * may be {@code null}. 566 * 567 * @param <T> the type of the value returned by the 568 * PrivilegedExceptionAction's {@code run} method. 569 * 570 * @param action the code to be run as the specified 571 * {@code Subject}. 572 * 573 * @return the value returned by the 574 * PrivilegedExceptionAction's {@code run} method. 575 * 576 * @throws PrivilegedActionException if the 577 * {@code PrivilegedExceptionAction.run} 578 * method throws a checked exception. 579 * 580 * @throws NullPointerException if the specified 581 * {@code PrivilegedExceptionAction} is 582 * {@code null}. 583 * 584 * @throws SecurityException if a security manager is installed and the 585 * caller does not have an 586 * {@link AuthPermission#AuthPermission(String) 587 * AuthPermission("doAs")} permission to invoke this 588 * method. 589 * 590 * @deprecated This method depends on {@link AccessControlContext} 591 * which, in conjunction with 592 * {@linkplain SecurityManager the Security Manager}, is deprecated 593 * and subject to removal in a future release. However, performing 594 * work as a Subject is useful independent of the Security Manager. 595 * Thus, a replacement API named {@link #callAs} has been added 596 * which can be used to perform the same work. 597 */ 598 @SuppressWarnings("removal") 599 @Deprecated(since="18", forRemoval=true) 600 public static <T> T doAs(final Subject subject, 601 final java.security.PrivilegedExceptionAction<T> action) 602 throws java.security.PrivilegedActionException { 603 604 java.lang.SecurityManager sm = System.getSecurityManager(); 605 if (sm != null) { 606 sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION); 607 } 608 609 Objects.requireNonNull(action, 610 ResourcesMgr.getString("invalid.null.action.provided")); 611 612 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 613 try { 614 return callAs(subject, action::run); 615 } catch (CompletionException ce) { 616 var cause = ce.getCause(); 617 if (cause instanceof RuntimeException re) { 618 throw re; 619 } else if (cause instanceof Error er) { 620 throw er; 621 } else if (cause instanceof Exception e) { 622 throw new PrivilegedActionException(e); 623 } else { 624 throw new PrivilegedActionException(ce); 625 } 626 } 627 } else { 628 // set up the new Subject-based AccessControlContext for doPrivileged 629 final AccessControlContext currentAcc = AccessController.getContext(); 630 631 // call doPrivileged and push this new context on the stack 632 return java.security.AccessController.doPrivileged 633 (action, 634 createContext(subject, currentAcc)); 635 } 636 } 637 638 /** 639 * Perform privileged work as a particular {@code Subject}. 640 * 641 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, 642 * this method behaves exactly as {@code Subject.doAs}, 643 * except that instead of retrieving the current Thread's 644 * {@code AccessControlContext}, it uses the provided 645 * {@code AccessControlContext}. If the provided 646 * {@code AccessControlContext} is {@code null}, 647 * this method instantiates a new {@code AccessControlContext} 648 * with an empty collection of ProtectionDomains. 649 * 650 * <p> If a security manager is not allowed, 651 * this method ignores the {@code acc} argument, launches {@code action}, 652 * and binds {@code subject} to the period of its execution. 653 * 654 * @param subject the {@code Subject} that the specified 655 * {@code action} will run as. This parameter 656 * may be {@code null}. 657 * 658 * @param <T> the type of the value returned by the PrivilegedAction's 659 * {@code run} method. 660 * 661 * @param action the code to be run as the specified 662 * {@code Subject}. 663 * 664 * @param acc the {@code AccessControlContext} to be tied to the 665 * specified <i>subject</i> and <i>action</i>. 666 * 667 * @return the value returned by the PrivilegedAction's 668 * {@code run} method. 669 * 670 * @throws NullPointerException if the {@code PrivilegedAction} 671 * is {@code null}. 672 * 673 * @throws SecurityException if a security manager is installed and the 674 * caller does not have a 675 * {@link AuthPermission#AuthPermission(String) 676 * AuthPermission("doAsPrivileged")} permission to invoke 677 * this method. 678 * 679 * @deprecated This method is only useful in conjunction with 680 * {@linkplain SecurityManager the Security Manager}, which is 681 * deprecated and subject to removal in a future release. 682 * Consequently, this method is also deprecated and subject to 683 * removal. There is no replacement for the Security Manager or this 684 * method. 685 */ 686 @SuppressWarnings("removal") 687 @Deprecated(since="17", forRemoval=true) 688 public static <T> T doAsPrivileged(final Subject subject, 689 final java.security.PrivilegedAction<T> action, 690 final java.security.AccessControlContext acc) { 691 692 java.lang.SecurityManager sm = System.getSecurityManager(); 693 if (sm != null) { 694 sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION); 695 } 696 697 Objects.requireNonNull(action, 698 ResourcesMgr.getString("invalid.null.action.provided")); 699 700 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 701 try { 702 return callAs(subject, action::run); 703 } catch (CompletionException ce) { 704 var cause = ce.getCause(); 705 if (cause instanceof RuntimeException re) { 706 throw re; 707 } else if (cause instanceof Error er) { 708 throw er; 709 } else { 710 throw new AssertionError(ce); 711 } 712 } 713 } else { 714 // set up the new Subject-based AccessControlContext 715 // for doPrivileged 716 final AccessControlContext callerAcc = 717 (acc == null ? 718 new AccessControlContext(NULL_PD_ARRAY) : 719 acc); 720 721 // call doPrivileged and push this new context on the stack 722 return java.security.AccessController.doPrivileged 723 (action, 724 createContext(subject, callerAcc)); 725 } 726 } 727 728 /** 729 * Perform privileged work as a particular {@code Subject}. 730 * 731 * <p> If a security manager is <a href=#sm-allowed>allowed</a>, 732 * this method behaves exactly as {@code Subject.doAs}, 733 * except that instead of retrieving the current Thread's 734 * {@code AccessControlContext}, it uses the provided 735 * {@code AccessControlContext}. If the provided 736 * {@code AccessControlContext} is {@code null}, 737 * this method instantiates a new {@code AccessControlContext} 738 * with an empty collection of ProtectionDomains. 739 * 740 * <p> If a security manager is not allowed, 741 * this method ignores the {@code acc} argument, launches {@code action}, 742 * and binds {@code subject} to the period of its execution. 743 * 744 * @param subject the {@code Subject} that the specified 745 * {@code action} will run as. This parameter 746 * may be {@code null}. 747 * 748 * @param <T> the type of the value returned by the 749 * PrivilegedExceptionAction's {@code run} method. 750 * 751 * @param action the code to be run as the specified 752 * {@code Subject}. 753 * 754 * @param acc the {@code AccessControlContext} to be tied to the 755 * specified <i>subject</i> and <i>action</i>. 756 * 757 * @return the value returned by the 758 * PrivilegedExceptionAction's {@code run} method. 759 * 760 * @throws PrivilegedActionException if the 761 * {@code PrivilegedExceptionAction.run} 762 * method throws a checked exception. 763 * 764 * @throws NullPointerException if the specified 765 * {@code PrivilegedExceptionAction} is 766 * {@code null}. 767 * 768 * @throws SecurityException if a security manager is installed and the 769 * caller does not have a 770 * {@link AuthPermission#AuthPermission(String) 771 * AuthPermission("doAsPrivileged")} permission to invoke 772 * this method. 773 * 774 * @deprecated This method is only useful in conjunction with 775 * {@linkplain SecurityManager the Security Manager}, which is 776 * deprecated and subject to removal in a future release. 777 * Consequently, this method is also deprecated and subject to 778 * removal. There is no replacement for the Security Manager or this 779 * method. 780 */ 781 @SuppressWarnings("removal") 782 @Deprecated(since="17", forRemoval=true) 783 public static <T> T doAsPrivileged(final Subject subject, 784 final java.security.PrivilegedExceptionAction<T> action, 785 final java.security.AccessControlContext acc) 786 throws java.security.PrivilegedActionException { 787 788 java.lang.SecurityManager sm = System.getSecurityManager(); 789 if (sm != null) { 790 sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION); 791 } 792 793 Objects.requireNonNull(action, 794 ResourcesMgr.getString("invalid.null.action.provided")); 795 796 if (!SharedSecrets.getJavaLangAccess().allowSecurityManager()) { 797 try { 798 return callAs(subject, action::run); 799 } catch (CompletionException ce) { 800 var cause = ce.getCause(); 801 if (cause instanceof RuntimeException re) { 802 throw re; 803 } else if (cause instanceof Error er) { 804 throw er; 805 } else if (cause instanceof Exception e) { 806 throw new PrivilegedActionException(e); 807 } else { 808 throw new PrivilegedActionException(ce); 809 } 810 } 811 } else { 812 // set up the new Subject-based AccessControlContext for doPrivileged 813 final AccessControlContext callerAcc = 814 (acc == null ? 815 new AccessControlContext(NULL_PD_ARRAY) : 816 acc); 817 818 // call doPrivileged and push this new context on the stack 819 return java.security.AccessController.doPrivileged 820 (action, 821 createContext(subject, callerAcc)); 822 } 823 } 824 825 @SuppressWarnings("removal") 826 private static AccessControlContext createContext(final Subject subject, 827 final AccessControlContext acc) { 828 829 830 return java.security.AccessController.doPrivileged 831 (new java.security.PrivilegedAction<>() { 832 public AccessControlContext run() { 833 if (subject == null) { 834 return new AccessControlContext(acc, null); 835 } else { 836 return new AccessControlContext 837 (acc, 838 new SubjectDomainCombiner(subject)); 839 } 840 } 841 }); 842 } 843 844 /** 845 * Return the {@code Set} of Principals associated with this 846 * {@code Subject}. Each {@code Principal} represents 847 * an identity for this {@code Subject}. 848 * 849 * <p> The returned {@code Set} is backed by this Subject's 850 * internal {@code Principal} {@code Set}. Any modification 851 * to the returned {@code Set} affects the internal 852 * {@code Principal} {@code Set} as well. 853 * 854 * <p> If a security manager is installed, the caller must have a 855 * {@link AuthPermission#AuthPermission(String) 856 * AuthPermission("modifyPrincipals")} permission to modify 857 * the returned set, or a {@code SecurityException} will be thrown. 858 * 859 * @return the {@code Set} of Principals associated with this 860 * {@code Subject}. 861 */ 862 public Set<Principal> getPrincipals() { 863 864 // always return an empty Set instead of null 865 // so LoginModules can add to the Set if necessary 866 return principals; 867 } 868 869 /** 870 * Return a {@code Set} of Principals associated with this 871 * {@code Subject} that are instances or subclasses of the specified 872 * {@code Class}. 873 * 874 * <p> The returned {@code Set} is not backed by this Subject's 875 * internal {@code Principal} {@code Set}. A new 876 * {@code Set} is created and returned for each method invocation. 877 * Modifications to the returned {@code Set} 878 * will not affect the internal {@code Principal} {@code Set}. 879 * 880 * @param <T> the type of the class modeled by {@code c} 881 * 882 * @param c the returned {@code Set} of Principals will all be 883 * instances of this class. 884 * 885 * @return a {@code Set} of Principals that are instances of the 886 * specified {@code Class}. 887 * 888 * @throws NullPointerException if the specified {@code Class} 889 * is {@code null}. 890 */ 891 public <T extends Principal> Set<T> getPrincipals(Class<T> c) { 892 893 Objects.requireNonNull(c, 894 ResourcesMgr.getString("invalid.null.Class.provided")); 895 896 // always return an empty Set instead of null 897 // so LoginModules can add to the Set if necessary 898 return new ClassSet<>(PRINCIPAL_SET, c); 899 } 900 901 /** 902 * Return the {@code Set} of public credentials held by this 903 * {@code Subject}. 904 * 905 * <p> The returned {@code Set} is backed by this Subject's 906 * internal public Credential {@code Set}. Any modification 907 * to the returned {@code Set} affects the internal public 908 * Credential {@code Set} as well. 909 * 910 * <p> If a security manager is installed, the caller must have a 911 * {@link AuthPermission#AuthPermission(String) 912 * AuthPermission("modifyPublicCredentials")} permission to modify 913 * the returned set, or a {@code SecurityException} will be thrown. 914 * 915 * @return a {@code Set} of public credentials held by this 916 * {@code Subject}. 917 */ 918 public Set<Object> getPublicCredentials() { 919 920 // always return an empty Set instead of null 921 // so LoginModules can add to the Set if necessary 922 return pubCredentials; 923 } 924 925 /** 926 * Return the {@code Set} of private credentials held by this 927 * {@code Subject}. 928 * 929 * <p> The returned {@code Set} is backed by this Subject's 930 * internal private Credential {@code Set}. Any modification 931 * to the returned {@code Set} affects the internal private 932 * Credential {@code Set} as well. 933 * 934 * <p> If a security manager is installed, the caller must have a 935 * {@link AuthPermission#AuthPermission(String) 936 * AuthPermission("modifyPrivateCredentials")} permission to modify 937 * the returned set, or a {@code SecurityException} will be thrown. 938 * 939 * <p> While iterating through the {@code Set}, 940 * a {@code SecurityException} is thrown if a security manager is installed 941 * and the caller does not have a {@link PrivateCredentialPermission} 942 * to access a particular Credential. The {@code Iterator} 943 * is nevertheless advanced to the next element in the {@code Set}. 944 * 945 * @return a {@code Set} of private credentials held by this 946 * {@code Subject}. 947 */ 948 public Set<Object> getPrivateCredentials() { 949 950 // XXX 951 // we do not need a security check for 952 // AuthPermission(getPrivateCredentials) 953 // because we already restrict access to private credentials 954 // via the PrivateCredentialPermission. all the extra AuthPermission 955 // would do is protect the set operations themselves 956 // (like size()), which don't seem security-sensitive. 957 958 // always return an empty Set instead of null 959 // so LoginModules can add to the Set if necessary 960 return privCredentials; 961 } 962 963 /** 964 * Return a {@code Set} of public credentials associated with this 965 * {@code Subject} that are instances or subclasses of the specified 966 * {@code Class}. 967 * 968 * <p> The returned {@code Set} is not backed by this Subject's 969 * internal public Credential {@code Set}. A new 970 * {@code Set} is created and returned for each method invocation. 971 * Modifications to the returned {@code Set} 972 * will not affect the internal public Credential {@code Set}. 973 * 974 * @param <T> the type of the class modeled by {@code c} 975 * 976 * @param c the returned {@code Set} of public credentials will all be 977 * instances of this class. 978 * 979 * @return a {@code Set} of public credentials that are instances 980 * of the specified {@code Class}. 981 * 982 * @throws NullPointerException if the specified {@code Class} 983 * is {@code null}. 984 */ 985 public <T> Set<T> getPublicCredentials(Class<T> c) { 986 987 Objects.requireNonNull(c, 988 ResourcesMgr.getString("invalid.null.Class.provided")); 989 990 // always return an empty Set instead of null 991 // so LoginModules can add to the Set if necessary 992 return new ClassSet<>(PUB_CREDENTIAL_SET, c); 993 } 994 995 /** 996 * Return a {@code Set} of private credentials associated with this 997 * {@code Subject} that are instances or subclasses of the specified 998 * {@code Class}. 999 * 1000 * <p> If a security manager is installed, the caller must have a 1001 * {@link PrivateCredentialPermission} to access all of the requested 1002 * Credentials, or a {@code SecurityException} will be thrown. 1003 * 1004 * <p> The returned {@code Set} is not backed by this Subject's 1005 * internal private Credential {@code Set}. A new 1006 * {@code Set} is created and returned for each method invocation. 1007 * Modifications to the returned {@code Set} 1008 * will not affect the internal private Credential {@code Set}. 1009 * 1010 * @param <T> the type of the class modeled by {@code c} 1011 * 1012 * @param c the returned {@code Set} of private credentials will all be 1013 * instances of this class. 1014 * 1015 * @return a {@code Set} of private credentials that are instances 1016 * of the specified {@code Class}. 1017 * 1018 * @throws NullPointerException if the specified {@code Class} 1019 * is {@code null}. 1020 */ 1021 public <T> Set<T> getPrivateCredentials(Class<T> c) { 1022 1023 // XXX 1024 // we do not need a security check for 1025 // AuthPermission(getPrivateCredentials) 1026 // because we already restrict access to private credentials 1027 // via the PrivateCredentialPermission. all the extra AuthPermission 1028 // would do is protect the set operations themselves 1029 // (like size()), which don't seem security-sensitive. 1030 1031 Objects.requireNonNull(c, 1032 ResourcesMgr.getString("invalid.null.Class.provided")); 1033 1034 // always return an empty Set instead of null 1035 // so LoginModules can add to the Set if necessary 1036 return new ClassSet<>(PRIV_CREDENTIAL_SET, c); 1037 } 1038 1039 /** 1040 * Compares the specified Object with this {@code Subject} 1041 * for equality. Returns true if the given object is also a Subject 1042 * and the two {@code Subject} instances are equivalent. 1043 * More formally, two {@code Subject} instances are 1044 * equal if their {@code Principal} and {@code Credential} 1045 * Sets are equal. 1046 * 1047 * @param o Object to be compared for equality with this 1048 * {@code Subject}. 1049 * 1050 * @return true if the specified Object is equal to this 1051 * {@code Subject}. 1052 * 1053 * @throws SecurityException if a security manager is installed and the 1054 * caller does not have a {@link PrivateCredentialPermission} 1055 * permission to access the private credentials for this 1056 * {@code Subject} or the provided {@code Subject}. 1057 */ 1058 @Override 1059 public boolean equals(Object o) { 1060 1061 if (this == o) { 1062 return true; 1063 } 1064 1065 if (o instanceof final Subject that) { 1066 1067 // check the principal and credential sets 1068 Set<Principal> thatPrincipals; 1069 synchronized(that.principals) { 1070 // avoid deadlock from dual locks 1071 thatPrincipals = new HashSet<>(that.principals); 1072 } 1073 if (!principals.equals(thatPrincipals)) { 1074 return false; 1075 } 1076 1077 Set<Object> thatPubCredentials; 1078 synchronized(that.pubCredentials) { 1079 // avoid deadlock from dual locks 1080 thatPubCredentials = new HashSet<>(that.pubCredentials); 1081 } 1082 if (!pubCredentials.equals(thatPubCredentials)) { 1083 return false; 1084 } 1085 1086 Set<Object> thatPrivCredentials; 1087 synchronized(that.privCredentials) { 1088 // avoid deadlock from dual locks 1089 thatPrivCredentials = new HashSet<>(that.privCredentials); 1090 } 1091 return privCredentials.equals(thatPrivCredentials); 1092 } 1093 return false; 1094 } 1095 1096 /** 1097 * Return the String representation of this {@code Subject}. 1098 * 1099 * @return the String representation of this {@code Subject}. 1100 */ 1101 @Override 1102 public String toString() { 1103 return toString(true); 1104 } 1105 1106 /** 1107 * package private convenience method to print out the Subject 1108 * without firing off a security check when trying to access 1109 * the Private Credentials 1110 */ 1111 String toString(boolean includePrivateCredentials) { 1112 1113 String s = ResourcesMgr.getString("Subject."); 1114 String suffix = ""; 1115 1116 synchronized(principals) { 1117 for (Principal p : principals) { 1118 suffix = suffix + ResourcesMgr.getString(".Principal.") + 1119 p.toString() + ResourcesMgr.getString("NEWLINE"); 1120 } 1121 } 1122 1123 synchronized(pubCredentials) { 1124 for (Object o : pubCredentials) { 1125 suffix = suffix + 1126 ResourcesMgr.getString(".Public.Credential.") + 1127 o.toString() + ResourcesMgr.getString("NEWLINE"); 1128 } 1129 } 1130 1131 if (includePrivateCredentials) { 1132 synchronized(privCredentials) { 1133 Iterator<Object> pI = privCredentials.iterator(); 1134 while (pI.hasNext()) { 1135 try { 1136 Object o = pI.next(); 1137 suffix += ResourcesMgr.getString 1138 (".Private.Credential.") + 1139 o.toString() + 1140 ResourcesMgr.getString("NEWLINE"); 1141 } catch (SecurityException se) { 1142 suffix += ResourcesMgr.getString 1143 (".Private.Credential.inaccessible."); 1144 break; 1145 } 1146 } 1147 } 1148 } 1149 return s + suffix; 1150 } 1151 1152 /** 1153 * {@return a hashcode for this {@code Subject}} 1154 * 1155 * @throws SecurityException if a security manager is installed and the 1156 * caller does not have a {@link PrivateCredentialPermission} 1157 * permission to access this Subject's private credentials. 1158 */ 1159 @Override 1160 public int hashCode() { 1161 1162 /* 1163 * The hashcode is derived exclusive or-ing the 1164 * hashcodes of this Subject's Principals and credentials. 1165 * 1166 * If a particular credential was destroyed 1167 * ({@code credential.hashCode()} throws an 1168 * {@code IllegalStateException}), 1169 * the hashcode for that credential is derived via: 1170 * {@code credential.getClass().toString().hashCode()}. 1171 */ 1172 1173 int hashCode = 0; 1174 1175 synchronized(principals) { 1176 for (Principal p : principals) { 1177 hashCode ^= p.hashCode(); 1178 } 1179 } 1180 1181 synchronized(pubCredentials) { 1182 for (Object pubCredential : pubCredentials) { 1183 hashCode ^= getCredHashCode(pubCredential); 1184 } 1185 } 1186 return hashCode; 1187 } 1188 1189 /** 1190 * get a credential's hashcode 1191 */ 1192 private int getCredHashCode(Object o) { 1193 try { 1194 return o.hashCode(); 1195 } catch (IllegalStateException ise) { 1196 return o.getClass().toString().hashCode(); 1197 } 1198 } 1199 1200 /** 1201 * Writes this object out to a stream (i.e., serializes it). 1202 * 1203 * @param oos the {@code ObjectOutputStream} to which data is written 1204 * @throws IOException if an I/O error occurs 1205 */ 1206 @java.io.Serial 1207 private void writeObject(java.io.ObjectOutputStream oos) 1208 throws java.io.IOException { 1209 synchronized(principals) { 1210 oos.defaultWriteObject(); 1211 } 1212 } 1213 1214 /** 1215 * Reads this object from a stream (i.e., deserializes it) 1216 * 1217 * @param s the {@code ObjectInputStream} from which data is read 1218 * @throws IOException if an I/O error occurs 1219 * @throws ClassNotFoundException if a serialized class cannot be loaded 1220 */ 1221 @SuppressWarnings("unchecked") 1222 @java.io.Serial 1223 private void readObject(java.io.ObjectInputStream s) 1224 throws java.io.IOException, ClassNotFoundException { 1225 1226 ObjectInputStream.GetField gf = s.readFields(); 1227 1228 readOnly = gf.get("readOnly", false); 1229 1230 Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null); 1231 1232 Objects.requireNonNull(inputPrincs, 1233 ResourcesMgr.getString("invalid.null.input.s.")); 1234 1235 // Rewrap the principals into a SecureSet 1236 try { 1237 LinkedList<Principal> principalList = collectionNullClean(inputPrincs); 1238 principals = Collections.synchronizedSet(new SecureSet<> 1239 (this, PRINCIPAL_SET, principalList)); 1240 } catch (NullPointerException npe) { 1241 // Sometimes people deserialize the principals set only. 1242 // Subject is not accessible, so just don't fail. 1243 principals = Collections.synchronizedSet 1244 (new SecureSet<>(this, PRINCIPAL_SET)); 1245 } 1246 1247 // The Credential {@code Set} is not serialized, but we do not 1248 // want the default deserialization routine to set it to null. 1249 this.pubCredentials = Collections.synchronizedSet 1250 (new SecureSet<>(this, PUB_CREDENTIAL_SET)); 1251 this.privCredentials = Collections.synchronizedSet 1252 (new SecureSet<>(this, PRIV_CREDENTIAL_SET)); 1253 } 1254 1255 /** 1256 * Tests for null-clean collections (both non-null reference and 1257 * no null elements) 1258 * 1259 * @param coll A {@code Collection} to be tested for null references 1260 * 1261 * @throws NullPointerException if the specified collection is either 1262 * {@code null} or contains a {@code null} element 1263 */ 1264 private static <E> LinkedList<E> collectionNullClean( 1265 Collection<? extends E> coll) { 1266 1267 Objects.requireNonNull(coll, 1268 ResourcesMgr.getString("invalid.null.input.s.")); 1269 1270 LinkedList<E> output = new LinkedList<>(); 1271 for (E e : coll) { 1272 output.add(Objects.requireNonNull(e, 1273 ResourcesMgr.getString("invalid.null.input.s."))); 1274 } 1275 return output; 1276 } 1277 1278 /** 1279 * Prevent modifications unless caller has permission. 1280 * 1281 * @serial include 1282 */ 1283 private static class SecureSet<E> 1284 implements Set<E>, java.io.Serializable { 1285 1286 @java.io.Serial 1287 private static final long serialVersionUID = 7911754171111800359L; 1288 1289 /** 1290 * @serialField this$0 Subject The outer Subject instance. 1291 * @serialField elements LinkedList The elements in this set. 1292 */ 1293 @java.io.Serial 1294 private static final ObjectStreamField[] serialPersistentFields = { 1295 new ObjectStreamField("this$0", Subject.class), 1296 new ObjectStreamField("elements", LinkedList.class), 1297 new ObjectStreamField("which", int.class) 1298 }; 1299 1300 Subject subject; 1301 LinkedList<E> elements; 1302 1303 /** 1304 * @serial An integer identifying the type of objects contained 1305 * in this set. If {@code which == 1}, 1306 * this is a Principal set and all the elements are 1307 * of type {@code java.security.Principal}. 1308 * If {@code which == 2}, this is a public credential 1309 * set and all the elements are of type {@code Object}. 1310 * If {@code which == 3}, this is a private credential 1311 * set and all the elements are of type {@code Object}. 1312 */ 1313 private int which; 1314 1315 SecureSet(Subject subject, int which) { 1316 this.subject = subject; 1317 this.which = which; 1318 this.elements = new LinkedList<>(); 1319 } 1320 1321 SecureSet(Subject subject, int which, LinkedList<E> list) { 1322 this.subject = subject; 1323 this.which = which; 1324 this.elements = list; 1325 } 1326 1327 public int size() { 1328 return elements.size(); 1329 } 1330 1331 public Iterator<E> iterator() { 1332 final LinkedList<E> list = elements; 1333 return new Iterator<>() { 1334 final ListIterator<E> i = list.listIterator(0); 1335 1336 public boolean hasNext() { 1337 return i.hasNext(); 1338 } 1339 1340 public E next() { 1341 if (which != Subject.PRIV_CREDENTIAL_SET) { 1342 return i.next(); 1343 } 1344 1345 @SuppressWarnings("removal") 1346 SecurityManager sm = System.getSecurityManager(); 1347 if (sm != null) { 1348 try { 1349 sm.checkPermission(new PrivateCredentialPermission 1350 (list.get(i.nextIndex()).getClass().getName(), 1351 subject.getPrincipals())); 1352 } catch (SecurityException se) { 1353 i.next(); 1354 throw (se); 1355 } 1356 } 1357 return i.next(); 1358 } 1359 1360 public void remove() { 1361 1362 if (subject.isReadOnly()) { 1363 throw new IllegalStateException(ResourcesMgr.getString 1364 ("Subject.is.read.only")); 1365 } 1366 1367 @SuppressWarnings("removal") 1368 java.lang.SecurityManager sm = System.getSecurityManager(); 1369 if (sm != null) { 1370 switch (which) { 1371 case Subject.PRINCIPAL_SET: 1372 sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION); 1373 break; 1374 case Subject.PUB_CREDENTIAL_SET: 1375 sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION); 1376 break; 1377 default: 1378 sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION); 1379 break; 1380 } 1381 } 1382 i.remove(); 1383 } 1384 }; 1385 } 1386 1387 public boolean add(E o) { 1388 1389 Objects.requireNonNull(o, 1390 ResourcesMgr.getString("invalid.null.input.s.")); 1391 1392 if (subject.isReadOnly()) { 1393 throw new IllegalStateException 1394 (ResourcesMgr.getString("Subject.is.read.only")); 1395 } 1396 1397 @SuppressWarnings("removal") 1398 java.lang.SecurityManager sm = System.getSecurityManager(); 1399 if (sm != null) { 1400 switch (which) { 1401 case Subject.PRINCIPAL_SET: 1402 sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION); 1403 break; 1404 case Subject.PUB_CREDENTIAL_SET: 1405 sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION); 1406 break; 1407 default: 1408 sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION); 1409 break; 1410 } 1411 } 1412 1413 switch (which) { 1414 case Subject.PRINCIPAL_SET: 1415 if (!(o instanceof Principal)) { 1416 throw new SecurityException(ResourcesMgr.getString 1417 ("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set")); 1418 } 1419 break; 1420 default: 1421 // ok to add Objects of any kind to credential sets 1422 break; 1423 } 1424 1425 // check for duplicates 1426 if (!elements.contains(o)) 1427 return elements.add(o); 1428 else { 1429 return false; 1430 } 1431 } 1432 1433 @SuppressWarnings("removal") 1434 public boolean remove(Object o) { 1435 1436 Objects.requireNonNull(o, 1437 ResourcesMgr.getString("invalid.null.input.s.")); 1438 1439 final Iterator<E> e = iterator(); 1440 while (e.hasNext()) { 1441 E next; 1442 if (which != Subject.PRIV_CREDENTIAL_SET) { 1443 next = e.next(); 1444 } else { 1445 next = java.security.AccessController.doPrivileged 1446 (new java.security.PrivilegedAction<E>() { 1447 public E run() { 1448 return e.next(); 1449 } 1450 }); 1451 } 1452 1453 if (next.equals(o)) { 1454 e.remove(); 1455 return true; 1456 } 1457 } 1458 return false; 1459 } 1460 1461 @SuppressWarnings("removal") 1462 public boolean contains(Object o) { 1463 1464 Objects.requireNonNull(o, 1465 ResourcesMgr.getString("invalid.null.input.s.")); 1466 1467 final Iterator<E> e = iterator(); 1468 while (e.hasNext()) { 1469 E next; 1470 if (which != Subject.PRIV_CREDENTIAL_SET) { 1471 next = e.next(); 1472 } else { 1473 1474 // For private credentials: 1475 // If the caller does not have read permission 1476 // for o.getClass(), we throw a SecurityException. 1477 // Otherwise, we check the private cred set to see whether 1478 // it contains the Object 1479 1480 SecurityManager sm = System.getSecurityManager(); 1481 if (sm != null) { 1482 sm.checkPermission(new PrivateCredentialPermission 1483 (o.getClass().getName(), 1484 subject.getPrincipals())); 1485 } 1486 next = java.security.AccessController.doPrivileged 1487 (new java.security.PrivilegedAction<E>() { 1488 public E run() { 1489 return e.next(); 1490 } 1491 }); 1492 } 1493 1494 if (next.equals(o)) { 1495 return true; 1496 } 1497 } 1498 return false; 1499 } 1500 1501 public boolean addAll(Collection<? extends E> c) { 1502 boolean result = false; 1503 1504 c = collectionNullClean(c); 1505 1506 for (E item : c) { 1507 result |= this.add(item); 1508 } 1509 1510 return result; 1511 } 1512 1513 @SuppressWarnings("removal") 1514 public boolean removeAll(Collection<?> c) { 1515 c = collectionNullClean(c); 1516 1517 boolean modified = false; 1518 final Iterator<E> e = iterator(); 1519 while (e.hasNext()) { 1520 E next; 1521 if (which != Subject.PRIV_CREDENTIAL_SET) { 1522 next = e.next(); 1523 } else { 1524 next = java.security.AccessController.doPrivileged 1525 (new java.security.PrivilegedAction<E>() { 1526 public E run() { 1527 return e.next(); 1528 } 1529 }); 1530 } 1531 1532 for (Object o : c) { 1533 if (next.equals(o)) { 1534 e.remove(); 1535 modified = true; 1536 break; 1537 } 1538 } 1539 } 1540 return modified; 1541 } 1542 1543 public boolean containsAll(Collection<?> c) { 1544 c = collectionNullClean(c); 1545 1546 for (Object item : c) { 1547 if (!this.contains(item)) { 1548 return false; 1549 } 1550 } 1551 1552 return true; 1553 } 1554 1555 @SuppressWarnings("removal") 1556 public boolean retainAll(Collection<?> c) { 1557 c = collectionNullClean(c); 1558 1559 boolean modified = false; 1560 final Iterator<E> e = iterator(); 1561 while (e.hasNext()) { 1562 E next; 1563 if (which != Subject.PRIV_CREDENTIAL_SET) { 1564 next = e.next(); 1565 } else { 1566 next = java.security.AccessController.doPrivileged 1567 (new java.security.PrivilegedAction<E>() { 1568 public E run() { 1569 return e.next(); 1570 } 1571 }); 1572 } 1573 1574 if (c.contains(next) == false) { 1575 e.remove(); 1576 modified = true; 1577 } 1578 } 1579 1580 return modified; 1581 } 1582 1583 @SuppressWarnings("removal") 1584 public void clear() { 1585 final Iterator<E> e = iterator(); 1586 while (e.hasNext()) { 1587 E next; 1588 if (which != Subject.PRIV_CREDENTIAL_SET) { 1589 next = e.next(); 1590 } else { 1591 next = java.security.AccessController.doPrivileged 1592 (new java.security.PrivilegedAction<E>() { 1593 public E run() { 1594 return e.next(); 1595 } 1596 }); 1597 } 1598 e.remove(); 1599 } 1600 } 1601 1602 public boolean isEmpty() { 1603 return elements.isEmpty(); 1604 } 1605 1606 public Object[] toArray() { 1607 final Iterator<E> e = iterator(); 1608 while (e.hasNext()) { 1609 // The next() method performs a security manager check 1610 // on each element in the SecureSet. If we make it all 1611 // the way through we should be able to simply return 1612 // element's toArray results. Otherwise, we'll let 1613 // the SecurityException pass up the call stack. 1614 e.next(); 1615 } 1616 1617 return elements.toArray(); 1618 } 1619 1620 public <T> T[] toArray(T[] a) { 1621 final Iterator<E> e = iterator(); 1622 while (e.hasNext()) { 1623 // The next() method performs a security manager check 1624 // on each element in the SecureSet. If we make it all 1625 // the way through we should be able to simply return 1626 // element's toArray results. Otherwise, we'll let 1627 // the SecurityException pass up the call stack. 1628 e.next(); 1629 } 1630 1631 return elements.toArray(a); 1632 } 1633 1634 @Override 1635 public boolean equals(Object o) { 1636 if (o == this) { 1637 return true; 1638 } 1639 1640 if (!(o instanceof Set)) { 1641 return false; 1642 } 1643 1644 Collection<?> c = (Collection<?>) o; 1645 if (c.size() != size()) { 1646 return false; 1647 } 1648 1649 try { 1650 return containsAll(c); 1651 } catch (ClassCastException | NullPointerException unused) { 1652 return false; 1653 } 1654 } 1655 1656 @Override 1657 public int hashCode() { 1658 int h = 0; 1659 for (E obj : this) { 1660 h += Objects.hashCode(obj); 1661 } 1662 return h; 1663 } 1664 1665 /** 1666 * Writes this object out to a stream (i.e., serializes it). 1667 * 1668 * @serialData If this is a private credential set, 1669 * a security check is performed to ensure that 1670 * the caller has permission to access each credential 1671 * in the set. If the security check passes, 1672 * the set is serialized. 1673 * 1674 * @param oos the {@code ObjectOutputStream} to which data is written 1675 * @throws IOException if an I/O error occurs 1676 */ 1677 @java.io.Serial 1678 private void writeObject(java.io.ObjectOutputStream oos) 1679 throws java.io.IOException { 1680 1681 if (which == Subject.PRIV_CREDENTIAL_SET) { 1682 // check permissions before serializing 1683 Iterator<E> i = iterator(); 1684 while (i.hasNext()) { 1685 i.next(); 1686 } 1687 } 1688 ObjectOutputStream.PutField fields = oos.putFields(); 1689 fields.put("this$0", subject); 1690 fields.put("elements", elements); 1691 fields.put("which", which); 1692 oos.writeFields(); 1693 } 1694 1695 /** 1696 * Restores the state of this object from the stream. 1697 * 1698 * @param ois the {@code ObjectInputStream} from which data is read 1699 * @throws IOException if an I/O error occurs 1700 * @throws ClassNotFoundException if a serialized class cannot be loaded 1701 */ 1702 @SuppressWarnings("unchecked") 1703 @java.io.Serial 1704 private void readObject(ObjectInputStream ois) 1705 throws IOException, ClassNotFoundException 1706 { 1707 ObjectInputStream.GetField fields = ois.readFields(); 1708 subject = (Subject) fields.get("this$0", null); 1709 which = fields.get("which", 0); 1710 1711 LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null); 1712 1713 elements = Subject.collectionNullClean(tmp); 1714 } 1715 1716 } 1717 1718 /** 1719 * This class implements a {@code Set} which returns only 1720 * members that are an instance of a specified Class. 1721 */ 1722 private class ClassSet<T> extends AbstractSet<T> { 1723 1724 private final int which; 1725 private final Class<T> c; 1726 private final Set<T> set; 1727 1728 ClassSet(int which, Class<T> c) { 1729 this.which = which; 1730 this.c = c; 1731 set = new HashSet<>(); 1732 1733 switch (which) { 1734 case Subject.PRINCIPAL_SET: 1735 synchronized(principals) { populateSet(); } 1736 break; 1737 case Subject.PUB_CREDENTIAL_SET: 1738 synchronized(pubCredentials) { populateSet(); } 1739 break; 1740 default: 1741 synchronized(privCredentials) { populateSet(); } 1742 break; 1743 } 1744 } 1745 1746 @SuppressWarnings({"removal","unchecked"}) /*To suppress warning from line 1374*/ 1747 private void populateSet() { 1748 final Iterator<?> iterator; 1749 switch(which) { 1750 case Subject.PRINCIPAL_SET: 1751 iterator = Subject.this.principals.iterator(); 1752 break; 1753 case Subject.PUB_CREDENTIAL_SET: 1754 iterator = Subject.this.pubCredentials.iterator(); 1755 break; 1756 default: 1757 iterator = Subject.this.privCredentials.iterator(); 1758 break; 1759 } 1760 1761 // Check whether the caller has permission to get 1762 // credentials of Class c 1763 1764 while (iterator.hasNext()) { 1765 Object next; 1766 if (which == Subject.PRIV_CREDENTIAL_SET) { 1767 next = java.security.AccessController.doPrivileged 1768 (new java.security.PrivilegedAction<>() { 1769 public Object run() { 1770 return iterator.next(); 1771 } 1772 }); 1773 } else { 1774 next = iterator.next(); 1775 } 1776 if (c.isAssignableFrom(next.getClass())) { 1777 if (which != Subject.PRIV_CREDENTIAL_SET) { 1778 set.add((T)next); 1779 } else { 1780 // Check permission for private creds 1781 SecurityManager sm = System.getSecurityManager(); 1782 if (sm != null) { 1783 sm.checkPermission(new PrivateCredentialPermission 1784 (next.getClass().getName(), 1785 Subject.this.getPrincipals())); 1786 } 1787 set.add((T)next); 1788 } 1789 } 1790 } 1791 } 1792 1793 @Override 1794 public int size() { 1795 return set.size(); 1796 } 1797 1798 @Override 1799 public Iterator<T> iterator() { 1800 return set.iterator(); 1801 } 1802 1803 @Override 1804 public boolean add(T o) { 1805 1806 if (!c.isAssignableFrom(o.getClass())) { 1807 MessageFormat form = new MessageFormat(ResourcesMgr.getString 1808 ("attempting.to.add.an.object.which.is.not.an.instance.of.class")); 1809 Object[] source = {c.toString()}; 1810 throw new SecurityException(form.format(source)); 1811 } 1812 1813 return set.add(o); 1814 } 1815 } 1816 1817 static final class AuthPermissionHolder { 1818 static final AuthPermission DO_AS_PERMISSION = 1819 new AuthPermission("doAs"); 1820 1821 static final AuthPermission DO_AS_PRIVILEGED_PERMISSION = 1822 new AuthPermission("doAsPrivileged"); 1823 1824 static final AuthPermission SET_READ_ONLY_PERMISSION = 1825 new AuthPermission("setReadOnly"); 1826 1827 static final AuthPermission GET_SUBJECT_PERMISSION = 1828 new AuthPermission("getSubject"); 1829 1830 static final AuthPermission MODIFY_PRINCIPALS_PERMISSION = 1831 new AuthPermission("modifyPrincipals"); 1832 1833 static final AuthPermission MODIFY_PUBLIC_CREDENTIALS_PERMISSION = 1834 new AuthPermission("modifyPublicCredentials"); 1835 1836 static final AuthPermission MODIFY_PRIVATE_CREDENTIALS_PERMISSION = 1837 new AuthPermission("modifyPrivateCredentials"); 1838 } 1839 }