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