7150092: NTLM authentication fail if user specified a different realm
authorweijun
Wed, 09 Jul 2014 15:10:42 +0800
changeset 25396 5e73c95f95db
parent 25395 4c004dfa3340
child 25397 26482834c5bc
7150092: NTLM authentication fail if user specified a different realm Reviewed-by: michaelm
jdk/src/share/classes/com/sun/security/ntlm/Client.java
jdk/src/share/classes/com/sun/security/ntlm/Server.java
jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java
jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java
jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java
--- 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 {