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