-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8279842: HTTPS Channel Binding support for Java GSS/Kerberos #7065
Changes from 1 commit
f6d273a
853ed4d
f2ee58e
fd56b5e
c9975fd
058c383
daf2fe0
ad80dfa
0d529f9
004466e
e5a5a79
b44184d
d604ee7
af3d28b
59f703d
468e534
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -214,6 +214,19 @@ <H2>Misc HTTP URL stream protocol handler properties</H2> | |
property is defined, then its value will be used as the domain | ||
name.</P> | ||
</OL> | ||
<LI><P><B>{@systemProperty jdk.https.negotiate.cbt}</B> (default: <never>)<BR> | ||
This controls the generation and sending of TLS channel binding tokens (CBT) when Kerberos | ||
or the Negotiate authentication scheme using Kerberos are employed over HTTPS with | ||
{@code HttpURLConnection}. There are three possible settings:</P> | ||
<OL> | ||
<LI><P>"never". This is also the default value if the property is not set. In this case, | ||
CBT's are never sent.</P> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo, "CBTs"? |
||
<LI><P>"always". CBTs are sent for all Kerberos authentication attempts over HTTPS.</P> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we remove "Kerberos"? Or we can use "Kerberos or Negotiate". |
||
<LI><P>"domain:<comma separated domain list>" Each domain in the list specifies destination | ||
host or hosts for which a CBT is sent. Domains can be single hosts like foo, or foo.com, | ||
or wildcards like *.foo.com which matches all hosts under foo.com and its sub-domains. | ||
CBTs are not sent to any destinations that don't match one of the list entries</P> | ||
</OL> | ||
</UL> | ||
<P>All these properties are checked only once at startup.</P> | ||
<a id="AddressCache"></a> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,7 +144,7 @@ private static int getDefaultPort(String proto) { | |
// Traffic capture tool, if configured. See HttpCapture class for info | ||
private HttpCapture capture = null; | ||
|
||
/* "jdk.spnego.cbt" property can be set to "always" (always sent), "never" (never sent) or | ||
/* "jdk.https.negotiate.cbt" property can be set to "always" (always sent), "never" (never sent) or | ||
* "domain:a,c.d,*.e.f" (sent to host a, or c.d or to the domain e.f and any of its subdomains). This is | ||
* a comma separated list of arbitrary length with no white-space allowed. | ||
* If enabled (for a particular destination) then SPNEGO authentication requests will include | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Negotiate" is the name of the HTTP authentication scheme which uses the SPNEGO mechanism. Possibly makes more sense to refer to Negotiate here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I know. That's the point. Clearly differentiate between GSS-API mech and HTTP auth scheme. |
||
|
@@ -160,6 +160,11 @@ private static void logFinest(String msg) { | |
logger.finest(msg); | ||
} | ||
} | ||
private static void logError(String msg) { | ||
if (logger.isLoggable(PlatformLogger.Level.SEVERE)) { | ||
logger.severe(msg); | ||
} | ||
} | ||
|
||
protected volatile String authenticatorKey; | ||
|
||
|
@@ -180,6 +185,7 @@ static String normalizeCBT(String s) { | |
s.equals("never") || s.startsWith("domain:"))) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess there's a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what was intended (equivalent)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Argh - you're right I missed the fact that the 3 expressions where included in parenthesis. I read it as
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we log a message if the value is not one of the 3 forms? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually malformed values are just ignored - and the property takes its default value. But yes - s.n.w.h.HttpClient has a logger so it wouldn't be much effort to log it as a DEBUG trace for better diagnostic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I will log it using the same debug/logging mechanism already in the same source file.. |
||
return "never"; | ||
} else { | ||
logError("Unexpected value for \"jdk.https.negotiate.cbt\" system property"); | ||
return s; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this return either "always" or "never" instead? It seems that junk values will be treated as "always". It would be better to make it clear here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was being handled elsewhere as "never". But, I agree it would be clearer to normalise it to "never" here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I should have checked back to the source rather than the snippet quoted. The problem is that the logError call is in the wrong place. It should be before line 186. Though some other adjustments are also required There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah! Yes - I was also bitten again by the negation in the |
||
} | ||
} | ||
|
@@ -191,7 +197,7 @@ static String normalizeCBT(String s) { | |
String cacheNTLM = props.getProperty("jdk.ntlm.cache"); | ||
String cacheSPNEGO = props.getProperty("jdk.spnego.cache"); | ||
|
||
String s = props.getProperty("jdk.spnego.cbt"); | ||
String s = props.getProperty("jdk.https.negotiate.cbt"); | ||
spnegoCBT = normalizeCBT(s); | ||
|
||
if (keepAlive != null) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (c) 2022, 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.util; | ||
|
||
/** | ||
* Thrown by TlsChannelBinding if an error occurs | ||
*/ | ||
public class ChannelBindingException extends Exception { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this extend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a distinct exception is necessary. I don't have a strong opinion on whether it should extend GeneralSecurityException. |
||
|
||
@java.io.Serial | ||
private static final long serialVersionUID = -5021387249782788460L; | ||
|
||
/** | ||
* Constructs a ChannelBindingException with no detail message. A detail | ||
* message is a String that describes this particular exception. | ||
*/ | ||
public ChannelBindingException() { | ||
super(); | ||
} | ||
|
||
/** | ||
* Constructs a ChannelBindingException with a detail message and | ||
* specified cause. | ||
*/ | ||
public ChannelBindingException(String msg, Exception e) { | ||
super(msg, e); | ||
} | ||
|
||
/** | ||
* Constructs a ChannelBindingException with a detail message | ||
*/ | ||
public ChannelBindingException(String msg) { | ||
super(msg); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,9 @@ | |
import com.sun.jndi.ldap.Connection; | ||
import com.sun.jndi.ldap.LdapClient; | ||
import com.sun.jndi.ldap.LdapResult; | ||
import com.sun.jndi.ldap.sasl.TlsChannelBinding.TlsChannelBindingType; | ||
import sun.security.util.ChannelBindingException; | ||
import sun.security.util.TlsChannelBinding; | ||
import sun.security.util.TlsChannelBinding.TlsChannelBindingType; | ||
|
||
/** | ||
* Handles SASL support. | ||
|
@@ -123,15 +125,23 @@ public static LdapResult saslBind(LdapClient clnt, Connection conn, | |
try { | ||
// Prepare TLS Channel Binding data | ||
if (conn.isTlsConnection()) { | ||
TlsChannelBindingType cbType = | ||
TlsChannelBinding.parseType( | ||
TlsChannelBindingType cbType; | ||
try { | ||
cbType = TlsChannelBinding.parseType( | ||
(String)env.get(TlsChannelBinding.CHANNEL_BINDING_TYPE)); | ||
} catch (ChannelBindingException e) { | ||
throw new SaslException(e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about setting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. |
||
} | ||
if (cbType == TlsChannelBindingType.TLS_SERVER_END_POINT) { | ||
// set tls-server-end-point channel binding | ||
X509Certificate cert = conn.getTlsServerCertificate(); | ||
if (cert != null) { | ||
TlsChannelBinding tlsCB = | ||
TlsChannelBinding.create(cert); | ||
TlsChannelBinding tlsCB; | ||
try { | ||
tlsCB = TlsChannelBinding.create(cert); | ||
} catch (ChannelBindingException e) { | ||
throw new SaslException(e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is there a difference compared to line 133? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, that was a mistake. |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we call initCause here and above? I see that we do call initCause in NegotiatorImpl.java. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As long as the spec has not dictated what the cause should be, I don't care if the exception type is internal or not. |
||
envProps = (Hashtable<String, Object>) env.clone(); | ||
envProps.put(TlsChannelBinding.CHANNEL_BINDING, tlsCB.getData()); | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,6 @@ | |
|
||
import java.io.IOException; | ||
import java.security.cert.Certificate; | ||
import javax.security.sasl.SaslException; | ||
|
||
import org.ietf.jgss.GSSContext; | ||
import org.ietf.jgss.GSSException; | ||
|
@@ -43,7 +42,8 @@ | |
import sun.security.jgss.GSSUtil; | ||
import sun.security.jgss.HttpCaller; | ||
import sun.security.jgss.krb5.internal.TlsChannelBindingImpl; | ||
import com.sun.jndi.ldap.sasl.TlsChannelBinding; | ||
import sun.security.util.ChannelBindingException; | ||
import sun.security.util.TlsChannelBinding; | ||
|
||
/** | ||
* This class encapsulates all JAAS and JGSS API calls in a separate class | ||
|
@@ -69,7 +69,7 @@ public class NegotiatorImpl extends Negotiator { | |
* <li>Creating GSSContext | ||
* <li>A first call to initSecContext</ul> | ||
*/ | ||
private void init(HttpCallerInfo hci) throws GSSException, SaslException { | ||
private void init(HttpCallerInfo hci) throws GSSException, ChannelBindingException { | ||
final Oid oid; | ||
|
||
if (hci.scheme.equalsIgnoreCase("Kerberos")) { | ||
|
@@ -122,7 +122,7 @@ private void init(HttpCallerInfo hci) throws GSSException, SaslException { | |
public NegotiatorImpl(HttpCallerInfo hci) throws IOException { | ||
try { | ||
init(hci); | ||
} catch (GSSException | SaslException e) { | ||
} catch (GSSException | ChannelBindingException e) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two spaces before "e". |
||
if (DEBUG) { | ||
System.out.println("Negotiate support not initiated, will " + | ||
"fallback to other scheme if allowed. Reason:"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be
{@code HttpsURLConnection}
?(BTW - can we use {@code } here ? Would be worth checking the generated doc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right HttpsURLConnection is better. {@code} works here.