/* * 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; } }}
/*
* 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;
}
}
}