Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/GSSUtil.java
41159 views
/*1* Copyright (c) 2000, 2021, 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 javax.security.auth.Subject;28import javax.security.auth.kerberos.KerberosPrincipal;29import javax.security.auth.kerberos.KerberosTicket;30import javax.security.auth.kerberos.KerberosKey;31import org.ietf.jgss.*;32import sun.security.jgss.spi.GSSNameSpi;33import sun.security.jgss.spi.GSSCredentialSpi;34import sun.security.action.GetPropertyAction;35import sun.security.jgss.krb5.Krb5NameElement;36import sun.security.jgss.spnego.SpNegoCredElement;37import java.util.Set;38import java.util.HashSet;39import java.util.Vector;40import java.util.Iterator;41import java.security.AccessController;42import java.security.AccessControlContext;43import java.security.PrivilegedExceptionAction;44import java.security.PrivilegedActionException;45import javax.security.auth.callback.CallbackHandler;46import javax.security.auth.login.LoginContext;47import javax.security.auth.login.LoginException;48import sun.security.action.GetBooleanAction;49import sun.security.util.ConsoleCallbackHandler;5051/**52* The GSSUtilImplementation that knows how to work with the internals of53* the GSS-API.54*/55public class GSSUtil {5657public static final Oid GSS_KRB5_MECH_OID =58GSSUtil.createOid("1.2.840.113554.1.2.2");59public static final Oid GSS_KRB5_MECH_OID2 =60GSSUtil.createOid("1.3.5.1.5.2");61public static final Oid GSS_KRB5_MECH_OID_MS =62GSSUtil.createOid("1.2.840.48018.1.2.2");6364public static final Oid GSS_SPNEGO_MECH_OID =65GSSUtil.createOid("1.3.6.1.5.5.2");6667public static final Oid NT_GSS_KRB5_PRINCIPAL =68GSSUtil.createOid("1.2.840.113554.1.2.2.1");6970static final boolean DEBUG =71GetBooleanAction.privilegedGetProperty("sun.security.jgss.debug");7273static void debug(String message) {74if (DEBUG) {75assert(message != null);76System.out.println(message);77}78}7980// NOTE: this method is only for creating Oid objects with81// known to be valid <code>oidStr</code> given it ignores82// the GSSException83public static Oid createOid(String oidStr) {84try {85return new Oid(oidStr);86} catch (GSSException e) {87debug("Ignored invalid OID: " + oidStr);88return null;89}90}9192public static boolean isSpNegoMech(Oid oid) {93return (GSS_SPNEGO_MECH_OID.equals(oid));94}9596public static boolean isKerberosMech(Oid oid) {97return (GSS_KRB5_MECH_OID.equals(oid) ||98GSS_KRB5_MECH_OID2.equals(oid) ||99GSS_KRB5_MECH_OID_MS.equals(oid));100101}102103public static String getMechStr(Oid oid) {104if (isSpNegoMech(oid)) {105return "SPNEGO";106} else if (isKerberosMech(oid)) {107return "Kerberos V5";108} else {109return oid.toString();110}111}112113/**114* Note: The current impl only works with Sun's impl of115* GSSName and GSSCredential since it depends on package116* private APIs.117*/118public static Subject getSubject(GSSName name,119GSSCredential creds) {120121HashSet<Object> privCredentials = null;122HashSet<Object> pubCredentials = new HashSet<Object>(); // empty Set123124Set<GSSCredentialSpi> gssCredentials = null;125126Set<KerberosPrincipal> krb5Principals =127new HashSet<KerberosPrincipal>();128129if (name instanceof GSSNameImpl) {130try {131GSSNameSpi ne = ((GSSNameImpl) name).getElement132(GSS_KRB5_MECH_OID);133String krbName = ne.toString();134if (ne instanceof Krb5NameElement) {135krbName =136((Krb5NameElement) ne).getKrb5PrincipalName().getName();137}138KerberosPrincipal krbPrinc = new KerberosPrincipal(krbName);139krb5Principals.add(krbPrinc);140} catch (GSSException ge) {141debug("Skipped name " + name + " due to " + ge);142}143}144145if (creds instanceof GSSCredentialImpl) {146gssCredentials = ((GSSCredentialImpl) creds).getElements();147privCredentials = new HashSet<Object>(gssCredentials.size());148populateCredentials(privCredentials, gssCredentials);149} else {150privCredentials = new HashSet<Object>(); // empty Set151}152debug("Created Subject with the following");153debug("principals=" + krb5Principals);154debug("public creds=" + pubCredentials);155debug("private creds=" + privCredentials);156157return new Subject(false, krb5Principals, pubCredentials,158privCredentials);159160}161162/**163* Populates the set credentials with elements from gssCredentials. At164* the same time, it converts any subclasses of KerberosTicket165* into KerberosTicket instances and any subclasses of KerberosKey into166* KerberosKey instances. (It is not desirable to expose the customer167* to sun.security.jgss.krb5.Krb5InitCredential which extends168* KerberosTicket and sun.security.jgss.krb5.Kbr5AcceptCredential which169* extends KerberosKey.)170*/171private static void populateCredentials(Set<Object> credentials,172Set<?> gssCredentials) {173174Object cred;175176Iterator<?> elements = gssCredentials.iterator();177while (elements.hasNext()) {178179cred = elements.next();180181// Retrieve the internal cred out of SpNegoCredElement182if (cred instanceof SpNegoCredElement) {183cred = ((SpNegoCredElement) cred).getInternalCred();184}185186if (cred instanceof KerberosTicket) {187if (!cred.getClass().getName().equals188("javax.security.auth.kerberos.KerberosTicket")) {189KerberosTicket tempTkt = (KerberosTicket) cred;190cred = new KerberosTicket(tempTkt.getEncoded(),191tempTkt.getClient(),192tempTkt.getServer(),193tempTkt.getSessionKey().getEncoded(),194tempTkt.getSessionKeyType(),195tempTkt.getFlags(),196tempTkt.getAuthTime(),197tempTkt.getStartTime(),198tempTkt.getEndTime(),199tempTkt.getRenewTill(),200tempTkt.getClientAddresses());201}202credentials.add(cred);203} else if (cred instanceof KerberosKey) {204if (!cred.getClass().getName().equals205("javax.security.auth.kerberos.KerberosKey")) {206KerberosKey tempKey = (KerberosKey) cred;207cred = new KerberosKey(tempKey.getPrincipal(),208tempKey.getEncoded(),209tempKey.getKeyType(),210tempKey.getVersionNumber());211}212credentials.add(cred);213} else {214// Ignore non-KerberosTicket and non-KerberosKey elements215debug("Skipped cred element: " + cred);216}217}218}219220/**221* Authenticate using the login module from the specified222* configuration entry.223*224* @param caller the caller of JAAS Login225* @param mech the mech to be used226* @return the authenticated subject227*/228public static Subject login(GSSCaller caller, Oid mech) throws LoginException {229230CallbackHandler cb = null;231if (caller instanceof HttpCaller) {232cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler(233((HttpCaller)caller).info());234} else {235String defaultHandler = java.security.Security236.getProperty("auth.login.defaultCallbackHandler");237// get the default callback handler238if ((defaultHandler != null) && (defaultHandler.length() != 0)) {239cb = null;240} else {241cb = new ConsoleCallbackHandler();242}243}244245// New instance of LoginConfigImpl must be created for each login,246// since the entry name is not passed as the first argument, but247// generated with caller and mech inside LoginConfigImpl248LoginContext lc = new LoginContext("", null, cb,249new LoginConfigImpl(caller, mech));250lc.login();251return lc.getSubject();252}253254/**255* Determines if the application doesn't mind if the mechanism obtains256* the required credentials from outside of the current Subject. Our257* Kerberos v5 mechanism would do a JAAS login on behalf of the258* application if this were the case.259*260* The application indicates this by explicitly setting the system261* property javax.security.auth.useSubjectCredsOnly to false.262*/263public static boolean useSubjectCredsOnly(GSSCaller caller) {264265String propValue = GetPropertyAction266.privilegedGetProperty("javax.security.auth.useSubjectCredsOnly");267268// Invalid values should be ignored and the default assumed.269if (caller instanceof HttpCaller) {270// Default for HTTP/SPNEGO is false.271return "true".equalsIgnoreCase(propValue);272} else {273// Default for JGSS is true.274return !("false".equalsIgnoreCase(propValue));275}276}277278/**279* Determines the SPNEGO interoperability mode with Microsoft;280* by default it is set to true.281*282* To disable it, the application indicates this by explicitly setting283* the system property sun.security.spnego.interop to false.284*/285public static boolean useMSInterop() {286/*287* Don't use GetBooleanAction because the default value in the JRE288* (when this is unset) has to treated as true.289*/290String propValue = GetPropertyAction291.privilegedGetProperty("sun.security.spnego.msinterop", "true");292/*293* This property has to be explicitly set to "false". Invalid294* values should be ignored and the default "true" assumed.295*/296return (!propValue.equalsIgnoreCase("false"));297}298299/**300* Searches the private credentials of current Subject with the301* specified criteria and returns the matching GSSCredentialSpi302* object out of Sun's impl of GSSCredential. Returns null if303* no Subject present or a Vector which contains 0 or more304* matching GSSCredentialSpi objects.305*/306public static <T extends GSSCredentialSpi> Vector<T>307searchSubject(final GSSNameSpi name,308final Oid mech,309final boolean initiate,310final Class<? extends T> credCls) {311debug("Search Subject for " + getMechStr(mech) +312(initiate? " INIT" : " ACCEPT") + " cred (" +313(name == null? "<<DEF>>" : name.toString()) + ", " +314credCls.getName() + ")");315@SuppressWarnings("removal")316final AccessControlContext acc = AccessController.getContext();317try {318@SuppressWarnings("removal")319Vector<T> creds =320AccessController.doPrivileged321(new PrivilegedExceptionAction<Vector<T>>() {322public Vector<T> run() throws Exception {323Subject accSubj = Subject.getSubject(acc);324Vector<T> result = null;325if (accSubj != null) {326result = new Vector<T>();327Iterator<GSSCredentialImpl> iterator =328accSubj.getPrivateCredentials329(GSSCredentialImpl.class).iterator();330while (iterator.hasNext()) {331GSSCredentialImpl cred = iterator.next();332debug("...Found cred" + cred);333try {334GSSCredentialSpi ce =335cred.getElement(mech, initiate);336debug("......Found element: " + ce);337if (ce.getClass().equals(credCls) &&338(name == null ||339name.equals((Object) ce.getName()))) {340result.add(credCls.cast(ce));341} else {342debug("......Discard element");343}344} catch (GSSException ge) {345debug("...Discard cred (" + ge + ")");346}347}348} else debug("No Subject");349return result;350}351});352return creds;353} catch (PrivilegedActionException pae) {354debug("Unexpected exception when searching Subject:");355if (DEBUG) pae.printStackTrace();356return null;357}358}359}360361362