1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestAuthenticator.java,v 1.42 2004/04/29 14:28:29 olegk Exp $
3    * $Revision: 1.42 $
4    * $Date: 2004/04/29 14:28:29 $
5    * ====================================================================
6    *
7    *  Copyright 1999-2004 The Apache Software Foundation
8    *
9    *  Licensed under the Apache License, Version 2.0 (the "License");
10   *  you may not use this file except in compliance with the License.
11   *  You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing, software
16   *  distributed under the License is distributed on an "AS IS" BASIS,
17   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   *  See the License for the specific language governing permissions and
19   *  limitations under the License.
20   * ====================================================================
21   *
22   * This software consists of voluntary contributions made by many
23   * individuals on behalf of the Apache Software Foundation.  For more
24   * information on the Apache Software Foundation, please see
25   * <http://www.apache.org/>.
26   *
27   * [Additional notices, if required by prior licensing conditions]
28   *
29   */
30  
31  package org.apache.commons.httpclient;
32  
33  import java.util.Map;
34  
35  import junit.framework.Test;
36  import junit.framework.TestSuite;
37  
38  import org.apache.commons.httpclient.auth.AuthChallengeParser;
39  import org.apache.commons.httpclient.auth.AuthScheme;
40  import org.apache.commons.httpclient.auth.AuthenticationException;
41  import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
42  import org.apache.commons.httpclient.auth.DigestScheme;
43  import org.apache.commons.httpclient.auth.MalformedChallengeException;
44  import org.apache.commons.httpclient.auth.NTLMScheme;
45  
46  /***
47   * Unit tests for {@link Authenticator}.
48   *
49   * @author Rodney Waldhoff
50   * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
51   * @version $Id: TestAuthenticator.java,v 1.42 2004/04/29 14:28:29 olegk Exp $
52   */
53  public class TestAuthenticator extends TestNoHostBase {
54  
55      // ------------------------------------------------------------ Constructor
56      public TestAuthenticator(String testName) {
57          super(testName);
58      }
59  
60      // ------------------------------------------------------------------- Main
61      public static void main(String args[]) {
62          String[] testCaseName = { TestAuthenticator.class.getName() };
63          junit.textui.TestRunner.main(testCaseName);
64      }
65  
66      // ------------------------------------------------------- TestCase Methods
67  
68      public static Test suite() {
69          return new TestSuite(TestAuthenticator.class);
70      }
71  
72  
73      // ---------------------------------- Helper functions
74  
75      protected static boolean doAuthenticate(
76          AuthScheme authscheme, 
77          HttpMethod method, 
78          HttpConnection conn,
79          HttpState state, 
80          boolean proxy)
81         throws AuthenticationException {
82  
83          if (authscheme == null) {
84              throw new IllegalArgumentException("Authentication scheme may not be null");
85          }
86          if (method == null) {
87              throw new IllegalArgumentException("HTTP method may not be null");
88          }
89          if (state == null) {
90              throw new IllegalArgumentException("HTTP state may not be null");
91          }
92          String host = null;
93          if (conn != null) {
94              if (proxy) {
95                  host = conn.getProxyHost();
96              } else {
97                  host = conn.getVirtualHost();
98                  if (host == null) {
99                      host = conn.getHost();
100                 }
101             }
102         }
103         String realm = authscheme.getRealm();
104         Credentials credentials = proxy 
105             ? state.getProxyCredentials(realm, host) 
106             : state.getCredentials(realm, host);
107         if (credentials == null) {
108             throw new CredentialsNotAvailableException("No credentials available");
109         }
110         String auth = authscheme.authenticate(credentials, method);
111         if (auth != null) {
112             String s = proxy ? "Proxy-Authorization" : "Authorization";
113             Header header = new Header(s, auth, true);
114             method.addRequestHeader(header);
115             return true;
116         } else {
117             return false;
118         }
119     }
120 
121     private static boolean authenticate(
122         AuthScheme authscheme, 
123         HttpMethod method, 
124         HttpConnection conn,
125         HttpState state) 
126         throws AuthenticationException {
127         return doAuthenticate(authscheme, method, conn, state, false);
128     }
129 
130     public static boolean authenticateProxy(
131         AuthScheme authscheme, 
132         HttpMethod method, 
133         HttpConnection conn,
134         HttpState state
135     ) throws AuthenticationException {
136        return doAuthenticate(authscheme, method, conn, state, true);
137     }
138 
139 
140     public void testCredentialConstructors() {
141         try {
142             new UsernamePasswordCredentials(null, null);
143             fail("IllegalArgumentException should have been thrown");
144         } catch (IllegalArgumentException e) {
145             // expected
146         }
147         try {
148             new NTCredentials("user", "password", null, null);
149             fail("IllegalArgumentException should have been thrown");
150         } catch (IllegalArgumentException e) {
151             // expected
152         }
153         try {
154             new NTCredentials("user", "password", "host", null);
155             fail("IllegalArgumentException should have been thrown");
156         } catch (IllegalArgumentException e) {
157             // expected
158         }
159         NTCredentials creds = new NTCredentials("user", null, "host", "domain");
160         assertNotNull(creds.getUserName());
161         assertNull(creds.getPassword());
162         assertNotNull(creds.getDomain());
163         assertNotNull(creds.getHost());
164     }
165 
166     // ---------------------------------- Test Methods for BasicScheme Authentication
167 
168     // Moved to a separate test case based on a new testing framework
169 
170     // --------------------------------- Test Methods for DigestScheme Authentication
171 
172     public void testDigestAuthenticationWithNoCreds() throws Exception {
173         String challenge = "Digest realm=\"realm1\", nonce=\"ABC123\"";
174         HttpState state = new HttpState();
175         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
176         try {
177             AuthScheme authscheme = new DigestScheme();
178             authscheme.processChallenge(challenge);
179             authenticate(authscheme, method, null, state);
180             fail("Should have thrown CredentialsNotAvailableException");
181         } catch(CredentialsNotAvailableException e) {
182             // expected
183         }
184     }
185 
186     public void testDigestAuthenticationWithNoRealm() throws Exception {
187         String challenge = "Digest";
188         try {
189             AuthScheme authscheme = new DigestScheme();
190             authscheme.processChallenge(challenge);
191             fail("Should have thrown MalformedChallengeException");
192         } catch(MalformedChallengeException e) {
193             // expected
194         }
195     }
196 
197     public void testDigestAuthenticationWithNoRealm2() throws Exception {
198         String challenge = "Digest ";
199         try {
200             AuthScheme authscheme = new DigestScheme();
201             authscheme.processChallenge(challenge);
202             fail("Should have thrown MalformedChallengeException");
203         } catch(MalformedChallengeException e) {
204             // expected
205         }
206     }
207 
208     public void testDigestAuthenticationWithNullHttpState() throws Exception {
209         String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
210         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
211         try {
212             AuthScheme authscheme = new DigestScheme();
213             authscheme.processChallenge(challenge);
214             authenticate(authscheme, method, null, null);
215             fail("Should have thrown IllegalArgumentException");
216         } catch(IllegalArgumentException e) {
217             // expected
218         }
219     }
220 
221     public void testDigestAuthenticationCaseInsensitivity() throws Exception {
222         String challenge = "dIgEsT ReAlM=\"realm1\", nOnCE=\"f2a3F18799759D4f1a1C068b92b573cB\"";
223         HttpState state = new HttpState();
224         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
225         state.setCredentials(null, null, cred);
226         HttpMethod method = new SimpleHttpMethod(new Header("WwW-AuThEnTiCaTe", challenge));
227         AuthScheme authscheme = new DigestScheme();
228         authscheme.processChallenge(challenge);
229         assertTrue(authenticate(authscheme, method, null, state));
230         assertTrue(null != method.getRequestHeader("Authorization"));
231     }
232 
233 
234     public void testDigestAuthenticationWithDefaultCreds() throws Exception {
235         String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
236         HttpState state = new HttpState();
237         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
238         state.setCredentials(null, null, cred);
239         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
240         AuthScheme authscheme = new DigestScheme();
241         authscheme.processChallenge(challenge);
242         assertTrue(authenticate(authscheme, method, null, state));
243         assertTrue(null != method.getRequestHeader("Authorization"));
244         Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
245         assertEquals("username", table.get("username"));
246         assertEquals("realm1", table.get("realm"));
247         assertEquals("/", table.get("uri"));
248         assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
249         assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
250     }
251 
252     public void testDigestAuthentication() throws Exception {
253         String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
254         HttpState state = new HttpState();
255         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
256         state.setCredentials(null, null, cred);
257         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
258         AuthScheme authscheme = new DigestScheme();
259         authscheme.processChallenge(challenge);
260         assertTrue(authenticate(authscheme, method, null, state));
261         assertTrue(null != method.getRequestHeader("Authorization"));
262         Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
263         assertEquals("username", table.get("username"));
264         assertEquals("realm1", table.get("realm"));
265         assertEquals("/", table.get("uri"));
266         assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
267         assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
268     }
269 
270     public void testDigestAuthenticationWithStaleNonce() throws Exception {
271         
272         String headers =
273             "HTTP/1.1 401 OK\r\n" +
274             "Connection: close\r\n" +
275             "Content-Length: 0\r\n" +
276             "WWW-Authenticate: Digest realm=\"realm1\", nonce=\"ABC123\"\r\n";
277         String headers2 =
278             "HTTP/1.1 401 OK\r\n" +
279             "Connection: close\r\n" +
280             "Content-Length: 0\r\n" +
281             "WWW-Authenticate: Digest realm=\"realm1\", nonce=\"321CBA\", stale=\"true\"\r\n";
282         String headers3 = 
283             "HTTP/1.1 200 OK\r\n" +
284             "Connection: close\r\n" +
285             "Server: HttpClient Test/2.0\r\n\r\n" +
286             "stuff\r\n";
287         
288         SimpleHttpConnection conn = new SimpleHttpConnection();
289         
290         conn.addResponse(headers);
291         conn.addResponse(headers2);
292         conn.addResponse(headers3);
293         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
294         client.getState().setCredentials(null, null, cred);
295 
296         connectionManager.setConnection(conn);
297 
298         SimpleHttpMethod method = new SimpleHttpMethod();
299         method.setDoAuthentication(true);
300         assertEquals("Authentication failed", 200, client.executeMethod(method));
301         Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
302         assertEquals("username", table.get("username"));
303         assertEquals("realm1", table.get("realm"));
304         assertEquals("/", table.get("uri"));
305         assertEquals("321CBA", table.get("nonce"));
306         assertEquals("7f5948eefa115296e9279225041527b3", table.get("response"));
307     }
308 
309     public void testDigestAuthenticationWithMultipleRealms() throws Exception {
310         String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\"";
311         String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\"";
312         HttpState state = new HttpState();
313         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
314         state.setCredentials("realm1", null, cred);
315         UsernamePasswordCredentials cred2 = new UsernamePasswordCredentials("uname2","password2");
316         state.setCredentials("realm2", null, cred2);
317         AuthScheme authscheme1 = new DigestScheme();
318         authscheme1.processChallenge(challenge1);
319         AuthScheme authscheme2 = new DigestScheme();
320         authscheme2.processChallenge(challenge2);
321         {
322             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate",challenge1));
323             assertTrue(authenticate(authscheme1, method, null, state));
324             assertTrue(null != method.getRequestHeader("Authorization"));
325             Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
326             assertEquals("username", table.get("username"));
327             assertEquals("realm1", table.get("realm"));
328             assertEquals("/", table.get("uri"));
329             assertEquals("abcde", table.get("nonce"));
330             assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response"));
331         }
332         {
333             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate",challenge2));
334             assertTrue(authenticate(authscheme2, method, null, state));
335             assertTrue(null != method.getRequestHeader("Authorization"));
336             Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
337             assertEquals("uname2", table.get("username"));
338             assertEquals("realm2", table.get("realm"));
339             assertEquals("/", table.get("uri"));
340             assertEquals("123546", table.get("nonce"));
341             assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response"));
342         }
343     }
344 
345     /*** 
346      * Test digest authentication using the MD5-sess algorithm.
347      */
348     public void testDigestAuthenticationMD5Sess() throws Exception {
349         // Example using Digest auth with MD5-sess
350 
351         String realm="realm";
352         String username="username";
353         String password="password";
354         String nonce="e273f1776275974f1a120d8b92c5b3cb";
355 
356         String challenge="Digest realm=\"" + realm + "\", "
357             + "nonce=\"" + nonce + "\", "
358             + "opaque=\"SomeString\", "
359             + "stale=false, "
360             + "algorithm=MD5-sess, "
361             + "qop=\"auth,auth-int\""; // we pass both but expect auth to be used
362 
363         HttpState state = new HttpState();
364         UsernamePasswordCredentials cred =
365             new UsernamePasswordCredentials(username, password);
366         state.setCredentials(realm, null, cred);
367         AuthScheme authscheme = new DigestScheme();
368         authscheme.processChallenge(challenge);
369         HttpMethod method =
370             new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
371         assertTrue(authenticate(
372             authscheme, method, null, state));
373         assertTrue(null != method.getRequestHeader("Authorization"));
374         Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
375         assertEquals(username, table.get("username"));
376         assertEquals(realm, table.get("realm"));
377         assertEquals("MD5-sess", table.get("algorithm"));
378         assertEquals("/", table.get("uri"));
379         assertEquals(nonce, table.get("nonce"));
380         assertEquals(1, Integer.parseInt((String) table.get("nc"),16));
381         assertTrue(null != table.get("cnonce"));
382         assertEquals("SomeString", table.get("opaque"));
383         assertEquals("auth", table.get("qop"));
384         //@TODO: add better check
385         assertTrue(null != table.get("response")); 
386     }
387     
388     /*** 
389      * Test digest authentication using the MD5-sess algorithm.
390      */
391     public void testDigestAuthenticationMD5SessNoQop() throws Exception {
392         // Example using Digest auth with MD5-sess
393 
394         String realm="realm";
395         String username="username";
396         String password="password";
397         String nonce="e273f1776275974f1a120d8b92c5b3cb";
398 
399         String challenge="Digest realm=\"" + realm + "\", "
400             + "nonce=\"" + nonce + "\", "
401             + "opaque=\"SomeString\", "
402             + "stale=false, "
403             + "algorithm=MD5-sess";
404 
405         HttpState state = new HttpState();
406         UsernamePasswordCredentials cred =
407             new UsernamePasswordCredentials(username, password);
408         state.setCredentials(realm, null, cred);
409         AuthScheme authscheme = new DigestScheme();
410         authscheme.processChallenge(challenge);
411         HttpMethod method =
412             new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
413         assertTrue(authenticate(
414             authscheme, method, null, state));
415         assertTrue(null != method.getRequestHeader("Authorization"));
416         Map table = AuthChallengeParser.extractParams(method.getRequestHeader("Authorization").getValue());
417         assertEquals(username, table.get("username"));
418         assertEquals(realm, table.get("realm"));
419         assertEquals("MD5-sess", table.get("algorithm"));
420         assertEquals("/", table.get("uri"));
421         assertEquals(nonce, table.get("nonce"));
422         assertTrue(null == table.get("nc"));
423         assertEquals("SomeString", table.get("opaque"));
424         assertTrue(null == table.get("qop"));
425         //@TODO: add better check
426         assertTrue(null != table.get("response")); 
427     }
428     
429     /*** 
430      * Test digest authentication with invalud qop value
431      */
432     public void testDigestAuthenticationMD5SessInvalidQop() throws Exception {
433         // Example using Digest auth with MD5-sess
434 
435         String realm="realm";
436         String username="username";
437         String password="password";
438         String nonce="e273f1776275974f1a120d8b92c5b3cb";
439 
440         String challenge="Digest realm=\"" + realm + "\", "
441             + "nonce=\"" + nonce + "\", "
442             + "opaque=\"SomeString\", "
443             + "stale=false, "
444             + "algorithm=MD5-sess, "
445             + "qop=\"jakarta\""; // jakarta is an invalid qop value
446 
447         HttpState state = new HttpState();
448         UsernamePasswordCredentials cred =
449             new UsernamePasswordCredentials(username, password);
450         state.setCredentials(realm, null, cred);
451         try {
452             AuthScheme authscheme = new DigestScheme();
453             authscheme.processChallenge(challenge);
454             fail("MalformedChallengeException exception expected due to invalid qop value");
455         } catch(MalformedChallengeException e) {
456             /* expected */
457         }
458     }    
459 
460     
461 
462     // --------------------------------- Test Methods for NTLM Authentication
463 
464     public void testNTLMAuthenticationWithNoCreds() {
465         String challenge = "NTLM";
466         HttpState state = new HttpState();
467         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
468         method.addRequestHeader("Host", "host");
469         try {
470             AuthScheme authscheme = new NTLMScheme(challenge);
471             authenticate(authscheme, method, null, state);
472             fail("Should have thrown HttpException");
473         } catch(HttpException e) {
474             // expected
475         }
476     }
477 
478     public void testNTLMAuthenticationWithNullHttpState() throws Exception {
479         String challenge = "NTLM";
480         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
481         method.addRequestHeader("Host", "host");
482         try {
483             AuthScheme authscheme = new NTLMScheme(challenge);
484             authenticate(authscheme, method, null, null);
485             fail("Should have thrown IllegalArgumentException");
486         } catch(IllegalArgumentException e) {
487             // expected
488         }
489     }
490 
491     public void testNTLMAuthenticationCaseInsensitivity() throws Exception {
492         String challenge = "nTlM";
493         HttpState state = new HttpState();
494         NTCredentials cred = new NTCredentials("username","password", "host",
495                 "domain");
496         state.setCredentials(null, null, cred);
497         HttpMethod method = new SimpleHttpMethod(new Header("WwW-AuThEnTiCaTe", challenge));
498         AuthScheme authscheme = new NTLMScheme(challenge);
499         assertTrue(authenticate(authscheme, method, null, state));
500         assertTrue(null != method.getRequestHeader("Authorization"));
501     }
502 
503     public void testNTLMAuthenticationResponse1() throws Exception {
504         String challenge = "NTLM";
505         String expected = "NTLM TlRMTVNTUAABAAAABlIAAAYABgAkAAAABAAEACAAAABIT" +
506             "1NURE9NQUlO";
507         HttpState state = new HttpState();
508         NTCredentials cred = new NTCredentials("username","password", "host",
509                 "domain");
510         state.setCredentials(null, null, cred);
511         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
512         AuthScheme authscheme = new NTLMScheme(challenge);
513         assertTrue(authenticate(authscheme, method, null, state));
514         assertTrue(null != method.getRequestHeader("Authorization"));
515         assertEquals(expected,
516                 method.getRequestHeader("Authorization").getValue());
517     }
518     
519     public void testNTLMAuthenticationResponse2() throws Exception {
520         String challenge = 
521             "NTLM TlRMTVNTUAACAAAACgAKADAAAAAGgoEAPc4kP4LtCV8AAAAAAAAAAJ4AngA" +
522             "6AAAASU5UUkFFUEhPWAIAFABJAE4AVABSAEEARQBQAEgATwBYAAEAEgBCAE8AQQB" +
523             "SAEQAUgBPAE8ATQAEACgAaQBuAHQAcgBhAGUAcABoAG8AeAAuAGUAcABoAG8AeAA" +
524             "uAGMAbwBtAAMAPABCAG8AYQByAGQAcgBvAG8AbQAuAGkAbgB0AHIAYQBlAHAAaAB" +
525             "vAHgALgBlAHAAaABvAHgALgBjAG8AbQAAAAAA";
526 
527         String expected = "NTLM TlRMTVNTUAADAAAAGAAYAFIAAAAAAAAAagAAAAYABgB" +
528             "AAAAACAAIAEYAAAAEAAQATgAAAAAAAABqAAAABlIAAERPTUFJTlVTRVJOQU1FSE" +
529             "9TVAaC+vLxUEHnUtpItj9Dp4kzwQfd61Lztg==";
530         HttpState state = new HttpState();
531         NTCredentials cred = new NTCredentials("username","password", "host",
532                 "domain");
533         state.setCredentials(null, null, cred);
534         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
535         AuthScheme authscheme = new NTLMScheme(challenge);
536         assertTrue(authenticate(authscheme, method, null, state));
537         assertTrue(null != method.getRequestHeader("Authorization"));
538         assertEquals(expected,
539                 method.getRequestHeader("Authorization").getValue());
540     }
541     
542     public void testNTLMAuthenticationWithDefaultCreds() throws Exception {
543         String challenge = 
544             "NTLM TlRMTVNTUAACAAAACgAKADAAAAAGgoEAPc4kP4LtCV8AAAAAAAAAAJ4AngA" +
545             "6AAAASU5UUkFFUEhPWAIAFABJAE4AVABSAEEARQBQAEgATwBYAAEAEgBCAE8AQQB" +
546             "SAEQAUgBPAE8ATQAEACgAaQBuAHQAcgBhAGUAcABoAG8AeAAuAGUAcABoAG8AeAA" +
547             "uAGMAbwBtAAMAPABCAG8AYQByAGQAcgBvAG8AbQAuAGkAbgB0AHIAYQBlAHAAaAB" +
548             "vAHgALgBlAHAAaABvAHgALgBjAG8AbQAAAAAA";
549         String expected = "NTLM TlRMTVNTUAADAAAAGAAYAFIAAAAAAAAAagAAAAYABgB" +
550             "AAAAACAAIAEYAAAAEAAQATgAAAAAAAABqAAAABlIAAERPTUFJTlVTRVJOQU1FSE" +
551             "9TVAaC+vLxUEHnUtpItj9Dp4kzwQfd61Lztg==";
552         HttpState state = new HttpState();
553         NTCredentials cred = new NTCredentials("username","password", "host",
554                 "domain");
555         state.setCredentials(null, null, cred);
556         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
557         method.addRequestHeader("Host", "host");
558         AuthScheme authscheme = new NTLMScheme(challenge);
559         assertTrue(authenticate(authscheme, method, null, state));
560         assertTrue(null != method.getRequestHeader("Authorization"));
561         assertEquals(expected,
562                 method.getRequestHeader("Authorization").getValue());
563     }
564     
565     public void testNTLMAuthenticationRetry() throws Exception {
566         NTCredentials cred = new NTCredentials("username", "password", "host", "domain");
567         client.getState().setCredentials(null, null, cred);
568         HttpMethod method = new SimpleHttpMethod();
569         conn.addResponse(
570             "HTTP/1.1 401 Unauthorized\r\n" +
571             "WWW-Authenticate: NTLM\r\n" +
572             "Connection: close\r\n" +
573             "Server: HttpClient Test/2.0\r\n");
574         conn.addResponse(
575             "HTTP/1.1 401 Unauthorized\r\n" +
576             "WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n" +
577             "Connection: close\r\n" +
578             "Server: HttpClient Test/2.0\r\n");
579         conn.addResponse(
580             "HTTP/1.1 200 OK\r\n" +
581             "Connection: close\r\n" +
582             "Server: HttpClient Test/2.0\r\n\r\n" +
583             "stuff\r\n");
584         client.executeMethod(method);
585         assertNull(method.getResponseHeader("WWW-Authenticate"));
586         assertEquals(200, method.getStatusCode());
587     }
588 
589     /*** 
590      * Test that the Unauthorized response is returned when doAuthentication is false.
591      */
592     public void testDoAuthenticateFalse() throws Exception {
593         client.getState().setCredentials(null, "Protected",
594                 new UsernamePasswordCredentials("name", "pass"));
595         HttpMethod method = new SimpleHttpMethod();
596         method.setDoAuthentication(false);
597         conn.addResponse(
598             "HTTP/1.1 401 Unauthorized\r\n" + 
599             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
600             "Connection: close\r\n" +
601             "Server: HttpClient Test/2.0\r\n");
602         conn.addResponse( 
603             "HTTP/1.1 200 OK\r\n" +
604             "Connection: close\r\n" +
605             "Server: HttpClient Test/2.0\r\n"); 
606         client.executeMethod(method);
607         assertNotNull(method.getResponseHeader("WWW-Authenticate"));
608         assertNull(method.getRequestHeader("Authorization"));
609         assertEquals(401, method.getStatusCode());
610 
611     }
612 
613 
614     /*** 
615      */
616     public void testInvalidCredentials() throws Exception {
617         client.getState().setCredentials(null, "Protected", new UsernamePasswordCredentials("name", "pass"));
618         HttpMethod method = new SimpleHttpMethod();
619         method.setDoAuthentication(false);
620         conn.addResponse(
621             "HTTP/1.1 401 Unauthorized\r\n" + 
622             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
623             "Connection: close\r\n" +
624             "Server: HttpClient Test/2.0\r\n"
625                 );
626         client.executeMethod(method);
627         assertEquals(401, method.getStatusCode());
628     }
629 
630 
631     // --------------------------------- Test Methods for Multiple Authentication
632 
633     public void testMultipleChallengeBasic() throws Exception {
634         client.getState().setCredentials(null, null, new UsernamePasswordCredentials("name", "pass"));
635         HttpMethod method = new SimpleHttpMethod();
636         conn.addResponse(
637             "HTTP/1.1 401 Unauthorized\r\n" + 
638             "WWW-Authenticate: Unsupported\r\n" +
639             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
640             "Connection: close\r\n" +
641             "Server: HttpClient Test/2.0\r\n"
642                 );
643         conn.addResponse( 
644             "HTTP/1.1 200 OK\r\n" +
645             "Connection: close\r\n" +
646             "Server: HttpClient Test/2.0\r\n"
647                 );
648         client.executeMethod(method);
649         Header authHeader = method.getRequestHeader("Authorization");
650         assertNotNull(authHeader);
651 
652         String authValue = authHeader.getValue();
653         assertTrue(authValue.startsWith("Basic"));
654     }
655 
656     public void testMultipleChallengeBasicLongRealm() throws Exception {
657         client.getState().setCredentials(null, null, new UsernamePasswordCredentials("name", "pass"));
658         HttpMethod method = new SimpleHttpMethod();
659         conn.addResponse(
660             "HTTP/1.1 401 Unauthorized\r\n" + 
661             "WWW-Authenticate: Unsupported\r\n" +
662             "WWW-Authenticate: Basic realm=\"This site is protected.  We put this message into the realm string, against all reasonable rationale, so that users would see it in the authentication dialog generated by your browser.\"\r\n" +
663             "Connection: close\r\n" +
664             "Server: HttpClient Test/2.0\r\n"
665                 );
666         conn.addResponse( 
667             "HTTP/1.1 200 OK\r\n" +
668             "Connection: close\r\n" +
669             "Server: HttpClient Test/2.0\r\n"
670                 ); 
671         client.executeMethod(method);
672         Header authHeader = method.getRequestHeader("Authorization");
673         assertNotNull(authHeader);
674 
675         String authValue = authHeader.getValue();
676         assertTrue(authValue.startsWith("Basic"));
677     }
678 
679 
680 
681 
682     public void testMultipleChallengeDigest() throws Exception {
683         client.getState().setCredentials(null, null, new UsernamePasswordCredentials("name", "pass"));
684         HttpMethod method = new SimpleHttpMethod();
685         conn.addResponse(
686             "HTTP/1.1 401 Unauthorized\r\n" + 
687             "WWW-Authenticate: Unsupported\r\n" +
688             "WWW-Authenticate: Digest realm=\"Protected\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"\r\n" +
689             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
690             "Connection: close\r\n" +
691             "Server: HttpClient Test/2.0\r\n"
692                 );
693         conn.addResponse( 
694             "HTTP/1.1 200 OK\r\n" +
695             "Connection: close\r\n" +
696             "Server: HttpClient Test/2.0\r\n"
697                 ); 
698         client.executeMethod(method);
699         Header authHeader = method.getRequestHeader("Authorization");
700         assertNotNull(authHeader);
701 
702         String authValue = authHeader.getValue();
703         assertTrue(authValue.startsWith("Digest"));
704     }
705 
706 
707     public void testMultipleProxyChallengeBasic() throws Exception {
708         client.getState().setProxyCredentials("Protected", null, new UsernamePasswordCredentials("name", "pass"));
709         HttpMethod method = new SimpleHttpMethod();
710         conn.addResponse(
711             "HTTP/1.1 407 Proxy Authentication Required\r\n" + 
712             "Proxy-Authenticate: Basic realm=\"Protected\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"\r\n" +
713             "Proxy-Authenticate: Unsupported\r\n" +
714             "Connection: close\r\n" +
715             "Server: HttpClient Test/2.0\r\n"
716                 );
717         conn.addResponse( 
718             "HTTP/1.1 200 OK\r\n" +
719             "Connection: close\r\n" +
720             "Server: HttpClient Test/2.0\r\n"
721                 ); 
722         client.executeMethod(method);
723         Header authHeader = method.getRequestHeader("Proxy-Authorization");
724         assertNotNull(authHeader);
725 
726         String authValue = authHeader.getValue();
727         assertTrue(authValue.startsWith("Basic"));
728     }
729 
730 
731     public void testMultipleProxyChallengeDigest() throws Exception {
732         client.getState().setProxyCredentials("Protected", null, new UsernamePasswordCredentials("name", "pass"));
733         HttpMethod method = new SimpleHttpMethod();
734         conn.addResponse(
735             "HTTP/1.1 407 Proxy Authentication Required\r\n" + 
736             "Proxy-Authenticate: Basic realm=\"Protected\"\r\n" +
737             "Proxy-Authenticate: Digest realm=\"Protected\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"\r\n" +
738             "Proxy-Authenticate: Unsupported\r\n" +
739             "Connection: close\r\n" +
740             "Server: HttpClient Test/2.0\r\n"
741                 );
742         conn.addResponse( 
743             "HTTP/1.1 200 OK\r\n" +
744             "Connection: close\r\n" +
745             "Server: HttpClient Test/2.0\r\n"
746                 ); 
747         client.executeMethod(method);
748         Header authHeader = method.getRequestHeader("Proxy-Authorization");
749         assertNotNull(authHeader);
750 
751         String authValue = authHeader.getValue();
752         assertTrue(authValue.startsWith("Digest"));
753     }
754 
755 
756     // --------------------------------- Test Methods for Selecting Credentials
757     
758     public void testDefaultCredentials() throws Exception {
759         HttpState state = new HttpState();
760         Credentials expected = new UsernamePasswordCredentials("name", "pass");
761         state.setCredentials(null, null, expected);
762         Credentials got = state.getCredentials("realm", "host");
763         assertEquals(got, expected);
764     }
765     
766     public void testRealmCredentials() throws Exception {
767         HttpState state = new HttpState();
768         Credentials expected = new UsernamePasswordCredentials("name", "pass");
769         state.setCredentials("realm", "host", expected);
770         Credentials got = state.getCredentials("realm", "host");
771         assertEquals(expected, got);
772     }
773     
774     public void testHostCredentials() throws Exception {
775         HttpState state = new HttpState();
776         Credentials expected = new UsernamePasswordCredentials("name", "pass");
777         state.setCredentials(null, "host", expected);
778         Credentials got = state.getCredentials("realm", "host");
779         assertEquals(expected, got);
780     }
781     
782     public void testBothCredentials() throws Exception {
783         HttpState state = new HttpState();
784         Credentials expected = new UsernamePasswordCredentials("name", "pass");
785         state.setCredentials("realm", "host", expected);
786         Credentials got = state.getCredentials("realm", "host");
787         assertEquals(expected, got);
788     }
789     
790     public void testWrongHostCredentials() throws Exception {
791         HttpState state = new HttpState();
792         Credentials expected = new UsernamePasswordCredentials("name", "pass");
793         state.setCredentials(null, "host1", expected);
794         Credentials got = state.getCredentials("realm", "host2");
795         assertNotSame(expected, got);
796     }
797     
798     public void testWrongRealmCredentials() throws Exception {
799         HttpState state = new HttpState();
800         Credentials cred = new UsernamePasswordCredentials("name", "pass");
801         state.setCredentials("realm1", "host", cred);
802         Credentials got = state.getCredentials("realm2", "host");
803         assertNotSame(cred, got);
804     }
805     
806     public void testRealmSpoof() throws Exception {
807         HttpState state = new HttpState();
808         Credentials cred = new UsernamePasswordCredentials("name", "pass");
809         state.setCredentials(null, "admin.apache.org", cred);
810         Credentials got = state.getCredentials("admin.apache.org", "myhost");
811         assertNotSame(cred, got);
812     }
813     
814     public void testRealmSpoof2() throws Exception {
815         HttpState state = new HttpState();
816         Credentials cred = new UsernamePasswordCredentials("name", "pass");
817         state.setCredentials(null, "whatever", cred);
818         Credentials got = state.getCredentials("nullwhatever", null);
819         assertNotSame(cred, got);
820     }
821 }