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 sun.security.util.ResourcesMgr; 39 40 /** 41 * <p> A {@code Subject} represents a grouping of related information 42 * for a single entity, such as a person. 43 * Such information includes the Subject's identities as well as 44 * its security-related attributes 45 * (passwords and cryptographic keys, for example). 46 * 47 * <p> Subjects may potentially have multiple identities. 48 * Each identity is represented as a {@code Principal} 49 * within the {@code Subject}. Principals simply bind names to a 50 * {@code Subject}. For example, a {@code Subject} that happens 51 * to be a person, Alice, might have two Principals: 52 * one which binds "Alice Bar", the name on her driver license, 53 * to the {@code Subject}, and another which binds, 54 * "999-99-9999", the number on her student identification card, 55 * to the {@code Subject}. Both Principals refer to the same 56 * {@code Subject} even though each has a different name. 57 * 58 * <p> A {@code Subject} may also own security-related attributes, 59 * which are referred to as credentials. 60 * Sensitive credentials that require special protection, such as 61 * private cryptographic keys, are stored within a private credential 62 * {@code Set}. Credentials intended to be shared, such as 63 * public key certificates or Kerberos server tickets are stored 64 * within a public credential {@code Set}. 65 * 66 * <p> To retrieve all the Principals associated with a {@code Subject}, 67 * invoke the {@code getPrincipals} method. To retrieve 68 * all the public or private credentials belonging to a {@code Subject}, 69 * invoke the {@code getPublicCredentials} method or 70 * {@code getPrivateCredentials} method, respectively. 71 * To modify the returned {@code Set} of Principals and credentials, 72 * use the methods defined in the {@code Set} class. 73 * For example: 74 * <pre> 75 * Subject subject; 76 * Principal principal; 77 * Object credential; 78 * 79 * // add a Principal and credential to the Subject 80 * subject.getPrincipals().add(principal); 81 * subject.getPublicCredentials().add(credential); 82 * </pre> 83 * 84 * <p> This {@code Subject} class implements {@code Serializable}. 85 * While the Principals associated with the {@code Subject} are serialized, 86 * the credentials associated with the {@code Subject} are not. 87 * Note that the {@code java.security.Principal} class 88 * does not implement {@code Serializable}. Therefore, all concrete 89 * {@code Principal} implementations associated with Subjects 90 * must implement {@code Serializable}. 91 * 92 * <h2>Deprecated Methods and Replacements</h2> 93 * 94 * <p> The following methods in this class for user-based authorization 95 * that are dependent on Security Manager APIs are deprecated for removal: 96 * <ul> 97 * <li>{@link #getSubject(AccessControlContext)} 98 * <li>{@link #doAs(Subject, PrivilegedAction)} 99 * <li>{@link #doAs(Subject, PrivilegedExceptionAction)} 100 * <li>{@link #doAsPrivileged(Subject, PrivilegedAction, AccessControlContext)} 101 * <li>{@link #doAsPrivileged(Subject, PrivilegedExceptionAction, AccessControlContext)} 102 * </ul> 103 * Methods {@link #current()} and {@link #callAs(Subject, Callable)} 104 * are replacements for these methods, where {@code current} is equivalent to 105 * {@code getSubject(AccessController.getContext())} (as originally specified) 106 * and {@code callAs} is similar to {@code doAs} except that the 107 * input type and exceptions thrown are slightly different. 108 * 109 * <p> A {@code doAs} or {@code callAs} call 110 * binds a {@code Subject} object to the period of execution of an action, 111 * and the subject can be retrieved using the {@code current} method inside 112 * the action. This subject can be inherited by child threads if they are 113 * started and terminate within the execution of its parent thread using 114 * structured concurrency. 115 * 116 * @since 1.4 117 * @see java.security.Principal 118 * @see java.security.DomainCombiner 119 */ 120 public final class Subject implements java.io.Serializable { 121 122 @java.io.Serial 123 private static final long serialVersionUID = -8308522755600156056L; 124 125 /** 126 * A {@code Set} that provides a view of all of this 127 * Subject's Principals 128 * 129 * @serial Each element in this set is a 130 * {@code java.security.Principal}. 131 * The set is a {@code Subject.SecureSet}. 132 */ 133 @SuppressWarnings("serial") // Not statically typed as Serializable 134 Set<Principal> principals; 135 136 /** 137 * Sets that provide a view of all of this 138 * Subject's Credentials 139 */ 140 transient Set<Object> pubCredentials; 141 transient Set<Object> privCredentials; 142 143 /** 144 * Whether this Subject is read-only 145 * 146 * @serial 147 */ 148 private volatile boolean readOnly; 149 150 private static final int PRINCIPAL_SET = 1; 151 private static final int PUB_CREDENTIAL_SET = 2; 152 private static final int PRIV_CREDENTIAL_SET = 3; 153 154 private static final ProtectionDomain[] NULL_PD_ARRAY 155 = new ProtectionDomain[0]; 156 157 /** 158 * Create an instance of a {@code Subject} 159 * with an empty {@code Set} of Principals and empty 160 * Sets of public and private credentials. 161 * 162 * <p> The newly constructed Sets check whether this {@code Subject} 163 * has been set read-only before permitting subsequent modifications. 164 * These Sets also prohibit null elements, and attempts to add, query, 165 * or remove a null element will result in a {@code NullPointerException}. 166 */ 167 public Subject() { 168 169 this.principals = Collections.synchronizedSet 170 (new SecureSet<>(this, PRINCIPAL_SET)); 171 this.pubCredentials = Collections.synchronizedSet 172 (new SecureSet<>(this, PUB_CREDENTIAL_SET)); 173 this.privCredentials = Collections.synchronizedSet 174 (new SecureSet<>(this, PRIV_CREDENTIAL_SET)); 175 } 176 177 /** 178 * Create an instance of a {@code Subject} with 179 * Principals and credentials. 180 * 181 * <p> The Principals and credentials from the specified Sets 182 * are copied into newly constructed Sets. 183 * These newly created Sets check whether this {@code Subject} 184 * has been set read-only before permitting subsequent modifications. 185 * These Sets also prohibit null elements, and attempts to add, query, 186 * or remove a null element will result in a {@code NullPointerException}. 187 * 188 * @param readOnly true if the {@code Subject} is to be read-only, 189 * and false otherwise. 190 * 191 * @param principals the {@code Set} of Principals 192 * to be associated with this {@code Subject}. 193 * 194 * @param pubCredentials the {@code Set} of public credentials 195 * to be associated with this {@code Subject}. 196 * 197 * @param privCredentials the {@code Set} of private credentials 198 * to be associated with this {@code Subject}. 199 * 200 * @throws NullPointerException if the specified 201 * {@code principals}, {@code pubCredentials}, 202 * or {@code privCredentials} are {@code null}, 203 * or a null value exists within any of these three 204 * Sets. 205 */ 206 public Subject(boolean readOnly, Set<? extends Principal> principals, 207 Set<?> pubCredentials, Set<?> privCredentials) { 208 LinkedList<Principal> principalList 209 = collectionNullClean(principals); 210 LinkedList<Object> pubCredsList 211 = collectionNullClean(pubCredentials); 212 LinkedList<Object> privCredsList 213 = collectionNullClean(privCredentials); 214 215 this.principals = Collections.synchronizedSet( 216 new SecureSet<>(this, PRINCIPAL_SET, principalList)); 217 this.pubCredentials = Collections.synchronizedSet( 218 new SecureSet<>(this, PUB_CREDENTIAL_SET, pubCredsList)); 219 this.privCredentials = Collections.synchronizedSet( 220 new SecureSet<>(this, PRIV_CREDENTIAL_SET, privCredsList)); 221 this.readOnly = readOnly; 222 } 223 224 /** 225 * Set this {@code Subject} to be read-only. 226 * 227 * <p> Modifications (additions and removals) to this Subject's 228 * {@code Principal} {@code Set} and 229 * credential Sets will be disallowed. 230 * The {@code destroy} operation on this Subject's credentials will 231 * still be permitted. 232 * 233 * <p> Subsequent attempts to modify the Subject's {@code Principal} 234 * and credential Sets will result in an 235 * {@code IllegalStateException} being thrown. 236 * Also, once a {@code Subject} is read-only, 237 * it can not be reset to being writable again. 238 */ 239 public void setReadOnly() { 240 this.readOnly = true; 241 } 242 243 /** 244 * Query whether this {@code Subject} is read-only. 245 * 246 * @return true if this {@code Subject} is read-only, false otherwise. 247 */ 248 public boolean isReadOnly() { 249 return this.readOnly; 250 } 251 252 /** 253 * Throws {@code UnsupportedOperationException}. A replacement API 254 * named {@link #current()} has been added which can be used to obtain 255 * the current subject. 256 * 257 * @param acc ignored 258 * 259 * @return n/a 260 * 261 * @throws UnsupportedOperationException always 262 * 263 * @deprecated This method used to get the subject associated with the 264 * provided {@link AccessControlContext}, which was only useful in 265 * conjunction with {@linkplain SecurityManager the Security Manager}, 266 * which is no longer supported. This method has been changed to 267 * always throw {@code UnsupportedOperationException}. A replacement 268 * API named {@link #current()} has been added which can be used to 269 * obtain the current subject. There is no replacement for the 270 * Security Manager. 271 * 272 * @see #current() 273 */ 274 @SuppressWarnings("removal") 275 @Deprecated(since="17", forRemoval=true) 276 public static Subject getSubject(final AccessControlContext acc) { 277 throw new UnsupportedOperationException("getSubject is not supported"); 278 } 279 280 private static final ScopedValue<Subject> SCOPED_SUBJECT = 281 ScopedValue.newInstance(); 282 283 /** 284 * Returns the current subject. 285 * 286 * <p> The current subject is installed by the {@link #callAs} method. 287 * When {@code callAs(subject, action)} is called, {@code action} is 288 * executed with {@code subject} as its current subject which can be 289 * retrieved by this method. After {@code action} is finished, the current 290 * subject is reset to its previous value. The current 291 * subject is {@code null} before the first call of {@code callAs()}. 292 * 293 * <p> This method returns the 294 * {@code Subject} bound to the period of the execution of the current 295 * thread. 296 * 297 * @return the current subject, or {@code null} if a current subject is 298 * not installed or the current subject is set to {@code null}. 299 * @see #callAs(Subject, Callable) 300 * @since 18 301 */ 302 public static Subject current() { 303 return SCOPED_SUBJECT.isBound() ? SCOPED_SUBJECT.get() : null; 304 } 305 306 /** 307 * Executes a {@code Callable} with {@code subject} as the 308 * current subject. 309 * 310 * <p> This method launches {@code action} and binds {@code subject} to the 311 * period of its execution. 312 * 313 * @param subject the {@code Subject} that the specified {@code action} 314 * will run as. This parameter may be {@code null}. 315 * @param action the code to be run with {@code subject} as its current 316 * subject. Must not be {@code null}. 317 * @param <T> the type of value returned by the {@code call} method 318 * of {@code action} 319 * @return the value returned by the {@code call} method of {@code action} 320 * @throws NullPointerException if {@code action} is {@code null} 321 * @throws CompletionException if {@code action.call()} throws an exception. 322 * The cause of the {@code CompletionException} is set to the exception 323 * thrown by {@code action.call()}. 324 * @see #current() 325 * @since 18 326 */ 327 public static <T> T callAs(final Subject subject, 328 final Callable<T> action) throws CompletionException { 329 Objects.requireNonNull(action); 330 try { 331 return ScopedValue.where(SCOPED_SUBJECT, subject).call(action::call); 332 } catch (Exception e) { 333 throw new CompletionException(e); 334 } 335 } 336 337 /** 338 * Perform work as a particular {@code Subject}. 339 * 340 * <p> This method launches {@code action} and binds {@code subject} to the 341 * period of its execution. 342 * 343 * @param subject the {@code Subject} that the specified 344 * {@code action} will run as. This parameter 345 * may be {@code null}. 346 * 347 * @param <T> the type of the value returned by the PrivilegedAction's 348 * {@code run} method. 349 * 350 * @param action the code to be run as the specified 351 * {@code Subject}. 352 * 353 * @return the value returned by the PrivilegedAction's 354 * {@code run} method. 355 * 356 * @throws NullPointerException if the {@code PrivilegedAction} 357 * is {@code null}. 358 * 359 * @deprecated This method originally performed the specified 360 * {@code PrivilegedAction} with privileges enabled. Running the 361 * action with privileges enabled was only useful in conjunction 362 * with {@linkplain SecurityManager the Security Manager}, which is 363 * no longer supported. This method has been changed to launch the 364 * action as is and bind the subject to the period of its execution. 365 * A replacement API named {@link #callAs} has been added which can 366 * be used to perform the same work. There is no replacement for the 367 * Security Manager. 368 * 369 * @see #callAs(Subject, Callable) 370 */ 371 @Deprecated(since="18", forRemoval=true) 372 public static <T> T doAs(final Subject subject, 373 final java.security.PrivilegedAction<T> action) { 374 375 Objects.requireNonNull(action, 376 ResourcesMgr.getString("invalid.null.action.provided")); 377 378 try { 379 return callAs(subject, action::run); 380 } catch (CompletionException ce) { 381 var cause = ce.getCause(); 382 if (cause instanceof RuntimeException re) { 383 throw re; 384 } else if (cause instanceof Error er) { 385 throw er; 386 } else { 387 throw new AssertionError(ce); 388 } 389 } 390 } 391 392 /** 393 * Perform work as a particular {@code Subject}. 394 * 395 * <p> This method launches {@code action} and binds {@code subject} to the 396 * period of its execution. 397 * 398 * @param subject the {@code Subject} that the specified 399 * {@code action} will run as. This parameter 400 * may be {@code null}. 401 * 402 * @param <T> the type of the value returned by the 403 * PrivilegedExceptionAction's {@code run} method. 404 * 405 * @param action the code to be run as the specified 406 * {@code Subject}. 407 * 408 * @return the value returned by the 409 * PrivilegedExceptionAction's {@code run} method. 410 * 411 * @throws PrivilegedActionException if the 412 * {@code PrivilegedExceptionAction.run} 413 * method throws a checked exception. 414 * 415 * @throws NullPointerException if the specified 416 * {@code PrivilegedExceptionAction} is 417 * {@code null}. 418 * 419 * @deprecated This method originally performed the specified 420 * {@code PrivilegedExceptionAction} with privileges enabled. 421 * Running the action with privileges enabled was only useful in 422 * conjunction with {@linkplain SecurityManager the Security Manager}, 423 * which is no longer supported. This method has been changed to 424 * launch the action as is and bind the subject to the period of its 425 * execution. A replacement API named {@link #callAs} has been added 426 * which can be used to perform the same work. There is no 427 * replacement for the Security Manager. 428 * 429 * @see #callAs(Subject, Callable) 430 */ 431 @Deprecated(since="18", forRemoval=true) 432 public static <T> T doAs(final Subject subject, 433 final java.security.PrivilegedExceptionAction<T> action) 434 throws java.security.PrivilegedActionException { 435 436 Objects.requireNonNull(action, 437 ResourcesMgr.getString("invalid.null.action.provided")); 438 439 try { 440 return callAs(subject, action::run); 441 } catch (CompletionException ce) { 442 var cause = ce.getCause(); 443 if (cause instanceof RuntimeException re) { 444 throw re; 445 } else if (cause instanceof Error er) { 446 throw er; 447 } else if (cause instanceof Exception e) { 448 throw new PrivilegedActionException(e); 449 } else { 450 throw new PrivilegedActionException(ce); 451 } 452 } 453 } 454 455 /** 456 * Perform work as a particular {@code Subject}. 457 * 458 * <p> This method launches {@code action} and binds {@code subject} to 459 * the period of its execution. 460 * 461 * @param subject the {@code Subject} that the specified 462 * {@code action} will run as. This parameter 463 * may be {@code null}. 464 * 465 * @param <T> the type of the value returned by the PrivilegedAction's 466 * {@code run} method. 467 * 468 * @param action the code to be run as the specified 469 * {@code Subject}. 470 * 471 * @param acc ignored 472 * 473 * @return the value returned by the PrivilegedAction's 474 * {@code run} method. 475 * 476 * @throws NullPointerException if the {@code PrivilegedAction} 477 * is {@code null}. 478 * 479 * @deprecated This method originally performed the specified 480 * {@code PrivilegedAction} with privileges enabled and restricted 481 * by the specified {@code AccessControlContext}. Running the 482 * action with privileges enabled was only useful in conjunction 483 * with {@linkplain SecurityManager the Security Manager}, which is 484 * no longer supported. This method has been changed to ignore the 485 * {@code AccessControlContext} and launch the action as is and bind 486 * the subject to the period of its execution. A replacement API 487 * named {@link #callAs} has been added which can be used to perform 488 * the same work. There is no replacement for the Security Manager. 489 * 490 * @see #callAs(Subject, Callable) 491 */ 492 @SuppressWarnings("removal") 493 @Deprecated(since="17", forRemoval=true) 494 public static <T> T doAsPrivileged(final Subject subject, 495 final java.security.PrivilegedAction<T> action, 496 final java.security.AccessControlContext acc) { 497 498 Objects.requireNonNull(action, 499 ResourcesMgr.getString("invalid.null.action.provided")); 500 501 try { 502 return callAs(subject, action::run); 503 } catch (CompletionException ce) { 504 var cause = ce.getCause(); 505 if (cause instanceof RuntimeException re) { 506 throw re; 507 } else if (cause instanceof Error er) { 508 throw er; 509 } else { 510 throw new AssertionError(ce); 511 } 512 } 513 } 514 515 /** 516 * Perform work as a particular {@code Subject}. 517 * 518 * <p> This method launches {@code action} and binds {@code subject} to 519 * the period of its execution. 520 * 521 * @param subject the {@code Subject} that the specified 522 * {@code action} will run as. This parameter 523 * may be {@code null}. 524 * 525 * @param <T> the type of the value returned by the 526 * PrivilegedExceptionAction's {@code run} method. 527 * 528 * @param action the code to be run as the specified 529 * {@code Subject}. 530 * 531 * @param acc ignored 532 * 533 * @return the value returned by the 534 * PrivilegedExceptionAction's {@code run} method. 535 * 536 * @throws PrivilegedActionException if the 537 * {@code PrivilegedExceptionAction.run} 538 * method throws a checked exception. 539 * 540 * @throws NullPointerException if the specified 541 * {@code PrivilegedExceptionAction} is 542 * {@code null}. 543 * 544 * @deprecated This method originally performed the specified 545 * {@code PrivilegedExceptionAction} with privileges enabled and 546 * restricted by the specified {@code AccessControlContext}. Running 547 * the action with privileges enabled was only useful in conjunction 548 * with {@linkplain SecurityManager the Security Manager}, which is 549 * no longer supported. This method has been changed to ignore the 550 * {@code AccessControlContext} and launch the action as is and bind 551 * the subject to the period of its execution. A replacement API 552 * named {@link #callAs} has been added which can be used to perform 553 * the same work. There is no replacement for the Security Manager. 554 * 555 * @see #callAs(Subject, Callable) 556 */ 557 @SuppressWarnings("removal") 558 @Deprecated(since="17", forRemoval=true) 559 public static <T> T doAsPrivileged(final Subject subject, 560 final java.security.PrivilegedExceptionAction<T> action, 561 final java.security.AccessControlContext acc) 562 throws java.security.PrivilegedActionException { 563 564 Objects.requireNonNull(action, 565 ResourcesMgr.getString("invalid.null.action.provided")); 566 567 try { 568 return callAs(subject, action::run); 569 } catch (CompletionException ce) { 570 var cause = ce.getCause(); 571 if (cause instanceof RuntimeException re) { 572 throw re; 573 } else if (cause instanceof Error er) { 574 throw er; 575 } else if (cause instanceof Exception e) { 576 throw new PrivilegedActionException(e); 577 } else { 578 throw new PrivilegedActionException(ce); 579 } 580 } 581 } 582 583 /** 584 * Return the {@code Set} of Principals associated with this 585 * {@code Subject}. Each {@code Principal} represents 586 * an identity for this {@code Subject}. 587 * 588 * <p> The returned {@code Set} is backed by this Subject's 589 * internal {@code Principal} {@code Set}. Any modification 590 * to the returned {@code Set} affects the internal 591 * {@code Principal} {@code Set} as well. 592 * 593 * @return the {@code Set} of Principals associated with this 594 * {@code Subject}. 595 */ 596 public Set<Principal> getPrincipals() { 597 598 // always return an empty Set instead of null 599 // so LoginModules can add to the Set if necessary 600 return principals; 601 } 602 603 /** 604 * Return a {@code Set} of Principals associated with this 605 * {@code Subject} that are instances or subclasses of the specified 606 * {@code Class}. 607 * 608 * <p> The returned {@code Set} is not backed by this Subject's 609 * internal {@code Principal} {@code Set}. A new 610 * {@code Set} is created and returned for each method invocation. 611 * Modifications to the returned {@code Set} 612 * will not affect the internal {@code Principal} {@code Set}. 613 * 614 * @param <T> the type of the class modeled by {@code c} 615 * 616 * @param c the returned {@code Set} of Principals will all be 617 * instances of this class. 618 * 619 * @return a {@code Set} of Principals that are instances of the 620 * specified {@code Class}. 621 * 622 * @throws NullPointerException if the specified {@code Class} 623 * is {@code null}. 624 */ 625 public <T extends Principal> Set<T> getPrincipals(Class<T> c) { 626 627 Objects.requireNonNull(c, 628 ResourcesMgr.getString("invalid.null.Class.provided")); 629 630 // always return an empty Set instead of null 631 // so LoginModules can add to the Set if necessary 632 return new ClassSet<>(PRINCIPAL_SET, c); 633 } 634 635 /** 636 * Return the {@code Set} of public credentials held by this 637 * {@code Subject}. 638 * 639 * <p> The returned {@code Set} is backed by this Subject's 640 * internal public Credential {@code Set}. Any modification 641 * to the returned {@code Set} affects the internal public 642 * Credential {@code Set} as well. 643 * 644 * @return a {@code Set} of public credentials held by this 645 * {@code Subject}. 646 */ 647 public Set<Object> getPublicCredentials() { 648 649 // always return an empty Set instead of null 650 // so LoginModules can add to the Set if necessary 651 return pubCredentials; 652 } 653 654 /** 655 * Return the {@code Set} of private credentials held by this 656 * {@code Subject}. 657 * 658 * <p> The returned {@code Set} is backed by this Subject's 659 * internal private Credential {@code Set}. Any modification 660 * to the returned {@code Set} affects the internal private 661 * Credential {@code Set} as well. 662 * 663 * @return a {@code Set} of private credentials held by this 664 * {@code Subject}. 665 */ 666 public Set<Object> getPrivateCredentials() { 667 668 // always return an empty Set instead of null 669 // so LoginModules can add to the Set if necessary 670 return privCredentials; 671 } 672 673 /** 674 * Return a {@code Set} of public credentials associated with this 675 * {@code Subject} that are instances or subclasses of the specified 676 * {@code Class}. 677 * 678 * <p> The returned {@code Set} is not backed by this Subject's 679 * internal public Credential {@code Set}. A new 680 * {@code Set} is created and returned for each method invocation. 681 * Modifications to the returned {@code Set} 682 * will not affect the internal public Credential {@code Set}. 683 * 684 * @param <T> the type of the class modeled by {@code c} 685 * 686 * @param c the returned {@code Set} of public credentials will all be 687 * instances of this class. 688 * 689 * @return a {@code Set} of public credentials that are instances 690 * of the specified {@code Class}. 691 * 692 * @throws NullPointerException if the specified {@code Class} 693 * is {@code null}. 694 */ 695 public <T> Set<T> getPublicCredentials(Class<T> c) { 696 697 Objects.requireNonNull(c, 698 ResourcesMgr.getString("invalid.null.Class.provided")); 699 700 // always return an empty Set instead of null 701 // so LoginModules can add to the Set if necessary 702 return new ClassSet<>(PUB_CREDENTIAL_SET, c); 703 } 704 705 /** 706 * Return a {@code Set} of private credentials associated with this 707 * {@code Subject} that are instances or subclasses of the specified 708 * {@code Class}. 709 * 710 * <p> The returned {@code Set} is not backed by this Subject's 711 * internal private Credential {@code Set}. A new 712 * {@code Set} is created and returned for each method invocation. 713 * Modifications to the returned {@code Set} 714 * will not affect the internal private Credential {@code Set}. 715 * 716 * @param <T> the type of the class modeled by {@code c} 717 * 718 * @param c the returned {@code Set} of private credentials will all be 719 * instances of this class. 720 * 721 * @return a {@code Set} of private credentials that are instances 722 * of the specified {@code Class}. 723 * 724 * @throws NullPointerException if the specified {@code Class} 725 * is {@code null}. 726 */ 727 public <T> Set<T> getPrivateCredentials(Class<T> c) { 728 729 Objects.requireNonNull(c, 730 ResourcesMgr.getString("invalid.null.Class.provided")); 731 732 // always return an empty Set instead of null 733 // so LoginModules can add to the Set if necessary 734 return new ClassSet<>(PRIV_CREDENTIAL_SET, c); 735 } 736 737 /** 738 * Compares the specified Object with this {@code Subject} 739 * for equality. Returns true if the given object is also a Subject 740 * and the two {@code Subject} instances are equivalent. 741 * More formally, two {@code Subject} instances are 742 * equal if their {@code Principal} and {@code Credential} 743 * Sets are equal. 744 * 745 * @param o Object to be compared for equality with this 746 * {@code Subject}. 747 * 748 * @return true if the specified Object is equal to this 749 * {@code Subject}. 750 */ 751 @Override 752 public boolean equals(Object o) { 753 754 if (this == o) { 755 return true; 756 } 757 758 if (o instanceof final Subject that) { 759 760 // check the principal and credential sets 761 Set<Principal> thatPrincipals; 762 synchronized(that.principals) { 763 // avoid deadlock from dual locks 764 thatPrincipals = new HashSet<>(that.principals); 765 } 766 if (!principals.equals(thatPrincipals)) { 767 return false; 768 } 769 770 Set<Object> thatPubCredentials; 771 synchronized(that.pubCredentials) { 772 // avoid deadlock from dual locks 773 thatPubCredentials = new HashSet<>(that.pubCredentials); 774 } 775 if (!pubCredentials.equals(thatPubCredentials)) { 776 return false; 777 } 778 779 Set<Object> thatPrivCredentials; 780 synchronized(that.privCredentials) { 781 // avoid deadlock from dual locks 782 thatPrivCredentials = new HashSet<>(that.privCredentials); 783 } 784 return privCredentials.equals(thatPrivCredentials); 785 } 786 return false; 787 } 788 789 /** 790 * Return the String representation of this {@code Subject}. 791 * 792 * @return the String representation of this {@code Subject}. 793 */ 794 @Override 795 public String toString() { 796 797 String s = ResourcesMgr.getString("Subject."); 798 String suffix = ""; 799 800 synchronized(principals) { 801 for (Principal p : principals) { 802 suffix = suffix + ResourcesMgr.getString(".Principal.") + 803 p.toString() + ResourcesMgr.getString("NEWLINE"); 804 } 805 } 806 807 synchronized(pubCredentials) { 808 for (Object o : pubCredentials) { 809 suffix = suffix + 810 ResourcesMgr.getString(".Public.Credential.") + 811 o.toString() + ResourcesMgr.getString("NEWLINE"); 812 } 813 } 814 815 synchronized(privCredentials) { 816 Iterator<Object> pI = privCredentials.iterator(); 817 while (pI.hasNext()) { 818 try { 819 Object o = pI.next(); 820 suffix += ResourcesMgr.getString 821 (".Private.Credential.") + 822 o.toString() + 823 ResourcesMgr.getString("NEWLINE"); 824 } catch (SecurityException se) { 825 suffix += ResourcesMgr.getString 826 (".Private.Credential.inaccessible."); 827 break; 828 } 829 } 830 } 831 return s + suffix; 832 } 833 834 /** 835 * {@return a hashcode for this {@code Subject}} 836 */ 837 @Override 838 public int hashCode() { 839 840 /* 841 * The hashcode is derived exclusive or-ing the 842 * hashcodes of this Subject's Principals and credentials. 843 * 844 * If a particular credential was destroyed 845 * ({@code credential.hashCode()} throws an 846 * {@code IllegalStateException}), 847 * the hashcode for that credential is derived via: 848 * {@code credential.getClass().toString().hashCode()}. 849 */ 850 851 int hashCode = 0; 852 853 synchronized(principals) { 854 for (Principal p : principals) { 855 hashCode ^= p.hashCode(); 856 } 857 } 858 859 synchronized(pubCredentials) { 860 for (Object pubCredential : pubCredentials) { 861 hashCode ^= getCredHashCode(pubCredential); 862 } 863 } 864 return hashCode; 865 } 866 867 /** 868 * get a credential's hashcode 869 */ 870 private int getCredHashCode(Object o) { 871 try { 872 return o.hashCode(); 873 } catch (IllegalStateException ise) { 874 return o.getClass().toString().hashCode(); 875 } 876 } 877 878 /** 879 * Writes this object out to a stream (i.e., serializes it). 880 * 881 * @param oos the {@code ObjectOutputStream} to which data is written 882 * @throws IOException if an I/O error occurs 883 */ 884 @java.io.Serial 885 private void writeObject(java.io.ObjectOutputStream oos) 886 throws java.io.IOException { 887 synchronized(principals) { 888 oos.defaultWriteObject(); 889 } 890 } 891 892 /** 893 * Reads this object from a stream (i.e., deserializes it) 894 * 895 * @param s the {@code ObjectInputStream} from which data is read 896 * @throws IOException if an I/O error occurs 897 * @throws ClassNotFoundException if a serialized class cannot be loaded 898 */ 899 @SuppressWarnings("unchecked") 900 @java.io.Serial 901 private void readObject(java.io.ObjectInputStream s) 902 throws java.io.IOException, ClassNotFoundException { 903 904 ObjectInputStream.GetField gf = s.readFields(); 905 906 readOnly = gf.get("readOnly", false); 907 908 Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null); 909 910 Objects.requireNonNull(inputPrincs, 911 ResourcesMgr.getString("invalid.null.input.s.")); 912 913 // Rewrap the principals into a SecureSet 914 try { 915 LinkedList<Principal> principalList = collectionNullClean(inputPrincs); 916 principals = Collections.synchronizedSet(new SecureSet<> 917 (this, PRINCIPAL_SET, principalList)); 918 } catch (NullPointerException npe) { 919 // Sometimes people deserialize the principals set only. 920 // Subject is not accessible, so just don't fail. 921 principals = Collections.synchronizedSet 922 (new SecureSet<>(this, PRINCIPAL_SET)); 923 } 924 925 // The Credential {@code Set} is not serialized, but we do not 926 // want the default deserialization routine to set it to null. 927 this.pubCredentials = Collections.synchronizedSet 928 (new SecureSet<>(this, PUB_CREDENTIAL_SET)); 929 this.privCredentials = Collections.synchronizedSet 930 (new SecureSet<>(this, PRIV_CREDENTIAL_SET)); 931 } 932 933 /** 934 * Tests for null-clean collections (both non-null reference and 935 * no null elements) 936 * 937 * @param coll A {@code Collection} to be tested for null references 938 * 939 * @throws NullPointerException if the specified collection is either 940 * {@code null} or contains a {@code null} element 941 */ 942 private static <E> LinkedList<E> collectionNullClean( 943 Collection<? extends E> coll) { 944 945 Objects.requireNonNull(coll, 946 ResourcesMgr.getString("invalid.null.input.s.")); 947 948 LinkedList<E> output = new LinkedList<>(); 949 for (E e : coll) { 950 output.add(Objects.requireNonNull(e, 951 ResourcesMgr.getString("invalid.null.input.s."))); 952 } 953 return output; 954 } 955 956 /** 957 * Prevent modifications unless caller has permission. 958 * 959 * @serial include 960 */ 961 private static class SecureSet<E> 962 implements Set<E>, java.io.Serializable { 963 964 @java.io.Serial 965 private static final long serialVersionUID = 7911754171111800359L; 966 967 /** 968 * @serialField this$0 Subject The outer Subject instance. 969 * @serialField elements LinkedList The elements in this set. 970 */ 971 @java.io.Serial 972 private static final ObjectStreamField[] serialPersistentFields = { 973 new ObjectStreamField("this$0", Subject.class), 974 new ObjectStreamField("elements", LinkedList.class), 975 new ObjectStreamField("which", int.class) 976 }; 977 978 Subject subject; 979 LinkedList<E> elements; 980 981 /** 982 * @serial An integer identifying the type of objects contained 983 * in this set. If {@code which == 1}, 984 * this is a Principal set and all the elements are 985 * of type {@code java.security.Principal}. 986 * If {@code which == 2}, this is a public credential 987 * set and all the elements are of type {@code Object}. 988 * If {@code which == 3}, this is a private credential 989 * set and all the elements are of type {@code Object}. 990 */ 991 private int which; 992 993 SecureSet(Subject subject, int which) { 994 this.subject = subject; 995 this.which = which; 996 this.elements = new LinkedList<>(); 997 } 998 999 SecureSet(Subject subject, int which, LinkedList<E> list) { 1000 this.subject = subject; 1001 this.which = which; 1002 this.elements = list; 1003 } 1004 1005 public int size() { 1006 return elements.size(); 1007 } 1008 1009 public Iterator<E> iterator() { 1010 final LinkedList<E> list = elements; 1011 return new Iterator<>() { 1012 final ListIterator<E> i = list.listIterator(0); 1013 1014 public boolean hasNext() { 1015 return i.hasNext(); 1016 } 1017 1018 public E next() { 1019 return i.next(); 1020 } 1021 1022 public void remove() { 1023 1024 if (subject.isReadOnly()) { 1025 throw new IllegalStateException(ResourcesMgr.getString 1026 ("Subject.is.read.only")); 1027 } 1028 1029 i.remove(); 1030 } 1031 }; 1032 } 1033 1034 public boolean add(E o) { 1035 1036 Objects.requireNonNull(o, 1037 ResourcesMgr.getString("invalid.null.input.s.")); 1038 1039 if (subject.isReadOnly()) { 1040 throw new IllegalStateException 1041 (ResourcesMgr.getString("Subject.is.read.only")); 1042 } 1043 1044 switch (which) { 1045 case Subject.PRINCIPAL_SET: 1046 if (!(o instanceof Principal)) { 1047 throw new SecurityException(ResourcesMgr.getString 1048 ("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set")); 1049 } 1050 break; 1051 default: 1052 // ok to add Objects of any kind to credential sets 1053 break; 1054 } 1055 1056 // check for duplicates 1057 if (!elements.contains(o)) 1058 return elements.add(o); 1059 else { 1060 return false; 1061 } 1062 } 1063 1064 public boolean remove(Object o) { 1065 1066 Objects.requireNonNull(o, 1067 ResourcesMgr.getString("invalid.null.input.s.")); 1068 1069 final Iterator<E> e = iterator(); 1070 while (e.hasNext()) { 1071 E next = e.next(); 1072 1073 if (next.equals(o)) { 1074 e.remove(); 1075 return true; 1076 } 1077 } 1078 return false; 1079 } 1080 1081 public boolean contains(Object o) { 1082 1083 Objects.requireNonNull(o, 1084 ResourcesMgr.getString("invalid.null.input.s.")); 1085 1086 final Iterator<E> e = iterator(); 1087 while (e.hasNext()) { 1088 E next = e.next(); 1089 1090 if (next.equals(o)) { 1091 return true; 1092 } 1093 } 1094 return false; 1095 } 1096 1097 public boolean addAll(Collection<? extends E> c) { 1098 boolean result = false; 1099 1100 c = collectionNullClean(c); 1101 1102 for (E item : c) { 1103 result |= this.add(item); 1104 } 1105 1106 return result; 1107 } 1108 1109 public boolean removeAll(Collection<?> c) { 1110 c = collectionNullClean(c); 1111 1112 boolean modified = false; 1113 final Iterator<E> e = iterator(); 1114 while (e.hasNext()) { 1115 E next = e.next(); 1116 1117 for (Object o : c) { 1118 if (next.equals(o)) { 1119 e.remove(); 1120 modified = true; 1121 break; 1122 } 1123 } 1124 } 1125 return modified; 1126 } 1127 1128 public boolean containsAll(Collection<?> c) { 1129 c = collectionNullClean(c); 1130 1131 for (Object item : c) { 1132 if (!this.contains(item)) { 1133 return false; 1134 } 1135 } 1136 1137 return true; 1138 } 1139 1140 public boolean retainAll(Collection<?> c) { 1141 c = collectionNullClean(c); 1142 1143 boolean modified = false; 1144 final Iterator<E> e = iterator(); 1145 while (e.hasNext()) { 1146 E next = e.next(); 1147 1148 if (c.contains(next) == false) { 1149 e.remove(); 1150 modified = true; 1151 } 1152 } 1153 1154 return modified; 1155 } 1156 1157 public void clear() { 1158 final Iterator<E> e = iterator(); 1159 while (e.hasNext()) { 1160 E next = e.next(); 1161 e.remove(); 1162 } 1163 } 1164 1165 public boolean isEmpty() { 1166 return elements.isEmpty(); 1167 } 1168 1169 public Object[] toArray() { 1170 return elements.toArray(); 1171 } 1172 1173 public <T> T[] toArray(T[] a) { 1174 return elements.toArray(a); 1175 } 1176 1177 @Override 1178 public boolean equals(Object o) { 1179 if (o == this) { 1180 return true; 1181 } 1182 1183 if (!(o instanceof Set)) { 1184 return false; 1185 } 1186 1187 Collection<?> c = (Collection<?>) o; 1188 if (c.size() != size()) { 1189 return false; 1190 } 1191 1192 try { 1193 return containsAll(c); 1194 } catch (ClassCastException | NullPointerException unused) { 1195 return false; 1196 } 1197 } 1198 1199 @Override 1200 public int hashCode() { 1201 int h = 0; 1202 for (E obj : this) { 1203 h += Objects.hashCode(obj); 1204 } 1205 return h; 1206 } 1207 1208 /** 1209 * Writes this object out to a stream (i.e., serializes it). 1210 * 1211 * @param oos the {@code ObjectOutputStream} to which data is written 1212 * @throws IOException if an I/O error occurs 1213 */ 1214 @java.io.Serial 1215 private void writeObject(java.io.ObjectOutputStream oos) 1216 throws java.io.IOException { 1217 1218 ObjectOutputStream.PutField fields = oos.putFields(); 1219 fields.put("this$0", subject); 1220 fields.put("elements", elements); 1221 fields.put("which", which); 1222 oos.writeFields(); 1223 } 1224 1225 /** 1226 * Restores the state of this object from the stream. 1227 * 1228 * @param ois the {@code ObjectInputStream} from which data is read 1229 * @throws IOException if an I/O error occurs 1230 * @throws ClassNotFoundException if a serialized class cannot be loaded 1231 */ 1232 @SuppressWarnings("unchecked") 1233 @java.io.Serial 1234 private void readObject(ObjectInputStream ois) 1235 throws IOException, ClassNotFoundException 1236 { 1237 ObjectInputStream.GetField fields = ois.readFields(); 1238 subject = (Subject) fields.get("this$0", null); 1239 which = fields.get("which", 0); 1240 1241 LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null); 1242 1243 elements = Subject.collectionNullClean(tmp); 1244 } 1245 1246 } 1247 1248 /** 1249 * This class implements a {@code Set} which returns only 1250 * members that are an instance of a specified Class. 1251 */ 1252 private class ClassSet<T> extends AbstractSet<T> { 1253 1254 private final int which; 1255 private final Class<T> c; 1256 private final Set<T> set; 1257 1258 ClassSet(int which, Class<T> c) { 1259 this.which = which; 1260 this.c = c; 1261 set = new HashSet<>(); 1262 1263 switch (which) { 1264 case Subject.PRINCIPAL_SET: 1265 synchronized(principals) { populateSet(); } 1266 break; 1267 case Subject.PUB_CREDENTIAL_SET: 1268 synchronized(pubCredentials) { populateSet(); } 1269 break; 1270 default: 1271 synchronized(privCredentials) { populateSet(); } 1272 break; 1273 } 1274 } 1275 1276 @SuppressWarnings("unchecked") 1277 private void populateSet() { 1278 final Iterator<?> iterator; 1279 switch(which) { 1280 case Subject.PRINCIPAL_SET: 1281 iterator = Subject.this.principals.iterator(); 1282 break; 1283 case Subject.PUB_CREDENTIAL_SET: 1284 iterator = Subject.this.pubCredentials.iterator(); 1285 break; 1286 default: 1287 iterator = Subject.this.privCredentials.iterator(); 1288 break; 1289 } 1290 1291 while (iterator.hasNext()) { 1292 Object next = iterator.next(); 1293 if (c.isAssignableFrom(next.getClass())) { 1294 set.add((T)next); 1295 } 1296 } 1297 } 1298 1299 @Override 1300 public int size() { 1301 return set.size(); 1302 } 1303 1304 @Override 1305 public Iterator<T> iterator() { 1306 return set.iterator(); 1307 } 1308 1309 @Override 1310 public boolean add(T o) { 1311 1312 if (!c.isAssignableFrom(o.getClass())) { 1313 MessageFormat form = new MessageFormat(ResourcesMgr.getString 1314 ("attempting.to.add.an.object.which.is.not.an.instance.of.class")); 1315 Object[] source = {c.toString()}; 1316 throw new SecurityException(form.format(source)); 1317 } 1318 1319 return set.add(o); 1320 } 1321 } 1322 }