blob: bbc54d81b75c3aa58def9c2f1d571b1a3a3691e4 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/**
25 * @test
26 * @bug 4432213
27 * @run main/othervm -Dhttp.auth.digest.validateServer=true DigestTest
28 * @summary Need to support Digest Authentication for Proxies
29 */
30
31import java.io.*;
32import java.util.*;
33import java.net.*;
34import java.security.*;
35import sun.net.www.*;
36
37/* This is one simple test of the RFC2617 digest authentication behavior
38 * It specifically tests that the client correctly checks the returned
39 * Authentication-Info header field from the server and throws an exception
40 * if the password is wrong
41 */
42
43class DigestServer extends Thread {
44
45 ServerSocket s;
46 Socket s1;
47 InputStream is;
48 OutputStream os;
49 int port;
50
51 String reply1 = "HTTP/1.1 401 Unauthorized\r\n"+
52 "WWW-Authenticate: Digest realm=\""+realm+"\" domain=/ "+
53 "nonce=\""+nonce+"\" qop=\"auth\"\r\n\r\n";
54
55 String reply2 = "HTTP/1.1 200 OK\r\n" +
56 "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" +
57 "Server: Apache/1.3.14 (Unix)\r\n" +
58 "Content-Type: text/html; charset=iso-8859-1\r\n" +
59 "Transfer-encoding: chunked\r\n\r\n"+
60 "B\r\nHelloWorld1\r\n"+
61 "B\r\nHelloWorld2\r\n"+
62 "B\r\nHelloWorld3\r\n"+
63 "B\r\nHelloWorld4\r\n"+
64 "B\r\nHelloWorld5\r\n"+
65 "0\r\n"+
66 "Authentication-Info: ";
67
68 DigestServer (ServerSocket y) {
69 s = y;
70 port = s.getLocalPort();
71 }
72
73 public void run () {
74 try {
75 s1 = s.accept ();
76 is = s1.getInputStream ();
77 os = s1.getOutputStream ();
78 is.read ();
79 os.write (reply1.getBytes());
80 Thread.sleep (2000);
81 s1.close ();
82
83 s1 = s.accept ();
84 is = s1.getInputStream ();
85 os = s1.getOutputStream ();
86 is.read ();
87 // need to get the cnonce out of the response
88 MessageHeader header = new MessageHeader (is);
89 String raw = header.findValue ("Authorization");
90 HeaderParser parser = new HeaderParser (raw);
91 String cnonce = parser.findValue ("cnonce");
92 String cnstring = parser.findValue ("nc");
93
94 String reply = reply2 + getAuthorization (uri, "GET", cnonce, cnstring) +"\r\n";
95 os.write (reply.getBytes());
96 Thread.sleep (2000);
97 s1.close ();
98 }
99 catch (Exception e) {
100 System.out.println (e);
101 e.printStackTrace();
102 }
103 }
104
105 static char[] passwd = "password".toCharArray();
106 static String username = "user";
107 static String nonce = "abcdefghijklmnopqrstuvwxyz";
108 static String realm = "wallyworld";
109 static String uri = "/foo.html";
110
111 private String getAuthorization (String uri, String method, String cnonce, String cnstring) {
112 String response;
113
114 try {
115 response = computeDigest(false, username,passwd,realm,
116 method, uri, nonce, cnonce, cnstring);
117 } catch (NoSuchAlgorithmException ex) {
118 return null;
119 }
120
121 String value = "Digest"
122 + " qop=auth\""
123 + "\", cnonce=\"" + cnonce
124 + "\", rspauth=\"" + response
125 + "\", nc=\"" + cnstring + "\"";
126 return (value+ "\r\n");
127 }
128
129 private String computeDigest(
130 boolean isRequest, String userName, char[] password,
131 String realm, String connMethod,
132 String requestURI, String nonceString,
133 String cnonce, String ncValue
134 ) throws NoSuchAlgorithmException
135 {
136
137 String A1, HashA1;
138
139 MessageDigest md = MessageDigest.getInstance("MD5");
140
141 {
142 A1 = userName + ":" + realm + ":";
143 HashA1 = encode(A1, password, md);
144 }
145
146 String A2;
147 if (isRequest) {
148 A2 = connMethod + ":" + requestURI;
149 } else {
150 A2 = ":" + requestURI;
151 }
152 String HashA2 = encode(A2, null, md);
153 String combo, finalHash;
154
155 { /* RRC2617 when qop=auth */
156 combo = HashA1+ ":" + nonceString + ":" + ncValue + ":" +
157 cnonce + ":auth:" +HashA2;
158
159 }
160 finalHash = encode(combo, null, md);
161 return finalHash;
162 }
163
164 private final static char charArray[] = {
165 '0', '1', '2', '3', '4', '5', '6', '7',
166 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
167 };
168
169 private String encode(String src, char[] passwd, MessageDigest md) {
170 md.update(src.getBytes());
171 if (passwd != null) {
172 byte[] passwdBytes = new byte[passwd.length];
173 for (int i=0; i<passwd.length; i++)
174 passwdBytes[i] = (byte)passwd[i];
175 md.update(passwdBytes);
176 Arrays.fill(passwdBytes, (byte)0x00);
177 }
178 byte[] digest = md.digest();
179
180 StringBuffer res = new StringBuffer(digest.length * 2);
181 for (int i = 0; i < digest.length; i++) {
182 int hashchar = ((digest[i] >>> 4) & 0xf);
183 res.append(charArray[hashchar]);
184 hashchar = (digest[i] & 0xf);
185 res.append(charArray[hashchar]);
186 }
187 return res.toString();
188 }
189
190}
191
192public class DigestTest {
193
194 static class MyAuthenticator extends Authenticator {
195 public MyAuthenticator () {
196 super ();
197 }
198
199 public PasswordAuthentication getPasswordAuthentication ()
200 {
201 return (new PasswordAuthentication ("user", "Wrongpassword".toCharArray()));
202 }
203 }
204
205
206 public static void main(String[] args) throws Exception {
207 int nLoops = 1;
208 int nSize = 10;
209 int port, n =0;
210 byte b[] = new byte[nSize];
211 DigestServer server;
212 ServerSocket sock;
213
214 try {
215 sock = new ServerSocket (5000);
216 port = sock.getLocalPort ();
217 }
218 catch (Exception e) {
219 System.out.println ("Exception: " + e);
220 return;
221 }
222
223 server = new DigestServer(sock);
224 server.start ();
225 boolean passed = false;
226
227 try {
228
229 Authenticator.setDefault (new MyAuthenticator ());
230 String s = "http://localhost:" + port + DigestServer.uri;
231 URL url = new URL(s);
232 java.net.URLConnection conURL = url.openConnection();
233
234 InputStream in = conURL.getInputStream();
235 int c;
236 while ((c = in.read ()) != -1) {
237 }
238 in.close ();
239 }
240 catch(ProtocolException e) {
241 passed = true;
242 }
243 if (!passed) {
244 throw new RuntimeException ("Expected a ProtocolException from wrong password");
245 }
246 }
247}