1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8225425 27 * @summary Verifies that transparent NTLM (on Windows) is not used by default, 28 * and is used only when the relevant property is set. 29 * @requires os.family == "windows" 30 * @library /test/lib 31 * @run testng/othervm 32 * -Dtest.auth.succeed=false 33 * TestTransparentNTLM 34 * @run testng/othervm 35 * -Djdk.http.ntlm.transparentAuth=allHosts 36 * -Dtest.auth.succeed=true 37 * TestTransparentNTLM 38 * @run testng/othervm 39 * -Djdk.http.ntlm.transparentAuth=blahblah 40 * -Dtest.auth.succeed=false 41 * TestTransparentNTLM 42 * @run testng/othervm 43 * -Djdk.http.ntlm.transparentAuth=trustedHosts 44 * -Dtest.auth.succeed=false 45 * TestTransparentNTLM 46 */ 47 48 // Run with `trustedHosts` to exercise the native code, nothing more. 49 50 import java.io.Closeable; 51 import java.io.IOException; 52 import java.io.InputStream; 53 import java.net.HttpURLConnection; 54 import java.net.InetAddress; 55 import java.net.InetSocketAddress; 56 import java.net.ServerSocket; 57 import java.net.Socket; 58 import java.net.URL; 59 import jdk.test.lib.net.URIBuilder; 60 import org.testng.annotations.AfterTest; 61 import org.testng.annotations.BeforeTest; 62 import org.testng.annotations.Test; 63 import org.testng.SkipException; 64 import static java.lang.System.out; 65 import static java.net.Proxy.NO_PROXY; 66 import static java.nio.charset.StandardCharsets.UTF_8; 67 import static org.testng.Assert.assertEquals; 68 import static org.testng.Assert.fail; 69 70 public class TestTransparentNTLM { 71 72 boolean succeed; // true if authentication is expected to succeed 73 Server server; 74 URL url; 75 76 @Test testNTLM()77 public void testNTLM() throws IOException { 78 out.println("connecting to url: " + url); 79 HttpURLConnection uc = (HttpURLConnection)url.openConnection(NO_PROXY); 80 int respCode = uc.getResponseCode(); 81 out.println("received: " + respCode); 82 83 if (succeed) { 84 assertEquals(respCode, HttpURLConnection.HTTP_OK); 85 String body = new String(uc.getInputStream().readAllBytes(), UTF_8); 86 out.println("received body: " + body); 87 } else { 88 assertEquals(respCode, HttpURLConnection.HTTP_UNAUTHORIZED); 89 } 90 } 91 92 static class Server extends Thread implements Closeable { 93 94 static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); 95 final ServerSocket serverSocket; 96 final boolean expectAuthToSucceed; 97 Server(boolean expectAuthToSucceed)98 Server(boolean expectAuthToSucceed) throws IOException { 99 super("TestTransparentNTLM-Server"); 100 serverSocket = new ServerSocket(); 101 serverSocket.bind(new InetSocketAddress(LOOPBACK, 0)); 102 this.expectAuthToSucceed = expectAuthToSucceed; 103 } 104 port()105 int port() { 106 return serverSocket.getLocalPort(); 107 } 108 109 static final String AUTH_REQUIRED = 110 "HTTP/1.1 401 Unauthorized\r\n" + 111 "Content-Length: 0\r\n" + 112 "Connection: close\r\n" + 113 "WWW-Authenticate: NTLM\r\n\r\n"; 114 115 static final String AUTH_STAGE_TWO = 116 "HTTP/1.1 401 Unauthorized\r\n" + 117 "Content-Length: 0\r\n" + 118 "WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n\r\n"; 119 120 static final String AUTH_SUCCESSFUL = 121 "HTTP/1.1 200 OK\r\n" + 122 "Content-Length: 11\r\n\r\n" + 123 "Hello world"; 124 125 @Override run()126 public void run() { 127 try { 128 try (Socket s = serverSocket.accept()) { 129 out.println("Server accepted connection - 1"); 130 readRequestHeaders(s.getInputStream()); 131 s.getOutputStream().write(AUTH_REQUIRED.getBytes(UTF_8)); 132 } 133 134 if (expectAuthToSucceed) { 135 // await the second follow up connection 136 try (Socket s = serverSocket.accept()) { 137 out.println("Server accepted connection - 2"); 138 readRequestHeaders(s.getInputStream()); 139 s.getOutputStream().write(AUTH_STAGE_TWO.getBytes(UTF_8)); 140 readRequestHeaders(s.getInputStream()); 141 s.getOutputStream().write(AUTH_SUCCESSFUL.getBytes(UTF_8)); 142 } 143 } 144 } catch (IOException e) { 145 fail("Unexpected exception", e); 146 } 147 } 148 149 @Override close()150 public void close() throws IOException { 151 serverSocket.close(); 152 } 153 154 static final byte[] REQUEST_END = new byte[] {'\r', '\n', '\r', '\n'}; 155 156 // Read until the end of the HTTP request headers readRequestHeaders(InputStream is)157 static void readRequestHeaders(InputStream is) throws IOException { 158 int requestEndCount = 0, r; 159 while ((r = is.read()) != -1) { 160 if (r == REQUEST_END[requestEndCount]) { 161 requestEndCount++; 162 if (requestEndCount == 4) { 163 break; 164 } 165 } else { 166 requestEndCount = 0; 167 } 168 } 169 } 170 } 171 172 @BeforeTest setup()173 public void setup() throws Exception { 174 succeed = System.getProperty("test.auth.succeed").equals("true"); 175 if (succeed) 176 out.println("Expect client to succeed, with 200 Ok"); 177 else 178 out.println("Expect client to fail, with 401 Unauthorized"); 179 180 server = new Server(succeed); 181 server.start(); 182 url = URIBuilder.newBuilder() 183 .scheme("http") 184 .loopback() 185 .port(server.port()) 186 .path("/xxyyzz") 187 .toURL(); 188 } 189 190 @AfterTest teardown()191 public void teardown() throws Exception { 192 server.close(); 193 server.join(); 194 } 195 } 196