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