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