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