369 lines · 14.8 KB · Java
RawDownload
/* * Copyright (c) 2000, 2010, 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. */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_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));     }     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.     */    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.)     */    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.     *     * @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.     */    public static boolean useSubjectCredsOnly(GSSCaller caller) {         // HTTP/SPNEGO doesn't use the standard JAAS framework. Instead, it        // uses the java.net.Authenticator style, therefore always return        // false here.        if (caller instanceof HttpCaller) {            return false;        }        /*         * 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("javax.security.auth.useSubjectCredsOnly",                "true"));        /*         * This property has to be explicitly set to "false". Invalid         * values should be ignored and the default "true" assumed.         */        return (!propValue.equalsIgnoreCase("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.     */    public static Vector searchSubject(final GSSNameSpi name,                                       final Oid mech,                                       final boolean initiate,                                       final Class 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 creds =                AccessController.doPrivileged                (new PrivilegedExceptionAction<Vector>() {                    public Vector run() throws Exception {                        Subject accSubj = Subject.getSubject(acc);                        Vector<GSSCredentialSpi> result = null;                        if (accSubj != null) {                            result = new Vector<GSSCredentialSpi>();                            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(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;        }    }}