Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/Subject.java
38918 views
/*1* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth;2627import java.util.*;28import java.io.*;29import java.lang.reflect.*;30import java.text.MessageFormat;31import java.security.AccessController;32import java.security.AccessControlContext;33import java.security.DomainCombiner;34import java.security.Permission;35import java.security.PermissionCollection;36import java.security.Principal;37import java.security.PrivilegedAction;38import java.security.PrivilegedExceptionAction;39import java.security.PrivilegedActionException;40import java.security.ProtectionDomain;41import sun.security.util.ResourcesMgr;4243/**44* <p> A {@code Subject} represents a grouping of related information45* for a single entity, such as a person.46* Such information includes the Subject's identities as well as47* its security-related attributes48* (passwords and cryptographic keys, for example).49*50* <p> Subjects may potentially have multiple identities.51* Each identity is represented as a {@code Principal}52* within the {@code Subject}. Principals simply bind names to a53* {@code Subject}. For example, a {@code Subject} that happens54* to be a person, Alice, might have two Principals:55* one which binds "Alice Bar", the name on her driver license,56* to the {@code Subject}, and another which binds,57* "999-99-9999", the number on her student identification card,58* to the {@code Subject}. Both Principals refer to the same59* {@code Subject} even though each has a different name.60*61* <p> A {@code Subject} may also own security-related attributes,62* which are referred to as credentials.63* Sensitive credentials that require special protection, such as64* private cryptographic keys, are stored within a private credential65* {@code Set}. Credentials intended to be shared, such as66* public key certificates or Kerberos server tickets are stored67* within a public credential {@code Set}. Different permissions68* are required to access and modify the different credential Sets.69*70* <p> To retrieve all the Principals associated with a {@code Subject},71* invoke the {@code getPrincipals} method. To retrieve72* all the public or private credentials belonging to a {@code Subject},73* invoke the {@code getPublicCredentials} method or74* {@code getPrivateCredentials} method, respectively.75* To modify the returned {@code Set} of Principals and credentials,76* use the methods defined in the {@code Set} class.77* For example:78* <pre>79* Subject subject;80* Principal principal;81* Object credential;82*83* // add a Principal and credential to the Subject84* subject.getPrincipals().add(principal);85* subject.getPublicCredentials().add(credential);86* </pre>87*88* <p> This {@code Subject} class implements {@code Serializable}.89* While the Principals associated with the {@code Subject} are serialized,90* the credentials associated with the {@code Subject} are not.91* Note that the {@code java.security.Principal} class92* does not implement {@code Serializable}. Therefore all concrete93* {@code Principal} implementations associated with Subjects94* must implement {@code Serializable}.95*96* @see java.security.Principal97* @see java.security.DomainCombiner98*/99public final class Subject implements java.io.Serializable {100101private static final long serialVersionUID = -8308522755600156056L;102103/**104* A {@code Set} that provides a view of all of this105* Subject's Principals106*107* <p>108*109* @serial Each element in this set is a110* {@code java.security.Principal}.111* The set is a {@code Subject.SecureSet}.112*/113Set<Principal> principals;114115/**116* Sets that provide a view of all of this117* Subject's Credentials118*/119transient Set<Object> pubCredentials;120transient Set<Object> privCredentials;121122/**123* Whether this Subject is read-only124*125* @serial126*/127private volatile boolean readOnly = false;128129private static final int PRINCIPAL_SET = 1;130private static final int PUB_CREDENTIAL_SET = 2;131private static final int PRIV_CREDENTIAL_SET = 3;132133private static final ProtectionDomain[] NULL_PD_ARRAY134= new ProtectionDomain[0];135136/**137* Create an instance of a {@code Subject}138* with an empty {@code Set} of Principals and empty139* Sets of public and private credentials.140*141* <p> The newly constructed Sets check whether this {@code Subject}142* has been set read-only before permitting subsequent modifications.143* The newly created Sets also prevent illegal modifications144* by ensuring that callers have sufficient permissions.145*146* <p> To modify the Principals Set, the caller must have147* {@code AuthPermission("modifyPrincipals")}.148* To modify the public credential Set, the caller must have149* {@code AuthPermission("modifyPublicCredentials")}.150* To modify the private credential Set, the caller must have151* {@code AuthPermission("modifyPrivateCredentials")}.152*/153public Subject() {154155this.principals = Collections.synchronizedSet156(new SecureSet<Principal>(this, PRINCIPAL_SET));157this.pubCredentials = Collections.synchronizedSet158(new SecureSet<Object>(this, PUB_CREDENTIAL_SET));159this.privCredentials = Collections.synchronizedSet160(new SecureSet<Object>(this, PRIV_CREDENTIAL_SET));161}162163/**164* Create an instance of a {@code Subject} with165* Principals and credentials.166*167* <p> The Principals and credentials from the specified Sets168* are copied into newly constructed Sets.169* These newly created Sets check whether this {@code Subject}170* has been set read-only before permitting subsequent modifications.171* The newly created Sets also prevent illegal modifications172* by ensuring that callers have sufficient permissions.173*174* <p> To modify the Principals Set, the caller must have175* {@code AuthPermission("modifyPrincipals")}.176* To modify the public credential Set, the caller must have177* {@code AuthPermission("modifyPublicCredentials")}.178* To modify the private credential Set, the caller must have179* {@code AuthPermission("modifyPrivateCredentials")}.180* <p>181*182* @param readOnly true if the {@code Subject} is to be read-only,183* and false otherwise. <p>184*185* @param principals the {@code Set} of Principals186* to be associated with this {@code Subject}. <p>187*188* @param pubCredentials the {@code Set} of public credentials189* to be associated with this {@code Subject}. <p>190*191* @param privCredentials the {@code Set} of private credentials192* to be associated with this {@code Subject}.193*194* @exception NullPointerException if the specified195* {@code principals}, {@code pubCredentials},196* or {@code privCredentials} are {@code null}.197*/198public Subject(boolean readOnly, Set<? extends Principal> principals,199Set<?> pubCredentials, Set<?> privCredentials)200{201202if (principals == null ||203pubCredentials == null ||204privCredentials == null)205throw new NullPointerException206(ResourcesMgr.getString("invalid.null.input.s."));207208this.principals = Collections.synchronizedSet(new SecureSet<Principal>209(this, PRINCIPAL_SET, principals));210this.pubCredentials = Collections.synchronizedSet(new SecureSet<Object>211(this, PUB_CREDENTIAL_SET, pubCredentials));212this.privCredentials = Collections.synchronizedSet(new SecureSet<Object>213(this, PRIV_CREDENTIAL_SET, privCredentials));214this.readOnly = readOnly;215}216217/**218* Set this {@code Subject} to be read-only.219*220* <p> Modifications (additions and removals) to this Subject's221* {@code Principal} {@code Set} and222* credential Sets will be disallowed.223* The {@code destroy} operation on this Subject's credentials will224* still be permitted.225*226* <p> Subsequent attempts to modify the Subject's {@code Principal}227* and credential Sets will result in an228* {@code IllegalStateException} being thrown.229* Also, once a {@code Subject} is read-only,230* it can not be reset to being writable again.231*232* <p>233*234* @exception SecurityException if the caller does not have permission235* to set this {@code Subject} to be read-only.236*/237public void setReadOnly() {238java.lang.SecurityManager sm = System.getSecurityManager();239if (sm != null) {240sm.checkPermission(AuthPermissionHolder.SET_READ_ONLY_PERMISSION);241}242243this.readOnly = true;244}245246/**247* Query whether this {@code Subject} is read-only.248*249* <p>250*251* @return true if this {@code Subject} is read-only, false otherwise.252*/253public boolean isReadOnly() {254return this.readOnly;255}256257/**258* Get the {@code Subject} associated with the provided259* {@code AccessControlContext}.260*261* <p> The {@code AccessControlContext} may contain many262* Subjects (from nested {@code doAs} calls).263* In this situation, the most recent {@code Subject} associated264* with the {@code AccessControlContext} is returned.265*266* <p>267*268* @param acc the {@code AccessControlContext} from which to retrieve269* the {@code Subject}.270*271* @return the {@code Subject} associated with the provided272* {@code AccessControlContext}, or {@code null}273* if no {@code Subject} is associated274* with the provided {@code AccessControlContext}.275*276* @exception SecurityException if the caller does not have permission277* to get the {@code Subject}. <p>278*279* @exception NullPointerException if the provided280* {@code AccessControlContext} is {@code null}.281*/282public static Subject getSubject(final AccessControlContext acc) {283284java.lang.SecurityManager sm = System.getSecurityManager();285if (sm != null) {286sm.checkPermission(AuthPermissionHolder.GET_SUBJECT_PERMISSION);287}288289if (acc == null) {290throw new NullPointerException(ResourcesMgr.getString291("invalid.null.AccessControlContext.provided"));292}293294// return the Subject from the DomainCombiner of the provided context295return AccessController.doPrivileged296(new java.security.PrivilegedAction<Subject>() {297public Subject run() {298DomainCombiner dc = acc.getDomainCombiner();299if (!(dc instanceof SubjectDomainCombiner))300return null;301SubjectDomainCombiner sdc = (SubjectDomainCombiner)dc;302return sdc.getSubject();303}304});305}306307/**308* Perform work as a particular {@code Subject}.309*310* <p> This method first retrieves the current Thread's311* {@code AccessControlContext} via312* {@code AccessController.getContext},313* and then instantiates a new {@code AccessControlContext}314* using the retrieved context along with a new315* {@code SubjectDomainCombiner} (constructed using316* the provided {@code Subject}).317* Finally, this method invokes {@code AccessController.doPrivileged},318* passing it the provided {@code PrivilegedAction},319* as well as the newly constructed {@code AccessControlContext}.320*321* <p>322*323* @param subject the {@code Subject} that the specified324* {@code action} will run as. This parameter325* may be {@code null}. <p>326*327* @param <T> the type of the value returned by the PrivilegedAction's328* {@code run} method.329*330* @param action the code to be run as the specified331* {@code Subject}. <p>332*333* @return the value returned by the PrivilegedAction's334* {@code run} method.335*336* @exception NullPointerException if the {@code PrivilegedAction}337* is {@code null}. <p>338*339* @exception SecurityException if the caller does not have permission340* to invoke this method.341*/342public static <T> T doAs(final Subject subject,343final java.security.PrivilegedAction<T> action) {344345java.lang.SecurityManager sm = System.getSecurityManager();346if (sm != null) {347sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);348}349if (action == null)350throw new NullPointerException351(ResourcesMgr.getString("invalid.null.action.provided"));352353// set up the new Subject-based AccessControlContext354// for doPrivileged355final AccessControlContext currentAcc = AccessController.getContext();356357// call doPrivileged and push this new context on the stack358return java.security.AccessController.doPrivileged359(action,360createContext(subject, currentAcc));361}362363/**364* Perform work as a particular {@code Subject}.365*366* <p> This method first retrieves the current Thread's367* {@code AccessControlContext} via368* {@code AccessController.getContext},369* and then instantiates a new {@code AccessControlContext}370* using the retrieved context along with a new371* {@code SubjectDomainCombiner} (constructed using372* the provided {@code Subject}).373* Finally, this method invokes {@code AccessController.doPrivileged},374* passing it the provided {@code PrivilegedExceptionAction},375* as well as the newly constructed {@code AccessControlContext}.376*377* <p>378*379* @param subject the {@code Subject} that the specified380* {@code action} will run as. This parameter381* may be {@code null}. <p>382*383* @param <T> the type of the value returned by the384* PrivilegedExceptionAction's {@code run} method.385*386* @param action the code to be run as the specified387* {@code Subject}. <p>388*389* @return the value returned by the390* PrivilegedExceptionAction's {@code run} method.391*392* @exception PrivilegedActionException if the393* {@code PrivilegedExceptionAction.run}394* method throws a checked exception. <p>395*396* @exception NullPointerException if the specified397* {@code PrivilegedExceptionAction} is398* {@code null}. <p>399*400* @exception SecurityException if the caller does not have permission401* to invoke this method.402*/403public static <T> T doAs(final Subject subject,404final java.security.PrivilegedExceptionAction<T> action)405throws java.security.PrivilegedActionException {406407java.lang.SecurityManager sm = System.getSecurityManager();408if (sm != null) {409sm.checkPermission(AuthPermissionHolder.DO_AS_PERMISSION);410}411412if (action == null)413throw new NullPointerException414(ResourcesMgr.getString("invalid.null.action.provided"));415416// set up the new Subject-based AccessControlContext for doPrivileged417final AccessControlContext currentAcc = AccessController.getContext();418419// call doPrivileged and push this new context on the stack420return java.security.AccessController.doPrivileged421(action,422createContext(subject, currentAcc));423}424425/**426* Perform privileged work as a particular {@code Subject}.427*428* <p> This method behaves exactly as {@code Subject.doAs},429* except that instead of retrieving the current Thread's430* {@code AccessControlContext}, it uses the provided431* {@code AccessControlContext}. If the provided432* {@code AccessControlContext} is {@code null},433* this method instantiates a new {@code AccessControlContext}434* with an empty collection of ProtectionDomains.435*436* <p>437*438* @param subject the {@code Subject} that the specified439* {@code action} will run as. This parameter440* may be {@code null}. <p>441*442* @param <T> the type of the value returned by the PrivilegedAction's443* {@code run} method.444*445* @param action the code to be run as the specified446* {@code Subject}. <p>447*448* @param acc the {@code AccessControlContext} to be tied to the449* specified <i>subject</i> and <i>action</i>. <p>450*451* @return the value returned by the PrivilegedAction's452* {@code run} method.453*454* @exception NullPointerException if the {@code PrivilegedAction}455* is {@code null}. <p>456*457* @exception SecurityException if the caller does not have permission458* to invoke this method.459*/460public static <T> T doAsPrivileged(final Subject subject,461final java.security.PrivilegedAction<T> action,462final java.security.AccessControlContext acc) {463464java.lang.SecurityManager sm = System.getSecurityManager();465if (sm != null) {466sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);467}468469if (action == null)470throw new NullPointerException471(ResourcesMgr.getString("invalid.null.action.provided"));472473// set up the new Subject-based AccessControlContext474// for doPrivileged475final AccessControlContext callerAcc =476(acc == null ?477new AccessControlContext(NULL_PD_ARRAY) :478acc);479480// call doPrivileged and push this new context on the stack481return java.security.AccessController.doPrivileged482(action,483createContext(subject, callerAcc));484}485486/**487* Perform privileged work as a particular {@code Subject}.488*489* <p> This method behaves exactly as {@code Subject.doAs},490* except that instead of retrieving the current Thread's491* {@code AccessControlContext}, it uses the provided492* {@code AccessControlContext}. If the provided493* {@code AccessControlContext} is {@code null},494* this method instantiates a new {@code AccessControlContext}495* with an empty collection of ProtectionDomains.496*497* <p>498*499* @param subject the {@code Subject} that the specified500* {@code action} will run as. This parameter501* may be {@code null}. <p>502*503* @param <T> the type of the value returned by the504* PrivilegedExceptionAction's {@code run} method.505*506* @param action the code to be run as the specified507* {@code Subject}. <p>508*509* @param acc the {@code AccessControlContext} to be tied to the510* specified <i>subject</i> and <i>action</i>. <p>511*512* @return the value returned by the513* PrivilegedExceptionAction's {@code run} method.514*515* @exception PrivilegedActionException if the516* {@code PrivilegedExceptionAction.run}517* method throws a checked exception. <p>518*519* @exception NullPointerException if the specified520* {@code PrivilegedExceptionAction} is521* {@code null}. <p>522*523* @exception SecurityException if the caller does not have permission524* to invoke this method.525*/526public static <T> T doAsPrivileged(final Subject subject,527final java.security.PrivilegedExceptionAction<T> action,528final java.security.AccessControlContext acc)529throws java.security.PrivilegedActionException {530531java.lang.SecurityManager sm = System.getSecurityManager();532if (sm != null) {533sm.checkPermission(AuthPermissionHolder.DO_AS_PRIVILEGED_PERMISSION);534}535536if (action == null)537throw new NullPointerException538(ResourcesMgr.getString("invalid.null.action.provided"));539540// set up the new Subject-based AccessControlContext for doPrivileged541final AccessControlContext callerAcc =542(acc == null ?543new AccessControlContext(NULL_PD_ARRAY) :544acc);545546// call doPrivileged and push this new context on the stack547return java.security.AccessController.doPrivileged548(action,549createContext(subject, callerAcc));550}551552private static AccessControlContext createContext(final Subject subject,553final AccessControlContext acc) {554555556return java.security.AccessController.doPrivileged557(new java.security.PrivilegedAction<AccessControlContext>() {558public AccessControlContext run() {559if (subject == null)560return new AccessControlContext(acc, null);561else562return new AccessControlContext563(acc,564new SubjectDomainCombiner(subject));565}566});567}568569/**570* Return the {@code Set} of Principals associated with this571* {@code Subject}. Each {@code Principal} represents572* an identity for this {@code Subject}.573*574* <p> The returned {@code Set} is backed by this Subject's575* internal {@code Principal} {@code Set}. Any modification576* to the returned {@code Set} affects the internal577* {@code Principal} {@code Set} as well.578*579* <p>580*581* @return The {@code Set} of Principals associated with this582* {@code Subject}.583*/584public Set<Principal> getPrincipals() {585586// always return an empty Set instead of null587// so LoginModules can add to the Set if necessary588return principals;589}590591/**592* Return a {@code Set} of Principals associated with this593* {@code Subject} that are instances or subclasses of the specified594* {@code Class}.595*596* <p> The returned {@code Set} is not backed by this Subject's597* internal {@code Principal} {@code Set}. A new598* {@code Set} is created and returned for each method invocation.599* Modifications to the returned {@code Set}600* will not affect the internal {@code Principal} {@code Set}.601*602* <p>603*604* @param <T> the type of the class modeled by {@code c}605*606* @param c the returned {@code Set} of Principals will all be607* instances of this class.608*609* @return a {@code Set} of Principals that are instances of the610* specified {@code Class}.611*612* @exception NullPointerException if the specified {@code Class}613* is {@code null}.614*/615public <T extends Principal> Set<T> getPrincipals(Class<T> c) {616617if (c == null)618throw new NullPointerException619(ResourcesMgr.getString("invalid.null.Class.provided"));620621// always return an empty Set instead of null622// so LoginModules can add to the Set if necessary623return new ClassSet<T>(PRINCIPAL_SET, c);624}625626/**627* Return the {@code Set} of public credentials held by this628* {@code Subject}.629*630* <p> The returned {@code Set} is backed by this Subject's631* internal public Credential {@code Set}. Any modification632* to the returned {@code Set} affects the internal public633* Credential {@code Set} as well.634*635* <p>636*637* @return A {@code Set} of public credentials held by this638* {@code Subject}.639*/640public Set<Object> getPublicCredentials() {641642// always return an empty Set instead of null643// so LoginModules can add to the Set if necessary644return pubCredentials;645}646647/**648* Return the {@code Set} of private credentials held by this649* {@code Subject}.650*651* <p> The returned {@code Set} is backed by this Subject's652* internal private Credential {@code Set}. Any modification653* to the returned {@code Set} affects the internal private654* Credential {@code Set} as well.655*656* <p> A caller requires permissions to access the Credentials657* in the returned {@code Set}, or to modify the658* {@code Set} itself. A {@code SecurityException}659* is thrown if the caller does not have the proper permissions.660*661* <p> While iterating through the {@code Set},662* a {@code SecurityException} is thrown663* if the caller does not have permission to access a664* particular Credential. The {@code Iterator}665* is nevertheless advanced to next element in the {@code Set}.666*667* <p>668*669* @return A {@code Set} of private credentials held by this670* {@code Subject}.671*/672public Set<Object> getPrivateCredentials() {673674// XXX675// we do not need a security check for676// AuthPermission(getPrivateCredentials)677// because we already restrict access to private credentials678// via the PrivateCredentialPermission. all the extra AuthPermission679// would do is protect the set operations themselves680// (like size()), which don't seem security-sensitive.681682// always return an empty Set instead of null683// so LoginModules can add to the Set if necessary684return privCredentials;685}686687/**688* Return a {@code Set} of public credentials associated with this689* {@code Subject} that are instances or subclasses of the specified690* {@code Class}.691*692* <p> The returned {@code Set} is not backed by this Subject's693* internal public Credential {@code Set}. A new694* {@code Set} is created and returned for each method invocation.695* Modifications to the returned {@code Set}696* will not affect the internal public Credential {@code Set}.697*698* <p>699*700* @param <T> the type of the class modeled by {@code c}701*702* @param c the returned {@code Set} of public credentials will all be703* instances of this class.704*705* @return a {@code Set} of public credentials that are instances706* of the specified {@code Class}.707*708* @exception NullPointerException if the specified {@code Class}709* is {@code null}.710*/711public <T> Set<T> getPublicCredentials(Class<T> c) {712713if (c == null)714throw new NullPointerException715(ResourcesMgr.getString("invalid.null.Class.provided"));716717// always return an empty Set instead of null718// so LoginModules can add to the Set if necessary719return new ClassSet<T>(PUB_CREDENTIAL_SET, c);720}721722/**723* Return a {@code Set} of private credentials associated with this724* {@code Subject} that are instances or subclasses of the specified725* {@code Class}.726*727* <p> The caller must have permission to access all of the728* requested Credentials, or a {@code SecurityException}729* will be thrown.730*731* <p> The returned {@code Set} is not backed by this Subject's732* internal private Credential {@code Set}. A new733* {@code Set} is created and returned for each method invocation.734* Modifications to the returned {@code Set}735* will not affect the internal private Credential {@code Set}.736*737* <p>738*739* @param <T> the type of the class modeled by {@code c}740*741* @param c the returned {@code Set} of private credentials will all be742* instances of this class.743*744* @return a {@code Set} of private credentials that are instances745* of the specified {@code Class}.746*747* @exception NullPointerException if the specified {@code Class}748* is {@code null}.749*/750public <T> Set<T> getPrivateCredentials(Class<T> c) {751752// XXX753// we do not need a security check for754// AuthPermission(getPrivateCredentials)755// because we already restrict access to private credentials756// via the PrivateCredentialPermission. all the extra AuthPermission757// would do is protect the set operations themselves758// (like size()), which don't seem security-sensitive.759760if (c == null)761throw new NullPointerException762(ResourcesMgr.getString("invalid.null.Class.provided"));763764// always return an empty Set instead of null765// so LoginModules can add to the Set if necessary766return new ClassSet<T>(PRIV_CREDENTIAL_SET, c);767}768769/**770* Compares the specified Object with this {@code Subject}771* for equality. Returns true if the given object is also a Subject772* and the two {@code Subject} instances are equivalent.773* More formally, two {@code Subject} instances are774* equal if their {@code Principal} and {@code Credential}775* Sets are equal.776*777* <p>778*779* @param o Object to be compared for equality with this780* {@code Subject}.781*782* @return true if the specified Object is equal to this783* {@code Subject}.784*785* @exception SecurityException if the caller does not have permission786* to access the private credentials for this {@code Subject},787* or if the caller does not have permission to access the788* private credentials for the provided {@code Subject}.789*/790public boolean equals(Object o) {791792if (o == null)793return false;794795if (this == o)796return true;797798if (o instanceof Subject) {799800final Subject that = (Subject)o;801802// check the principal and credential sets803Set<Principal> thatPrincipals;804synchronized(that.principals) {805// avoid deadlock from dual locks806thatPrincipals = new HashSet<Principal>(that.principals);807}808if (!principals.equals(thatPrincipals)) {809return false;810}811812Set<Object> thatPubCredentials;813synchronized(that.pubCredentials) {814// avoid deadlock from dual locks815thatPubCredentials = new HashSet<Object>(that.pubCredentials);816}817if (!pubCredentials.equals(thatPubCredentials)) {818return false;819}820821Set<Object> thatPrivCredentials;822synchronized(that.privCredentials) {823// avoid deadlock from dual locks824thatPrivCredentials = new HashSet<Object>(that.privCredentials);825}826if (!privCredentials.equals(thatPrivCredentials)) {827return false;828}829return true;830}831return false;832}833834/**835* Return the String representation of this {@code Subject}.836*837* <p>838*839* @return the String representation of this {@code Subject}.840*/841public String toString() {842return toString(true);843}844845/**846* package private convenience method to print out the Subject847* without firing off a security check when trying to access848* the Private Credentials849*/850String toString(boolean includePrivateCredentials) {851852String s = ResourcesMgr.getString("Subject.");853String suffix = "";854855synchronized(principals) {856Iterator<Principal> pI = principals.iterator();857while (pI.hasNext()) {858Principal p = pI.next();859suffix = suffix + ResourcesMgr.getString(".Principal.") +860p.toString() + ResourcesMgr.getString("NEWLINE");861}862}863864synchronized(pubCredentials) {865Iterator<Object> pI = pubCredentials.iterator();866while (pI.hasNext()) {867Object o = pI.next();868suffix = suffix +869ResourcesMgr.getString(".Public.Credential.") +870o.toString() + ResourcesMgr.getString("NEWLINE");871}872}873874if (includePrivateCredentials) {875synchronized(privCredentials) {876Iterator<Object> pI = privCredentials.iterator();877while (pI.hasNext()) {878try {879Object o = pI.next();880suffix += ResourcesMgr.getString881(".Private.Credential.") +882o.toString() +883ResourcesMgr.getString("NEWLINE");884} catch (SecurityException se) {885suffix += ResourcesMgr.getString886(".Private.Credential.inaccessible.");887break;888}889}890}891}892return s + suffix;893}894895/**896* Returns a hashcode for this {@code Subject}.897*898* <p>899*900* @return a hashcode for this {@code Subject}.901*902* @exception SecurityException if the caller does not have permission903* to access this Subject's private credentials.904*/905public int hashCode() {906907/**908* The hashcode is derived exclusive or-ing the909* hashcodes of this Subject's Principals and credentials.910*911* If a particular credential was destroyed912* ({@code credential.hashCode()} throws an913* {@code IllegalStateException}),914* the hashcode for that credential is derived via:915* {@code credential.getClass().toString().hashCode()}.916*/917918int hashCode = 0;919920synchronized(principals) {921Iterator<Principal> pIterator = principals.iterator();922while (pIterator.hasNext()) {923Principal p = pIterator.next();924hashCode ^= p.hashCode();925}926}927928synchronized(pubCredentials) {929Iterator<Object> pubCIterator = pubCredentials.iterator();930while (pubCIterator.hasNext()) {931hashCode ^= getCredHashCode(pubCIterator.next());932}933}934return hashCode;935}936937/**938* get a credential's hashcode939*/940private int getCredHashCode(Object o) {941try {942return o.hashCode();943} catch (IllegalStateException ise) {944return o.getClass().toString().hashCode();945}946}947948/**949* Writes this object out to a stream (i.e., serializes it).950*/951private void writeObject(java.io.ObjectOutputStream oos)952throws java.io.IOException {953synchronized(principals) {954oos.defaultWriteObject();955}956}957958/**959* Reads this object from a stream (i.e., deserializes it)960*/961@SuppressWarnings("unchecked")962private void readObject(java.io.ObjectInputStream s)963throws java.io.IOException, ClassNotFoundException {964965ObjectInputStream.GetField gf = s.readFields();966967readOnly = gf.get("readOnly", false);968969Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null);970971// Rewrap the principals into a SecureSet972if (inputPrincs == null) {973throw new NullPointerException974(ResourcesMgr.getString("invalid.null.input.s."));975}976try {977principals = Collections.synchronizedSet(new SecureSet<Principal>978(this, PRINCIPAL_SET, inputPrincs));979} catch (NullPointerException npe) {980// Sometimes people deserialize the principals set only.981// Subject is not accessible, so just don't fail.982principals = Collections.synchronizedSet983(new SecureSet<Principal>(this, PRINCIPAL_SET));984}985986// The Credential {@code Set} is not serialized, but we do not987// want the default deserialization routine to set it to null.988this.pubCredentials = Collections.synchronizedSet989(new SecureSet<Object>(this, PUB_CREDENTIAL_SET));990this.privCredentials = Collections.synchronizedSet991(new SecureSet<Object>(this, PRIV_CREDENTIAL_SET));992}993994/**995* Prevent modifications unless caller has permission.996*997* @serial include998*/999private static class SecureSet<E>1000extends AbstractSet<E>1001implements java.io.Serializable {10021003private static final long serialVersionUID = 7911754171111800359L;10041005/**1006* @serialField this$0 Subject The outer Subject instance.1007* @serialField elements LinkedList The elements in this set.1008*/1009private static final ObjectStreamField[] serialPersistentFields = {1010new ObjectStreamField("this$0", Subject.class),1011new ObjectStreamField("elements", LinkedList.class),1012new ObjectStreamField("which", int.class)1013};10141015Subject subject;1016LinkedList<E> elements;10171018/**1019* @serial An integer identifying the type of objects contained1020* in this set. If {@code which == 1},1021* this is a Principal set and all the elements are1022* of type {@code java.security.Principal}.1023* If {@code which == 2}, this is a public credential1024* set and all the elements are of type {@code Object}.1025* If {@code which == 3}, this is a private credential1026* set and all the elements are of type {@code Object}.1027*/1028private int which;10291030SecureSet(Subject subject, int which) {1031this.subject = subject;1032this.which = which;1033this.elements = new LinkedList<E>();1034}10351036SecureSet(Subject subject, int which, Set<? extends E> set) {1037this.subject = subject;1038this.which = which;1039this.elements = new LinkedList<E>(set);1040}10411042public int size() {1043return elements.size();1044}10451046public Iterator<E> iterator() {1047final LinkedList<E> list = elements;1048return new Iterator<E>() {1049ListIterator<E> i = list.listIterator(0);10501051public boolean hasNext() {return i.hasNext();}10521053public E next() {1054if (which != Subject.PRIV_CREDENTIAL_SET) {1055return i.next();1056}10571058SecurityManager sm = System.getSecurityManager();1059if (sm != null) {1060try {1061sm.checkPermission(new PrivateCredentialPermission1062(list.get(i.nextIndex()).getClass().getName(),1063subject.getPrincipals()));1064} catch (SecurityException se) {1065i.next();1066throw (se);1067}1068}1069return i.next();1070}10711072public void remove() {10731074if (subject.isReadOnly()) {1075throw new IllegalStateException(ResourcesMgr.getString1076("Subject.is.read.only"));1077}10781079java.lang.SecurityManager sm = System.getSecurityManager();1080if (sm != null) {1081switch (which) {1082case Subject.PRINCIPAL_SET:1083sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);1084break;1085case Subject.PUB_CREDENTIAL_SET:1086sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);1087break;1088default:1089sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);1090break;1091}1092}1093i.remove();1094}1095};1096}10971098public boolean add(E o) {10991100if (subject.isReadOnly()) {1101throw new IllegalStateException1102(ResourcesMgr.getString("Subject.is.read.only"));1103}11041105java.lang.SecurityManager sm = System.getSecurityManager();1106if (sm != null) {1107switch (which) {1108case Subject.PRINCIPAL_SET:1109sm.checkPermission(AuthPermissionHolder.MODIFY_PRINCIPALS_PERMISSION);1110break;1111case Subject.PUB_CREDENTIAL_SET:1112sm.checkPermission(AuthPermissionHolder.MODIFY_PUBLIC_CREDENTIALS_PERMISSION);1113break;1114default:1115sm.checkPermission(AuthPermissionHolder.MODIFY_PRIVATE_CREDENTIALS_PERMISSION);1116break;1117}1118}11191120switch (which) {1121case Subject.PRINCIPAL_SET:1122if (!(o instanceof Principal)) {1123throw new SecurityException(ResourcesMgr.getString1124("attempting.to.add.an.object.which.is.not.an.instance.of.java.security.Principal.to.a.Subject.s.Principal.Set"));1125}1126break;1127default:1128// ok to add Objects of any kind to credential sets1129break;1130}11311132// check for duplicates1133if (!elements.contains(o))1134return elements.add(o);1135else1136return false;1137}11381139public boolean remove(Object o) {11401141final Iterator<E> e = iterator();1142while (e.hasNext()) {1143E next;1144if (which != Subject.PRIV_CREDENTIAL_SET) {1145next = e.next();1146} else {1147next = java.security.AccessController.doPrivileged1148(new java.security.PrivilegedAction<E>() {1149public E run() {1150return e.next();1151}1152});1153}11541155if (next == null) {1156if (o == null) {1157e.remove();1158return true;1159}1160} else if (next.equals(o)) {1161e.remove();1162return true;1163}1164}1165return false;1166}11671168public boolean contains(Object o) {1169final Iterator<E> e = iterator();1170while (e.hasNext()) {1171E next;1172if (which != Subject.PRIV_CREDENTIAL_SET) {1173next = e.next();1174} else {11751176// For private credentials:1177// If the caller does not have read permission for1178// for o.getClass(), we throw a SecurityException.1179// Otherwise we check the private cred set to see whether1180// it contains the Object11811182SecurityManager sm = System.getSecurityManager();1183if (sm != null) {1184sm.checkPermission(new PrivateCredentialPermission1185(o.getClass().getName(),1186subject.getPrincipals()));1187}1188next = java.security.AccessController.doPrivileged1189(new java.security.PrivilegedAction<E>() {1190public E run() {1191return e.next();1192}1193});1194}11951196if (next == null) {1197if (o == null) {1198return true;1199}1200} else if (next.equals(o)) {1201return true;1202}1203}1204return false;1205}12061207public boolean removeAll(Collection<?> c) {1208Objects.requireNonNull(c);1209boolean modified = false;1210final Iterator<E> e = iterator();1211while (e.hasNext()) {1212E next;1213if (which != Subject.PRIV_CREDENTIAL_SET) {1214next = e.next();1215} else {1216next = java.security.AccessController.doPrivileged1217(new java.security.PrivilegedAction<E>() {1218public E run() {1219return e.next();1220}1221});1222}12231224Iterator<?> ce = c.iterator();1225while (ce.hasNext()) {1226Object o = ce.next();1227if (next == null) {1228if (o == null) {1229e.remove();1230modified = true;1231break;1232}1233} else if (next.equals(o)) {1234e.remove();1235modified = true;1236break;1237}1238}1239}1240return modified;1241}12421243public boolean retainAll(Collection<?> c) {1244Objects.requireNonNull(c);1245boolean modified = false;1246boolean retain = false;1247final Iterator<E> e = iterator();1248while (e.hasNext()) {1249retain = false;1250E next;1251if (which != Subject.PRIV_CREDENTIAL_SET) {1252next = e.next();1253} else {1254next = java.security.AccessController.doPrivileged1255(new java.security.PrivilegedAction<E>() {1256public E run() {1257return e.next();1258}1259});1260}12611262Iterator<?> ce = c.iterator();1263while (ce.hasNext()) {1264Object o = ce.next();1265if (next == null) {1266if (o == null) {1267retain = true;1268break;1269}1270} else if (next.equals(o)) {1271retain = true;1272break;1273}1274}12751276if (!retain) {1277e.remove();1278retain = false;1279modified = true;1280}1281}1282return modified;1283}12841285public void clear() {1286final Iterator<E> e = iterator();1287while (e.hasNext()) {1288E next;1289if (which != Subject.PRIV_CREDENTIAL_SET) {1290next = e.next();1291} else {1292next = java.security.AccessController.doPrivileged1293(new java.security.PrivilegedAction<E>() {1294public E run() {1295return e.next();1296}1297});1298}1299e.remove();1300}1301}13021303/**1304* Writes this object out to a stream (i.e., serializes it).1305*1306* <p>1307*1308* @serialData If this is a private credential set,1309* a security check is performed to ensure that1310* the caller has permission to access each credential1311* in the set. If the security check passes,1312* the set is serialized.1313*/1314private void writeObject(java.io.ObjectOutputStream oos)1315throws java.io.IOException {13161317if (which == Subject.PRIV_CREDENTIAL_SET) {1318// check permissions before serializing1319Iterator<E> i = iterator();1320while (i.hasNext()) {1321i.next();1322}1323}1324ObjectOutputStream.PutField fields = oos.putFields();1325fields.put("this$0", subject);1326fields.put("elements", elements);1327fields.put("which", which);1328oos.writeFields();1329}13301331@SuppressWarnings("unchecked")1332private void readObject(ObjectInputStream ois)1333throws IOException, ClassNotFoundException1334{1335ObjectInputStream.GetField fields = ois.readFields();1336subject = (Subject) fields.get("this$0", null);1337which = fields.get("which", 0);13381339LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null);1340if (tmp.getClass() != LinkedList.class) {1341elements = new LinkedList<E>(tmp);1342} else {1343elements = tmp;1344}1345}1346}13471348/**1349* This class implements a {@code Set} which returns only1350* members that are an instance of a specified Class.1351*/1352private class ClassSet<T> extends AbstractSet<T> {13531354private int which;1355private Class<T> c;1356private Set<T> set;13571358ClassSet(int which, Class<T> c) {1359this.which = which;1360this.c = c;1361set = new HashSet<T>();13621363switch (which) {1364case Subject.PRINCIPAL_SET:1365synchronized(principals) { populateSet(); }1366break;1367case Subject.PUB_CREDENTIAL_SET:1368synchronized(pubCredentials) { populateSet(); }1369break;1370default:1371synchronized(privCredentials) { populateSet(); }1372break;1373}1374}13751376@SuppressWarnings("unchecked") /*To suppress warning from line 1374*/1377private void populateSet() {1378final Iterator<?> iterator;1379switch(which) {1380case Subject.PRINCIPAL_SET:1381iterator = Subject.this.principals.iterator();1382break;1383case Subject.PUB_CREDENTIAL_SET:1384iterator = Subject.this.pubCredentials.iterator();1385break;1386default:1387iterator = Subject.this.privCredentials.iterator();1388break;1389}13901391// Check whether the caller has permisson to get1392// credentials of Class c13931394while (iterator.hasNext()) {1395Object next;1396if (which == Subject.PRIV_CREDENTIAL_SET) {1397next = java.security.AccessController.doPrivileged1398(new java.security.PrivilegedAction<Object>() {1399public Object run() {1400return iterator.next();1401}1402});1403} else {1404next = iterator.next();1405}1406if (c.isAssignableFrom(next.getClass())) {1407if (which != Subject.PRIV_CREDENTIAL_SET) {1408set.add((T)next);1409} else {1410// Check permission for private creds1411SecurityManager sm = System.getSecurityManager();1412if (sm != null) {1413sm.checkPermission(new PrivateCredentialPermission1414(next.getClass().getName(),1415Subject.this.getPrincipals()));1416}1417set.add((T)next);1418}1419}1420}1421}14221423public int size() {1424return set.size();1425}14261427public Iterator<T> iterator() {1428return set.iterator();1429}14301431public boolean add(T o) {14321433if (!o.getClass().isAssignableFrom(c)) {1434MessageFormat form = new MessageFormat(ResourcesMgr.getString1435("attempting.to.add.an.object.which.is.not.an.instance.of.class"));1436Object[] source = {c.toString()};1437throw new SecurityException(form.format(source));1438}14391440return set.add(o);1441}1442}14431444static class AuthPermissionHolder {1445static final AuthPermission DO_AS_PERMISSION =1446new AuthPermission("doAs");14471448static final AuthPermission DO_AS_PRIVILEGED_PERMISSION =1449new AuthPermission("doAsPrivileged");14501451static final AuthPermission SET_READ_ONLY_PERMISSION =1452new AuthPermission("setReadOnly");14531454static final AuthPermission GET_SUBJECT_PERMISSION =1455new AuthPermission("getSubject");14561457static final AuthPermission MODIFY_PRINCIPALS_PERMISSION =1458new AuthPermission("modifyPrincipals");14591460static final AuthPermission MODIFY_PUBLIC_CREDENTIALS_PERMISSION =1461new AuthPermission("modifyPublicCredentials");14621463static final AuthPermission MODIFY_PRIVATE_CREDENTIALS_PERMISSION =1464new AuthPermission("modifyPrivateCredentials");1465}1466}146714681469