Path: blob/master/test/jdk/sun/net/www/protocol/http/NoNTLM.java
41159 views
/*1* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 800450225* @library /test/lib26* @summary Sanity check that NTLM will not be selected by the http protocol27* handler when running on a profile that does not support NTLM28* @modules java.base/sun.net.www29* java.base/sun.net.www.protocol.http:open30* @run main/othervm NoNTLM31* @run main/othervm -Djava.net.preferIPv6Addresses=true NoNTLM32*/3334import java.io.IOException;35import java.lang.reflect.Field;36import java.net.Authenticator;37import java.net.HttpURLConnection;38import java.net.InetAddress;39import java.net.PasswordAuthentication;40import java.net.Proxy;41import java.net.ServerSocket;42import java.net.Socket;43import java.net.URL;44import jdk.test.lib.net.URIBuilder;45import sun.net.www.MessageHeader;4647public class NoNTLM {4849static final String CRLF = "\r\n";5051static final String OKAY =52"HTTP/1.1 200" + CRLF +53"Content-Length: 0" + CRLF +54"Connection: close" + CRLF +55CRLF;5657static class Client implements Runnable {58private final URL url;59private volatile IOException ioe;60private volatile int respCode;6162Client(int port) throws IOException {63this.url = URIBuilder.newBuilder()64.scheme("http")65.loopback()66.port(port)67.path("/foo.html")68.toURLUnchecked();69System.out.println("Client URL: " + this.url);70}7172public void run() {73try {74HttpURLConnection uc =75(HttpURLConnection)url.openConnection(Proxy.NO_PROXY);76try {77uc.getInputStream();78} catch (IOException x) {79respCode = uc.getResponseCode();80throw x;81}82uc.disconnect();83} catch (IOException x) {84if (respCode == 0)85respCode = -1;86ioe = x;87}88}8990IOException ioException() {91return ioe;92}9394int respCode() {95return respCode;96}9798static void start(int port) throws IOException {99Client client = new Client(port);100new Thread(client).start();101}102}103104/**105* Return the http response with WWW-Authenticate headers for the given106* authentication schemes.107*/108static String authReplyFor(String... schemes) {109// construct the server reply110String reply = "HTTP/1.1 401 Unauthorized" + CRLF +111"Content-Length: 0"+ CRLF +112"Connection: close" + CRLF;113for (String s: schemes) {114switch (s) {115case "Basic" :116reply += "WWW-Authenticate: Basic realm=\"wallyworld\"" + CRLF;117break;118case "Digest" :119reply += "WWW-Authenticate: Digest" +120" realm=\"wallyworld\"" +121" domain=/" +122" nonce=\"abcdefghijklmnopqrstuvwxyz\"" +123" qop=\"auth\"" + CRLF;124break;125case "NTLM" :126reply += "WWW-Authenticate: NTLM" + CRLF;127break;128default :129throw new RuntimeException("Should not get here");130}131}132reply += CRLF;133return reply;134}135136/**137* Test the http protocol handler with the given authentication schemes138* in the WWW-Authenticate header.139*/140static void test(String... schemes) throws IOException {141142// the authentication scheme that the client is expected to choose143String expected = null;144for (String s: schemes) {145if (expected == null) {146expected = s;147} else if (s.equals("Digest")) {148expected = s;149}150}151152// server reply153String reply = authReplyFor(schemes);154155System.out.println("====================================");156System.out.println("Expect client to choose: " + expected);157System.out.println(reply);158InetAddress loopback = InetAddress.getLoopbackAddress();159try (ServerSocket ss = new ServerSocket(0, 0, loopback)) {160Client.start(ss.getLocalPort());161162// client ---- GET ---> server163// client <--- 401 ---- server164try (Socket s = ss.accept()) {165new MessageHeader().parseHeader(s.getInputStream());166s.getOutputStream().write(reply.getBytes("US-ASCII"));167}168169// client ---- GET ---> server170// client <--- 200 ---- server171String auth;172try (Socket s = ss.accept()) {173MessageHeader mh = new MessageHeader();174mh.parseHeader(s.getInputStream());175s.getOutputStream().write(OKAY.getBytes("US-ASCII"));176auth = mh.findValue("Authorization");177}178179// check Authorization header180if (auth == null)181throw new RuntimeException("Authorization header not found");182System.out.println("Server received Authorization header: " + auth);183String[] values = auth.split(" ");184if (!values[0].equals(expected))185throw new RuntimeException("Unexpected value");186}187}188189/**190* Test the http protocol handler with one WWW-Authenticate header with191* the value "NTLM".192*/193static void testNTLM() throws Exception {194// server reply195String reply = authReplyFor("NTLM");196197System.out.println("====================================");198System.out.println("Expect client to fail with 401 Unauthorized");199System.out.println(reply);200201InetAddress loopback = InetAddress.getLoopbackAddress();202try (ServerSocket ss = new ServerSocket(0, 0, loopback)) {203Client client = new Client(ss.getLocalPort());204Thread thr = new Thread(client);205thr.start();206207// client ---- GET ---> server208// client <--- 401 ---- client209try (Socket s = ss.accept()) {210new MessageHeader().parseHeader(s.getInputStream());211s.getOutputStream().write(reply.getBytes("US-ASCII"));212}213214// the client should fail with 401215System.out.println("Waiting for client to terminate");216thr.join();217IOException ioe = client.ioException();218if (ioe != null)219System.out.println("Client failed: " + ioe);220int respCode = client.respCode();221if (respCode != 0 && respCode != -1)222System.out.println("Client received HTTP response code: " + respCode);223if (respCode != HttpURLConnection.HTTP_UNAUTHORIZED)224throw new RuntimeException("Unexpected response code");225}226}227228public static void main(String[] args) throws Exception {229boolean ntlmSupported = false;230try {231Class<?> ntlmProxyClass = Class.forName("sun.net.www.protocol.http.NTLMAuthenticationProxy", true, NoNTLM.class.getClassLoader());232Field ntlmSupportedField = ntlmProxyClass.getDeclaredField("supported");233ntlmSupportedField.setAccessible(true);234if (ntlmSupportedField.getBoolean(null)) {235System.out.println("NTLM is supported.");236ntlmSupported = true;237}238} catch (ClassNotFoundException okay) { }239240// setup Authenticator241Authenticator.setDefault(new Authenticator() {242@Override243protected PasswordAuthentication getPasswordAuthentication() {244return new PasswordAuthentication("user", "pass".toCharArray());245}246});247248// test combinations of authentication schemes249test("Basic");250test("Digest");251test("Basic", "Digest");252253if (ntlmSupported) {254System.out.println("====================================");255System.out.println("NTLM is supported: client would select NTLM: skipping `test(\"Basic\", \"NTLM\")`..");256} else {257test("Basic", "NTLM");258}259260test("Digest", "NTLM");261test("Basic", "Digest", "NTLM");262263if (ntlmSupported) {264System.out.println("====================================");265System.out.println("NTLM is supported: client would select NTLM: skipping `testNTLM()`..");266} else {267// test NTLM only, this should fail with "401 Unauthorized"268testNTLM();269}270271System.out.println();272System.out.println("TEST PASSED");273}274}275276277