7150092: NTLM authentication fail if user specified a different realm
Reviewed-by: michaelm
--- a/jdk/src/share/classes/com/sun/security/ntlm/Client.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java Wed Jul 09 15:10:42 2014 +0800
@@ -46,7 +46,7 @@
final private String hostname;
final private String username;
- private String domain; // might be updated by Type 2 msg
+ private String domain;
private byte[] pw1, pw2;
/**
@@ -82,7 +82,7 @@
}
this.hostname = hostname;
this.username = username;
- this.domain = domain;
+ this.domain = domain == null ? "" : domain;
this.pw1 = getP1(password);
this.pw2 = getP2(password);
debug("NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n",
@@ -95,19 +95,13 @@
*/
public byte[] type1() {
Writer p = new Writer(1, 32);
- int flags = 0x8203;
- if (hostname != null) {
- flags |= 0x2000;
- }
- if (domain != null) {
- flags |= 0x1000;
- }
+ // Negotiate always sign, Negotiate NTLM,
+ // Request Target, Negotiate OEM, Negotiate unicode
+ int flags = 0x8207;
if (v != Version.NTLM) {
flags |= 0x80000;
}
p.writeInt(12, flags);
- p.writeSecurityBuffer(24, hostname, false);
- p.writeSecurityBuffer(16, domain, false);
debug("NTLM Client: Type 1 created\n");
debug(p.getBytes());
return p.getBytes();
@@ -133,13 +127,10 @@
byte[] challenge = r.readBytes(24, 8);
int inputFlags = r.readInt(20);
boolean unicode = (inputFlags & 1) == 1;
- String domainFromServer = r.readSecurityBuffer(12, unicode);
- if (domainFromServer != null) {
- domain = domainFromServer;
- }
- if (domain == null) {
- domain = "";
- }
+
+ // IE uses domainFromServer to generate an alist if server has not
+ // provided one. Firefox/WebKit do not. Neither do we.
+ //String domainFromServer = r.readSecurityBuffer(12, unicode);
int flags = 0x88200 | (inputFlags & 3);
Writer p = new Writer(3, 64);
@@ -163,7 +154,9 @@
if (writeLM) lm = calcV2(nthash,
username.toUpperCase(Locale.US)+domain, nonce, challenge);
if (writeNTLM) {
- byte[] alist = type2.length > 48 ?
+ // Some client create a alist even if server does not send
+ // one: (i16)2 (i16)len target_in_unicode (i16)0 (i16) 0
+ byte[] alist = ((inputFlags & 0x800000) != 0) ?
r.readSecurityBuffer(40) : new byte[0];
byte[] blob = new byte[32+alist.length];
System.arraycopy(new byte[]{1,1,0,0,0,0,0,0}, 0, blob, 0, 8);
--- a/jdk/src/share/classes/com/sun/security/ntlm/Server.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/src/share/classes/com/sun/security/ntlm/Server.java Wed Jul 09 15:10:42 2014 +0800
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -92,7 +93,9 @@
debug("NTLM Server: Type 1 received\n");
if (type1 != null) debug(type1);
Writer p = new Writer(2, 32);
- int flags = 0x80205;
+ // Negotiate NTLM2 Key, Target Type Domain,
+ // Negotiate NTLM, Request Target, Negotiate unicode
+ int flags = 0x90205;
p.writeSecurityBuffer(12, domain, true);
p.writeInt(20, flags);
p.writeBytes(24, nonce);
@@ -127,8 +130,9 @@
"Wrong domain: " + incomingDomain +
" vs " + domain); // Needed?
}*/
+
boolean verified = false;
- char[] password = getPassword(domain, username);
+ char[] password = getPassword(incomingDomain, username);
if (password == null) {
throw new NTLMException(NTLMException.USER_UNKNOWN,
"Unknown user");
@@ -179,6 +183,8 @@
}
}
if (incomingNTLM.length > 0) {
+ // We didn't sent alist in type2(), so there
+ // is nothing to check here.
byte[] clientBlob = Arrays.copyOfRange(
incomingNTLM, 16, incomingNTLM.length);
byte[] ntlmresponse = calcV2(nthash,
--- a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java Wed Jul 09 15:10:42 2014 +0800
@@ -160,9 +160,17 @@
}
}
try {
+ String name = ncb.getName();
+ if (name == null) {
+ name = authzid;
+ }
+ String domain = dcb.getText();
+ if (domain == null) {
+ domain = serverName;
+ }
client = new Client(version, hostname,
- ncb.getName(),
- dcb.getText(),
+ name,
+ domain,
pcb.getPassword());
} catch (NTLMException ne) {
throw new SaslException(
--- a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java Wed Jul 09 15:10:42 2014 +0800
@@ -141,8 +141,10 @@
server = new Server(version, domain) {
public char[] getPassword(String ntdomain, String username) {
try {
- RealmCallback rcb = new RealmCallback(
- "Domain: ", ntdomain);
+ RealmCallback rcb =
+ (ntdomain == null || ntdomain.isEmpty())
+ ? new RealmCallback("Domain: ")
+ : new RealmCallback("Domain: ", ntdomain);
NameCallback ncb = new NameCallback(
"Name: ", username);
PasswordCallback pcb = new PasswordCallback(
--- a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java Wed Jul 09 15:10:42 2014 +0800
@@ -77,8 +77,7 @@
static {
defaultDomain = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
- "domain"));
+ new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", ""));
};
public static boolean supportsTransparentAuth () {
@@ -100,17 +99,13 @@
public String run() {
String localhost;
try {
- localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
+ localhost = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
localhost = "localhost";
}
return localhost;
}
});
- int x = hostname.indexOf ('.');
- if (x != -1) {
- hostname = hostname.substring (0, x);
- }
};
PasswordAuthentication pw;
--- a/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java Tue Jul 08 12:38:47 2014 -0700
+++ b/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java Wed Jul 09 15:10:42 2014 +0800
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6911951
+ * @bug 6911951 7150092
* @summary NTLM should be a supported Java SASL mechanism
*/
import java.io.IOException;
@@ -59,7 +59,6 @@
checkAuthOnly();
checkClientNameOverride();
- checkServerDomainOverride();
checkClientDomainOverride();
checkVersions();
checkClientHostname();
@@ -116,15 +115,12 @@
Map<String,Object> ps = new HashMap<>();
ps.put("com.sun.security.sasl.ntlm.version", vs);
SaslClient clnt = Sasl.createSaslClient(
- new String[]{MECH}, USER1, PROTOCOL, null, pc,
+ new String[]{MECH}, USER1, PROTOCOL, REALM, pc,
new CallbackHandler() {
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (Callback cb: callbacks) {
- if (cb instanceof NameCallback) {
- NameCallback ncb = (NameCallback)cb;
- ncb.setName(ncb.getDefaultName());
- } else if (cb instanceof PasswordCallback) {
+ if (cb instanceof PasswordCallback) {
((PasswordCallback)cb).setPassword(PASS1);
}
}
@@ -159,15 +155,12 @@
Map<String,Object> pc = new HashMap<>();
pc.put("com.sun.security.sasl.ntlm.hostname", "this.is.com");
SaslClient clnt = Sasl.createSaslClient(
- new String[]{MECH}, USER1, PROTOCOL, null, pc,
+ new String[]{MECH}, USER1, PROTOCOL, REALM, pc,
new CallbackHandler() {
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (Callback cb: callbacks) {
- if (cb instanceof NameCallback) {
- NameCallback ncb = (NameCallback)cb;
- ncb.setName(ncb.getDefaultName());
- } else if (cb instanceof PasswordCallback) {
+ if (cb instanceof PasswordCallback) {
((PasswordCallback)cb).setPassword(PASS1);
}
}
@@ -212,12 +205,8 @@
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (Callback cb: callbacks) {
- if (cb instanceof NameCallback) {
- NameCallback ncb = (NameCallback)cb;
- ncb.setName(ncb.getDefaultName());
- } else if(cb instanceof RealmCallback) {
- RealmCallback dcb = (RealmCallback)cb;
- dcb.setText("THIRDDOMAIN");
+ if (cb instanceof RealmCallback) {
+ ((RealmCallback)cb).setText(REALM);
} else if (cb instanceof PasswordCallback) {
((PasswordCallback)cb).setPassword(PASS1);
}
@@ -255,13 +244,13 @@
*/
private static void checkClientNameOverride() throws Exception {
SaslClient clnt = Sasl.createSaslClient(
- new String[]{MECH}, null, PROTOCOL, null, null,
+ new String[]{MECH}, "someone", PROTOCOL, REALM, null,
new CallbackHandler() {
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {
for (Callback cb: callbacks) {
if (cb instanceof NameCallback) {
- NameCallback ncb = (NameCallback)cb;
+ NameCallback ncb = (NameCallback) cb;
ncb.setName(USER1);
} else if (cb instanceof PasswordCallback) {
((PasswordCallback)cb).setPassword(PASS1);
@@ -270,54 +259,7 @@
}
});
- SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
- new CallbackHandler() {
- public void handle(Callback[] callbacks)
- throws IOException, UnsupportedCallbackException {
- String domain = null, name = null;
- PasswordCallback pcb = null;
- for (Callback cb: callbacks) {
- if (cb instanceof NameCallback) {
- name = ((NameCallback)cb).getDefaultName();
- } else if (cb instanceof RealmCallback) {
- domain = ((RealmCallback)cb).getDefaultText();
- } else if (cb instanceof PasswordCallback) {
- pcb = (PasswordCallback)cb;
- }
- }
- if (pcb != null) {
- pcb.setPassword(getPass(domain, name));
- }
- }
- });
-
- handshake(clnt, srv);
- }
-
- /**
- * server side domain provided in props.
- * @throws Exception
- */
- private static void checkServerDomainOverride() throws Exception {
- SaslClient clnt = Sasl.createSaslClient(
- new String[]{MECH}, USER1, PROTOCOL, null, null,
- new CallbackHandler() {
- public void handle(Callback[] callbacks)
- throws IOException, UnsupportedCallbackException {
- for (Callback cb: callbacks) {
- if (cb instanceof NameCallback) {
- NameCallback ncb = (NameCallback)cb;
- ncb.setName(ncb.getDefaultName());
- } else if (cb instanceof PasswordCallback) {
- ((PasswordCallback)cb).setPassword(PASS1);
- }
- }
- }
- });
-
- Map<String,Object> ps = new HashMap<>();
- ps.put("com.sun.security.sasl.ntlm.domain", REALM);
- SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, null, ps,
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, "FAKE", null,
new CallbackHandler() {
public void handle(Callback[] callbacks)
throws IOException, UnsupportedCallbackException {