0N/A/*
2362N/A * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.jgss;
0N/A
0N/Aimport org.ietf.jgss.*;
0N/Aimport sun.security.jgss.spi.*;
0N/Aimport java.util.*;
0N/A
0N/Apublic class GSSCredentialImpl implements GSSCredential {
0N/A
0N/A private GSSManagerImpl gssManager = null;
0N/A private boolean destroyed = false;
0N/A
0N/A /*
0N/A * We store all elements in a hashtable, using <oid, usage> as the
0N/A * key. This makes it easy to locate the specific kind of credential we
0N/A * need. The implementation needs to be optimized for the case where
0N/A * there is just one element (tempCred).
0N/A */
0N/A private Hashtable<SearchKey, GSSCredentialSpi> hashtable = null;
0N/A
0N/A // XXX Optimization for single mech usage
0N/A private GSSCredentialSpi tempCred = null;
0N/A
0N/A GSSCredentialImpl(GSSManagerImpl gssManager, int usage)
0N/A throws GSSException {
0N/A this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,
0N/A (Oid[]) null, usage);
0N/A }
0N/A
0N/A GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
0N/A int lifetime, Oid mech, int usage)
0N/A throws GSSException {
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A init(gssManager);
0N/A add(name, lifetime, lifetime, mech, usage);
0N/A }
0N/A
0N/A GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
0N/A int lifetime, Oid mechs[], int usage)
0N/A throws GSSException {
0N/A init(gssManager);
0N/A boolean defaultList = false;
0N/A if (mechs == null) {
0N/A mechs = gssManager.getMechs();
0N/A defaultList = true;
0N/A }
0N/A
0N/A for (int i = 0; i < mechs.length; i++) {
0N/A try {
0N/A add(name, lifetime, lifetime, mechs[i], usage);
0N/A } catch (GSSException e) {
0N/A if (defaultList) {
0N/A // Try the next mechanism
0N/A GSSUtil.debug("Ignore " + e + " while acquring cred for "
0N/A + mechs[i]);
0N/A //e.printStackTrace();
0N/A } else throw e; // else try the next mechanism
0N/A }
0N/A }
0N/A if ((hashtable.size() == 0) || (usage != getUsage()))
0N/A throw new GSSException(GSSException.NO_CRED);
0N/A }
0N/A
0N/A public GSSCredentialImpl(GSSManagerImpl gssManager,
0N/A GSSCredentialSpi mechElement) throws GSSException {
0N/A
0N/A init(gssManager);
0N/A int usage = GSSCredential.ACCEPT_ONLY;
0N/A if (mechElement.isInitiatorCredential()) {
0N/A if (mechElement.isAcceptorCredential()) {
0N/A usage = GSSCredential.INITIATE_AND_ACCEPT;
0N/A } else {
0N/A usage = GSSCredential.INITIATE_ONLY;
0N/A }
0N/A }
0N/A SearchKey key = new SearchKey(mechElement.getMechanism(),
0N/A usage);
0N/A tempCred = mechElement;
0N/A hashtable.put(key, tempCred);
0N/A }
0N/A
0N/A void init(GSSManagerImpl gssManager) {
0N/A this.gssManager = gssManager;
0N/A hashtable = new Hashtable<SearchKey, GSSCredentialSpi>(
0N/A gssManager.getMechs().length);
0N/A }
0N/A
0N/A public void dispose() throws GSSException {
0N/A if (!destroyed) {
0N/A GSSCredentialSpi element;
0N/A Enumeration<GSSCredentialSpi> values = hashtable.elements();
0N/A while (values.hasMoreElements()) {
0N/A element = values.nextElement();
0N/A element.dispose();
0N/A }
0N/A destroyed = true;
0N/A }
0N/A }
0N/A
0N/A public GSSName getName() throws GSSException {
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A return GSSNameImpl.wrapElement(gssManager, tempCred.getName());
0N/A }
0N/A
0N/A public GSSName getName(Oid mech) throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A SearchKey key = null;
0N/A GSSCredentialSpi element = null;
0N/A
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element == null) {
0N/A key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
0N/A element = hashtable.get(key);
0N/A }
0N/A
0N/A if (element == null) {
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A }
0N/A
0N/A if (element == null) {
0N/A throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
0N/A }
0N/A
0N/A return GSSNameImpl.wrapElement(gssManager, element.getName());
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Returns the remaining lifetime of this credential. The remaining
0N/A * lifetime is defined as the minimum lifetime, either for initiate or
0N/A * for accept, across all elements contained in it. Not terribly
0N/A * useful, but required by GSS-API.
0N/A */
0N/A public int getRemainingLifetime() throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A SearchKey tempKey;
0N/A GSSCredentialSpi tempCred;
0N/A int tempLife = 0, tempInitLife = 0, tempAcceptLife = 0;
0N/A int min = INDEFINITE_LIFETIME;
0N/A
0N/A for (Enumeration<SearchKey> e = hashtable.keys();
0N/A e.hasMoreElements(); ) {
0N/A tempKey = e.nextElement();
0N/A tempCred = hashtable.get(tempKey);
0N/A if (tempKey.getUsage() == INITIATE_ONLY)
0N/A tempLife = tempCred.getInitLifetime();
0N/A else if (tempKey.getUsage() == ACCEPT_ONLY)
0N/A tempLife = tempCred.getAcceptLifetime();
0N/A else {
0N/A tempInitLife = tempCred.getInitLifetime();
0N/A tempAcceptLife = tempCred.getAcceptLifetime();
0N/A tempLife = (tempInitLife < tempAcceptLife ?
0N/A tempInitLife:
0N/A tempAcceptLife);
0N/A }
0N/A if (min > tempLife)
0N/A min = tempLife;
0N/A }
0N/A
0N/A return min;
0N/A }
0N/A
0N/A public int getRemainingInitLifetime(Oid mech) throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A GSSCredentialSpi element = null;
0N/A SearchKey key = null;
0N/A boolean found = false;
0N/A int max = 0;
0N/A
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A found = true;
0N/A if (max < element.getInitLifetime())
0N/A max = element.getInitLifetime();
0N/A }
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A found = true;
0N/A if (max < element.getInitLifetime())
0N/A max = element.getInitLifetime();
0N/A }
0N/A
0N/A if (!found) {
0N/A throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
0N/A }
0N/A
0N/A return max;
0N/A
0N/A }
0N/A
0N/A public int getRemainingAcceptLifetime(Oid mech) throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A GSSCredentialSpi element = null;
0N/A SearchKey key = null;
0N/A boolean found = false;
0N/A int max = 0;
0N/A
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A found = true;
0N/A if (max < element.getAcceptLifetime())
0N/A max = element.getAcceptLifetime();
0N/A }
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A found = true;
0N/A if (max < element.getAcceptLifetime())
0N/A max = element.getAcceptLifetime();
0N/A }
0N/A
0N/A if (!found) {
0N/A throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
0N/A }
0N/A
0N/A return max;
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Returns the usage mode for this credential. Returns
0N/A * INITIATE_AND_ACCEPT if any one element contained in it supports
0N/A * INITIATE_AND_ACCEPT or if two different elements exist where one
0N/A * support INITIATE_ONLY and the other supports ACCEPT_ONLY.
0N/A */
0N/A public int getUsage() throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A SearchKey tempKey;
0N/A boolean initiate = false;
0N/A boolean accept = false;
0N/A
0N/A for (Enumeration<SearchKey> e = hashtable.keys();
0N/A e.hasMoreElements(); ) {
0N/A tempKey = e.nextElement();
0N/A if (tempKey.getUsage() == INITIATE_ONLY)
0N/A initiate = true;
0N/A else if (tempKey.getUsage() == ACCEPT_ONLY)
0N/A accept = true;
0N/A else
0N/A return INITIATE_AND_ACCEPT;
0N/A }
0N/A if (initiate) {
0N/A if (accept)
0N/A return INITIATE_AND_ACCEPT;
0N/A else
0N/A return INITIATE_ONLY;
0N/A } else
0N/A return ACCEPT_ONLY;
0N/A }
0N/A
0N/A public int getUsage(Oid mech) throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A GSSCredentialSpi element = null;
0N/A SearchKey key = null;
0N/A boolean initiate = false;
0N/A boolean accept = false;
0N/A
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A initiate = true;
0N/A }
0N/A
0N/A key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A accept = true;
0N/A }
0N/A
0N/A key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A
0N/A if (element != null) {
0N/A initiate = true;
0N/A accept = true;
0N/A }
0N/A
0N/A if (initiate && accept)
0N/A return GSSCredential.INITIATE_AND_ACCEPT;
0N/A else if (initiate)
0N/A return GSSCredential.INITIATE_ONLY;
0N/A else if (accept)
0N/A return GSSCredential.ACCEPT_ONLY;
0N/A else {
0N/A throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
0N/A }
0N/A }
0N/A
0N/A public Oid[] getMechs() throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A Vector<Oid> result = new Vector<Oid>(hashtable.size());
0N/A
0N/A for (Enumeration<SearchKey> e = hashtable.keys();
0N/A e.hasMoreElements(); ) {
0N/A SearchKey tempKey = e.nextElement();
0N/A result.addElement(tempKey.getMech());
0N/A }
0N/A return result.toArray(new Oid[0]);
0N/A }
0N/A
0N/A public void add(GSSName name, int initLifetime, int acceptLifetime,
0N/A Oid mech, int usage) throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
0N/A
0N/A SearchKey key = new SearchKey(mech, usage);
0N/A if (hashtable.containsKey(key)) {
0N/A throw new GSSExceptionImpl(GSSException.DUPLICATE_ELEMENT,
0N/A "Duplicate element found: " +
0N/A getElementStr(mech, usage));
0N/A }
0N/A
0N/A // XXX If not instance of GSSNameImpl then throw exception
0N/A // Application mixing GSS implementations
0N/A GSSNameSpi nameElement = (name == null ? null :
0N/A ((GSSNameImpl)name).getElement(mech));
0N/A
0N/A tempCred = gssManager.getCredentialElement(nameElement,
0N/A initLifetime,
0N/A acceptLifetime,
0N/A mech,
0N/A usage);
0N/A /*
0N/A * Not all mechanisms support the concept of one credential element
0N/A * that can be used for both initiating and accepting a context. In
0N/A * the event that an application requests usage INITIATE_AND_ACCEPT
0N/A * for a credential from such a mechanism, the GSS framework will
0N/A * need to obtain two different credential elements from the
0N/A * mechanism, one that will have usage INITIATE_ONLY and another
0N/A * that will have usage ACCEPT_ONLY. The mechanism will help the
0N/A * GSS-API realize this by returning a credential element with
0N/A * usage INITIATE_ONLY or ACCEPT_ONLY prompting it to make another
0N/A * call to getCredentialElement, this time with the other usage
0N/A * mode.
0N/A */
0N/A
0N/A if (tempCred != null) {
0N/A if (usage == GSSCredential.INITIATE_AND_ACCEPT &&
0N/A (!tempCred.isAcceptorCredential() ||
0N/A !tempCred.isInitiatorCredential())) {
0N/A
0N/A int currentUsage;
0N/A int desiredUsage;
0N/A
0N/A if (!tempCred.isInitiatorCredential()) {
0N/A currentUsage = GSSCredential.ACCEPT_ONLY;
0N/A desiredUsage = GSSCredential.INITIATE_ONLY;
0N/A } else {
0N/A currentUsage = GSSCredential.INITIATE_ONLY;
0N/A desiredUsage = GSSCredential.ACCEPT_ONLY;
0N/A }
0N/A
0N/A key = new SearchKey(mech, currentUsage);
0N/A hashtable.put(key, tempCred);
0N/A
0N/A tempCred = gssManager.getCredentialElement(nameElement,
0N/A initLifetime,
0N/A acceptLifetime,
0N/A mech,
0N/A desiredUsage);
0N/A
0N/A key = new SearchKey(mech, desiredUsage);
0N/A hashtable.put(key, tempCred);
0N/A } else {
0N/A hashtable.put(key, tempCred);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public boolean equals(Object another) {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A if (this == another) {
0N/A return true;
0N/A }
0N/A
0N/A if (!(another instanceof GSSCredentialImpl)) {
0N/A return false;
0N/A }
0N/A
0N/A // NOTE: The specification does not define the criteria to compare
0N/A // credentials.
0N/A /*
0N/A * XXX
0N/A * The RFC says: "Tests if this GSSCredential refers to the same
0N/A * entity as the supplied object. The two credentials must be
0N/A * acquired over the same mechanisms and must refer to the same
0N/A * principal. Returns "true" if the two GSSCredentials refer to
0N/A * the same entity; "false" otherwise."
0N/A *
0N/A * Well, when do two credentials refer to the same principal? Do
0N/A * they need to have one GSSName in common for the different
0N/A * GSSName's that the credential elements return? Or do all
0N/A * GSSName's have to be in common when the names are exported with
0N/A * their respective mechanisms for the credential elements?
0N/A */
0N/A return false;
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Returns a hashcode value for this GSSCredential.
0N/A *
0N/A * @return a hashCode value
0N/A */
0N/A public int hashCode() {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A // NOTE: The specification does not define the criteria to compare
0N/A // credentials.
0N/A /*
0N/A * XXX
0N/A * Decide on a criteria for equals first then do this.
0N/A */
0N/A return 1;
0N/A }
0N/A
0N/A /**
0N/A * Returns the specified mechanism's credential-element.
0N/A *
0N/A * @param mechOid - the oid for mechanism to retrieve
0N/A * @param throwExcep - boolean indicating if the function is
0N/A * to throw exception or return null when element is not
0N/A * found.
0N/A * @return mechanism credential object
0N/A * @exception GSSException of invalid mechanism
0N/A */
0N/A public GSSCredentialSpi getElement(Oid mechOid, boolean initiate)
0N/A throws GSSException {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A SearchKey key;
0N/A GSSCredentialSpi element;
0N/A
0N/A if (mechOid == null) {
0N/A /*
0N/A * First see if the default mechanism satisfies the
0N/A * desired usage.
0N/A */
0N/A mechOid = ProviderList.DEFAULT_MECH_OID;
0N/A key = new SearchKey(mechOid,
0N/A initiate? INITIATE_ONLY : ACCEPT_ONLY);
0N/A element = hashtable.get(key);
0N/A if (element == null) {
0N/A key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A if (element == null) {
0N/A /*
0N/A * Now just return any element that satisfies the
0N/A * desired usage.
0N/A */
0N/A Object[] elements = hashtable.entrySet().toArray();
0N/A for (int i = 0; i < elements.length; i++) {
0N/A element = (GSSCredentialSpi)
0N/A ((Map.Entry)elements[i]).getValue();
0N/A if (element.isInitiatorCredential() == initiate)
0N/A break;
0N/A } // for loop
0N/A }
0N/A }
0N/A } else {
0N/A
0N/A if (initiate)
0N/A key = new SearchKey(mechOid, INITIATE_ONLY);
0N/A else
0N/A key = new SearchKey(mechOid, ACCEPT_ONLY);
0N/A
0N/A element = hashtable.get(key);
0N/A
0N/A if (element == null) {
0N/A key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
0N/A element = hashtable.get(key);
0N/A }
0N/A }
0N/A
0N/A if (element == null)
0N/A throw new GSSExceptionImpl(GSSException.NO_CRED,
0N/A "No credential found for: " +
0N/A mechOid + getElementStr(mechOid,
0N/A initiate? INITIATE_ONLY : ACCEPT_ONLY));
0N/A return element;
0N/A }
0N/A
0N/A Set<GSSCredentialSpi> getElements() {
0N/A HashSet<GSSCredentialSpi> retVal =
0N/A new HashSet<GSSCredentialSpi>(hashtable.size());
0N/A Enumeration<GSSCredentialSpi> values = hashtable.elements();
0N/A while (values.hasMoreElements()) {
0N/A GSSCredentialSpi o = values.nextElement();
0N/A retVal.add(o);
0N/A }
0N/A return retVal;
0N/A }
0N/A
0N/A private static String getElementStr(Oid mechOid, int usage) {
0N/A String displayString = mechOid.toString();
0N/A if (usage == GSSCredential.INITIATE_ONLY) {
0N/A displayString =
0N/A displayString.concat(" usage: Initiate");
0N/A } else if (usage == GSSCredential.ACCEPT_ONLY) {
0N/A displayString =
0N/A displayString.concat(" usage: Accept");
0N/A } else {
0N/A displayString =
0N/A displayString.concat(" usage: Initiate and Accept");
0N/A }
0N/A return displayString;
0N/A }
0N/A
0N/A public String toString() {
0N/A
0N/A if (destroyed) {
0N/A throw new IllegalStateException("This credential is " +
0N/A "no longer valid");
0N/A }
0N/A
0N/A GSSCredentialSpi element = null;
0N/A StringBuffer buffer = new StringBuffer("[GSSCredential: ");
0N/A Object[] elements = hashtable.entrySet().toArray();
0N/A for (int i = 0; i < elements.length; i++) {
0N/A try {
0N/A buffer.append('\n');
0N/A element = (GSSCredentialSpi)
0N/A ((Map.Entry)elements[i]).getValue();
0N/A buffer.append(element.getName());
0N/A buffer.append(' ');
0N/A buffer.append(element.getMechanism());
0N/A buffer.append(element.isInitiatorCredential() ?
0N/A " Initiate" : "");
0N/A buffer.append(element.isAcceptorCredential() ?
0N/A " Accept" : "");
0N/A buffer.append(" [");
0N/A buffer.append(element.toString());
0N/A buffer.append(']');
0N/A } catch (GSSException e) {
0N/A // skip to next element
0N/A }
0N/A }
0N/A buffer.append(']');
0N/A return buffer.toString();
0N/A }
0N/A
0N/A static class SearchKey {
0N/A private Oid mechOid = null;
0N/A private int usage = GSSCredential.INITIATE_AND_ACCEPT;
0N/A public SearchKey(Oid mechOid, int usage) {
0N/A
0N/A this.mechOid = mechOid;
0N/A this.usage = usage;
0N/A }
0N/A public Oid getMech() {
0N/A return mechOid;
0N/A }
0N/A public int getUsage() {
0N/A return usage;
0N/A }
0N/A public boolean equals(Object other) {
0N/A if (! (other instanceof SearchKey))
0N/A return false;
0N/A SearchKey that = (SearchKey) other;
0N/A return ((this.mechOid.equals(that.mechOid)) &&
0N/A (this.usage == that.usage));
0N/A }
0N/A public int hashCode() {
0N/A return mechOid.hashCode();
0N/A }
0N/A }
0N/A
0N/A}