Package javax.security.auth

Source Code of javax.security.auth.Subject$ClassSet

/*
* @(#)Subject.java  1.127 05/11/17
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

package javax.security.auth;

import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.DomainCombiner;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.ProtectionDomain;
import sun.security.util.ResourcesMgr;
import sun.security.util.SecurityConstants;

/**
* <p> A <code>Subject</code> represents a grouping of related information
* for a single entity, such as a person.
* Such information includes the Subject's identities as well as
* its security-related attributes
* (passwords and cryptographic keys, for example).
*
* <p> Subjects may potentially have multiple identities.
* Each identity is represented as a <code>Principal</code>
* within the <code>Subject</code>.  Principals simply bind names to a
* <code>Subject</code>.  For example, a <code>Subject</code> that happens
* to be a person, Alice, might have two Principals:
* one which binds "Alice Bar", the name on her driver license,
* to the <code>Subject</code>, and another which binds,
* "999-99-9999", the number on her student identification card,
* to the <code>Subject</code>.  Both Principals refer to the same
* <code>Subject</code> even though each has a different name.
*
* <p> A <code>Subject</code> may also own security-related attributes,
* which are referred to as credentials.
* Sensitive credentials that require special protection, such as
* private cryptographic keys, are stored within a private credential
* <code>Set</code>.  Credentials intended to be shared, such as
* public key certificates or Kerberos server tickets are stored
* within a public credential <code>Set</code>.  Different permissions
* are required to access and modify the different credential Sets.
*
* <p> To retrieve all the Principals associated with a <code>Subject</code>,
* invoke the <code>getPrincipals</code> method.  To retrieve
* all the public or private credentials belonging to a <code>Subject</code>,
* invoke the <code>getPublicCredentials</code> method or
* <code>getPrivateCredentials</code> method, respectively.
* To modify the returned <code>Set</code> of Principals and credentials,
* use the methods defined in the <code>Set</code> class.
* For example:
* <pre>
*  Subject subject;
*  Principal principal;
*  Object credential;
*
*  // add a Principal and credential to the Subject
*  subject.getPrincipals().add(principal);
*  subject.getPublicCredentials().add(credential);
* </pre>
*
* <p> This <code>Subject</code> class implements <code>Serializable</code>.
* While the Principals associated with the <code>Subject</code> are serialized,
* the credentials associated with the <code>Subject</code> are not.
* Note that the <code>java.security.Principal</code> class
* does not implement <code>Serializable</code>.  Therefore all concrete
* <code>Principal</code> implementations associated with Subjects
* must implement <code>Serializable</code>.
*
* @version 1.127, 11/17/05
* @see java.security.Principal
* @see java.security.DomainCombiner
*/
public final class Subject implements java.io.Serializable {

    private static final long serialVersionUID = -8308522755600156056L;

    /**
     * A <code>Set</code> that provides a view of all of this
     * Subject's Principals
     *
     * <p>
     *
     * @serial Each element in this set is a
     *    <code>java.security.Principal</code>.
     *    The set is a <code>Subject.SecureSet</code>.
     */
    Set principals;

    /**
     * Sets that provide a view of all of this
     * Subject's Credentials
     */
    transient Set pubCredentials;
    transient Set privCredentials;

    /**
     * Whether this Subject is read-only
     *
     * @serial
     */
    private volatile boolean readOnly = false;

    private static final int PRINCIPAL_SET = 1;
    private static final int PUB_CREDENTIAL_SET = 2;
    private static final int PRIV_CREDENTIAL_SET = 3;

    /**
     * Create an instance of a <code>Subject</code>
     * with an empty <code>Set</code> of Principals and empty
     * Sets of public and private credentials.
     *
     * <p> The newly constructed Sets check whether this <code>Subject</code>
     * has been set read-only before permitting subsequent modifications.
     * The newly created Sets also prevent illegal modifications
     * by ensuring that callers have sufficient permissions.
     *
     * <p> To modify the Principals Set, the caller must have
     * <code>AuthPermission("modifyPrincipals")</code>.
     * To modify the public credential Set, the caller must have
     * <code>AuthPermission("modifyPublicCredentials")</code>.
     * To modify the private credential Set, the caller must have
     * <code>AuthPermission("modifyPrivateCredentials")</code>.
     */
    public Subject() {

  this.principals = Collections.synchronizedSet
        (new SecureSet(this, PRINCIPAL_SET));
  this.pubCredentials = Collections.synchronizedSet
        (new SecureSet(this, PUB_CREDENTIAL_SET));
  this.privCredentials = Collections.synchronizedSet
        (new SecureSet(this, PRIV_CREDENTIAL_SET));
    }

    /**
     * Create an instance of a <code>Subject</code> with
     * Principals and credentials.
     *
     * <p> The Principals and credentials from the specified Sets
     * are copied into newly constructed Sets.
     * These newly created Sets check whether this <code>Subject</code>
     * has been set read-only before permitting subsequent modifications.
     * The newly created Sets also prevent illegal modifications
     * by ensuring that callers have sufficient permissions.
     *
     * <p> To modify the Principals Set, the caller must have
     * <code>AuthPermission("modifyPrincipals")</code>.
     * To modify the public credential Set, the caller must have
     * <code>AuthPermission("modifyPublicCredentials")</code>.
     * To modify the private credential Set, the caller must have
     * <code>AuthPermission("modifyPrivateCredentials")</code>.
     * <p>
     *
     * @param readOnly true if the <code>Subject</code> is to be read-only,
     *    and false otherwise. <p>
     *
     * @param principals the <code>Set</code> of Principals
     *    to be associated with this <code>Subject</code>. <p>
     *
     * @param pubCredentials the <code>Set</code> of public credentials
     *    to be associated with this <code>Subject</code>. <p>
     *
     * @param privCredentials the <code>Set</code> of private credentials
     *    to be associated with this <code>Subject</code>.
     *
     * @exception NullPointerException if the specified
     *    <code>principals</code>, <code>pubCredentials</code>,
     *    or <code>privCredentials</code> are <code>null</code>.
     */
    public Subject(boolean readOnly, Set<? extends Principal> principals,
       Set<?> pubCredentials, Set<?> privCredentials)
    {

  if (principals == null ||
      pubCredentials == null ||
      privCredentials == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null input(s)"));

  this.principals = Collections.synchronizedSet(new SecureSet
        (this, PRINCIPAL_SET, principals));
  this.pubCredentials = Collections.synchronizedSet(new SecureSet
        (this, PUB_CREDENTIAL_SET, pubCredentials));
  this.privCredentials = Collections.synchronizedSet(new SecureSet
        (this, PRIV_CREDENTIAL_SET, privCredentials));
  this.readOnly = readOnly;
    }

    /**
     * Set this <code>Subject</code> to be read-only.
     *
     * <p> Modifications (additions and removals) to this Subject's
     * <code>Principal</code> <code>Set</code> and
     * credential Sets will be disallowed.
     * The <code>destroy</code> operation on this Subject's credentials will
     * still be permitted.
     *
     * <p> Subsequent attempts to modify the Subject's <code>Principal</code>
     * and credential Sets will result in an
     * <code>IllegalStateException</code> being thrown.
     * Also, once a <code>Subject</code> is read-only,
     * it can not be reset to being writable again.
     *
     * <p>
     *
     * @exception SecurityException if the caller does not have permission
     *    to set this <code>Subject</code> to be read-only.
     */
    public void setReadOnly() {
  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(new AuthPermission("setReadOnly"));
  }

  this.readOnly = true;
    }

    /**
     * Query whether this <code>Subject</code> is read-only.
     *
     * <p>
     *
     * @return true if this <code>Subject</code> is read-only, false otherwise.
     */
    public boolean isReadOnly() {
  return this.readOnly;
    }

    /**
     * Get the <code>Subject</code> associated with the provided
     * <code>AccessControlContext</code>.
     *
     * <p> The <code>AccessControlContext</code> may contain many
     * Subjects (from nested <code>doAs</code> calls).
     * In this situation, the most recent <code>Subject</code> associated
     * with the <code>AccessControlContext</code> is returned.
     *
     * <p>
     *
     * @param  acc the <code>AccessControlContext</code> from which to retrieve
     *    the <code>Subject</code>.
     *
     * @return  the <code>Subject</code> associated with the provided
     *    <code>AccessControlContext</code>, or <code>null</code>
     *    if no <code>Subject</code> is associated
     *    with the provided <code>AccessControlContext</code>.
     *
     * @exception SecurityException if the caller does not have permission
     *    to get the <code>Subject</code>. <p>
     *
     * @exception NullPointerException if the provided
     *    <code>AccessControlContext</code> is <code>null</code>.
     */
    public static Subject getSubject(final AccessControlContext acc) {

  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(new AuthPermission("getSubject"));
  }

  if (acc == null) {
      throw new NullPointerException(ResourcesMgr.getString
    ("invalid null AccessControlContext provided"));
  }

  // return the Subject from the DomainCombiner of the provided context
  return (Subject)AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
    DomainCombiner dc = acc.getDomainCombiner();
    if (!(dc instanceof SubjectDomainCombiner))
        return null;
    SubjectDomainCombiner sdc = (SubjectDomainCombiner)dc;
    return sdc.getSubject();
      }
  });
    }

    /**
     * Perform work as a particular <code>Subject</code>.
     *
     * <p> This method first retrieves the current Thread's
     * <code>AccessControlContext</code> via
     * <code>AccessController.getContext</code>,
     * and then instantiates a new <code>AccessControlContext</code>
     * using the retrieved context along with a new
     * <code>SubjectDomainCombiner</code> (constructed using
     * the provided <code>Subject</code>).
     * Finally, this method invokes <code>AccessController.doPrivileged</code>,
     * passing it the provided <code>PrivilegedAction</code>,
     * as well as the newly constructed <code>AccessControlContext</code>.
     *
     * <p>
     *
     * @param subject the <code>Subject</code> that the specified
     *      <code>action</code> will run as.  This parameter
     *      may be <code>null</code>. <p>
     *
     * @param action the code to be run as the specified
     *      <code>Subject</code>. <p>
     *
     * @return the value returned by the PrivilegedAction's
     *      <code>run</code> method.
     *
     * @exception NullPointerException if the <code>PrivilegedAction</code>
     *      is <code>null</code>. <p>
     *
     * @exception SecurityException if the caller does not have permission
     *      to invoke this method.
     */
    public static <T> T doAs(final Subject subject,
      final java.security.PrivilegedAction<T> action) {

  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(SecurityConstants.DO_AS_PERMISSION);
  }
  if (action == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null action provided"));

  // set up the new Subject-based AccessControlContext
  // for doPrivileged
  final AccessControlContext currentAcc = AccessController.getContext();

  // call doPrivileged and push this new context on the stack
  return java.security.AccessController.doPrivileged
          (action,
          createContext(subject, currentAcc));
    }

    /**
     * Perform work as a particular <code>Subject</code>.
     *
     * <p> This method first retrieves the current Thread's
     * <code>AccessControlContext</code> via
     * <code>AccessController.getContext</code>,
     * and then instantiates a new <code>AccessControlContext</code>
     * using the retrieved context along with a new
     * <code>SubjectDomainCombiner</code> (constructed using
     * the provided <code>Subject</code>).
     * Finally, this method invokes <code>AccessController.doPrivileged</code>,
     * passing it the provided <code>PrivilegedExceptionAction</code>,
     * as well as the newly constructed <code>AccessControlContext</code>.
     *
     * <p>
     *
     * @param subject the <code>Subject</code> that the specified
     *      <code>action</code> will run as.  This parameter
     *      may be <code>null</code>. <p>
     *
     * @param action the code to be run as the specified
     *      <code>Subject</code>. <p>
     *
     * @return the value returned by the
     *      PrivilegedExceptionAction's <code>run</code> method.
     *
     * @exception PrivilegedActionException if the
     *      <code>PrivilegedExceptionAction.run</code>
     *      method throws a checked exception. <p>
     *
     * @exception NullPointerException if the specified
     *      <code>PrivilegedExceptionAction</code> is
     *      <code>null</code>. <p>
     *
     * @exception SecurityException if the caller does not have permission
     *      to invoke this method.
     */
    public static <T> T doAs(final Subject subject,
      final java.security.PrivilegedExceptionAction<T> action)
      throws java.security.PrivilegedActionException {

  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(SecurityConstants.DO_AS_PERMISSION);
  }

  if (action == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null action provided"));

  // set up the new Subject-based AccessControlContext for doPrivileged
  final AccessControlContext currentAcc = AccessController.getContext();

  // call doPrivileged and push this new context on the stack
  return java.security.AccessController.doPrivileged
          (action,
          createContext(subject, currentAcc));
    }

    /**
     * Perform privileged work as a particular <code>Subject</code>.
     *
     * <p> This method behaves exactly as <code>Subject.doAs</code>,
     * except that instead of retrieving the current Thread's
     * <code>AccessControlContext</code>, it uses the provided
     * <code>AccessControlContext</code>.  If the provided
     * <code>AccessControlContext</code> is <code>null</code>,
     * this method instantiates a new <code>AccessControlContext</code>
     * with an empty collection of ProtectionDomains.
     *
     * <p>
     *
     * @param subject the <code>Subject</code> that the specified
     *      <code>action</code> will run as.  This parameter
     *      may be <code>null</code>. <p>
     *
     * @param action the code to be run as the specified
     *      <code>Subject</code>. <p>
     *
     * @param acc the <code>AccessControlContext</code> to be tied to the
     *      specified <i>subject</i> and <i>action</i>. <p>
     *
     * @return the value returned by the PrivilegedAction's
     *      <code>run</code> method.
     *
     * @exception NullPointerException if the <code>PrivilegedAction</code>
     *      is <code>null</code>. <p>
     *
     * @exception SecurityException if the caller does not have permission
     *      to invoke this method.
     */
    public static <T> T doAsPrivileged(final Subject subject,
      final java.security.PrivilegedAction<T> action,
      final java.security.AccessControlContext acc) {

  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(SecurityConstants.DO_AS_PRIVILEGED_PERMISSION);
  }

  if (action == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null action provided"));

  // set up the new Subject-based AccessControlContext
  // for doPrivileged
  final AccessControlContext callerAcc =
    (acc == null ?
    new AccessControlContext(new ProtectionDomain[0]) :
    acc);

  // call doPrivileged and push this new context on the stack
  return java.security.AccessController.doPrivileged
          (action,
          createContext(subject, callerAcc));
    }

    /**
     * Perform privileged work as a particular <code>Subject</code>.
     *
     * <p> This method behaves exactly as <code>Subject.doAs</code>,
     * except that instead of retrieving the current Thread's
     * <code>AccessControlContext</code>, it uses the provided
     * <code>AccessControlContext</code>.  If the provided
     * <code>AccessControlContext</code> is <code>null</code>,
     * this method instantiates a new <code>AccessControlContext</code>
     * with an empty collection of ProtectionDomains.
     *
     * <p>
     *
     * @param subject the <code>Subject</code> that the specified
     *      <code>action</code> will run as.  This parameter
     *      may be <code>null</code>. <p>
     *
     * @param action the code to be run as the specified
     *      <code>Subject</code>. <p>
     *
     * @param acc the <code>AccessControlContext</code> to be tied to the
     *      specified <i>subject</i> and <i>action</i>. <p>
     *
     * @return the value returned by the
     *      PrivilegedExceptionAction's <code>run</code> method.
     *
     * @exception PrivilegedActionException if the
     *      <code>PrivilegedExceptionAction.run</code>
     *      method throws a checked exception. <p>
     *
     * @exception NullPointerException if the specified
     *      <code>PrivilegedExceptionAction</code> is
     *      <code>null</code>. <p>
     *
     * @exception SecurityException if the caller does not have permission
     *      to invoke this method.
     */
    public static <T> T doAsPrivileged(final Subject subject,
      final java.security.PrivilegedExceptionAction<T> action,
      final java.security.AccessControlContext acc)
      throws java.security.PrivilegedActionException {

  java.lang.SecurityManager sm = System.getSecurityManager();
  if (sm != null) {
      sm.checkPermission(SecurityConstants.DO_AS_PRIVILEGED_PERMISSION);
  }

  if (action == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null action provided"));

  // set up the new Subject-based AccessControlContext for doPrivileged
  final AccessControlContext callerAcc =
    (acc == null ?
    new AccessControlContext(new ProtectionDomain[0]) :
    acc);

  // call doPrivileged and push this new context on the stack
  return java.security.AccessController.doPrivileged
          (action,
          createContext(subject, callerAcc));
    }

    private static AccessControlContext createContext(final Subject subject,
          final AccessControlContext acc) {


  return (AccessControlContext)
      java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
    if (subject == null)
              return new AccessControlContext(acc, null);
    else
        return new AccessControlContext
          (acc,
          new SubjectDomainCombiner(subject));
      }
  });
    }

    /**
     * Return the <code>Set</code> of Principals associated with this
     * <code>Subject</code>.  Each <code>Principal</code> represents
     * an identity for this <code>Subject</code>.
     *
     * <p> The returned <code>Set</code> is backed by this Subject's
     * internal <code>Principal</code> <code>Set</code>.  Any modification
     * to the returned <code>Set</code> affects the internal
     * <code>Principal</code> <code>Set</code> as well.
     *
     * <p>
     *
     * @return  The <code>Set</code> of Principals associated with this
     *    <code>Subject</code>.
     */
    public Set<Principal> getPrincipals() {

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return principals;
    }

    /**
     * Return a <code>Set</code> of Principals associated with this
     * <code>Subject</code> that are instances or subclasses of the specified
     * <code>Class</code>.
     *
     * <p> The returned <code>Set</code> is not backed by this Subject's
     * internal <code>Principal</code> <code>Set</code>.  A new
     * <code>Set</code> is created and returned for each method invocation.
     * Modifications to the returned <code>Set</code>
     * will not affect the internal <code>Principal</code> <code>Set</code>.
     *
     * <p>
     *
     * @param c the returned <code>Set</code> of Principals will all be
     *    instances of this class.
     *
     * @return a <code>Set</code> of Principals that are instances of the
     *    specified <code>Class</code>.
     *
     * @exception NullPointerException if the specified <code>Class</code>
     *      is <code>null</code>.
     */
    public <T extends Principal> Set<T> getPrincipals(Class<T> c) {

  if (c == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null Class provided"));

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return new ClassSet(PRINCIPAL_SET, c);
    }

    /**
     * Return the <code>Set</code> of public credentials held by this
     * <code>Subject</code>.
     *
     * <p> The returned <code>Set</code> is backed by this Subject's
     * internal public Credential <code>Set</code>.  Any modification
     * to the returned <code>Set</code> affects the internal public
     * Credential <code>Set</code> as well.
     *
     * <p>
     *
     * @return  A <code>Set</code> of public credentials held by this
     *    <code>Subject</code>.
     */
    public Set<Object> getPublicCredentials() {

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return pubCredentials;
    }

    /**
     * Return the <code>Set</code> of private credentials held by this
     * <code>Subject</code>.
     *
     * <p> The returned <code>Set</code> is backed by this Subject's
     * internal private Credential <code>Set</code>.  Any modification
     * to the returned <code>Set</code> affects the internal private
     * Credential <code>Set</code> as well.
     *
     * <p> A caller requires permissions to access the Credentials
     * in the returned <code>Set</code>, or to modify the
     * <code>Set</code> itself.  A <code>SecurityException</code>
     * is thrown if the caller does not have the proper permissions.
     *
     * <p> While iterating through the <code>Set</code>,
     * a <code>SecurityException</code> is thrown
     * if the caller does not have permission to access a
     * particular Credential.  The <code>Iterator</code>
     * is nevertheless advanced to next element in the <code>Set</code>.
     *
     * <p>
     *
     * @return  A <code>Set</code> of private credentials held by this
     *    <code>Subject</code>.
     */
    public Set<Object> getPrivateCredentials() {

  // XXX
  // we do not need a security check for
  // AuthPermission(getPrivateCredentials)
  // because we already restrict access to private credentials
  // via the PrivateCredentialPermission.  all the extra AuthPermission
  // would do is protect the set operations themselves
  // (like size()), which don't seem security-sensitive.

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return privCredentials;
    }

    /**
     * Return a <code>Set</code> of public credentials associated with this
     * <code>Subject</code> that are instances or subclasses of the specified
     * <code>Class</code>.
     *
     * <p> The returned <code>Set</code> is not backed by this Subject's
     * internal public Credential <code>Set</code>.  A new
     * <code>Set</code> is created and returned for each method invocation.
     * Modifications to the returned <code>Set</code>
     * will not affect the internal public Credential <code>Set</code>.
     *
     * <p>
     *
     * @param c the returned <code>Set</code> of public credentials will all be
     *    instances of this class.
     *
     * @return a <code>Set</code> of public credentials that are instances
     *    of the  specified <code>Class</code>.
     *
     * @exception NullPointerException if the specified <code>Class</code>
     *    is <code>null</code>.
     */
    public <T> Set<T> getPublicCredentials(Class<T> c) {

  if (c == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null Class provided"));

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return new ClassSet<T>(PUB_CREDENTIAL_SET, c);
    }

    /**
     * Return a <code>Set</code> of private credentials associated with this
     * <code>Subject</code> that are instances or subclasses of the specified
     * <code>Class</code>.
     *
     * <p> The caller must have permission to access all of the
     * requested Credentials, or a <code>SecurityException</code>
     * will be thrown.
     *
     * <p> The returned <code>Set</code> is not backed by this Subject's
     * internal private Credential <code>Set</code>.  A new
     * <code>Set</code> is created and returned for each method invocation.
     * Modifications to the returned <code>Set</code>
     * will not affect the internal private Credential <code>Set</code>.
     *
     * <p>
     *
     * @param c the returned <code>Set</code> of private credentials will all be
     *    instances of this class.
     *
     * @return a <code>Set</code> of private credentials that are instances
     *    of the  specified <code>Class</code>.
     *
     * @exception NullPointerException if the specified <code>Class</code>
     *    is <code>null</code>.
     */
    public <T> Set<T> getPrivateCredentials(Class<T> c) {

  // XXX
  // we do not need a security check for
  // AuthPermission(getPrivateCredentials)
  // because we already restrict access to private credentials
  // via the PrivateCredentialPermission.  all the extra AuthPermission
  // would do is protect the set operations themselves
  // (like size()), which don't seem security-sensitive.

  if (c == null)
      throw new NullPointerException
    (ResourcesMgr.getString("invalid null Class provided"));

  // always return an empty Set instead of null
  // so LoginModules can add to the Set if necessary
  return new ClassSet<T>(PRIV_CREDENTIAL_SET, c);
    }

    /**
     * Compares the specified Object with this <code>Subject</code>
     * for equality.  Returns true if the given object is also a Subject
     * and the two <code>Subject</code> instances are equivalent.
     * More formally, two <code>Subject</code> instances are
     * equal if their <code>Principal</code> and <code>Credential</code>
     * Sets are equal.
     *
     * <p>
     *
     * @param o Object to be compared for equality with this
     *    <code>Subject</code>.
     *
     * @return true if the specified Object is equal to this
     *    <code>Subject</code>.
     *
     * @exception SecurityException if the caller does not have permission
     *    to access the private credentials for this <code>Subject</code>,
     *    or if the caller does not have permission to access the
     *    private credentials for the provided <code>Subject</code>.
     */
    public boolean equals(Object o) {

  if (o == null)
      return false;

  if (this == o)
      return true;

  if (o instanceof Subject) {

      final Subject that = (Subject)o;

      // check the principal and credential sets
      Set thatPrincipals;
      synchronized(that.principals) {
    // avoid deadlock from dual locks
    thatPrincipals = new HashSet(that.principals);
      }
      if (!principals.equals(thatPrincipals)) {
    return false;
      }

      Set thatPubCredentials;
      synchronized(that.pubCredentials) {
    // avoid deadlock from dual locks
    thatPubCredentials = new HashSet(that.pubCredentials);
      }
      if (!pubCredentials.equals(thatPubCredentials)) {
    return false;
      }

      Set thatPrivCredentials;
      synchronized(that.privCredentials) {
    // avoid deadlock from dual locks
    thatPrivCredentials = new HashSet(that.privCredentials);
      }
      if (!privCredentials.equals(thatPrivCredentials)) {
    return false;
      }
      return true;
  }
  return false;
    }

    /**
     * Return the String representation of this <code>Subject</code>.
     *
     * <p>
     *
     * @return the String representation of this <code>Subject</code>.
     */
    public String toString() {
  return toString(true);
    }

    /**
     * package private convenience method to print out the Subject
     * without firing off a security check when trying to access
     * the Private Credentials
     */
    String toString(boolean includePrivateCredentials) {

  String s = ResourcesMgr.getString("Subject:\n");
  String suffix = "";

  synchronized(principals) {
      Iterator pI = principals.iterator();
      while (pI.hasNext()) {
    Principal p = (Principal)pI.next();
    suffix = suffix + ResourcesMgr.getString("\tPrincipal: ") +
      p.toString() + ResourcesMgr.getString("\n");
      }
  }

  synchronized(pubCredentials) {
      Iterator pI = pubCredentials.iterator();
      while (pI.hasNext()) {
    Object o = pI.next();
    suffix = suffix +
      ResourcesMgr.getString("\tPublic Credential: ") +
      o.toString() + ResourcesMgr.getString("\n");
      }
  }
      
  if (includePrivateCredentials) {
      synchronized(privCredentials) {
    Iterator pI = privCredentials.iterator();
    while (pI.hasNext()) {
        try {
      Object o = pI.next();
      suffix += ResourcesMgr.getString
          ("\tPrivate Credential: ") +
          o.toString() +
          ResourcesMgr.getString("\n");
        } catch (SecurityException se) {
      suffix += ResourcesMgr.getString
        ("\tPrivate Credential inaccessible\n");
      break;
        }
    }
      }
  }
  return s + suffix;
    }

    /**
     * Returns a hashcode for this <code>Subject</code>.
     *
     * <p>
     *
     * @return a hashcode for this <code>Subject</code>.
     *
     * @exception SecurityException if the caller does not have permission
     *    to access this Subject's private credentials.
     */
    public int hashCode() {

  /**
   * The hashcode is derived exclusive or-ing the
   * hashcodes of this Subject's Principals and credentials.
   *
   * If a particular credential was destroyed
   * (<code>credential.hashCode()</code> throws an
   * <code>IllegalStateException</code>),
   * the hashcode for that credential is derived via:
   * <code>credential.getClass().toString().hashCode()</code>.
   */

  int hashCode = 0;

  synchronized(principals) {
      Iterator pIterator = principals.iterator();
      while (pIterator.hasNext()) {
    Principal p = (Principal)pIterator.next();
    hashCode ^= p.hashCode();
      }
  }

  synchronized(pubCredentials) {
      Iterator pubCIterator = pubCredentials.iterator();
      while (pubCIterator.hasNext()) {
    hashCode ^= getCredHashCode(pubCIterator.next());
      }
  }
  return hashCode;
    }

    /**
     * get a credential's hashcode
     */
    private int getCredHashCode(Object o) {
  try {
      return o.hashCode();
  } catch (IllegalStateException ise) {
      return o.getClass().toString().hashCode();
  }
    }

    /**
     * Writes this object out to a stream (i.e., serializes it).
     */
    private void writeObject(java.io.ObjectOutputStream oos)
    throws java.io.IOException {
  synchronized(principals) {
      oos.defaultWriteObject();
  }
    }

    /**
     * Reads this object from a stream (i.e., deserializes it)
     */
    private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {

  s.defaultReadObject();

  // The Credential <code>Set</code> is not serialized, but we do not
  // want the default deserialization routine to set it to null.
  this.pubCredentials = Collections.synchronizedSet
        (new SecureSet(this, PUB_CREDENTIAL_SET));
  this.privCredentials = Collections.synchronizedSet
        (new SecureSet(this, PRIV_CREDENTIAL_SET));
    }

    /**
     * Prevent modifications unless caller has permission.
     *
     * @serial include
     */
    private static class SecureSet
  extends AbstractSet
  implements java.io.Serializable {

  private static final long serialVersionUID = 7911754171111800359L;

  /**
   * @serialField this$0 Subject The outer Subject instance.
   * @serialField elements LinkedList The elements in this set.
   */
  private static final ObjectStreamField[] serialPersistentFields = {
      new ObjectStreamField("this$0", Subject.class),
      new ObjectStreamField("elements", LinkedList.class),
      new ObjectStreamField("which", int.class)
  };

  Subject subject;
  LinkedList elements;

  /**
   * @serial An integer identifying the type of objects contained
   *  in this set.  If <code>which == 1</code>,
   *  this is a Principal set and all the elements are
   *  of type <code>java.security.Principal</code>.
   *  If <code>which == 2</code>, this is a public credential
   *  set and all the elements are of type <code>Object</code>.
   *  If <code>which == 3</code>, this is a private credential
   *  set and all the elements are of type <code>Object</code>.
   */
  private int which;

  SecureSet(Subject subject, int which) {
      this.subject = subject;
      this.which = which;
      this.elements = new LinkedList();
  }

  SecureSet(Subject subject, int which, Set set) {
      this.subject = subject;
      this.which = which;
      this.elements = new LinkedList(set);
  }

  public int size() {
      return elements.size();
  }

  public Iterator iterator() {
      final LinkedList list = elements;
      return new Iterator() {
    ListIterator i = list.listIterator(0);

    public boolean hasNext() {return i.hasNext();}
     
    public Object next() {
        if (which != Subject.PRIV_CREDENTIAL_SET) {
      return i.next();
        }

        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
      try {
          sm.checkPermission(new PrivateCredentialPermission
        (list.get(i.nextIndex()).getClass().getName(),
        subject.getPrincipals()));
      } catch (SecurityException se) {
          i.next();
          throw (se);
      }
        }
        return i.next();
    }
     
    public void remove() {

        if (subject.isReadOnly()) {
      throw new IllegalStateException(ResourcesMgr.getString
        ("Subject is read-only"));
        }

        java.lang.SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
      switch (which) {
      case Subject.PRINCIPAL_SET:
          sm.checkPermission(new AuthPermission
          ("modifyPrincipals"));
          break;
      case Subject.PUB_CREDENTIAL_SET:
          sm.checkPermission(new AuthPermission
          ("modifyPublicCredentials"));
          break;
      default:
          sm.checkPermission(new AuthPermission
          ("modifyPrivateCredentials"));
          break;
      }
        }
        i.remove();
    }
      };
  }
   
  public boolean add(Object o) {
 
      if (subject.isReadOnly()) {
    throw new IllegalStateException
      (ResourcesMgr.getString("Subject is read-only"));
      }
 
      java.lang.SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
    switch (which) {
    case Subject.PRINCIPAL_SET:
        sm.checkPermission
      (new AuthPermission("modifyPrincipals"));
        break;
    case Subject.PUB_CREDENTIAL_SET:
        sm.checkPermission
      (new AuthPermission("modifyPublicCredentials"));
        break;
    default:
        sm.checkPermission
      (new AuthPermission("modifyPrivateCredentials"));
        break;
    }
      }
 
      switch (which) {
      case Subject.PRINCIPAL_SET:
    if (!(o instanceof Principal)) {
        throw new SecurityException(ResourcesMgr.getString
      ("attempting to add an object which is not an " +
      "instance of java.security.Principal to a " +
      "Subject's Principal Set"));
    }
    break;
      default:
    // ok to add Objects of any kind to credential sets
    break;
      }
 
      // check for duplicates
      if (!elements.contains(o))
    return elements.add(o);
      else
    return false;
  }
   
  public boolean remove(Object o) {
 
      final Iterator e = iterator();
      while (e.hasNext()) {
    Object next;
    if (which != Subject.PRIV_CREDENTIAL_SET) {
        next = e.next();
    } else {
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
          return e.next();
      }
        });
    }
   
    if (next == null) {
        if (o == null) {
      e.remove();
      return true;
        }
    } else if (next.equals(o)) {
        e.remove();
        return true;
    }
      }
      return false;
  }
 
  public boolean contains(Object o) {
      final Iterator e = iterator();
      while (e.hasNext()) {
    Object next;
    if (which != Subject.PRIV_CREDENTIAL_SET) {
        next = e.next();
    } else {

        // For private credentials:
        // If the caller does not have read permission for
        // for o.getClass(), we throw a SecurityException.
        // Otherwise we check the private cred set to see whether
        // it contains the Object
 
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
      sm.checkPermission(new PrivateCredentialPermission
            (o.getClass().getName(),
            subject.getPrincipals()));
        }
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
          return e.next();
      }
        });
    }
   
    if (next == null) {
        if (o == null) {
      return true;
        }
    } else if (next.equals(o)) {
        return true;
    }
      }
      return false;
  }
   
  public boolean removeAll(Collection c) {
 
      boolean modified = false;
      final Iterator e = iterator();
      while (e.hasNext()) {
    Object next;
    if (which != Subject.PRIV_CREDENTIAL_SET) {
        next = e.next();
    } else {
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
          return e.next();
      }
        });
    }

    Iterator ce = c.iterator();
    while (ce.hasNext()) {
        Object o = ce.next();
        if (next == null) {
      if (o == null) {
          e.remove();
          modified = true;
          break;
      }
        } else if (next.equals(o)) {
      e.remove();
      modified = true;
      break;
        }
    }
      }
      return modified;
  }

  public boolean retainAll(Collection c) {

      boolean modified = false;
      boolean retain = false;
      final Iterator e = iterator();
      while (e.hasNext()) {
    retain = false;
    Object next;
    if (which != Subject.PRIV_CREDENTIAL_SET) {
        next = e.next();
    } else {
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
          return e.next();
      }
        });
    }

    Iterator ce = c.iterator();
    while (ce.hasNext()) {
        Object o = ce.next();     
        if (next == null) {
      if (o == null) {
          retain = true;
          break;
      }
        } else if (next.equals(o)) {   
      retain = true;
      break;
        }
    }
   
    if (!retain) {
        e.remove();
        retain = false;
        modified = true;
          }
      }
      return modified;
  }
   
  public void clear() {
      final Iterator e = iterator();
      while (e.hasNext()) {
    Object next;
    if (which != Subject.PRIV_CREDENTIAL_SET) {
        next = e.next();
    } else {
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
          return e.next();
      }
        });
    }
    e.remove();
     
  }

  /**
   * Writes this object out to a stream (i.e., serializes it).
   *
   * <p>
   *
   * @serialData If this is a private credential set,
   *  a security check is performed to ensure that
   *  the caller has permission to access each credential
   *  in the set.  If the security check passes,
   *  the set is serialized.
   */
  private void writeObject(java.io.ObjectOutputStream oos)
    throws java.io.IOException {
 
      if (which == Subject.PRIV_CREDENTIAL_SET) {
    // check permissions before serializing
    Iterator i = iterator();
    while (i.hasNext()) {
        i.next();
    }
      }
      ObjectOutputStream.PutField fields = oos.putFields();
      fields.put("this$0", subject);
      fields.put("elements", elements);
      fields.put("which", which);
      oos.writeFields();
  }

  private void readObject(ObjectInputStream ois)
      throws IOException, ClassNotFoundException
  {
      ObjectInputStream.GetField fields = ois.readFields();
      subject = (Subject) fields.get("this$0", null);
      elements = (LinkedList) fields.get("elements", null);
      which = fields.get("which", 0);
  }
    }

    /**
     * This class implements a <code>Set</code> which returns only
     * members that are an instance of a specified Class.
     */
    private class ClassSet<T> extends AbstractSet<T> {

  private int which;
  private Class c;
  private Set<T> set;

  ClassSet(int which, Class c) {
      this.which = which;
      this.c = c;
      set = new HashSet();

      switch (which) {
      case Subject.PRINCIPAL_SET:
    synchronized(principals) { populateSet(); }
    break;
      case Subject.PUB_CREDENTIAL_SET:
    synchronized(pubCredentials) { populateSet(); }
    break;
      default:
    synchronized(privCredentials) { populateSet(); }
    break;
      }
  }

  private void populateSet() {
      final Iterator iterator;
      switch(which) {
      case Subject.PRINCIPAL_SET:
    iterator = Subject.this.principals.iterator();
    break;
      case Subject.PUB_CREDENTIAL_SET:
    iterator = Subject.this.pubCredentials.iterator();
    break;
      default:
    iterator = Subject.this.privCredentials.iterator();
    break;
      }

      // Check whether the caller has permisson to get
      // credentials of Class c
    
      while (iterator.hasNext()) {
    Object next;
    if (which == Subject.PRIV_CREDENTIAL_SET) {
        next = (Object)java.security.AccessController.doPrivileged
      (new java.security.PrivilegedAction() {
      public Object run() {
              return iterator.next();
      }
        });
    } else {
            next = iterator.next();
    }
    if (c.isAssignableFrom(next.getClass())) {
        if (which != Subject.PRIV_CREDENTIAL_SET) {
      set.add((T)next);
        } else {
      // Check permission for private creds
      SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
          sm.checkPermission(new PrivateCredentialPermission
            (next.getClass().getName(),
            Subject.this.getPrincipals()));
      }
      set.add((T)next);
        }
    }
      }
  }

  public int size() {
      return set.size();
  }
 
  public Iterator<T> iterator() {
      return set.iterator();
  }
 
  public boolean add(T o) {
     
      if (!o.getClass().isAssignableFrom(c)) {
    MessageFormat form = new MessageFormat(ResourcesMgr.getString
      ("attempting to add an object which is not an " +
      "instance of class"));
    Object[] source = {c.toString()};
    throw new SecurityException(form.format(source));
      }
     
      return set.add(o);
  }
    }
}
TOP

Related Classes of javax.security.auth.Subject$ClassSet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.