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