0001 /*
0002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.security.auth;
0027
0028 import java.util.*;
0029 import java.io.*;
0030 import java.lang.reflect.*;
0031 import java.text.MessageFormat;
0032 import java.security.AccessController;
0033 import java.security.AccessControlContext;
0034 import java.security.DomainCombiner;
0035 import java.security.Permission;
0036 import java.security.PermissionCollection;
0037 import java.security.Principal;
0038 import java.security.PrivilegedAction;
0039 import java.security.PrivilegedExceptionAction;
0040 import java.security.PrivilegedActionException;
0041 import java.security.ProtectionDomain;
0042 import sun.security.util.ResourcesMgr;
0043 import sun.security.util.SecurityConstants;
0044
0045 /**
0046 * <p> A <code>Subject</code> represents a grouping of related information
0047 * for a single entity, such as a person.
0048 * Such information includes the Subject's identities as well as
0049 * its security-related attributes
0050 * (passwords and cryptographic keys, for example).
0051 *
0052 * <p> Subjects may potentially have multiple identities.
0053 * Each identity is represented as a <code>Principal</code>
0054 * within the <code>Subject</code>. Principals simply bind names to a
0055 * <code>Subject</code>. For example, a <code>Subject</code> that happens
0056 * to be a person, Alice, might have two Principals:
0057 * one which binds "Alice Bar", the name on her driver license,
0058 * to the <code>Subject</code>, and another which binds,
0059 * "999-99-9999", the number on her student identification card,
0060 * to the <code>Subject</code>. Both Principals refer to the same
0061 * <code>Subject</code> even though each has a different name.
0062 *
0063 * <p> A <code>Subject</code> may also own security-related attributes,
0064 * which are referred to as credentials.
0065 * Sensitive credentials that require special protection, such as
0066 * private cryptographic keys, are stored within a private credential
0067 * <code>Set</code>. Credentials intended to be shared, such as
0068 * public key certificates or Kerberos server tickets are stored
0069 * within a public credential <code>Set</code>. Different permissions
0070 * are required to access and modify the different credential Sets.
0071 *
0072 * <p> To retrieve all the Principals associated with a <code>Subject</code>,
0073 * invoke the <code>getPrincipals</code> method. To retrieve
0074 * all the public or private credentials belonging to a <code>Subject</code>,
0075 * invoke the <code>getPublicCredentials</code> method or
0076 * <code>getPrivateCredentials</code> method, respectively.
0077 * To modify the returned <code>Set</code> of Principals and credentials,
0078 * use the methods defined in the <code>Set</code> class.
0079 * For example:
0080 * <pre>
0081 * Subject subject;
0082 * Principal principal;
0083 * Object credential;
0084 *
0085 * // add a Principal and credential to the Subject
0086 * subject.getPrincipals().add(principal);
0087 * subject.getPublicCredentials().add(credential);
0088 * </pre>
0089 *
0090 * <p> This <code>Subject</code> class implements <code>Serializable</code>.
0091 * While the Principals associated with the <code>Subject</code> are serialized,
0092 * the credentials associated with the <code>Subject</code> are not.
0093 * Note that the <code>java.security.Principal</code> class
0094 * does not implement <code>Serializable</code>. Therefore all concrete
0095 * <code>Principal</code> implementations associated with Subjects
0096 * must implement <code>Serializable</code>.
0097 *
0098 * @version 1.135, 06/29/07
0099 * @see java.security.Principal
0100 * @see java.security.DomainCombiner
0101 */
0102 public final class Subject implements java.io.Serializable {
0103
0104 private static final long serialVersionUID = -8308522755600156056L;
0105
0106 /**
0107 * A <code>Set</code> that provides a view of all of this
0108 * Subject's Principals
0109 *
0110 * <p>
0111 *
0112 * @serial Each element in this set is a
0113 * <code>java.security.Principal</code>.
0114 * The set is a <code>Subject.SecureSet</code>.
0115 */
0116 Set<Principal> principals;
0117
0118 /**
0119 * Sets that provide a view of all of this
0120 * Subject's Credentials
0121 */
0122 transient Set<Object> pubCredentials;
0123 transient Set<Object> privCredentials;
0124
0125 /**
0126 * Whether this Subject is read-only
0127 *
0128 * @serial
0129 */
0130 private volatile boolean readOnly = false;
0131
0132 private static final int PRINCIPAL_SET = 1;
0133 private static final int PUB_CREDENTIAL_SET = 2;
0134 private static final int PRIV_CREDENTIAL_SET = 3;
0135
0136 private static final ProtectionDomain[] NULL_PD_ARRAY = new ProtectionDomain[0];
0137
0138 /**
0139 * Create an instance of a <code>Subject</code>
0140 * with an empty <code>Set</code> of Principals and empty
0141 * Sets of public and private credentials.
0142 *
0143 * <p> The newly constructed Sets check whether this <code>Subject</code>
0144 * has been set read-only before permitting subsequent modifications.
0145 * The newly created Sets also prevent illegal modifications
0146 * by ensuring that callers have sufficient permissions.
0147 *
0148 * <p> To modify the Principals Set, the caller must have
0149 * <code>AuthPermission("modifyPrincipals")</code>.
0150 * To modify the public credential Set, the caller must have
0151 * <code>AuthPermission("modifyPublicCredentials")</code>.
0152 * To modify the private credential Set, the caller must have
0153 * <code>AuthPermission("modifyPrivateCredentials")</code>.
0154 */
0155 public Subject() {
0156
0157 this .principals = Collections
0158 .synchronizedSet(new SecureSet<Principal>(this ,
0159 PRINCIPAL_SET));
0160 this .pubCredentials = Collections
0161 .synchronizedSet(new SecureSet<Object>(this ,
0162 PUB_CREDENTIAL_SET));
0163 this .privCredentials = Collections
0164 .synchronizedSet(new SecureSet<Object>(this ,
0165 PRIV_CREDENTIAL_SET));
0166 }
0167
0168 /**
0169 * Create an instance of a <code>Subject</code> with
0170 * Principals and credentials.
0171 *
0172 * <p> The Principals and credentials from the specified Sets
0173 * are copied into newly constructed Sets.
0174 * These newly created Sets check whether this <code>Subject</code>
0175 * has been set read-only before permitting subsequent modifications.
0176 * The newly created Sets also prevent illegal modifications
0177 * by ensuring that callers have sufficient permissions.
0178 *
0179 * <p> To modify the Principals Set, the caller must have
0180 * <code>AuthPermission("modifyPrincipals")</code>.
0181 * To modify the public credential Set, the caller must have
0182 * <code>AuthPermission("modifyPublicCredentials")</code>.
0183 * To modify the private credential Set, the caller must have
0184 * <code>AuthPermission("modifyPrivateCredentials")</code>.
0185 * <p>
0186 *
0187 * @param readOnly true if the <code>Subject</code> is to be read-only,
0188 * and false otherwise. <p>
0189 *
0190 * @param principals the <code>Set</code> of Principals
0191 * to be associated with this <code>Subject</code>. <p>
0192 *
0193 * @param pubCredentials the <code>Set</code> of public credentials
0194 * to be associated with this <code>Subject</code>. <p>
0195 *
0196 * @param privCredentials the <code>Set</code> of private credentials
0197 * to be associated with this <code>Subject</code>.
0198 *
0199 * @exception NullPointerException if the specified
0200 * <code>principals</code>, <code>pubCredentials</code>,
0201 * or <code>privCredentials</code> are <code>null</code>.
0202 */
0203 public Subject(boolean readOnly,
0204 Set<? extends Principal> principals, Set<?> pubCredentials,
0205 Set<?> privCredentials) {
0206
0207 if (principals == null || pubCredentials == null
0208 || privCredentials == null)
0209 throw new NullPointerException(ResourcesMgr
0210 .getString("invalid null input(s)"));
0211
0212 this .principals = Collections
0213 .synchronizedSet(new SecureSet<Principal>(this ,
0214 PRINCIPAL_SET, principals));
0215 this .pubCredentials = Collections
0216 .synchronizedSet(new SecureSet<Object>(this ,
0217 PUB_CREDENTIAL_SET, pubCredentials));
0218 this .privCredentials = Collections
0219 .synchronizedSet(new SecureSet<Object>(this ,
0220 PRIV_CREDENTIAL_SET, privCredentials));
0221 this .readOnly = readOnly;
0222 }
0223
0224 /**
0225 * Set this <code>Subject</code> to be read-only.
0226 *
0227 * <p> Modifications (additions and removals) to this Subject's
0228 * <code>Principal</code> <code>Set</code> and
0229 * credential Sets will be disallowed.
0230 * The <code>destroy</code> operation on this Subject's credentials will
0231 * still be permitted.
0232 *
0233 * <p> Subsequent attempts to modify the Subject's <code>Principal</code>
0234 * and credential Sets will result in an
0235 * <code>IllegalStateException</code> being thrown.
0236 * Also, once a <code>Subject</code> is read-only,
0237 * it can not be reset to being writable again.
0238 *
0239 * <p>
0240 *
0241 * @exception SecurityException if the caller does not have permission
0242 * to set this <code>Subject</code> to be read-only.
0243 */
0244 public void setReadOnly() {
0245 java.lang.SecurityManager sm = System.getSecurityManager();
0246 if (sm != null) {
0247 sm.checkPermission(new AuthPermission("setReadOnly"));
0248 }
0249
0250 this .readOnly = true;
0251 }
0252
0253 /**
0254 * Query whether this <code>Subject</code> is read-only.
0255 *
0256 * <p>
0257 *
0258 * @return true if this <code>Subject</code> is read-only, false otherwise.
0259 */
0260 public boolean isReadOnly() {
0261 return this .readOnly;
0262 }
0263
0264 /**
0265 * Get the <code>Subject</code> associated with the provided
0266 * <code>AccessControlContext</code>.
0267 *
0268 * <p> The <code>AccessControlContext</code> may contain many
0269 * Subjects (from nested <code>doAs</code> calls).
0270 * In this situation, the most recent <code>Subject</code> associated
0271 * with the <code>AccessControlContext</code> is returned.
0272 *
0273 * <p>
0274 *
0275 * @param acc the <code>AccessControlContext</code> from which to retrieve
0276 * the <code>Subject</code>.
0277 *
0278 * @return the <code>Subject</code> associated with the provided
0279 * <code>AccessControlContext</code>, or <code>null</code>
0280 * if no <code>Subject</code> is associated
0281 * with the provided <code>AccessControlContext</code>.
0282 *
0283 * @exception SecurityException if the caller does not have permission
0284 * to get the <code>Subject</code>. <p>
0285 *
0286 * @exception NullPointerException if the provided
0287 * <code>AccessControlContext</code> is <code>null</code>.
0288 */
0289 public static Subject getSubject(final AccessControlContext acc) {
0290
0291 java.lang.SecurityManager sm = System.getSecurityManager();
0292 if (sm != null) {
0293 sm.checkPermission(new AuthPermission("getSubject"));
0294 }
0295
0296 if (acc == null) {
0297 throw new NullPointerException(
0298 ResourcesMgr
0299 .getString("invalid null AccessControlContext provided"));
0300 }
0301
0302 // return the Subject from the DomainCombiner of the provided context
0303 return AccessController
0304 .doPrivileged(new java.security.PrivilegedAction<Subject>() {
0305 public Subject run() {
0306 DomainCombiner dc = acc.getDomainCombiner();
0307 if (!(dc instanceof SubjectDomainCombiner))
0308 return null;
0309 SubjectDomainCombiner sdc = (SubjectDomainCombiner) dc;
0310 return sdc.getSubject();
0311 }
0312 });
0313 }
0314
0315 /**
0316 * Perform work as a particular <code>Subject</code>.
0317 *
0318 * <p> This method first retrieves the current Thread's
0319 * <code>AccessControlContext</code> via
0320 * <code>AccessController.getContext</code>,
0321 * and then instantiates a new <code>AccessControlContext</code>
0322 * using the retrieved context along with a new
0323 * <code>SubjectDomainCombiner</code> (constructed using
0324 * the provided <code>Subject</code>).
0325 * Finally, this method invokes <code>AccessController.doPrivileged</code>,
0326 * passing it the provided <code>PrivilegedAction</code>,
0327 * as well as the newly constructed <code>AccessControlContext</code>.
0328 *
0329 * <p>
0330 *
0331 * @param subject the <code>Subject</code> that the specified
0332 * <code>action</code> will run as. This parameter
0333 * may be <code>null</code>. <p>
0334 *
0335 * @param action the code to be run as the specified
0336 * <code>Subject</code>. <p>
0337 *
0338 * @return the value returned by the PrivilegedAction's
0339 * <code>run</code> method.
0340 *
0341 * @exception NullPointerException if the <code>PrivilegedAction</code>
0342 * is <code>null</code>. <p>
0343 *
0344 * @exception SecurityException if the caller does not have permission
0345 * to invoke this method.
0346 */
0347 public static <T> T doAs(final Subject subject,
0348 final java.security.PrivilegedAction<T> action) {
0349
0350 java.lang.SecurityManager sm = System.getSecurityManager();
0351 if (sm != null) {
0352 sm.checkPermission(SecurityConstants.DO_AS_PERMISSION);
0353 }
0354 if (action == null)
0355 throw new NullPointerException(ResourcesMgr
0356 .getString("invalid null action provided"));
0357
0358 // set up the new Subject-based AccessControlContext
0359 // for doPrivileged
0360 final AccessControlContext currentAcc = AccessController
0361 .getContext();
0362
0363 // call doPrivileged and push this new context on the stack
0364 return java.security.AccessController.doPrivileged(action,
0365 createContext(subject, currentAcc));
0366 }
0367
0368 /**
0369 * Perform work as a particular <code>Subject</code>.
0370 *
0371 * <p> This method first retrieves the current Thread's
0372 * <code>AccessControlContext</code> via
0373 * <code>AccessController.getContext</code>,
0374 * and then instantiates a new <code>AccessControlContext</code>
0375 * using the retrieved context along with a new
0376 * <code>SubjectDomainCombiner</code> (constructed using
0377 * the provided <code>Subject</code>).
0378 * Finally, this method invokes <code>AccessController.doPrivileged</code>,
0379 * passing it the provided <code>PrivilegedExceptionAction</code>,
0380 * as well as the newly constructed <code>AccessControlContext</code>.
0381 *
0382 * <p>
0383 *
0384 * @param subject the <code>Subject</code> that the specified
0385 * <code>action</code> will run as. This parameter
0386 * may be <code>null</code>. <p>
0387 *
0388 * @param action the code to be run as the specified
0389 * <code>Subject</code>. <p>
0390 *
0391 * @return the value returned by the
0392 * PrivilegedExceptionAction's <code>run</code> method.
0393 *
0394 * @exception PrivilegedActionException if the
0395 * <code>PrivilegedExceptionAction.run</code>
0396 * method throws a checked exception. <p>
0397 *
0398 * @exception NullPointerException if the specified
0399 * <code>PrivilegedExceptionAction</code> is
0400 * <code>null</code>. <p>
0401 *
0402 * @exception SecurityException if the caller does not have permission
0403 * to invoke this method.
0404 */
0405 public static <T> T doAs(final Subject subject,
0406 final java.security.PrivilegedExceptionAction<T> action)
0407 throws java.security.PrivilegedActionException {
0408
0409 java.lang.SecurityManager sm = System.getSecurityManager();
0410 if (sm != null) {
0411 sm.checkPermission(SecurityConstants.DO_AS_PERMISSION);
0412 }
0413
0414 if (action == null)
0415 throw new NullPointerException(ResourcesMgr
0416 .getString("invalid null action provided"));
0417
0418 // set up the new Subject-based AccessControlContext for doPrivileged
0419 final AccessControlContext currentAcc = AccessController
0420 .getContext();
0421
0422 // call doPrivileged and push this new context on the stack
0423 return java.security.AccessController.doPrivileged(action,
0424 createContext(subject, currentAcc));
0425 }
0426
0427 /**
0428 * Perform privileged work as a particular <code>Subject</code>.
0429 *
0430 * <p> This method behaves exactly as <code>Subject.doAs</code>,
0431 * except that instead of retrieving the current Thread's
0432 * <code>AccessControlContext</code>, it uses the provided
0433 * <code>AccessControlContext</code>. If the provided
0434 * <code>AccessControlContext</code> is <code>null</code>,
0435 * this method instantiates a new <code>AccessControlContext</code>
0436 * with an empty collection of ProtectionDomains.
0437 *
0438 * <p>
0439 *
0440 * @param subject the <code>Subject</code> that the specified
0441 * <code>action</code> will run as. This parameter
0442 * may be <code>null</code>. <p>
0443 *
0444 * @param action the code to be run as the specified
0445 * <code>Subject</code>. <p>
0446 *
0447 * @param acc the <code>AccessControlContext</code> to be tied to the
0448 * specified <i>subject</i> and <i>action</i>. <p>
0449 *
0450 * @return the value returned by the PrivilegedAction's
0451 * <code>run</code> method.
0452 *
0453 * @exception NullPointerException if the <code>PrivilegedAction</code>
0454 * is <code>null</code>. <p>
0455 *
0456 * @exception SecurityException if the caller does not have permission
0457 * to invoke this method.
0458 */
0459 public static <T> T doAsPrivileged(final Subject subject,
0460 final java.security.PrivilegedAction<T> action,
0461 final java.security.AccessControlContext acc) {
0462
0463 java.lang.SecurityManager sm = System.getSecurityManager();
0464 if (sm != null) {
0465 sm
0466 .checkPermission(SecurityConstants.DO_AS_PRIVILEGED_PERMISSION);
0467 }
0468
0469 if (action == null)
0470 throw new NullPointerException(ResourcesMgr
0471 .getString("invalid null action provided"));
0472
0473 // set up the new Subject-based AccessControlContext
0474 // for doPrivileged
0475 final AccessControlContext callerAcc = (acc == null ? new AccessControlContext(
0476 NULL_PD_ARRAY)
0477 : acc);
0478
0479 // call doPrivileged and push this new context on the stack
0480 return java.security.AccessController.doPrivileged(action,
0481 createContext(subject, callerAcc));
0482 }
0483
0484 /**
0485 * Perform privileged work as a particular <code>Subject</code>.
0486 *
0487 * <p> This method behaves exactly as <code>Subject.doAs</code>,
0488 * except that instead of retrieving the current Thread's
0489 * <code>AccessControlContext</code>, it uses the provided
0490 * <code>AccessControlContext</code>. If the provided
0491 * <code>AccessControlContext</code> is <code>null</code>,
0492 * this method instantiates a new <code>AccessControlContext</code>
0493 * with an empty collection of ProtectionDomains.
0494 *
0495 * <p>
0496 *
0497 * @param subject the <code>Subject</code> that the specified
0498 * <code>action</code> will run as. This parameter
0499 * may be <code>null</code>. <p>
0500 *
0501 * @param action the code to be run as the specified
0502 * <code>Subject</code>. <p>
0503 *
0504 * @param acc the <code>AccessControlContext</code> to be tied to the
0505 * specified <i>subject</i> and <i>action</i>. <p>
0506 *
0507 * @return the value returned by the
0508 * PrivilegedExceptionAction's <code>run</code> method.
0509 *
0510 * @exception PrivilegedActionException if the
0511 * <code>PrivilegedExceptionAction.run</code>
0512 * method throws a checked exception. <p>
0513 *
0514 * @exception NullPointerException if the specified
0515 * <code>PrivilegedExceptionAction</code> is
0516 * <code>null</code>. <p>
0517 *
0518 * @exception SecurityException if the caller does not have permission
0519 * to invoke this method.
0520 */
0521 public static <T> T doAsPrivileged(final Subject subject,
0522 final java.security.PrivilegedExceptionAction<T> action,
0523 final java.security.AccessControlContext acc)
0524 throws java.security.PrivilegedActionException {
0525
0526 java.lang.SecurityManager sm = System.getSecurityManager();
0527 if (sm != null) {
0528 sm
0529 .checkPermission(SecurityConstants.DO_AS_PRIVILEGED_PERMISSION);
0530 }
0531
0532 if (action == null)
0533 throw new NullPointerException(ResourcesMgr
0534 .getString("invalid null action provided"));
0535
0536 // set up the new Subject-based AccessControlContext for doPrivileged
0537 final AccessControlContext callerAcc = (acc == null ? new AccessControlContext(
0538 NULL_PD_ARRAY)
0539 : acc);
0540
0541 // call doPrivileged and push this new context on the stack
0542 return java.security.AccessController.doPrivileged(action,
0543 createContext(subject, callerAcc));
0544 }
0545
0546 private static AccessControlContext createContext(
0547 final Subject subject, final AccessControlContext acc) {
0548
0549 return java.security.AccessController
0550 .doPrivileged(new java.security.PrivilegedAction<AccessControlContext>() {
0551 public AccessControlContext run() {
0552 if (subject == null)
0553 return new AccessControlContext(acc, null);
0554 else
0555 return new AccessControlContext(acc,
0556 new SubjectDomainCombiner(subject));
0557 }
0558 });
0559 }
0560
0561 /**
0562 * Return the <code>Set</code> of Principals associated with this
0563 * <code>Subject</code>. Each <code>Principal</code> represents
0564 * an identity for this <code>Subject</code>.
0565 *
0566 * <p> The returned <code>Set</code> is backed by this Subject's
0567 * internal <code>Principal</code> <code>Set</code>. Any modification
0568 * to the returned <code>Set</code> affects the internal
0569 * <code>Principal</code> <code>Set</code> as well.
0570 *
0571 * <p>
0572 *
0573 * @return The <code>Set</code> of Principals associated with this
0574 * <code>Subject</code>.
0575 */
0576 public Set<Principal> getPrincipals() {
0577
0578 // always return an empty Set instead of null
0579 // so LoginModules can add to the Set if necessary
0580 return principals;
0581 }
0582
0583 /**
0584 * Return a <code>Set</code> of Principals associated with this
0585 * <code>Subject</code> that are instances or subclasses of the specified
0586 * <code>Class</code>.
0587 *
0588 * <p> The returned <code>Set</code> is not backed by this Subject's
0589 * internal <code>Principal</code> <code>Set</code>. A new
0590 * <code>Set</code> is created and returned for each method invocation.
0591 * Modifications to the returned <code>Set</code>
0592 * will not affect the internal <code>Principal</code> <code>Set</code>.
0593 *
0594 * <p>
0595 *
0596 * @param c the returned <code>Set</code> of Principals will all be
0597 * instances of this class.
0598 *
0599 * @return a <code>Set</code> of Principals that are instances of the
0600 * specified <code>Class</code>.
0601 *
0602 * @exception NullPointerException if the specified <code>Class</code>
0603 * is <code>null</code>.
0604 */
0605 public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
0606
0607 if (c == null)
0608 throw new NullPointerException(ResourcesMgr
0609 .getString("invalid null Class provided"));
0610
0611 // always return an empty Set instead of null
0612 // so LoginModules can add to the Set if necessary
0613 return new ClassSet<T>(PRINCIPAL_SET, c);
0614 }
0615
0616 /**
0617 * Return the <code>Set</code> of public credentials held by this
0618 * <code>Subject</code>.
0619 *
0620 * <p> The returned <code>Set</code> is backed by this Subject's
0621 * internal public Credential <code>Set</code>. Any modification
0622 * to the returned <code>Set</code> affects the internal public
0623 * Credential <code>Set</code> as well.
0624 *
0625 * <p>
0626 *
0627 * @return A <code>Set</code> of public credentials held by this
0628 * <code>Subject</code>.
0629 */
0630 public Set<Object> getPublicCredentials() {
0631
0632 // always return an empty Set instead of null
0633 // so LoginModules can add to the Set if necessary
0634 return pubCredentials;
0635 }
0636
0637 /**
0638 * Return the <code>Set</code> of private credentials held by this
0639 * <code>Subject</code>.
0640 *
0641 * <p> The returned <code>Set</code> is backed by this Subject's
0642 * internal private Credential <code>Set</code>. Any modification
0643 * to the returned <code>Set</code> affects the internal private
0644 * Credential <code>Set</code> as well.
0645 *
0646 * <p> A caller requires permissions to access the Credentials
0647 * in the returned <code>Set</code>, or to modify the
0648 * <code>Set</code> itself. A <code>SecurityException</code>
0649 * is thrown if the caller does not have the proper permissions.
0650 *
0651 * <p> While iterating through the <code>Set</code>,
0652 * a <code>SecurityException</code> is thrown
0653 * if the caller does not have permission to access a
0654 * particular Credential. The <code>Iterator</code>
0655 * is nevertheless advanced to next element in the <code>Set</code>.
0656 *
0657 * <p>
0658 *
0659 * @return A <code>Set</code> of private credentials held by this
0660 * <code>Subject</code>.
0661 */
0662 public Set<Object> getPrivateCredentials() {
0663
0664 // XXX
0665 // we do not need a security check for
0666 // AuthPermission(getPrivateCredentials)
0667 // because we already restrict access to private credentials
0668 // via the PrivateCredentialPermission. all the extra AuthPermission
0669 // would do is protect the set operations themselves
0670 // (like size()), which don't seem security-sensitive.
0671
0672 // always return an empty Set instead of null
0673 // so LoginModules can add to the Set if necessary
0674 return privCredentials;
0675 }
0676
0677 /**
0678 * Return a <code>Set</code> of public credentials associated with this
0679 * <code>Subject</code> that are instances or subclasses of the specified
0680 * <code>Class</code>.
0681 *
0682 * <p> The returned <code>Set</code> is not backed by this Subject's
0683 * internal public Credential <code>Set</code>. A new
0684 * <code>Set</code> is created and returned for each method invocation.
0685 * Modifications to the returned <code>Set</code>
0686 * will not affect the internal public Credential <code>Set</code>.
0687 *
0688 * <p>
0689 *
0690 * @param c the returned <code>Set</code> of public credentials will all be
0691 * instances of this class.
0692 *
0693 * @return a <code>Set</code> of public credentials that are instances
0694 * of the specified <code>Class</code>.
0695 *
0696 * @exception NullPointerException if the specified <code>Class</code>
0697 * is <code>null</code>.
0698 */
0699 public <T> Set<T> getPublicCredentials(Class<T> c) {
0700
0701 if (c == null)
0702 throw new NullPointerException(ResourcesMgr
0703 .getString("invalid null Class provided"));
0704
0705 // always return an empty Set instead of null
0706 // so LoginModules can add to the Set if necessary
0707 return new ClassSet<T>(PUB_CREDENTIAL_SET, c);
0708 }
0709
0710 /**
0711 * Return a <code>Set</code> of private credentials associated with this
0712 * <code>Subject</code> that are instances or subclasses of the specified
0713 * <code>Class</code>.
0714 *
0715 * <p> The caller must have permission to access all of the
0716 * requested Credentials, or a <code>SecurityException</code>
0717 * will be thrown.
0718 *
0719 * <p> The returned <code>Set</code> is not backed by this Subject's
0720 * internal private Credential <code>Set</code>. A new
0721 * <code>Set</code> is created and returned for each method invocation.
0722 * Modifications to the returned <code>Set</code>
0723 * will not affect the internal private Credential <code>Set</code>.
0724 *
0725 * <p>
0726 *
0727 * @param c the returned <code>Set</code> of private credentials will all be
0728 * instances of this class.
0729 *
0730 * @return a <code>Set</code> of private credentials that are instances
0731 * of the specified <code>Class</code>.
0732 *
0733 * @exception NullPointerException if the specified <code>Class</code>
0734 * is <code>null</code>.
0735 */
0736 public <T> Set<T> getPrivateCredentials(Class<T> c) {
0737
0738 // XXX
0739 // we do not need a security check for
0740 // AuthPermission(getPrivateCredentials)
0741 // because we already restrict access to private credentials
0742 // via the PrivateCredentialPermission. all the extra AuthPermission
0743 // would do is protect the set operations themselves
0744 // (like size()), which don't seem security-sensitive.
0745
0746 if (c == null)
0747 throw new NullPointerException(ResourcesMgr
0748 .getString("invalid null Class provided"));
0749
0750 // always return an empty Set instead of null
0751 // so LoginModules can add to the Set if necessary
0752 return new ClassSet<T>(PRIV_CREDENTIAL_SET, c);
0753 }
0754
0755 /**
0756 * Compares the specified Object with this <code>Subject</code>
0757 * for equality. Returns true if the given object is also a Subject
0758 * and the two <code>Subject</code> instances are equivalent.
0759 * More formally, two <code>Subject</code> instances are
0760 * equal if their <code>Principal</code> and <code>Credential</code>
0761 * Sets are equal.
0762 *
0763 * <p>
0764 *
0765 * @param o Object to be compared for equality with this
0766 * <code>Subject</code>.
0767 *
0768 * @return true if the specified Object is equal to this
0769 * <code>Subject</code>.
0770 *
0771 * @exception SecurityException if the caller does not have permission
0772 * to access the private credentials for this <code>Subject</code>,
0773 * or if the caller does not have permission to access the
0774 * private credentials for the provided <code>Subject</code>.
0775 */
0776 public boolean equals(Object o) {
0777
0778 if (o == null)
0779 return false;
0780
0781 if (this == o)
0782 return true;
0783
0784 if (o instanceof Subject) {
0785
0786 final Subject that = (Subject) o;
0787
0788 // check the principal and credential sets
0789 Set<Principal> thatPrincipals;
0790 synchronized (that.principals) {
0791 // avoid deadlock from dual locks
0792 thatPrincipals = new HashSet<Principal>(that.principals);
0793 }
0794 if (!principals.equals(thatPrincipals)) {
0795 return false;
0796 }
0797
0798 Set<Object> thatPubCredentials;
0799 synchronized (that.pubCredentials) {
0800 // avoid deadlock from dual locks
0801 thatPubCredentials = new HashSet<Object>(
0802 that.pubCredentials);
0803 }
0804 if (!pubCredentials.equals(thatPubCredentials)) {
0805 return false;
0806 }
0807
0808 Set<Object> thatPrivCredentials;
0809 synchronized (that.privCredentials) {
0810 // avoid deadlock from dual locks
0811 thatPrivCredentials = new HashSet<Object>(
0812 that.privCredentials);
0813 }
0814 if (!privCredentials.equals(thatPrivCredentials)) {
0815 return false;
0816 }
0817 return true;
0818 }
0819 return false;
0820 }
0821
0822 /**
0823 * Return the String representation of this <code>Subject</code>.
0824 *
0825 * <p>
0826 *
0827 * @return the String representation of this <code>Subject</code>.
0828 */
0829 public String toString() {
0830 return toString(true);
0831 }
0832
0833 /**
0834 * package private convenience method to print out the Subject
0835 * without firing off a security check when trying to access
0836 * the Private Credentials
0837 */
0838 String toString(boolean includePrivateCredentials) {
0839
0840 String s = ResourcesMgr.getString("Subject:\n");
0841 String suffix = "";
0842
0843 synchronized (principals) {
0844 Iterator<Principal> pI = principals.iterator();
0845 while (pI.hasNext()) {
0846 Principal p = pI.next();
0847 suffix = suffix
0848 + ResourcesMgr.getString("\tPrincipal: ")
0849 + p.toString() + ResourcesMgr.getString("\n");
0850 }
0851 }
0852
0853 synchronized (pubCredentials) {
0854 Iterator<Object> pI = pubCredentials.iterator();
0855 while (pI.hasNext()) {
0856 Object o = pI.next();
0857 suffix = suffix
0858 + ResourcesMgr
0859 .getString("\tPublic Credential: ")
0860 + o.toString() + ResourcesMgr.getString("\n");
0861 }
0862 }
0863
0864 if (includePrivateCredentials) {
0865 synchronized (privCredentials) {
0866 Iterator<Object> pI = privCredentials.iterator();
0867 while (pI.hasNext()) {
0868 try {
0869 Object o = pI.next();
0870 suffix += ResourcesMgr
0871 .getString("\tPrivate Credential: ")
0872 + o.toString()
0873 + ResourcesMgr.getString("\n");
0874 } catch (SecurityException se) {
0875 suffix += ResourcesMgr
0876 .getString("\tPrivate Credential inaccessible\n");
0877 break;
0878 }
0879 }
0880 }
0881 }
0882 return s + suffix;
0883 }
0884
0885 /**
0886 * Returns a hashcode for this <code>Subject</code>.
0887 *
0888 * <p>
0889 *
0890 * @return a hashcode for this <code>Subject</code>.
0891 *
0892 * @exception SecurityException if the caller does not have permission
0893 * to access this Subject's private credentials.
0894 */
0895 public int hashCode() {
0896
0897 /**
0898 * The hashcode is derived exclusive or-ing the
0899 * hashcodes of this Subject's Principals and credentials.
0900 *
0901 * If a particular credential was destroyed
0902 * (<code>credential.hashCode()</code> throws an
0903 * <code>IllegalStateException</code>),
0904 * the hashcode for that credential is derived via:
0905 * <code>credential.getClass().toString().hashCode()</code>.
0906 */
0907
0908 int hashCode = 0;
0909
0910 synchronized (principals) {
0911 Iterator<Principal> pIterator = principals.iterator();
0912 while (pIterator.hasNext()) {
0913 Principal p = pIterator.next();
0914 hashCode ^= p.hashCode();
0915 }
0916 }
0917
0918 synchronized (pubCredentials) {
0919 Iterator<Object> pubCIterator = pubCredentials.iterator();
0920 while (pubCIterator.hasNext()) {
0921 hashCode ^= getCredHashCode(pubCIterator.next());
0922 }
0923 }
0924 return hashCode;
0925 }
0926
0927 /**
0928 * get a credential's hashcode
0929 */
0930 private int getCredHashCode(Object o) {
0931 try {
0932 return o.hashCode();
0933 } catch (IllegalStateException ise) {
0934 return o.getClass().toString().hashCode();
0935 }
0936 }
0937
0938 /**
0939 * Writes this object out to a stream (i.e., serializes it).
0940 */
0941 private void writeObject(java.io.ObjectOutputStream oos)
0942 throws java.io.IOException {
0943 synchronized (principals) {
0944 oos.defaultWriteObject();
0945 }
0946 }
0947
0948 /**
0949 * Reads this object from a stream (i.e., deserializes it)
0950 */
0951 private void readObject(java.io.ObjectInputStream s)
0952 throws java.io.IOException, ClassNotFoundException {
0953
0954 s.defaultReadObject();
0955
0956 // The Credential <code>Set</code> is not serialized, but we do not
0957 // want the default deserialization routine to set it to null.
0958 this .pubCredentials = Collections
0959 .synchronizedSet(new SecureSet<Object>(this ,
0960 PUB_CREDENTIAL_SET));
0961 this .privCredentials = Collections
0962 .synchronizedSet(new SecureSet<Object>(this ,
0963 PRIV_CREDENTIAL_SET));
0964 }
0965
0966 /**
0967 * Prevent modifications unless caller has permission.
0968 *
0969 * @serial include
0970 */
0971 private static class SecureSet<E> extends AbstractSet<E> implements
0972 java.io.Serializable {
0973
0974 private static final long serialVersionUID = 7911754171111800359L;
0975
0976 /**
0977 * @serialField this$0 Subject The outer Subject instance.
0978 * @serialField elements LinkedList The elements in this set.
0979 */
0980 private static final ObjectStreamField[] serialPersistentFields = {
0981 new ObjectStreamField("this$0", Subject.class),
0982 new ObjectStreamField("elements", LinkedList.class),
0983 new ObjectStreamField("which", int.class) };
0984
0985 Subject subject;
0986 LinkedList<E> elements;
0987
0988 /**
0989 * @serial An integer identifying the type of objects contained
0990 * in this set. If <code>which == 1</code>,
0991 * this is a Principal set and all the elements are
0992 * of type <code>java.security.Principal</code>.
0993 * If <code>which == 2</code>, this is a public credential
0994 * set and all the elements are of type <code>Object</code>.
0995 * If <code>which == 3</code>, this is a private credential
0996 * set and all the elements are of type <code>Object</code>.
0997 */
0998 private int which;
0999
1000 SecureSet(Subject subject, int which) {
1001 this .subject = subject;
1002 this .which = which;
1003 this .elements = new LinkedList<E>();
1004 }
1005
1006 SecureSet(Subject subject, int which, Set<? extends E> set) {
1007 this .subject = subject;
1008 this .which = which;
1009 this .elements = new LinkedList<E>(set);
1010 }
1011
1012 public int size() {
1013 return elements.size();
1014 }
1015
1016 public Iterator<E> iterator() {
1017 final LinkedList<E> list = elements;
1018 return new Iterator<E>() {
1019 ListIterator<E> i = list.listIterator(0);
1020
1021 public boolean hasNext() {
1022 return i.hasNext();
1023 }
1024
1025 public E next() {
1026 if (which != Subject.PRIV_CREDENTIAL_SET) {
1027 return i.next();
1028 }
1029
1030 SecurityManager sm = System.getSecurityManager();
1031 if (sm != null) {
1032 try {
1033 sm
1034 .checkPermission(new PrivateCredentialPermission(
1035 list.get(i.nextIndex())
1036 .getClass()
1037 .getName(), subject
1038 .getPrincipals()));
1039 } catch (SecurityException se) {
1040 i.next();
1041 throw (se);
1042 }
1043 }
1044 return i.next();
1045 }
1046
1047 public void remove() {
1048
1049 if (subject.isReadOnly()) {
1050 throw new IllegalStateException(ResourcesMgr
1051 .getString("Subject is read-only"));
1052 }
1053
1054 java.lang.SecurityManager sm = System
1055 .getSecurityManager();
1056 if (sm != null) {
1057 switch (which) {
1058 case Subject.PRINCIPAL_SET:
1059 sm.checkPermission(new AuthPermission(
1060 "modifyPrincipals"));
1061 break;
1062 case Subject.PUB_CREDENTIAL_SET:
1063 sm.checkPermission(new AuthPermission(
1064 "modifyPublicCredentials"));
1065 break;
1066 default:
1067 sm.checkPermission(new AuthPermission(
1068 "modifyPrivateCredentials"));
1069 break;
1070 }
1071 }
1072 i.remove();
1073 }
1074 };
1075 }
1076
1077 public boolean add(E o) {
1078
1079 if (subject.isReadOnly()) {
1080 throw new IllegalStateException(ResourcesMgr
1081 .getString("Subject is read-only"));
1082 }
1083
1084 java.lang.SecurityManager sm = System.getSecurityManager();
1085 if (sm != null) {
1086 switch (which) {
1087 case Subject.PRINCIPAL_SET:
1088 sm.checkPermission(new AuthPermission(
1089 "modifyPrincipals"));
1090 break;
1091 case Subject.PUB_CREDENTIAL_SET:
1092 sm.checkPermission(new AuthPermission(
1093 "modifyPublicCredentials"));
1094 break;
1095 default:
1096 sm.checkPermission(new AuthPermission(
1097 "modifyPrivateCredentials"));
1098 break;
1099 }
1100 }
1101
1102 switch (which) {
1103 case Subject.PRINCIPAL_SET:
1104 if (!(o instanceof Principal)) {
1105 throw new SecurityException(
1106 ResourcesMgr
1107 .getString("attempting to add an object which is not an "
1108 + "instance of java.security.Principal to a "
1109 + "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
1133 .doPrivileged(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
1170 .checkPermission(new PrivateCredentialPermission(
1171 o.getClass().getName(), subject
1172 .getPrincipals()));
1173 }
1174 next = java.security.AccessController
1175 .doPrivileged(new java.security.PrivilegedAction<E>() {
1176 public E run() {
1177 return e.next();
1178 }
1179 });
1180 }
1181
1182 if (next == null) {
1183 if (o == null) {
1184 return true;
1185 }
1186 } else if (next.equals(o)) {
1187 return true;
1188 }
1189 }
1190 return false;
1191 }
1192
1193 public boolean removeAll(Collection<?> c) {
1194
1195 boolean modified = false;
1196 final Iterator<E> e = iterator();
1197 while (e.hasNext()) {
1198 E next;
1199 if (which != Subject.PRIV_CREDENTIAL_SET) {
1200 next = e.next();
1201 } else {
1202 next = java.security.AccessController
1203 .doPrivileged(new java.security.PrivilegedAction<E>() {
1204 public E run() {
1205 return e.next();
1206 }
1207 });
1208 }
1209
1210 Iterator<?> ce = c.iterator();
1211 while (ce.hasNext()) {
1212 Object o = ce.next();
1213 if (next == null) {
1214 if (o == null) {
1215 e.remove();
1216 modified = true;
1217 break;
1218 }
1219 } else if (next.equals(o)) {
1220 e.remove();
1221 modified = true;
1222 break;
1223 }
1224 }
1225 }
1226 return modified;
1227 }
1228
1229 public boolean retainAll(Collection<?> c) {
1230
1231 boolean modified = false;
1232 boolean retain = false;
1233 final Iterator<E> e = iterator();
1234 while (e.hasNext()) {
1235 retain = false;
1236 E next;
1237 if (which != Subject.PRIV_CREDENTIAL_SET) {
1238 next = e.next();
1239 } else {
1240 next = java.security.AccessController
1241 .doPrivileged(new java.security.PrivilegedAction<E>() {
1242 public E run() {
1243 return e.next();
1244 }
1245 });
1246 }
1247
1248 Iterator<?> ce = c.iterator();
1249 while (ce.hasNext()) {
1250 Object o = ce.next();
1251 if (next == null) {
1252 if (o == null) {
1253 retain = true;
1254 break;
1255 }
1256 } else if (next.equals(o)) {
1257 retain = true;
1258 break;
1259 }
1260 }
1261
1262 if (!retain) {
1263 e.remove();
1264 retain = false;
1265 modified = true;
1266 }
1267 }
1268 return modified;
1269 }
1270
1271 public void clear() {
1272 final Iterator<E> e = iterator();
1273 while (e.hasNext()) {
1274 E next;
1275 if (which != Subject.PRIV_CREDENTIAL_SET) {
1276 next = e.next();
1277 } else {
1278 next = java.security.AccessController
1279 .doPrivileged(new java.security.PrivilegedAction<E>() {
1280 public E run() {
1281 return e.next();
1282 }
1283 });
1284 }
1285 e.remove();
1286 }
1287 }
1288
1289 /**
1290 * Writes this object out to a stream (i.e., serializes it).
1291 *
1292 * <p>
1293 *
1294 * @serialData If this is a private credential set,
1295 * a security check is performed to ensure that
1296 * the caller has permission to access each credential
1297 * in the set. If the security check passes,
1298 * the set is serialized.
1299 */
1300 private void writeObject(java.io.ObjectOutputStream oos)
1301 throws java.io.IOException {
1302
1303 if (which == Subject.PRIV_CREDENTIAL_SET) {
1304 // check permissions before serializing
1305 Iterator<E> i = iterator();
1306 while (i.hasNext()) {
1307 i.next();
1308 }
1309 }
1310 ObjectOutputStream.PutField fields = oos.putFields();
1311 fields.put("this$0", subject);
1312 fields.put("elements", elements);
1313 fields.put("which", which);
1314 oos.writeFields();
1315 }
1316
1317 private void readObject(ObjectInputStream ois)
1318 throws IOException, ClassNotFoundException {
1319 ObjectInputStream.GetField fields = ois.readFields();
1320 subject = (Subject) fields.get("this$0", null);
1321 elements = (LinkedList<E>) fields.get("elements", null);
1322 which = fields.get("which", 0);
1323 }
1324 }
1325
1326 /**
1327 * This class implements a <code>Set</code> which returns only
1328 * members that are an instance of a specified Class.
1329 */
1330 private class ClassSet<T> extends AbstractSet<T> {
1331
1332 private int which;
1333 private Class<T> c;
1334 private Set<T> set;
1335
1336 ClassSet(int which, Class<T> c) {
1337 this .which = which;
1338 this .c = c;
1339 set = new HashSet<T>();
1340
1341 switch (which) {
1342 case Subject.PRINCIPAL_SET:
1343 synchronized (principals) {
1344 populateSet();
1345 }
1346 break;
1347 case Subject.PUB_CREDENTIAL_SET:
1348 synchronized (pubCredentials) {
1349 populateSet();
1350 }
1351 break;
1352 default:
1353 synchronized (privCredentials) {
1354 populateSet();
1355 }
1356 break;
1357 }
1358 }
1359
1360 private void populateSet() {
1361 final Iterator<?> iterator;
1362 switch (which) {
1363 case Subject.PRINCIPAL_SET:
1364 iterator = Subject.this .principals.iterator();
1365 break;
1366 case Subject.PUB_CREDENTIAL_SET:
1367 iterator = Subject.this .pubCredentials.iterator();
1368 break;
1369 default:
1370 iterator = Subject.this .privCredentials.iterator();
1371 break;
1372 }
1373
1374 // Check whether the caller has permisson to get
1375 // credentials of Class c
1376
1377 while (iterator.hasNext()) {
1378 Object next;
1379 if (which == Subject.PRIV_CREDENTIAL_SET) {
1380 next = java.security.AccessController
1381 .doPrivileged(new java.security.PrivilegedAction<Object>() {
1382 public Object run() {
1383 return iterator.next();
1384 }
1385 });
1386 } else {
1387 next = iterator.next();
1388 }
1389 if (c.isAssignableFrom(next.getClass())) {
1390 if (which != Subject.PRIV_CREDENTIAL_SET) {
1391 set.add((T) next);
1392 } else {
1393 // Check permission for private creds
1394 SecurityManager sm = System
1395 .getSecurityManager();
1396 if (sm != null) {
1397 sm
1398 .checkPermission(new PrivateCredentialPermission(
1399 next.getClass().getName(),
1400 Subject.this
1401 .getPrincipals()));
1402 }
1403 set.add((T) next);
1404 }
1405 }
1406 }
1407 }
1408
1409 public int size() {
1410 return set.size();
1411 }
1412
1413 public Iterator<T> iterator() {
1414 return set.iterator();
1415 }
1416
1417 public boolean add(T o) {
1418
1419 if (!o.getClass().isAssignableFrom(c)) {
1420 MessageFormat form = new MessageFormat(
1421 ResourcesMgr
1422 .getString("attempting to add an object which is not an "
1423 + "instance of class"));
1424 Object[] source = { c.toString() };
1425 throw new SecurityException(form.format(source));
1426 }
1427
1428 return set.add(o);
1429 }
1430 }
1431 }
|