Path: blob/master/test/jdk/sun/net/www/protocol/http/DigestTest.java
41159 views
/*1* Copyright (c) 2001, 2021, 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/**24* @test25* @bug 443221326* @modules java.base/sun.net.www27* @run main/othervm -Dhttp.auth.digest.validateServer=true DigestTest28* @run main/othervm -Djava.net.preferIPv6Addresses=true29* -Dhttp.auth.digest.validateServer=true DigestTest30* @run main/othervm -Dhttp.auth.digest.validateServer=true31-Dtest.succeed=true DigestTest32* @run main/othervm -Djava.net.preferIPv6Addresses=true33* -Dhttp.auth.digest.validateServer=true34-Dtest.succeed=true DigestTest35* @summary Need to support Digest Authentication for Proxies36*/3738import java.io.*;39import java.util.*;40import java.net.*;41import java.security.*;42import sun.net.www.*;4344/* This is one simple test of the RFC2617 digest authentication behavior45* It specifically tests that the client correctly checks the returned46* Authentication-Info header field from the server and throws an exception47* if the password is wrong48*/4950class DigestServer extends Thread {5152ServerSocket s;53Socket s1;54InputStream is;55OutputStream os;56int port;5758String reply1 = "HTTP/1.1 401 Unauthorized\r\n"+59"WWW-Authenticate: Digest realm=\""+realm+"\" domain=/ "+60"nonce=\""+nonce+"\" qop=\"auth\"\r\n\r\n";6162String reply2 = "HTTP/1.1 200 OK\r\n" +63"Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" +64"Server: Apache/1.3.14 (Unix)\r\n" +65"Content-Type: text/html; charset=iso-8859-1\r\n" +66"Transfer-encoding: chunked\r\n";67String body =68"B\r\nHelloWorld1\r\n"+69"B\r\nHelloWorld2\r\n"+70"B\r\nHelloWorld3\r\n"+71"B\r\nHelloWorld4\r\n"+72"B\r\nHelloWorld5\r\n"+73"0\r\n\r\n";74String authInfo =75"Authentication-Info: ";7677DigestServer (ServerSocket y) {78s = y;79port = s.getLocalPort();80}8182public void run () {83try {84s1 = s.accept ();85is = s1.getInputStream ();86os = s1.getOutputStream ();87is.read ();88os.write (reply1.getBytes());89Thread.sleep (2000);90s1.close ();9192s1 = s.accept ();93is = s1.getInputStream ();94os = s1.getOutputStream ();95//is.read ();96// need to get the cnonce out of the response97MessageHeader header = new MessageHeader (is);98String raw = header.findValue ("Authorization");99HeaderParser parser = new HeaderParser (raw);100String cnonce = parser.findValue ("cnonce");101String cnstring = parser.findValue ("nc");102103String reply = reply2 + authInfo + getAuthorization (uri, "GET", cnonce, cnstring) +"\r\n" + body;104os.write (reply.getBytes());105Thread.sleep (2000);106s1.close ();107} catch (Exception e) {108System.out.println (e);109e.printStackTrace();110} finally {111try { s.close(); } catch (IOException unused) {}112}113}114115static char[] passwd = "password".toCharArray();116static String username = "user";117static String nonce = "abcdefghijklmnopqrstuvwxyz";118static String realm = "wallyworld";119static String uri = "/foo.html";120121private String getAuthorization (String uri, String method, String cnonce, String cnstring) {122String response;123124try {125response = computeDigest(false, username,passwd,realm,126method, uri, nonce, cnonce, cnstring);127} catch (NoSuchAlgorithmException ex) {128return null;129}130131String value = "Digest"132+ " qop=auth\""133+ "\", cnonce=\"" + cnonce134+ "\", rspauth=\"" + response135+ "\", nc=\"" + cnstring + "\"";136return (value+ "\r\n");137}138139private String computeDigest(140boolean isRequest, String userName, char[] password,141String realm, String connMethod,142String requestURI, String nonceString,143String cnonce, String ncValue144) throws NoSuchAlgorithmException145{146147String A1, HashA1;148149MessageDigest md = MessageDigest.getInstance("MD5");150151{152A1 = userName + ":" + realm + ":";153HashA1 = encode(A1, password, md);154}155156String A2;157if (isRequest) {158A2 = connMethod + ":" + requestURI;159} else {160A2 = ":" + requestURI;161}162String HashA2 = encode(A2, null, md);163String combo, finalHash;164165{ /* RRC2617 when qop=auth */166combo = HashA1+ ":" + nonceString + ":" + ncValue + ":" +167cnonce + ":auth:" +HashA2;168169}170finalHash = encode(combo, null, md);171return finalHash;172}173174private String encode(String src, char[] passwd, MessageDigest md) {175md.update(src.getBytes());176if (passwd != null) {177byte[] passwdBytes = new byte[passwd.length];178for (int i=0; i<passwd.length; i++)179passwdBytes[i] = (byte)passwd[i];180md.update(passwdBytes);181Arrays.fill(passwdBytes, (byte)0x00);182}183byte[] digest = md.digest();184return HexFormat.of().formatHex(digest);185}186187}188189public class DigestTest {190191static final boolean SUCCEED =192Boolean.parseBoolean(System.getProperty("test.succeed", "false"));193194static class MyAuthenticator extends Authenticator {195public MyAuthenticator () {196super ();197}198199public PasswordAuthentication getPasswordAuthentication ()200{201char[] passwd = SUCCEED ? DigestServer.passwd.clone()202: "Wrongpassword".toCharArray();203return new PasswordAuthentication("user", passwd);204}205}206207208public static void main(String[] args) throws Exception {209int port;210DigestServer server;211ServerSocket sock;212213InetAddress loopback = InetAddress.getLoopbackAddress();214try {215sock = new ServerSocket();216sock.bind(new InetSocketAddress(loopback, 0));217port = sock.getLocalPort();218}219catch (Exception e) {220System.out.println ("Exception: " + e);221throw e;222}223224server = new DigestServer(sock);225server.start ();226boolean passed = false;227ProtocolException exception = null;228229try {230Authenticator.setDefault (new MyAuthenticator ());231String address = loopback.getHostAddress();232if (address.indexOf(':') > -1) address = "[" + address + "]";233String s = "http://" + address + ":" + port + DigestServer.uri;234URL url = new URL(s);235java.net.URLConnection conURL = url.openConnection(Proxy.NO_PROXY);236237InputStream in = conURL.getInputStream();238while (in.read () != -1) {}239in.close ();240if (SUCCEED) passed = true;241} catch(ProtocolException e) {242exception = e;243if (!SUCCEED) passed = true;244}245246if (!passed) {247if (!SUCCEED) {248throw new RuntimeException("Expected a ProtocolException from wrong password");249} else {250assert exception != null;251throw new RuntimeException("Unexpected ProtocolException from correct password: "252+ exception, exception);253}254}255}256}257258259