       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     public static Subject getSubject(final AccessControlContext acc) {
     289
     290         java.lang.SecurityManager sm = System.getSecurityManager();
     291         if (sm != null) {
     292             sm.checkPermission(AuthPermissionHolder.GET_SUBJECT_PERMISSION);
     293         }
     294
     295         Objects.requireNonNull(acc, ResourcesMgr.getString
     296                 ("invalid.null.AccessControlContext.provided"));
     297
     298         // return the Subject from the DomainCombiner of the provided context
     299         return AccessController.doPrivileged
     300             (new java.security.PrivilegedAction<>() {
     301             public Subject run() {
     302                 DomainCombiner dc = acc.getDomainCombiner();
     303                 if (!(dc instanceof SubjectDomainCombiner)) {
     304                     return null;
     305                 }
     306                 SubjectDomainCombiner sdc = (SubjectDomainCombiner)dc;
     307                 return sdc.getSubject();
     308             }
     309         });
     310     }
     311
     312     /**
     313      * Perform work as a particular {@code Subject}.
     314      *
     315      * <p> This method first retrieves the current Thread's
     316      * {@code AccessControlContext} via
     317      * {@code AccessController.getContext},
     318      * and then instantiates a new {@code AccessControlContext}
     319      * using the retrieved context along with a new
     320      * {@code SubjectDomainCombiner} (constructed using
     321      * the provided {@code Subject}).
     322      * Finally, this method invokes {@code AccessController.doPrivileged},
     323      * passing it the provided {@code PrivilegedAction},
     324      * as well as the newly constructed {@code AccessControlContext}.
     325      *
     326      * @param subject the {@code Subject} that the specified
     327      *                  {@code action} will run as.  This parameter
     328      *                  may be {@code null}.
     329      *
     330      * @param <T> the type of the value returned by the PrivilegedAction's
     331      *                  {@code run} method.
     332      *
     333      * @param action the code to be run as the specified
     334      *                  {@code Subject}.
     335      *
     336      * @return the value returned by the PrivilegedAction's
     337      *                  {@code run} method.
     338      *
     339      * @throws NullPointerException if the {@code PrivilegedAction}
     340      *                  is {@code null}.
     341      *
     342      * @throws SecurityException if a security manager is installed and the
     343      *                  caller does not have an
     344      *                  {@link AuthPermission#AuthPermission(String)
     345      *                  AuthPermission("doAs")} permission to invoke this
     346      *                  method.
     347      */
     348     public static <T> T doAs(final Subject subject,
     349                         final java.security.PrivilegedAction<T> action) {
     350
     351         java.lang.SecurityManager sm = System.getSecurityManager();
     352         if (sm != null) {
     353             sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);
     354         }
     355
     356         Objects.requireNonNull(action,
     357                 ResourcesMgr.getString("invalid.null.action.provided"));
     358
     359         // set up the new Subject-based AccessControlContext
     360         // for doPrivileged
     361         final AccessControlContext currentAcc = AccessController.getContext();
     362
     363         // call doPrivileged and push this new context on the stack
     364         return java.security.AccessController.doPrivileged
     365                                         (action,
     366                                         createContext(subject, currentAcc));
     367     }
     368
     369     /**
     370      * Perform work as a particular {@code Subject}.
     371      *
     372      * <p> This method first retrieves the current Thread's
     373      * {@code AccessControlContext} via
     374      * {@code AccessController.getContext},
     375      * and then instantiates a new {@code AccessControlContext}
     376      * using the retrieved context along with a new
     377      * {@code SubjectDomainCombiner} (constructed using
     378      * the provided {@code Subject}).
     379      * Finally, this method invokes {@code AccessController.doPrivileged},
     380      * passing it the provided {@code PrivilegedExceptionAction},
     381      * as well as the newly constructed {@code AccessControlContext}.
     382      *
     383      * @param subject the {@code Subject} that the specified
     384      *                  {@code action} will run as.  This parameter
     385      *                  may be {@code null}.
     386      *
     387      * @param <T> the type of the value returned by the
     388      *                  PrivilegedExceptionAction's {@code run} method.
     389      *
     390      * @param action the code to be run as the specified
     391      *                  {@code Subject}.
     392      *
     393      * @return the value returned by the
     394      *                  PrivilegedExceptionAction's {@code run} method.
     395      *
     396      * @throws PrivilegedActionException if the
     397      *                  {@code PrivilegedExceptionAction.run}
     398      *                  method throws a checked exception.
     399      *
     400      * @throws NullPointerException if the specified
     401      *                  {@code PrivilegedExceptionAction} is
     402      *                  {@code null}.
     403      *
     404      * @throws SecurityException if a security manager is installed and the
     405      *                  caller does not have an
     406      *                  {@link AuthPermission#AuthPermission(String)
     407      *                  AuthPermission("doAs")} permission to invoke this
     408      *                  method.
     409      */
     410     public static <T> T doAs(final Subject subject,
     411                         final java.security.PrivilegedExceptionAction<T> action)
     412                         throws java.security.PrivilegedActionException {
     413
     414         java.lang.SecurityManager sm = System.getSecurityManager();
     415         if (sm != null) {
     416             sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);
     417         }
     418
     419         Objects.requireNonNull(action,
     420                 ResourcesMgr.getString("invalid.null.action.provided"));
     421
     422         // set up the new Subject-based AccessControlContext for doPrivileged
     423         final AccessControlContext currentAcc = AccessController.getContext();
     424
     425         // call doPrivileged and push this new context on the stack
     426         return java.security.AccessController.doPrivileged
     427                                         (action,
     428                                         createContext(subject, currentAcc));
     429     }
     430
     431     /**
     432      * Perform privileged work as a particular {@code Subject}.
     433      *
     434      * <p> This method behaves exactly as {@code Subject.doAs},
     435      * except that instead of retrieving the current Thread's
     436      * {@code AccessControlContext}, it uses the provided
     437      * {@code AccessControlContext}.  If the provided
     438      * {@code AccessControlContext} is {@code null},
     439      * this method instantiates a new {@code AccessControlContext}
     440      * with an empty collection of ProtectionDomains.
     441      *
     442      * @param subject the {@code Subject} that the specified
     443      *                  {@code action} will run as.  This parameter
     444      *                  may be {@code null}.
     445      *
     446      * @param <T> the type of the value returned by the PrivilegedAction's
     447      *                  {@code run} method.
     448      *
     449      * @param action the code to be run as the specified
     450      *                  {@code Subject}.
     451      *
     452      * @param acc the {@code AccessControlContext} to be tied to the
     453      *                  specified <i>subject</i> and <i>action</i>.
     454      *
     455      * @return the value returned by the PrivilegedAction's
     456      *                  {@code run} method.
     457      *
     458      * @throws NullPointerException if the {@code PrivilegedAction}
     459      *                  is {@code null}.
     460      *
     461      * @throws SecurityException if a security manager is installed and the
     462      *                  caller does not have a
     463      *                  {@link AuthPermission#AuthPermission(String)
     464      *                  AuthPermission("doAsPrivileged")} permission to invoke
     465      *                  this method.
     466      */
     467     public static <T> T doAsPrivileged(final Subject subject,
     468                         final java.security.PrivilegedAction<T> action,
     469                         final java.security.AccessControlContext acc) {
     470
     471         java.lang.SecurityManager sm = System.getSecurityManager();
     472         if (sm != null) {
     473             sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);
     474         }
     475
     476         Objects.requireNonNull(action,
     477                 ResourcesMgr.getString("invalid.null.action.provided"));
     478
     479         // set up the new Subject-based AccessControlContext
     480         // for doPrivileged
     481         final AccessControlContext callerAcc =
     482                 (acc == null ?
     483                 new AccessControlContext(NULL_PD_ARRAY) :
     484                 acc);
     485
     486         // call doPrivileged and push this new context on the stack
     487         return java.security.AccessController.doPrivileged
     488                                         (action,
     489                                         createContext(subject, callerAcc));
     490     }
     491
     492     /**
     493      * Perform privileged work as a particular {@code Subject}.
     494      *
     495      * <p> This method behaves exactly as {@code Subject.doAs},
     496      * except that instead of retrieving the current Thread's
     497      * {@code AccessControlContext}, it uses the provided
     498      * {@code AccessControlContext}.  If the provided
     499      * {@code AccessControlContext} is {@code null},
     500      * this method instantiates a new {@code AccessControlContext}
     501      * with an empty collection of ProtectionDomains.
     502      *
     503      * @param subject the {@code Subject} that the specified
     504      *                  {@code action} will run as.  This parameter
     505      *                  may be {@code null}.
     506      *
     507      * @param <T> the type of the value returned by the
     508      *                  PrivilegedExceptionAction's {@code run} method.
     509      *
     510      * @param action the code to be run as the specified
     511      *                  {@code Subject}.
     512      *
     513      * @param acc the {@code AccessControlContext} to be tied to the
     514      *                  specified <i>subject</i> and <i>action</i>.
     515      *
     516      * @return the value returned by the
     517      *                  PrivilegedExceptionAction's {@code run} method.
     518      *
     519      * @throws PrivilegedActionException if the
     520      *                  {@code PrivilegedExceptionAction.run}
     521      *                  method throws a checked exception.
     522      *
     523      * @throws NullPointerException if the specified
     524      *                  {@code PrivilegedExceptionAction} is
     525      *                  {@code null}.
     526      *
     527      * @throws SecurityException if a security manager is installed and the
     528      *                  caller does not have a
     529      *                  {@link AuthPermission#AuthPermission(String)
     530      *                  AuthPermission("doAsPrivileged")} permission to invoke
     531      *                  this method.
     532      */
     533     public static <T> T doAsPrivileged(final Subject subject,
     534                         final java.security.PrivilegedExceptionAction<T> action,
     535                         final java.security.AccessControlContext acc)
     536                         throws java.security.PrivilegedActionException {
     537
     538         java.lang.SecurityManager sm = System.getSecurityManager();
     539         if (sm != null) {
     540             sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);
     541         }
     542
     543         Objects.requireNonNull(action,
     544                 ResourcesMgr.getString("invalid.null.action.provided"));
     545
     546         // set up the new Subject-based AccessControlContext for doPrivileged
     547         final AccessControlContext callerAcc =
     548                 (acc == null ?
     549                 new AccessControlContext(NULL_PD_ARRAY) :
     550                 acc);
     551
     552         // call doPrivileged and push this new context on the stack
     553         return java.security.AccessController.doPrivileged
     554                                         (action,
     555                                         createContext(subject, callerAcc));
     556     }
     557
     558     private static AccessControlContext createContext(final Subject subject,
     559                                         final AccessControlContext acc) {
     560
     561
     562         return java.security.AccessController.doPrivileged
     563             (new java.security.PrivilegedAction<>() {
     564             public AccessControlContext run() {
     565                 if (subject == null) {
     566                     return new AccessControlContext(acc, null);
     567                 } else {
     568                     return new AccessControlContext
     569                                         (acc,
     570                                         new SubjectDomainCombiner(subject));
     571             }
     572             }
     573         });
     574     }
     575
     576     /**
     577      * Return the {@code Set} of Principals associated with this
     578      * {@code Subject}.  Each {@code Principal} represents
     579      * an identity for this {@code Subject}.
     580      *
     581      * <p> The returned {@code Set} is backed by this Subject's
     582      * internal {@code Principal} {@code Set}.  Any modification
     583      * to the returned {@code Set} affects the internal
     584      * {@code Principal} {@code Set} as well.
     585      *
     586      * <p> If a security manager is installed, the caller must have a
     587      * {@link AuthPermission#AuthPermission(String)
     588      * AuthPermission("modifyPrincipals")} permission to modify
     589      * the returned set, or a {@code SecurityException} will be thrown.
     590      *
     591      * @return  the {@code Set} of Principals associated with this
     592      *          {@code Subject}.
     593      */
     594     public Set<Principal> getPrincipals() {
     595
     596         // always return an empty Set instead of null
     597         // so LoginModules can add to the Set if necessary
     598         return principals;
     599     }
     600
     601     /**
     602      * Return a {@code Set} of Principals associated with this
     603      * {@code Subject} that are instances or subclasses of the specified
     604      * {@code Class}.
     605      *
     606      * <p> The returned {@code Set} is not backed by this Subject's
     607      * internal {@code Principal} {@code Set}.  A new
     608      * {@code Set} is created and returned for each method invocation.
     609      * Modifications to the returned {@code Set}
     610      * will not affect the internal {@code Principal} {@code Set}.
     611      *
     612      * @param <T> the type of the class modeled by {@code c}
     613      *
     614      * @param c the returned {@code Set} of Principals will all be
     615      *          instances of this class.
     616      *
     617      * @return a {@code Set} of Principals that are instances of the
     618      *          specified {@code Class}.
     619      *
     620      * @throws NullPointerException if the specified {@code Class}
     621      *          is {@code null}.
     622      */
     623     public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
     624
     625         Objects.requireNonNull(c,
     626                 ResourcesMgr.getString("invalid.null.Class.provided"));
     627
     628         // always return an empty Set instead of null
     629         // so LoginModules can add to the Set if necessary
     630         return new ClassSet<T>(PRINCIPAL_SET, c);
     631     }
     632
     633     /**
     634      * Return the {@code Set} of public credentials held by this
     635      * {@code Subject}.
     636      *
     637      * <p> The returned {@code Set} is backed by this Subject's
     638      * internal public Credential {@code Set}.  Any modification
     639      * to the returned {@code Set} affects the internal public
     640      * Credential {@code Set} as well.
     641      *
     642      * <p> If a security manager is installed, the caller must have a
     643      * {@link AuthPermission#AuthPermission(String)
     644      * AuthPermission("modifyPublicCredentials")} permission to modify
     645      * the returned set, or a {@code SecurityException} will be thrown.
     646      *
     647      * @return  a {@code Set} of public credentials held by this
     648      *          {@code Subject}.
     649      */
     650     public Set<Object> getPublicCredentials() {
     651
     652         // always return an empty Set instead of null
     653         // so LoginModules can add to the Set if necessary
     654         return pubCredentials;
     655     }
     656
     657     /**
     658      * Return the {@code Set} of private credentials held by this
     659      * {@code Subject}.
     660      *
     661      * <p> The returned {@code Set} is backed by this Subject's
     662      * internal private Credential {@code Set}.  Any modification
     663      * to the returned {@code Set} affects the internal private
     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("modifyPrivateCredentials")} permission to modify
     669      * the returned set, or a {@code SecurityException} will be thrown.
     670      *
     671      * <p> While iterating through the {@code Set},
     672      * a {@code SecurityException} is thrown if a security manager is installed
     673      * and the caller does not have a {@link PrivateCredentialPermission}
     674      * to access a particular Credential.  The {@code Iterator}
     675      * is nevertheless advanced to the next element in the {@code Set}.
     676      *
     677      * @return  a {@code Set} of private credentials held by this
     678      *          {@code Subject}.
     679      */
     680     public Set<Object> getPrivateCredentials() {
     681
     682         // XXX
     683         // we do not need a security check for
     684         // AuthPermission(getPrivateCredentials)
     685         // because we already restrict access to private credentials
     686         // via the PrivateCredentialPermission.  all the extra AuthPermission
     687         // would do is protect the set operations themselves
     688         // (like size()), which don't seem security-sensitive.
     689
     690         // always return an empty Set instead of null
     691         // so LoginModules can add to the Set if necessary
     692         return privCredentials;
     693     }
     694
     695     /**
     696      * Return a {@code Set} of public credentials associated with this
     697      * {@code Subject} that are instances or subclasses of the specified
     698      * {@code Class}.
     699      *
     700      * <p> The returned {@code Set} is not backed by this Subject's
     701      * internal public Credential {@code Set}.  A new
     702      * {@code Set} is created and returned for each method invocation.
     703      * Modifications to the returned {@code Set}
     704      * will not affect the internal public Credential {@code Set}.
     705      *
     706      * @param <T> the type of the class modeled by {@code c}
     707      *
     708      * @param c the returned {@code Set} of public credentials will all be
     709      *          instances of this class.
     710      *
     711      * @return a {@code Set} of public credentials that are instances
     712      *          of the  specified {@code Class}.
     713      *
     714      * @throws NullPointerException if the specified {@code Class}
     715      *          is {@code null}.
     716      */
     717     public <T> Set<T> getPublicCredentials(Class<T> c) {
     718
     719         Objects.requireNonNull(c,
     720                 ResourcesMgr.getString("invalid.null.Class.provided"));
     721
     722         // always return an empty Set instead of null
     723         // so LoginModules can add to the Set if necessary
     724         return new ClassSet<T>(PUB_CREDENTIAL_SET, c);
     725     }
     726
     727     /**
     728      * Return a {@code Set} of private credentials associated with this
     729      * {@code Subject} that are instances or subclasses of the specified
     730      * {@code Class}.
     731      *
     732      * <p> If a security manager is installed, the caller must have a
     733      * {@link PrivateCredentialPermission} to access all of the requested
     734      * Credentials, or a {@code SecurityException} will be thrown.
     735      *
     736      * <p> The returned {@code Set} is not backed by this Subject's
     737      * internal private Credential {@code Set}.  A new
     738      * {@code Set} is created and returned for each method invocation.
     739      * Modifications to the returned {@code Set}
     740      * will not affect the internal private Credential {@code Set}.
     741      *
     742      * @param <T> the type of the class modeled by {@code c}
     743      *
     744      * @param c the returned {@code Set} of private credentials will all be
     745      *          instances of this class.
     746      *
     747      * @return a {@code Set} of private credentials that are instances
     748      *          of the  specified {@code Class}.
     749      *
     750      * @throws NullPointerException if the specified {@code Class}
     751      *          is {@code null}.
     752      */
     753     public <T> Set<T> getPrivateCredentials(Class<T> c) {
     754
     755         // XXX
     756         // we do not need a security check for
     757         // AuthPermission(getPrivateCredentials)
     758         // because we already restrict access to private credentials
     759         // via the PrivateCredentialPermission.  all the extra AuthPermission
     760         // would do is protect the set operations themselves
     761         // (like size()), which don't seem security-sensitive.
     762
     763         Objects.requireNonNull(c,
     764                 ResourcesMgr.getString("invalid.null.Class.provided"));
     765
     766         // always return an empty Set instead of null
     767         // so LoginModules can add to the Set if necessary
     768         return new ClassSet<T>(PRIV_CREDENTIAL_SET, c);
     769     }
     770
     771     /**
     772      * Compares the specified Object with this {@code Subject}
     773      * for equality.  Returns true if the given object is also a Subject
     774      * and the two {@code Subject} instances are equivalent.
     775      * More formally, two {@code Subject} instances are
     776      * equal if their {@code Principal} and {@code Credential}
     777      * Sets are equal.
     778      *
     779      * @param o Object to be compared for equality with this
     780      *          {@code Subject}.
     781      *
     782      * @return true if the specified Object is equal to this
     783      *          {@code Subject}.
     784      *
     785      * @throws SecurityException if a security manager is installed and the
     786      *         caller does not have a {@link PrivateCredentialPermission}
     787      *         permission to access the private credentials for this
     788      *         {@code Subject} or the provided {@code Subject}.
     789      */
     790     @Override
     791     public boolean equals(Object o) {
     792
     793         if (o == null) {
     794             return false;
     795         }
     796
     797         if (this == o) {
     798             return true;
     799         }
     800
     801         if (o instanceof Subject) {
     802
     803             final Subject that = (Subject)o;
     804
     805             // check the principal and credential sets
     806             Set<Principal> thatPrincipals;
     807             synchronized(that.principals) {
     808                 // avoid deadlock from dual locks
     809                 thatPrincipals = new HashSet<>(that.principals);
     810             }
     811             if (!principals.equals(thatPrincipals)) {
     812                 return false;
     813             }
     814
     815             Set<Object> thatPubCredentials;
     816             synchronized(that.pubCredentials) {
     817                 // avoid deadlock from dual locks
     818                 thatPubCredentials = new HashSet<>(that.pubCredentials);
     819             }
     820             if (!pubCredentials.equals(thatPubCredentials)) {
     821                 return false;
     822             }
     823
     824             Set<Object> thatPrivCredentials;
     825             synchronized(that.privCredentials) {
     826                 // avoid deadlock from dual locks
     827                 thatPrivCredentials = new HashSet<>(that.privCredentials);
     828             }
     829             if (!privCredentials.equals(thatPrivCredentials)) {
     830                 return false;
     831             }
     832             return true;
     833         }
     834         return false;
     835     }
     836
     837     /**
     838      * Return the String representation of this {@code Subject}.
     839      *
     840      * @return the String representation of this {@code Subject}.
     841      */
     842     @Override
     843     public String toString() {
     844         return toString(true);
     845     }
     846
     847     /**
     848      * package private convenience method to print out the Subject
     849      * without firing off a security check when trying to access
     850      * the Private Credentials
     851      */
     852     String toString(boolean includePrivateCredentials) {
     853
     854         String s = ResourcesMgr.getString("Subject.");
     855         String suffix = "";
     856
     857         synchronized(principals) {
     858             Iterator<Principal> pI = principals.iterator();
     859             while (pI.hasNext()) {
     860                 Principal p = pI.next();
     861                 suffix = suffix + ResourcesMgr.getString(".Principal.") +
     862                         p.toString() + ResourcesMgr.getString("NEWLINE");
     863             }
     864         }
     865
     866         synchronized(pubCredentials) {
     867             Iterator<Object> pI = pubCredentials.iterator();
     868             while (pI.hasNext()) {
     869                 Object o = pI.next();
     870                 suffix = suffix +
     871                         ResourcesMgr.getString(".Public.Credential.") +
     872                         o.toString() + ResourcesMgr.getString("NEWLINE");
     873             }
     874         }
     875
     876         if (includePrivateCredentials) {
     877             synchronized(privCredentials) {
     878                 Iterator<Object> pI = privCredentials.iterator();
     879                 while (pI.hasNext()) {
     880                     try {
     881                         Object o = pI.next();
     882                         suffix += ResourcesMgr.getString
     883                                         (".Private.Credential.") +
     884                                         o.toString() +
     885                                         ResourcesMgr.getString("NEWLINE");
     886                     } catch (SecurityException se) {
     887                         suffix += ResourcesMgr.getString
     888                                 (".Private.Credential.inaccessible.");
     889                         break;
     890                     }
     891                 }
     892             }
     893         }
     894         return s + suffix;
     895     }
     896
     897     /**
     898      * Returns a hashcode for this {@code Subject}.
     899      *
     900      * @return a hashcode for this {@code Subject}.
     901      *
     902      * @throws SecurityException if a security manager is installed and the
     903      *         caller does not have a {@link PrivateCredentialPermission}
     904      *         permission to access this Subject's private credentials.
     905      */
     906     @Override
     907     public int hashCode() {
     908
     909         /**
     910          * The hashcode is derived exclusive or-ing the
     911          * hashcodes of this Subject's Principals and credentials.
     912          *
     913          * If a particular credential was destroyed
     914          * ({@code credential.hashCode()} throws an
     915          * {@code IllegalStateException}),
     916          * the hashcode for that credential is derived via:
     917          * {@code credential.getClass().toString().hashCode()}.
     918          */
     919
     920         int hashCode = 0;
     921
     922         synchronized(principals) {
     923             Iterator<Principal> pIterator = principals.iterator();
     924             while (pIterator.hasNext()) {
     925                 Principal p = pIterator.next();
     926                 hashCode ^= p.hashCode();
     927             }
     928         }
     929
     930         synchronized(pubCredentials) {
     931             Iterator<Object> pubCIterator = pubCredentials.iterator();
     932             while (pubCIterator.hasNext()) {
     933                 hashCode ^= getCredHashCode(pubCIterator.next());
     934             }
     935         }
     936         return hashCode;
     937     }
     938
     939     /**
     940      * get a credential's hashcode
     941      */
     942     private int getCredHashCode(Object o) {
     943         try {
     944             return o.hashCode();
     945         } catch (IllegalStateException ise) {
     946             return o.getClass().toString().hashCode();
     947         }
     948     }
     949
     950     /**
     951      * Writes this object out to a stream (i.e., serializes it).
     952      *
     953      * @param  oos the {@code ObjectOutputStream} to which data is written
     954      * @throws IOException if an I/O error occurs
     955      */
     956     @java.io.Serial
     957     private void writeObject(java.io.ObjectOutputStream oos)
     958                 throws java.io.IOException {
     959         synchronized(principals) {
     960             oos.defaultWriteObject();
     961         }
     962     }
     963
     964     /**
     965      * Reads this object from a stream (i.e., deserializes it)
     966      *
     967      * @param  s the {@code ObjectInputStream} from which data is read
     968      * @throws IOException if an I/O error occurs
     969      * @throws ClassNotFoundException if a serialized class cannot be loaded
     970      */
     971     @SuppressWarnings("unchecked")
     972     @java.io.Serial
     973     private void readObject(java.io.ObjectInputStream s)
     974                 throws java.io.IOException, ClassNotFoundException {
     975
     976         ObjectInputStream.GetField gf = s.readFields();
     977
     978         readOnly = gf.get("readOnly", false);
     979
     980         Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null);
     981
     982         Objects.requireNonNull(inputPrincs,
     983                 ResourcesMgr.getString("invalid.null.input.s."));
     984
     985         // Rewrap the principals into a SecureSet
     986         try {
     987             LinkedList<Principal> principalList = collectionNullClean(inputPrincs);
     988             principals = Collections.synchronizedSet(new SecureSet<>
     989                                 (this, PRINCIPAL_SET, principalList));
     990         } catch (NullPointerException npe) {
     991             // Sometimes people deserialize the principals set only.
     992             // Subject is not accessible, so just don't fail.
     993             principals = Collections.synchronizedSet
     994                         (new SecureSet<>(this, PRINCIPAL_SET));
     995         }
     996
     997         // The Credential {@code Set} is not serialized, but we do not
     998         // want the default deserialization routine to set it to null.
     999         this.pubCredentials = Collections.synchronizedSet
    1000                         (new SecureSet<>(this, PUB_CREDENTIAL_SET));
    1001         this.privCredentials = Collections.synchronizedSet
    1002                         (new SecureSet<>(this, PRIV_CREDENTIAL_SET));
    1003     }
    1004
    1005     /**
    1006      * Tests for null-clean collections (both non-null reference and
    1007      * no null elements)
    1008      *
    1009      * @param coll A {@code Collection} to be tested for null references
    1010      *
    1011      * @throws NullPointerException if the specified collection is either
    1012      *            {@code null} or contains a {@code null} element
    1013      */
    1014     private static <E> LinkedList<E> collectionNullClean(
    1015             Collection<? extends E> coll) {
    1016
    1017         Objects.requireNonNull(coll,
    1018                 ResourcesMgr.getString("invalid.null.input.s."));
    1019
    1020         LinkedList<E> output = new LinkedList<>();
    1021         for (E e : coll) {
    1022             output.add(Objects.requireNonNull(e,
    1023                     ResourcesMgr.getString("invalid.null.input.s.")));
    1024         }
    1025         return output;
    1026     }
    1027
    1028     /**
    1029      * Prevent modifications unless caller has permission.
    1030      *
    1031      * @serial include
    1032      */
    1033     private static class SecureSet<E>
    1034         implements Set<E>, java.io.Serializable {
    1035
    1036         @java.io.Serial
    1037         private static final long serialVersionUID = 7911754171111800359L;
    1038
    1039         /**
    1040          * @serialField this$0 Subject The outer Subject instance.
    1041          * @serialField elements LinkedList The elements in this set.
    1042          */
    1043         @java.io.Serial
    1044         private static final ObjectStreamField[] serialPersistentFields = {
    1045             new ObjectStreamField("this$0", Subject.class),
    1046             new ObjectStreamField("elements", LinkedList.class),
    1047             new ObjectStreamField("which", int.class)
    1048         };
    1049
    1050         Subject subject;
    1051         LinkedList<E> elements;
    1052
    1053         /**
    1054          * @serial An integer identifying the type of objects contained
    1055          *      in this set.  If {@code which == 1},
    1056          *      this is a Principal set and all the elements are
    1057          *      of type {@code java.security.Principal}.
    1058          *      If {@code which == 2}, this is a public credential
    1059          *      set and all the elements are of type {@code Object}.
    1060          *      If {@code which == 3}, this is a private credential
    1061          *      set and all the elements are of type {@code Object}.
    1062          */
    1063         private int which;
    1064
    1065         SecureSet(Subject subject, int which) {
    1066             this.subject = subject;
    1067             this.which = which;
    1068             this.elements = new LinkedList<E>();
    1069         }
    1070
    1071         SecureSet(Subject subject, int which, LinkedList<E> list) {
    1072             this.subject = subject;
    1073             this.which = which;
    1074             this.elements = list;
    1075         }
    1076
    1077         public int size() {
    1078             return elements.size();
    1079         }
    1080
    1081         public Iterator<E> iterator() {
    1082             final LinkedList<E> list = elements;
    1083             return new Iterator<E>() {
    1084                 ListIterator<E> i = list.listIterator(0);
    1085
    1086                 public boolean hasNext() {return i.hasNext();}
    1087
    1088                 public E next() {
    1089                     if (which != Subject.PRIV_CREDENTIAL_SET) {
    1090                         return i.next();
    1091                     }
    1092
    1093                     SecurityManager sm = System.getSecurityManager();
    1094                     if (sm != null) {
    1095                         try {
    1096                             sm.checkPermission(new PrivateCredentialPermission
    1097                                 (list.get(i.nextIndex()).getClass().getName(),
    1098                                 subject.getPrincipals()));
    1099                         } catch (SecurityException se) {
    1100                             i.next();
    1101                             throw (se);
    1102                         }
    1103                     }
    1104                     return i.next();
    1105                 }
    1106
    1107                 public void remove() {
    1108
    1109                     if (subject.isReadOnly()) {
    1110                         throw new IllegalStateException(ResourcesMgr.getString
    1111                                 ("Subject.is.read.only"));
    1112                     }
    1113
    1114                     java.lang.SecurityManager sm = System.getSecurityManager();
    1115                     if (sm != null) {
    1116                         switch (which) {
    1117                         case Subject.PRINCIPAL_SET:
    1118                             sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);
    1119                             break;
    1120                         case Subject.PUB_CREDENTIAL_SET:
    1121                             sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);
    1122                             break;
    1123                         default:
    1124                             sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);
    1125                             break;
    1126                         }
    1127                     }
    1128                     i.remove();
    1129                 }
    1130             };
    1131         }
    1132
    1133         public boolean add(E o) {
    1134
    1135             Objects.requireNonNull(o,
    1136                     ResourcesMgr.getString("invalid.null.input.s."));
    1137
    1138             if (subject.isReadOnly()) {
    1139                 throw new IllegalStateException
    1140                         (ResourcesMgr.getString("Subject.is.read.only"));
    1141             }
    1142
    1143             java.lang.SecurityManager sm = System.getSecurityManager();
    1144             if (sm != null) {
    1145                 switch (which) {
    1146                 case Subject.PRINCIPAL_SET:
    1147                     sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);
    1148                     break;
    1149                 case Subject.PUB_CREDENTIAL_SET:
    1150                     sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);
    1151                     break;
    1152                 default:
    1153                     sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);
    1154                     break;
    1155                 }
    1156             }
    1157
    1158             switch (which) {
    1159             case Subject.PRINCIPAL_SET:
    1160                 if (!(o instanceof Principal)) {
    1161                     throw new SecurityException(ResourcesMgr.getString
    1162                         ("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set"));
    1163                 }
    1164                 break;
    1165             default:
    1166                 // ok to add Objects of any kind to credential sets
    1167                 break;
    1168             }
    1169
    1170             // check for duplicates
    1171             if (!elements.contains(o))
    1172                 return elements.add(o);
    1173             else {
    1174                 return false;
    1175         }
    1176         }
    1177
    1178         public boolean remove(Object o) {
    1179
    1180             Objects.requireNonNull(o,
    1181                     ResourcesMgr.getString("invalid.null.input.s."));
    1182
    1183             final Iterator<E> e = iterator();
    1184             while (e.hasNext()) {
    1185                 E next;
    1186                 if (which != Subject.PRIV_CREDENTIAL_SET) {
    1187                     next = e.next();
    1188                 } else {
    1189                     next = java.security.AccessController.doPrivileged
    1190                         (new java.security.PrivilegedAction<E>() {
    1191                         public E run() {
    1192                             return e.next();
    1193                         }
    1194                     });
    1195                 }
    1196
    1197                 if (next.equals(o)) {
    1198                     e.remove();
    1199                     return true;
    1200                 }
    1201             }
    1202             return false;
    1203         }
    1204
    1205         public boolean contains(Object o) {
    1206
    1207             Objects.requireNonNull(o,
    1208                     ResourcesMgr.getString("invalid.null.input.s."));
    1209
    1210             final Iterator<E> e = iterator();
    1211             while (e.hasNext()) {
    1212                 E next;
    1213                 if (which != Subject.PRIV_CREDENTIAL_SET) {
    1214                     next = e.next();
    1215                 } else {
    1216
    1217                     // For private credentials:
    1218                     // If the caller does not have read permission for
    1219                     // for o.getClass(), we throw a SecurityException.
    1220                     // Otherwise we check the private cred set to see whether
    1221                     // it contains the Object
    1222
    1223                     SecurityManager sm = System.getSecurityManager();
    1224                     if (sm != null) {
    1225                         sm.checkPermission(new PrivateCredentialPermission
    1226                                                 (o.getClass().getName(),
    1227                                                 subject.getPrincipals()));
    1228                     }
    1229                     next = java.security.AccessController.doPrivileged
    1230                         (new java.security.PrivilegedAction<E>() {
    1231                         public E run() {
    1232                             return e.next();
    1233                         }
    1234                     });
    1235                 }
    1236
    1237                 if (next.equals(o)) {
    1238                     return true;
    1239                 }
    1240             }
    1241             return false;
    1242         }
    1243
    1244         public boolean addAll(Collection<? extends E> c) {
    1245             boolean result = false;
    1246
    1247             c = collectionNullClean(c);
    1248
    1249             for (E item : c) {
    1250                 result |= this.add(item);
    1251             }
    1252
    1253             return result;
    1254         }
    1255
    1256         public boolean removeAll(Collection<?> c) {
    1257             c = collectionNullClean(c);
    1258
    1259             boolean modified = false;
    1260             final Iterator<E> e = iterator();
    1261             while (e.hasNext()) {
    1262                 E next;
    1263                 if (which != Subject.PRIV_CREDENTIAL_SET) {
    1264                     next = e.next();
    1265                 } else {
    1266                     next = java.security.AccessController.doPrivileged
    1267                         (new java.security.PrivilegedAction<E>() {
    1268                         public E run() {
    1269                             return e.next();
    1270                         }
    1271                     });
    1272                 }
    1273
    1274                 Iterator<?> ce = c.iterator();
    1275                 while (ce.hasNext()) {
    1276                     if (next.equals(ce.next())) {
    1277                             e.remove();
    1278                             modified = true;
    1279                             break;
    1280                         }
    1281                 }
    1282             }
    1283             return modified;
    1284         }
    1285
    1286         public boolean containsAll(Collection<?> c) {
    1287             c = collectionNullClean(c);
    1288
    1289             for (Object item : c) {
    1290                 if (this.contains(item) == false) {
    1291                     return false;
    1292                 }
    1293             }
    1294
    1295             return true;
    1296         }
    1297
    1298         public boolean retainAll(Collection<?> c) {
    1299             c = collectionNullClean(c);
    1300
    1301             boolean modified = false;
    1302             final Iterator<E> e = iterator();
    1303             while (e.hasNext()) {
    1304                 E next;
    1305                 if (which != Subject.PRIV_CREDENTIAL_SET) {
    1306                     next = e.next();
    1307                 } else {
    1308                     next = java.security.AccessController.doPrivileged
    1309                         (new java.security.PrivilegedAction<E>() {
    1310                         public E run() {
    1311                             return e.next();
    1312                         }
    1313                     });
    1314                 }
    1315
    1316                 if (c.contains(next) == false) {
    1317                     e.remove();
    1318                     modified = true;
    1319                 }
    1320             }
    1321
    1322             return modified;
    1323         }
    1324
    1325         public void clear() {
    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                 e.remove();
    1340             }
    1341         }
    1342
    1343         public boolean isEmpty() {
    1344             return elements.isEmpty();
    1345         }
    1346
    1347         public Object[] toArray() {
    1348             final Iterator<E> e = iterator();
    1349             while (e.hasNext()) {
    1350                 // The next() method performs a security manager check
    1351                 // on each element in the SecureSet.  If we make it all
    1352                 // the way through we should be able to simply return
    1353                 // element's toArray results.  Otherwise we'll let
    1354                 // the SecurityException pass up the call stack.
    1355                 e.next();
    1356             }
    1357
    1358             return elements.toArray();
    1359         }
    1360
    1361         public <T> T[] toArray(T[] a) {
    1362             final Iterator<E> e = iterator();
    1363             while (e.hasNext()) {
    1364                 // The next() method performs a security manager check
    1365                 // on each element in the SecureSet.  If we make it all
    1366                 // the way through we should be able to simply return
    1367                 // element's toArray results.  Otherwise we'll let
    1368                 // the SecurityException pass up the call stack.
    1369                 e.next();
    1370             }
    1371
    1372             return elements.toArray(a);
    1373         }
    1374
    1375         public boolean equals(Object o) {
    1376             if (o == this) {
    1377                 return true;
    1378             }
    1379
    1380             if (!(o instanceof Set)) {
    1381                 return false;
    1382             }
    1383
    1384             Collection<?> c = (Collection<?>) o;
    1385             if (c.size() != size()) {
    1386                 return false;
    1387             }
    1388
    1389             try {
    1390                 return containsAll(c);
    1391             } catch (ClassCastException unused)   {
    1392                 return false;
    1393             } catch (NullPointerException unused) {
    1394                 return false;
    1395             }
    1396         }
    1397
    1398         public int hashCode() {
    1399             int h = 0;
    1400             Iterator<E> i = iterator();
    1401             while (i.hasNext()) {
    1402                 E obj = i.next();
    1403                 if (obj != null) {
    1404                     h += obj.hashCode();
    1405                 }
    1406             }
    1407             return h;
    1408         }
    1409
    1410         /**
    1411          * Writes this object out to a stream (i.e., serializes it).
    1412          *
    1413          * @serialData If this is a private credential set,
    1414          *      a security check is performed to ensure that
    1415          *      the caller has permission to access each credential
    1416          *      in the set.  If the security check passes,
    1417          *      the set is serialized.
    1418          *
    1419          * @param  oos the {@code ObjectOutputStream} to which data is written
    1420          * @throws IOException if an I/O error occurs
    1421          */
    1422         @java.io.Serial
    1423         private void writeObject(java.io.ObjectOutputStream oos)
    1424                 throws java.io.IOException {
    1425
    1426             if (which == Subject.PRIV_CREDENTIAL_SET) {
    1427                 // check permissions before serializing
    1428                 Iterator<E> i = iterator();
    1429                 while (i.hasNext()) {
    1430                     i.next();
    1431                 }
    1432             }
    1433             ObjectOutputStream.PutField fields = oos.putFields();
    1434             fields.put("this$0", subject);
    1435             fields.put("elements", elements);
    1436             fields.put("which", which);
    1437             oos.writeFields();
    1438         }
    1439
    1440         /**
    1441          * Restores the state of this object from the stream.
    1442          *
    1443          * @param  ois the {@code ObjectInputStream} from which data is read
    1444          * @throws IOException if an I/O error occurs
    1445          * @throws ClassNotFoundException if a serialized class cannot be loaded
    1446          */
    1447         @SuppressWarnings("unchecked")
    1448         @java.io.Serial
    1449         private void readObject(ObjectInputStream ois)
    1450             throws IOException, ClassNotFoundException
    1451         {
    1452             ObjectInputStream.GetField fields = ois.readFields();
    1453             subject = (Subject) fields.get("this$0", null);
    1454             which = fields.get("which", 0);
    1455
    1456             LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null);
    1457
    1458             elements = Subject.collectionNullClean(tmp);
    1459         }
    1460
    1461     }
    1462
    1463     /**
    1464      * This class implements a {@code Set} which returns only
    1465      * members that are an instance of a specified Class.
    1466      */
    1467     private class ClassSet<T> extends AbstractSet<T> {
    1468
    1469         private int which;
    1470         private Class<T> c;
    1471         private Set<T> set;
    1472
    1473         ClassSet(int which, Class<T> c) {
    1474             this.which = which;
    1475             this.c = c;
    1476             set = new HashSet<T>();
    1477
    1478             switch (which) {
    1479             case Subject.PRINCIPAL_SET:
    1480                 synchronized(principals) { populateSet(); }
    1481                 break;
    1482             case Subject.PUB_CREDENTIAL_SET:
    1483                 synchronized(pubCredentials) { populateSet(); }
    1484                 break;
    1485             default:
    1486                 synchronized(privCredentials) { populateSet(); }
    1487                 break;
    1488             }
    1489         }
    1490
    1491         @SuppressWarnings("unchecked")     /*To suppress warning from line 1374*/
    1492         private void populateSet() {
    1493             final Iterator<?> iterator;
    1494             switch(which) {
    1495             case Subject.PRINCIPAL_SET:
    1496                 iterator = Subject.this.principals.iterator();
    1497                 break;
    1498             case Subject.PUB_CREDENTIAL_SET:
    1499                 iterator = Subject.this.pubCredentials.iterator();
    1500                 break;
    1501             default:
    1502                 iterator = Subject.this.privCredentials.iterator();
    1503                 break;
    1504             }
    1505
    1506             // Check whether the caller has permisson to get
    1507             // credentials of Class c
    1508
    1509             while (iterator.hasNext()) {
    1510                 Object next;
    1511                 if (which == Subject.PRIV_CREDENTIAL_SET) {
    1512                     next = java.security.AccessController.doPrivileged
    1513                         (new java.security.PrivilegedAction<>() {
    1514                         public Object run() {
    1515                             return iterator.next();
    1516                         }
    1517                     });
    1518                 } else {
    1519                     next = iterator.next();
    1520                 }
    1521                 if (c.isAssignableFrom(next.getClass())) {
    1522                     if (which != Subject.PRIV_CREDENTIAL_SET) {
    1523                         set.add((T)next);
    1524                     } else {
    1525                         // Check permission for private creds
    1526                         SecurityManager sm = System.getSecurityManager();
    1527                         if (sm != null) {
    1528                             sm.checkPermission(new PrivateCredentialPermission
    1529                                                 (next.getClass().getName(),
    1530                                                 Subject.this.getPrincipals()));
    1531                         }
    1532                         set.add((T)next);
    1533                     }
    1534                 }
    1535             }
    1536         }
    1537
    1538         @Override
    1539         public int size() {
    1540             return set.size();
    1541         }
    1542
    1543         @Override
    1544         public Iterator<T> iterator() {
    1545             return set.iterator();
    1546         }
    1547
    1548         @Override
    1549         public boolean add(T o) {
    1550
    1551             if (!c.isAssignableFrom(o.getClass())) {
    1552                 MessageFormat form = new MessageFormat(ResourcesMgr.getString
    1553                         ("attempting.to.add.an.object.which.is.not.an.instance.of.class"));
    1554                 Object[] source = {c.toString()};
    1555                 throw new SecurityException(form.format(source));
    1556             }
    1557
    1558             return set.add(o);
    1559         }
    1560     }
    1561
    1562     static final class AuthPermissionHolder {
    1563         static final AuthPermission DO_AS_PERMISSION =
    1564             new AuthPermission("doAs");
    1565
    1566         static final AuthPermission DO_AS_PRIVILEGED_PERMISSION =
    1567             new AuthPermission("doAsPrivileged");
    1568
    1569         static final AuthPermission SET_READ_ONLY_PERMISSION =
    1570             new AuthPermission("setReadOnly");
    1571
    1572         static final AuthPermission GET_SUBJECT_PERMISSION =
    1573             new AuthPermission("getSubject");
    1574
    1575         static final AuthPermission MODIFY_PRINCIPALS_PERMISSION =
    1576             new AuthPermission("modifyPrincipals");
    1577
    1578         static final AuthPermission MODIFY_PUBLIC_CREDENTIALS_PERMISSION =
    1579             new AuthPermission("modifyPublicCredentials");
    1580
    1581         static final AuthPermission MODIFY_PRIVATE_CREDENTIALS_PERMISSION =
    1582             new AuthPermission("modifyPrivateCredentials");
    1583     }
    1584 }