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