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 ../../../../../lib/testlibrary 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.BufferedReader; 51 import java.io.Closeable; 52 import java.io.IOException; 53 import java.io.InputStream; 54 import java.io.InputStreamReader; 55 import java.net.HttpURLConnection; 56 import java.net.InetAddress; 57 import java.net.InetSocketAddress; 58 import java.net.ServerSocket; 59 import java.net.Socket; 60 import java.net.URL; 61 import jdk.testlibrary.net.URIBuilder; 62 import org.testng.annotations.AfterTest; 63 import org.testng.annotations.BeforeTest; 64 import org.testng.annotations.Test; 65 import org.testng.SkipException; 66 import static java.lang.System.out; 67 import static java.net.Proxy.NO_PROXY; 68 import static java.nio.charset.StandardCharsets.UTF_8; 69 import static org.testng.Assert.assertEquals; 70 import static org.testng.Assert.fail; 71 72 public class TestTransparentNTLM { 73 74 boolean succeed; // true if authentication is expected to succeed 75 Server server; 76 URL url; 77 78 @Test testNTLM()79 public void testNTLM() throws IOException { 80 out.println("connecting to url: " + url); 81 HttpURLConnection uc = (HttpURLConnection)url.openConnection(NO_PROXY); 82 int respCode = uc.getResponseCode(); 83 out.println("received: " + respCode); 84 85 if (succeed) { 86 assertEquals(respCode, HttpURLConnection.HTTP_OK); 87 InputStream is = uc.getInputStream(); 88 BufferedReader r = new BufferedReader(new InputStreamReader(is, UTF_8)); 89 String body = r.readLine(); 90 out.print("received body: "); 91 do { 92 out.print(body); 93 body = r.readLine(); 94 } while (body != null); 95 } else { 96 assertEquals(respCode, HttpURLConnection.HTTP_UNAUTHORIZED); 97 } 98 } 99 100 static class Server extends Thread implements Closeable { 101 102 static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); 103 final ServerSocket serverSocket; 104 final boolean expectAuthToSucceed; 105 Server(boolean expectAuthToSucceed)106 Server(boolean expectAuthToSucceed) throws IOException { 107 super("TestTransparentNTLM-Server"); 108 serverSocket = new ServerSocket(); 109 serverSocket.bind(new InetSocketAddress(LOOPBACK, 0)); 110 this.expectAuthToSucceed = expectAuthToSucceed; 111 } 112 port()113 int port() { 114 return serverSocket.getLocalPort(); 115 } 116 117 static final String AUTH_REQUIRED = 118 "HTTP/1.1 401 Unauthorized\r\n" + 119 "Content-Length: 0\r\n" + 120 "Connection: close\r\n" + 121 "WWW-Authenticate: NTLM\r\n\r\n"; 122 123 static final String AUTH_STAGE_TWO = 124 "HTTP/1.1 401 Unauthorized\r\n" + 125 "Content-Length: 0\r\n" + 126 "WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n\r\n"; 127 128 static final String AUTH_SUCCESSFUL = 129 "HTTP/1.1 200 OK\r\n" + 130 "Content-Length: 11\r\n\r\n" + 131 "Hello world"; 132 133 @Override run()134 public void run() { 135 try { 136 try (Socket s = serverSocket.accept()) { 137 out.println("Server accepted connection - 1"); 138 readRequestHeaders(s.getInputStream()); 139 s.getOutputStream().write(AUTH_REQUIRED.getBytes(UTF_8)); 140 } 141 142 if (expectAuthToSucceed) { 143 // await the second follow up connection 144 try (Socket s = serverSocket.accept()) { 145 out.println("Server accepted connection - 2"); 146 readRequestHeaders(s.getInputStream()); 147 s.getOutputStream().write(AUTH_STAGE_TWO.getBytes(UTF_8)); 148 readRequestHeaders(s.getInputStream()); 149 s.getOutputStream().write(AUTH_SUCCESSFUL.getBytes(UTF_8)); 150 } 151 } 152 } catch (IOException e) { 153 fail("Unexpected exception", e); 154 } 155 } 156 157 @Override close()158 public void close() throws IOException { 159 serverSocket.close(); 160 } 161 162 static final byte[] REQUEST_END = new byte[] {'\r', '\n', '\r', '\n'}; 163 164 // Read until the end of the HTTP request headers readRequestHeaders(InputStream is)165 static void readRequestHeaders(InputStream is) throws IOException { 166 int requestEndCount = 0, r; 167 while ((r = is.read()) != -1) { 168 if (r == REQUEST_END[requestEndCount]) { 169 requestEndCount++; 170 if (requestEndCount == 4) { 171 break; 172 } 173 } else { 174 requestEndCount = 0; 175 } 176 } 177 } 178 } 179 180 @BeforeTest setup()181 public void setup() throws Exception { 182 succeed = System.getProperty("test.auth.succeed").equals("true"); 183 if (succeed) 184 out.println("Expect client to succeed, with 200 Ok"); 185 else 186 out.println("Expect client to fail, with 401 Unauthorized"); 187 188 server = new Server(succeed); 189 server.start(); 190 url = URIBuilder.newBuilder() 191 .scheme("http") 192 .loopback() 193 .port(server.port()) 194 .path("/xxyyzz") 195 .toURL(); 196 } 197 198 @AfterTest teardown()199 public void teardown() throws Exception { 200 server.close(); 201 server.join(); 202 } 203 } 204