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><b><a id="sm-allowed">These methods behave differently depending on
 112  * whether a security manager is
 113  * <a href="../../../java/lang/SecurityManager.html#set-security-manager">allowed or disallowed</a></a></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.callWhere(SCOPED_SUBJECT, subject, 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 }