/*
 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.jgss;

import com.sun.security.auth.callback.TextCallbackHandler;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey;
import org.ietf.jgss.*;
import sun.security.jgss.spi.GSSNameSpi;
import sun.security.jgss.spi.GSSCredentialSpi;
import sun.security.action.GetPropertyAction;
import sun.security.jgss.krb5.Krb5NameElement;
import sun.security.jgss.spnego.SpNegoCredElement;
import java.util.Set;
import java.util.HashSet;
import java.util.Vector;
import java.util.Iterator;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import sun.security.action.GetBooleanAction;

The GSSUtilImplementation that knows how to work with the internals of the GSS-API.
/** * The GSSUtilImplementation that knows how to work with the internals of * the GSS-API. */
public class GSSUtil { public static final Oid GSS_KRB5_MECH_OID = GSSUtil.createOid("1.2.840.113554.1.2.2"); public static final Oid GSS_KRB5_MECH_OID2 = GSSUtil.createOid("1.3.5.1.5.2"); public static final Oid GSS_KRB5_MECH_OID_MS = GSSUtil.createOid("1.2.840.48018.1.2.2"); public static final Oid GSS_SPNEGO_MECH_OID = GSSUtil.createOid("1.3.6.1.5.5.2"); public static final Oid NT_GSS_KRB5_PRINCIPAL = GSSUtil.createOid("1.2.840.113554.1.2.2.1"); private static final String DEFAULT_HANDLER = "auth.login.defaultCallbackHandler"; static final boolean DEBUG; static { DEBUG = (AccessController.doPrivileged (new GetBooleanAction("sun.security.jgss.debug"))). booleanValue(); } static void debug(String message) { if (DEBUG) { assert(message != null); System.out.println(message); } } // NOTE: this method is only for creating Oid objects with // known to be valid <code>oidStr</code> given it ignores // the GSSException public static Oid createOid(String oidStr) { try { return new Oid(oidStr); } catch (GSSException e) { debug("Ignored invalid OID: " + oidStr); return null; } } public static boolean isSpNegoMech(Oid oid) { return (GSS_SPNEGO_MECH_OID.equals(oid)); } public static boolean isKerberosMech(Oid oid) { return (GSS_KRB5_MECH_OID.equals(oid) || GSS_KRB5_MECH_OID2.equals(oid) || GSS_KRB5_MECH_OID_MS.equals(oid)); } public static String getMechStr(Oid oid) { if (isSpNegoMech(oid)) { return "SPNEGO"; } else if (isKerberosMech(oid)) { return "Kerberos V5"; } else { return oid.toString(); } }
Note: The current impl only works with Sun's impl of GSSName and GSSCredential since it depends on package private APIs.
/** * Note: The current impl only works with Sun's impl of * GSSName and GSSCredential since it depends on package * private APIs. */
public static Subject getSubject(GSSName name, GSSCredential creds) { HashSet<Object> privCredentials = null; HashSet<Object> pubCredentials = new HashSet<Object>(); // empty Set Set<GSSCredentialSpi> gssCredentials = null; Set<KerberosPrincipal> krb5Principals = new HashSet<KerberosPrincipal>(); if (name instanceof GSSNameImpl) { try { GSSNameSpi ne = ((GSSNameImpl) name).getElement (GSS_KRB5_MECH_OID); String krbName = ne.toString(); if (ne instanceof Krb5NameElement) { krbName = ((Krb5NameElement) ne).getKrb5PrincipalName().getName(); } KerberosPrincipal krbPrinc = new KerberosPrincipal(krbName); krb5Principals.add(krbPrinc); } catch (GSSException ge) { debug("Skipped name " + name + " due to " + ge); } } if (creds instanceof GSSCredentialImpl) { gssCredentials = ((GSSCredentialImpl) creds).getElements(); privCredentials = new HashSet<Object>(gssCredentials.size()); populateCredentials(privCredentials, gssCredentials); } else { privCredentials = new HashSet<Object>(); // empty Set } debug("Created Subject with the following"); debug("principals=" + krb5Principals); debug("public creds=" + pubCredentials); debug("private creds=" + privCredentials); return new Subject(false, krb5Principals, pubCredentials, privCredentials); }
Populates the set credentials with elements from gssCredentials. At the same time, it converts any subclasses of KerberosTicket into KerberosTicket instances and any subclasses of KerberosKey into KerberosKey instances. (It is not desirable to expose the customer to sun.security.jgss.krb5.Krb5InitCredential which extends KerberosTicket and sun.security.jgss.krb5.Kbr5AcceptCredential which extends KerberosKey.)
/** * Populates the set credentials with elements from gssCredentials. At * the same time, it converts any subclasses of KerberosTicket * into KerberosTicket instances and any subclasses of KerberosKey into * KerberosKey instances. (It is not desirable to expose the customer * to sun.security.jgss.krb5.Krb5InitCredential which extends * KerberosTicket and sun.security.jgss.krb5.Kbr5AcceptCredential which * extends KerberosKey.) */
private static void populateCredentials(Set<Object> credentials, Set<?> gssCredentials) { Object cred; Iterator<?> elements = gssCredentials.iterator(); while (elements.hasNext()) { cred = elements.next(); // Retrieve the internal cred out of SpNegoCredElement if (cred instanceof SpNegoCredElement) { cred = ((SpNegoCredElement) cred).getInternalCred(); } if (cred instanceof KerberosTicket) { if (!cred.getClass().getName().equals ("javax.security.auth.kerberos.KerberosTicket")) { KerberosTicket tempTkt = (KerberosTicket) cred; cred = new KerberosTicket(tempTkt.getEncoded(), tempTkt.getClient(), tempTkt.getServer(), tempTkt.getSessionKey().getEncoded(), tempTkt.getSessionKeyType(), tempTkt.getFlags(), tempTkt.getAuthTime(), tempTkt.getStartTime(), tempTkt.getEndTime(), tempTkt.getRenewTill(), tempTkt.getClientAddresses()); } credentials.add(cred); } else if (cred instanceof KerberosKey) { if (!cred.getClass().getName().equals ("javax.security.auth.kerberos.KerberosKey")) { KerberosKey tempKey = (KerberosKey) cred; cred = new KerberosKey(tempKey.getPrincipal(), tempKey.getEncoded(), tempKey.getKeyType(), tempKey.getVersionNumber()); } credentials.add(cred); } else { // Ignore non-KerberosTicket and non-KerberosKey elements debug("Skipped cred element: " + cred); } } }
Authenticate using the login module from the specified configuration entry.
Params:
  • caller – the caller of JAAS Login
  • mech – the mech to be used
Returns:the authenticated subject
/** * Authenticate using the login module from the specified * configuration entry. * * @param caller the caller of JAAS Login * @param mech the mech to be used * @return the authenticated subject */
public static Subject login(GSSCaller caller, Oid mech) throws LoginException { CallbackHandler cb = null; if (caller instanceof HttpCaller) { cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler( ((HttpCaller)caller).info()); } else { String defaultHandler = java.security.Security.getProperty(DEFAULT_HANDLER); // get the default callback handler if ((defaultHandler != null) && (defaultHandler.length() != 0)) { cb = null; } else { cb = new TextCallbackHandler(); } } // New instance of LoginConfigImpl must be created for each login, // since the entry name is not passed as the first argument, but // generated with caller and mech inside LoginConfigImpl LoginContext lc = new LoginContext("", null, cb, new LoginConfigImpl(caller, mech)); lc.login(); return lc.getSubject(); }
Determines if the application doesn't mind if the mechanism obtains the required credentials from outside of the current Subject. Our Kerberos v5 mechanism would do a JAAS login on behalf of the application if this were the case. The application indicates this by explicitly setting the system property javax.security.auth.useSubjectCredsOnly to false.
/** * Determines if the application doesn't mind if the mechanism obtains * the required credentials from outside of the current Subject. Our * Kerberos v5 mechanism would do a JAAS login on behalf of the * application if this were the case. * * The application indicates this by explicitly setting the system * property javax.security.auth.useSubjectCredsOnly to false. */
public static boolean useSubjectCredsOnly(GSSCaller caller) { String propValue = GetPropertyAction.privilegedGetProperty( "javax.security.auth.useSubjectCredsOnly"); // Invalid values should be ignored and the default assumed. if (caller instanceof HttpCaller) { // Default for HTTP/SPNEGO is false. return "true".equalsIgnoreCase(propValue); } else { // Default for JGSS is true. return !("false".equalsIgnoreCase(propValue)); } }
Determines the SPNEGO interoperability mode with Microsoft; by default it is set to true. To disable it, the application indicates this by explicitly setting the system property sun.security.spnego.interop to false.
/** * Determines the SPNEGO interoperability mode with Microsoft; * by default it is set to true. * * To disable it, the application indicates this by explicitly setting * the system property sun.security.spnego.interop to false. */
public static boolean useMSInterop() { /* * Don't use GetBooleanAction because the default value in the JRE * (when this is unset) has to treated as true. */ String propValue = AccessController.doPrivileged( new GetPropertyAction("sun.security.spnego.msinterop", "true")); /* * This property has to be explicitly set to "false". Invalid * values should be ignored and the default "true" assumed. */ return (!propValue.equalsIgnoreCase("false")); }
Searches the private credentials of current Subject with the specified criteria and returns the matching GSSCredentialSpi object out of Sun's impl of GSSCredential. Returns null if no Subject present or a Vector which contains 0 or more matching GSSCredentialSpi objects.
/** * Searches the private credentials of current Subject with the * specified criteria and returns the matching GSSCredentialSpi * object out of Sun's impl of GSSCredential. Returns null if * no Subject present or a Vector which contains 0 or more * matching GSSCredentialSpi objects. */
public static <T extends GSSCredentialSpi> Vector<T> searchSubject(final GSSNameSpi name, final Oid mech, final boolean initiate, final Class<? extends T> credCls) { debug("Search Subject for " + getMechStr(mech) + (initiate? " INIT" : " ACCEPT") + " cred (" + (name == null? "<<DEF>>" : name.toString()) + ", " + credCls.getName() + ")"); final AccessControlContext acc = AccessController.getContext(); try { Vector<T> creds = AccessController.doPrivileged (new PrivilegedExceptionAction<Vector<T>>() { public Vector<T> run() throws Exception { Subject accSubj = Subject.getSubject(acc); Vector<T> result = null; if (accSubj != null) { result = new Vector<T>(); Iterator<GSSCredentialImpl> iterator = accSubj.getPrivateCredentials (GSSCredentialImpl.class).iterator(); while (iterator.hasNext()) { GSSCredentialImpl cred = iterator.next(); debug("...Found cred" + cred); try { GSSCredentialSpi ce = cred.getElement(mech, initiate); debug("......Found element: " + ce); if (ce.getClass().equals(credCls) && (name == null || name.equals((Object) ce.getName()))) { result.add(credCls.cast(ce)); } else { debug("......Discard element"); } } catch (GSSException ge) { debug("...Discard cred (" + ge + ")"); } } } else debug("No Subject"); return result; } }); return creds; } catch (PrivilegedActionException pae) { debug("Unexpected exception when searching Subject:"); if (DEBUG) pae.printStackTrace(); return null; } } }