/* * @(#)Subject.java 1.123 04/05/05 * * Copyright 2004 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; /** *
A Subject
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).
*
*
Subjects may potentially have multiple identities.
* Each identity is represented as a Principal
* within the Subject
. Principals simply bind names to a
* Subject
. For example, a Subject
that happens
* to be a person, Alice, might have two Principals:
* one which binds "Alice Bar", the name on her driver license,
* to the Subject
, and another which binds,
* "999-99-9999", the number on her student identification card,
* to the Subject
. Both Principals refer to the same
* Subject
even though each has a different name.
*
*
A Subject
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
* Set
. Credentials intended to be shared, such as
* public key certificates or Kerberos server tickets are stored
* within a public credential Set
. Different permissions
* are required to access and modify the different credential Sets.
*
*
To retrieve all the Principals associated with a Subject
,
* invoke the getPrincipals
method. To retrieve
* all the public or private credentials belonging to a Subject
,
* invoke the getPublicCredentials
method or
* getPrivateCredentials
method, respectively.
* To modify the returned Set
of Principals and credentials,
* use the methods defined in the Set
class.
* For example:
*
* Subject subject; * Principal principal; * Object credential; * * // add a Principal and credential to the Subject * subject.getPrincipals().add(principal); * subject.getPublicCredentials().add(credential); ** *
This Subject
class implements Serializable
.
* While the Principals associated with the Subject
are serialized,
* the credentials associated with the Subject
are not.
* Note that the java.security.Principal
class
* does not implement Serializable
. Therefore all concrete
* Principal
implementations associated with Subjects
* must implement Serializable
.
*
* @version 1.123, 05/05/04
* @see java.security.Principal
* @see java.security.DomainCombiner
*/
public final class Subject implements java.io.Serializable {
private static final long serialVersionUID = -8308522755600156056L;
/**
* A Set
that provides a view of all of this
* Subject's Principals
*
*
*
* @serial Each element in this set is a
* java.security.Principal
.
* The set is a Subject.SecureSet
.
*/
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 Subject
* with an empty Set
of Principals and empty
* Sets of public and private credentials.
*
*
The newly constructed Sets check whether this Subject
* has been set read-only before permitting subsequent modifications.
* The newly created Sets also prevent illegal modifications
* by ensuring that callers have sufficient permissions.
*
*
To modify the Principals Set, the caller must have
* AuthPermission("modifyPrincipals")
.
* To modify the public credential Set, the caller must have
* AuthPermission("modifyPublicCredentials")
.
* To modify the private credential Set, the caller must have
* AuthPermission("modifyPrivateCredentials")
.
*/
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 Subject
with
* Principals and credentials.
*
*
The Principals and credentials from the specified Sets
* are copied into newly constructed Sets.
* These newly created Sets check whether this Subject
* has been set read-only before permitting subsequent modifications.
* The newly created Sets also prevent illegal modifications
* by ensuring that callers have sufficient permissions.
*
*
To modify the Principals Set, the caller must have
* AuthPermission("modifyPrincipals")
.
* To modify the public credential Set, the caller must have
* AuthPermission("modifyPublicCredentials")
.
* To modify the private credential Set, the caller must have
* AuthPermission("modifyPrivateCredentials")
.
*
*
* @param readOnly true if the Subject
is to be read-only,
* and false otherwise.
*
* @param principals the Set
of Principals
* to be associated with this Subject
.
*
* @param pubCredentials the Set
of public credentials
* to be associated with this Subject
.
*
* @param privCredentials the Set
of private credentials
* to be associated with this Subject
.
*
* @exception NullPointerException if the specified
* principals
, pubCredentials
,
* or privCredentials
are null
.
*/
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 Subject
to be read-only.
*
*
Modifications (additions and removals) to this Subject's
* Principal
Set
and
* credential Sets will be disallowed.
* The destroy
operation on this Subject's credentials will
* still be permitted.
*
*
Subsequent attempts to modify the Subject's Principal
* and credential Sets will result in an
* IllegalStateException
being thrown.
* Also, once a Subject
is read-only,
* it can not be reset to being writable again.
*
*
*
* @exception SecurityException if the caller does not have permission
* to set this Subject
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 Subject
is read-only.
*
*
*
* @return true if this Subject
is read-only, false otherwise.
*/
public boolean isReadOnly() {
return this.readOnly;
}
/**
* Get the Subject
associated with the provided
* AccessControlContext
.
*
*
The AccessControlContext
may contain many
* Subjects (from nested doAs
calls).
* In this situation, the most recent Subject
associated
* with the AccessControlContext
is returned.
*
*
*
* @param acc the AccessControlContext
from which to retrieve
* the Subject
.
*
* @return the Subject
associated with the provided
* AccessControlContext
, or null
* if no Subject
is associated
* with the provided AccessControlContext
.
*
* @exception SecurityException if the caller does not have permission
* to get the Subject
.
*
* @exception NullPointerException if the provided
* AccessControlContext
is null
.
*/
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 Subject
.
*
*
This method first retrieves the current Thread's
* AccessControlContext
via
* AccessController.getContext
,
* and then instantiates a new AccessControlContext
* using the retrieved context along with a new
* SubjectDomainCombiner
(constructed using
* the provided Subject
).
* Finally, this method invokes AccessController.doPrivileged
,
* passing it the provided PrivilegedAction
,
* as well as the newly constructed AccessControlContext
.
*
*
*
* @param subject the Subject
that the specified
* action
will run as. This parameter
* may be null
.
*
* @param action the code to be run as the specified
* Subject
.
*
* @return the Object
returned by the PrivilegedAction's
* run
method.
*
* @exception NullPointerException if the PrivilegedAction
* is null
.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static Object doAs(final Subject subject,
final java.security.PrivilegedAction 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 Subject
.
*
*
This method first retrieves the current Thread's
* AccessControlContext
via
* AccessController.getContext
,
* and then instantiates a new AccessControlContext
* using the retrieved context along with a new
* SubjectDomainCombiner
(constructed using
* the provided Subject
).
* Finally, this method invokes AccessController.doPrivileged
,
* passing it the provided PrivilegedExceptionAction
,
* as well as the newly constructed AccessControlContext
.
*
*
*
* @param subject the Subject
that the specified
* action
will run as. This parameter
* may be null
.
*
* @param action the code to be run as the specified
* Subject
.
*
* @return the Object
returned by the
* PrivilegedExceptionAction's run
method.
*
* @exception PrivilegedActionException if the
* PrivilegedExceptionAction.run
* method throws a checked exception.
*
* @exception NullPointerException if the specified
* PrivilegedExceptionAction
is
* null
.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static Object doAs(final Subject subject,
final java.security.PrivilegedExceptionAction 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 Subject
.
*
*
This method behaves exactly as Subject.doAs
,
* except that instead of retrieving the current Thread's
* AccessControlContext
, it uses the provided
* AccessControlContext
. If the provided
* AccessControlContext
is null
,
* this method instantiates a new AccessControlContext
* with an empty collection of ProtectionDomains.
*
*
*
* @param subject the Subject
that the specified
* action
will run as. This parameter
* may be null
.
*
* @param action the code to be run as the specified
* Subject
.
*
* @param acc the AccessControlContext
to be tied to the
* specified subject and action.
*
* @return the Object
returned by the PrivilegedAction's
* run
method.
*
* @exception NullPointerException if the PrivilegedAction
* is null
.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static Object doAsPrivileged(final Subject subject,
final java.security.PrivilegedAction 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 Subject
.
*
*
This method behaves exactly as Subject.doAs
,
* except that instead of retrieving the current Thread's
* AccessControlContext
, it uses the provided
* AccessControlContext
. If the provided
* AccessControlContext
is null
,
* this method instantiates a new AccessControlContext
* with an empty collection of ProtectionDomains.
*
*
*
* @param subject the Subject
that the specified
* action
will run as. This parameter
* may be null
.
*
* @param action the code to be run as the specified
* Subject
.
*
* @param acc the AccessControlContext
to be tied to the
* specified subject and action.
*
* @return the Object
returned by the
* PrivilegedExceptionAction's run
method.
*
* @exception PrivilegedActionException if the
* PrivilegedExceptionAction.run
* method throws a checked exception.
*
* @exception NullPointerException if the specified
* PrivilegedExceptionAction
is
* null
.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static Object doAsPrivileged(final Subject subject,
final java.security.PrivilegedExceptionAction 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 Set
of Principals associated with this
* Subject
. Each Principal
represents
* an identity for this Subject
.
*
*
The returned Set
is backed by this Subject's
* internal Principal
Set
. Any modification
* to the returned Set
affects the internal
* Principal
Set
as well.
*
*
*
* @return The The returned
*
* @param c the returned The returned
*
* @return A Set
of Principals associated with this
* Subject
.
*/
public SetSet
of Principals associated with this
* Subject
that are instances or subclasses of the specified
* Class
.
*
* Set
is not backed by this Subject's
* internal Principal
Set
. A new
* Set
is created and returned for each method invocation.
* Modifications to the returned Set
* will not affect the internal Principal
Set
.
*
* Set
of Principals will all be
* instances of this class.
*
* @return a Set
of Principals that are instances of the
* specified Class
.
*
* @exception NullPointerException if the specified Class
* is null
.
*/
public Set
of public credentials held by this
* Subject
.
*
* Set
is backed by this Subject's
* internal public Credential Set
. Any modification
* to the returned Set
affects the internal public
* Credential Set
as well.
*
* Set
of public credentials held by this
* Subject
.
*/
public Set