Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/GSSCredentialImpl.java
38830 views
/*1* Copyright (c) 2000, 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 sun.security.jgss;2627import org.ietf.jgss.*;28import sun.security.jgss.spi.*;29import java.util.*;30import com.sun.security.jgss.*;31import sun.security.jgss.spnego.SpNegoCredElement;3233public class GSSCredentialImpl implements ExtendedGSSCredential {3435private GSSManagerImpl gssManager = null;36private boolean destroyed = false;3738/*39* We store all elements in a hashtable, using <oid, usage> as the40* key. This makes it easy to locate the specific kind of credential we41* need. The implementation needs to be optimized for the case where42* there is just one element (tempCred).43*/44private Hashtable<SearchKey, GSSCredentialSpi> hashtable = null;4546// XXX Optimization for single mech usage47private GSSCredentialSpi tempCred = null;4849GSSCredentialImpl(GSSManagerImpl gssManager, int usage)50throws GSSException {51this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,52(Oid[]) null, usage);53}5455GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,56int lifetime, Oid mech, int usage)57throws GSSException {58if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;5960init(gssManager);61add(name, lifetime, lifetime, mech, usage);62}6364GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,65int lifetime, Oid mechs[], int usage)66throws GSSException {67init(gssManager);68boolean defaultList = false;69if (mechs == null) {70mechs = gssManager.getMechs();71defaultList = true;72}7374for (int i = 0; i < mechs.length; i++) {75try {76add(name, lifetime, lifetime, mechs[i], usage);77} catch (GSSException e) {78if (defaultList) {79// Try the next mechanism80GSSUtil.debug("Ignore " + e + " while acquring cred for "81+ mechs[i]);82//e.printStackTrace();83} else throw e; // else try the next mechanism84}85}86if ((hashtable.size() == 0) || (usage != getUsage()))87throw new GSSException(GSSException.NO_CRED);88}8990// Wrap a mech cred into a GSS cred91public GSSCredentialImpl(GSSManagerImpl gssManager,92GSSCredentialSpi mechElement) throws GSSException {9394init(gssManager);95int usage = GSSCredential.ACCEPT_ONLY;96if (mechElement.isInitiatorCredential()) {97if (mechElement.isAcceptorCredential()) {98usage = GSSCredential.INITIATE_AND_ACCEPT;99} else {100usage = GSSCredential.INITIATE_ONLY;101}102}103SearchKey key = new SearchKey(mechElement.getMechanism(),104usage);105tempCred = mechElement;106hashtable.put(key, tempCred);107// More mechs that can use this cred, say, SPNEGO108if (!GSSUtil.isSpNegoMech(mechElement.getMechanism())) {109key = new SearchKey(GSSUtil.GSS_SPNEGO_MECH_OID, usage);110hashtable.put(key, new SpNegoCredElement(mechElement));111}112}113114void init(GSSManagerImpl gssManager) {115this.gssManager = gssManager;116hashtable = new Hashtable<SearchKey, GSSCredentialSpi>(117gssManager.getMechs().length);118}119120public void dispose() throws GSSException {121if (!destroyed) {122GSSCredentialSpi element;123Enumeration<GSSCredentialSpi> values = hashtable.elements();124while (values.hasMoreElements()) {125element = values.nextElement();126element.dispose();127}128destroyed = true;129}130}131132public GSSCredential impersonate(GSSName name) throws GSSException {133if (destroyed) {134throw new IllegalStateException("This credential is " +135"no longer valid");136}137Oid mech = tempCred.getMechanism();138GSSNameSpi nameElement = (name == null ? null :139((GSSNameImpl)name).getElement(mech));140GSSCredentialSpi cred = tempCred.impersonate(nameElement);141return (cred == null ?142null : new GSSCredentialImpl(gssManager, cred));143}144145public GSSName getName() throws GSSException {146if (destroyed) {147throw new IllegalStateException("This credential is " +148"no longer valid");149}150return GSSNameImpl.wrapElement(gssManager, tempCred.getName());151}152153public GSSName getName(Oid mech) throws GSSException {154155if (destroyed) {156throw new IllegalStateException("This credential is " +157"no longer valid");158}159160SearchKey key = null;161GSSCredentialSpi element = null;162163if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;164165key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);166element = hashtable.get(key);167168if (element == null) {169key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);170element = hashtable.get(key);171}172173if (element == null) {174key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);175element = hashtable.get(key);176}177178if (element == null) {179throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);180}181182return GSSNameImpl.wrapElement(gssManager, element.getName());183184}185186/**187* Returns the remaining lifetime of this credential. The remaining188* lifetime is defined as the minimum lifetime, either for initiate or189* for accept, across all elements contained in it. Not terribly190* useful, but required by GSS-API.191*/192public int getRemainingLifetime() throws GSSException {193194if (destroyed) {195throw new IllegalStateException("This credential is " +196"no longer valid");197}198199SearchKey tempKey;200GSSCredentialSpi tempCred;201int tempLife = 0, tempInitLife = 0, tempAcceptLife = 0;202int min = INDEFINITE_LIFETIME;203204for (Enumeration<SearchKey> e = hashtable.keys();205e.hasMoreElements(); ) {206tempKey = e.nextElement();207tempCred = hashtable.get(tempKey);208if (tempKey.getUsage() == INITIATE_ONLY)209tempLife = tempCred.getInitLifetime();210else if (tempKey.getUsage() == ACCEPT_ONLY)211tempLife = tempCred.getAcceptLifetime();212else {213tempInitLife = tempCred.getInitLifetime();214tempAcceptLife = tempCred.getAcceptLifetime();215tempLife = (tempInitLife < tempAcceptLife ?216tempInitLife:217tempAcceptLife);218}219if (min > tempLife)220min = tempLife;221}222223return min;224}225226public int getRemainingInitLifetime(Oid mech) throws GSSException {227228if (destroyed) {229throw new IllegalStateException("This credential is " +230"no longer valid");231}232233GSSCredentialSpi element = null;234SearchKey key = null;235boolean found = false;236int max = 0;237238if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;239240key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);241element = hashtable.get(key);242243if (element != null) {244found = true;245if (max < element.getInitLifetime())246max = element.getInitLifetime();247}248249key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);250element = hashtable.get(key);251252if (element != null) {253found = true;254if (max < element.getInitLifetime())255max = element.getInitLifetime();256}257258if (!found) {259throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);260}261262return max;263264}265266public int getRemainingAcceptLifetime(Oid mech) throws GSSException {267268if (destroyed) {269throw new IllegalStateException("This credential is " +270"no longer valid");271}272273GSSCredentialSpi element = null;274SearchKey key = null;275boolean found = false;276int max = 0;277278if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;279280key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);281element = hashtable.get(key);282283if (element != null) {284found = true;285if (max < element.getAcceptLifetime())286max = element.getAcceptLifetime();287}288289key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);290element = hashtable.get(key);291292if (element != null) {293found = true;294if (max < element.getAcceptLifetime())295max = element.getAcceptLifetime();296}297298if (!found) {299throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);300}301302return max;303304}305306/**307* Returns the usage mode for this credential. Returns308* INITIATE_AND_ACCEPT if any one element contained in it supports309* INITIATE_AND_ACCEPT or if two different elements exist where one310* support INITIATE_ONLY and the other supports ACCEPT_ONLY.311*/312public int getUsage() throws GSSException {313314if (destroyed) {315throw new IllegalStateException("This credential is " +316"no longer valid");317}318319SearchKey tempKey;320boolean initiate = false;321boolean accept = false;322323for (Enumeration<SearchKey> e = hashtable.keys();324e.hasMoreElements(); ) {325tempKey = e.nextElement();326if (tempKey.getUsage() == INITIATE_ONLY)327initiate = true;328else if (tempKey.getUsage() == ACCEPT_ONLY)329accept = true;330else331return INITIATE_AND_ACCEPT;332}333if (initiate) {334if (accept)335return INITIATE_AND_ACCEPT;336else337return INITIATE_ONLY;338} else339return ACCEPT_ONLY;340}341342public int getUsage(Oid mech) throws GSSException {343344if (destroyed) {345throw new IllegalStateException("This credential is " +346"no longer valid");347}348349GSSCredentialSpi element = null;350SearchKey key = null;351boolean initiate = false;352boolean accept = false;353354if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;355356key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);357element = hashtable.get(key);358359if (element != null) {360initiate = true;361}362363key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);364element = hashtable.get(key);365366if (element != null) {367accept = true;368}369370key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);371element = hashtable.get(key);372373if (element != null) {374initiate = true;375accept = true;376}377378if (initiate && accept)379return GSSCredential.INITIATE_AND_ACCEPT;380else if (initiate)381return GSSCredential.INITIATE_ONLY;382else if (accept)383return GSSCredential.ACCEPT_ONLY;384else {385throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);386}387}388389public Oid[] getMechs() throws GSSException {390391if (destroyed) {392throw new IllegalStateException("This credential is " +393"no longer valid");394}395Vector<Oid> result = new Vector<Oid>(hashtable.size());396397for (Enumeration<SearchKey> e = hashtable.keys();398e.hasMoreElements(); ) {399SearchKey tempKey = e.nextElement();400result.addElement(tempKey.getMech());401}402return result.toArray(new Oid[0]);403}404405public void add(GSSName name, int initLifetime, int acceptLifetime,406Oid mech, int usage) throws GSSException {407408if (destroyed) {409throw new IllegalStateException("This credential is " +410"no longer valid");411}412if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;413414SearchKey key = new SearchKey(mech, usage);415if (hashtable.containsKey(key)) {416throw new GSSExceptionImpl(GSSException.DUPLICATE_ELEMENT,417"Duplicate element found: " +418getElementStr(mech, usage));419}420421// XXX If not instance of GSSNameImpl then throw exception422// Application mixing GSS implementations423GSSNameSpi nameElement = (name == null ? null :424((GSSNameImpl)name).getElement(mech));425426tempCred = gssManager.getCredentialElement(nameElement,427initLifetime,428acceptLifetime,429mech,430usage);431/*432* Not all mechanisms support the concept of one credential element433* that can be used for both initiating and accepting a context. In434* the event that an application requests usage INITIATE_AND_ACCEPT435* for a credential from such a mechanism, the GSS framework will436* need to obtain two different credential elements from the437* mechanism, one that will have usage INITIATE_ONLY and another438* that will have usage ACCEPT_ONLY. The mechanism will help the439* GSS-API realize this by returning a credential element with440* usage INITIATE_ONLY or ACCEPT_ONLY prompting it to make another441* call to getCredentialElement, this time with the other usage442* mode.443*/444445if (tempCred != null) {446if (usage == GSSCredential.INITIATE_AND_ACCEPT &&447(!tempCred.isAcceptorCredential() ||448!tempCred.isInitiatorCredential())) {449450int currentUsage;451int desiredUsage;452453if (!tempCred.isInitiatorCredential()) {454currentUsage = GSSCredential.ACCEPT_ONLY;455desiredUsage = GSSCredential.INITIATE_ONLY;456} else {457currentUsage = GSSCredential.INITIATE_ONLY;458desiredUsage = GSSCredential.ACCEPT_ONLY;459}460461key = new SearchKey(mech, currentUsage);462hashtable.put(key, tempCred);463464tempCred = gssManager.getCredentialElement(nameElement,465initLifetime,466acceptLifetime,467mech,468desiredUsage);469470key = new SearchKey(mech, desiredUsage);471hashtable.put(key, tempCred);472} else {473hashtable.put(key, tempCred);474}475}476}477478public boolean equals(Object another) {479480if (destroyed) {481throw new IllegalStateException("This credential is " +482"no longer valid");483}484485if (this == another) {486return true;487}488489if (!(another instanceof GSSCredentialImpl)) {490return false;491}492493// NOTE: The specification does not define the criteria to compare494// credentials.495/*496* XXX497* The RFC says: "Tests if this GSSCredential refers to the same498* entity as the supplied object. The two credentials must be499* acquired over the same mechanisms and must refer to the same500* principal. Returns "true" if the two GSSCredentials refer to501* the same entity; "false" otherwise."502*503* Well, when do two credentials refer to the same principal? Do504* they need to have one GSSName in common for the different505* GSSName's that the credential elements return? Or do all506* GSSName's have to be in common when the names are exported with507* their respective mechanisms for the credential elements?508*/509return false;510511}512513/**514* Returns a hashcode value for this GSSCredential.515*516* @return a hashCode value517*/518public int hashCode() {519520if (destroyed) {521throw new IllegalStateException("This credential is " +522"no longer valid");523}524525// NOTE: The specification does not define the criteria to compare526// credentials.527/*528* XXX529* Decide on a criteria for equals first then do this.530*/531return 1;532}533534/**535* Returns the specified mechanism's credential-element.536*537* @param mechOid the oid for mechanism to retrieve538* @param initiate boolean indicating if the function is539* to throw exception or return null when element is not540* found.541* @return mechanism credential object542* @exception GSSException of invalid mechanism543*/544public GSSCredentialSpi getElement(Oid mechOid, boolean initiate)545throws GSSException {546547if (destroyed) {548throw new IllegalStateException("This credential is " +549"no longer valid");550}551552SearchKey key;553GSSCredentialSpi element;554555if (mechOid == null) {556/*557* First see if the default mechanism satisfies the558* desired usage.559*/560mechOid = ProviderList.DEFAULT_MECH_OID;561key = new SearchKey(mechOid,562initiate? INITIATE_ONLY : ACCEPT_ONLY);563element = hashtable.get(key);564if (element == null) {565key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);566element = hashtable.get(key);567if (element == null) {568/*569* Now just return any element that satisfies the570* desired usage.571*/572Object[] elements = hashtable.entrySet().toArray();573for (int i = 0; i < elements.length; i++) {574element = (GSSCredentialSpi)575((Map.Entry)elements[i]).getValue();576if (element.isInitiatorCredential() == initiate)577break;578} // for loop579}580}581} else {582583if (initiate)584key = new SearchKey(mechOid, INITIATE_ONLY);585else586key = new SearchKey(mechOid, ACCEPT_ONLY);587588element = hashtable.get(key);589590if (element == null) {591key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);592element = hashtable.get(key);593}594}595596if (element == null)597throw new GSSExceptionImpl(GSSException.NO_CRED,598"No credential found for: " +599getElementStr(mechOid,600initiate? INITIATE_ONLY : ACCEPT_ONLY));601return element;602}603604Set<GSSCredentialSpi> getElements() {605HashSet<GSSCredentialSpi> retVal =606new HashSet<GSSCredentialSpi>(hashtable.size());607Enumeration<GSSCredentialSpi> values = hashtable.elements();608while (values.hasMoreElements()) {609GSSCredentialSpi o = values.nextElement();610retVal.add(o);611}612return retVal;613}614615private static String getElementStr(Oid mechOid, int usage) {616String displayString = mechOid.toString();617if (usage == GSSCredential.INITIATE_ONLY) {618displayString =619displayString.concat(" usage: Initiate");620} else if (usage == GSSCredential.ACCEPT_ONLY) {621displayString =622displayString.concat(" usage: Accept");623} else {624displayString =625displayString.concat(" usage: Initiate and Accept");626}627return displayString;628}629630public String toString() {631632if (destroyed) {633throw new IllegalStateException("This credential is " +634"no longer valid");635}636637GSSCredentialSpi element = null;638StringBuffer buffer = new StringBuffer("[GSSCredential: ");639Object[] elements = hashtable.entrySet().toArray();640for (int i = 0; i < elements.length; i++) {641try {642buffer.append('\n');643element = (GSSCredentialSpi)644((Map.Entry)elements[i]).getValue();645buffer.append(element.getName());646buffer.append(' ');647buffer.append(element.getMechanism());648buffer.append(element.isInitiatorCredential() ?649" Initiate" : "");650buffer.append(element.isAcceptorCredential() ?651" Accept" : "");652buffer.append(" [");653buffer.append(element.getClass());654buffer.append(']');655} catch (GSSException e) {656// skip to next element657}658}659buffer.append(']');660return buffer.toString();661}662663static class SearchKey {664private Oid mechOid = null;665private int usage = GSSCredential.INITIATE_AND_ACCEPT;666public SearchKey(Oid mechOid, int usage) {667668this.mechOid = mechOid;669this.usage = usage;670}671public Oid getMech() {672return mechOid;673}674public int getUsage() {675return usage;676}677public boolean equals(Object other) {678if (! (other instanceof SearchKey))679return false;680SearchKey that = (SearchKey) other;681return ((this.mechOid.equals(that.mechOid)) &&682(this.usage == that.usage));683}684public int hashCode() {685return mechOid.hashCode();686}687}688689}690691692