1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestAuthenticator.java,v 1.25.2.6 2004/02/22 18:21:16 olegk Exp $
3    * $Revision: 1.25.2.6 $
4    * $Date: 2004/02/22 18:21:16 $
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 junit.framework.Test;
34  import junit.framework.TestCase;
35  import junit.framework.TestSuite;
36  
37  import java.util.Hashtable;
38  import java.util.StringTokenizer;
39  import org.apache.commons.httpclient.auth.*;
40  import org.apache.commons.httpclient.util.Base64;
41  
42  /***
43   * Unit tests for {@link Authenticator}.
44   *
45   * @author Rodney Waldhoff
46   * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
47   * @version $Id: TestAuthenticator.java,v 1.25.2.6 2004/02/22 18:21:16 olegk Exp $
48   */
49  public class TestAuthenticator extends TestCase {
50  
51      // ------------------------------------------------------------ Constructor
52      public TestAuthenticator(String testName) {
53          super(testName);
54      }
55  
56      // ------------------------------------------------------------------- Main
57      public static void main(String args[]) {
58          String[] testCaseName = { TestAuthenticator.class.getName() };
59          junit.textui.TestRunner.main(testCaseName);
60      }
61  
62      // ------------------------------------------------------- Utility Methods
63  
64      private void checkAuthorization(UsernamePasswordCredentials cred, String methodName, String auth) throws Exception {
65          Hashtable table = new Hashtable();
66          StringTokenizer tokenizer = new StringTokenizer(auth, ",=\"");
67          while(tokenizer.hasMoreTokens()){
68              String key = null;
69              String value = null;
70              if(tokenizer.hasMoreTokens())
71                  key = tokenizer.nextToken();
72              if(tokenizer.hasMoreTokens()) {
73                  value = tokenizer.nextToken();
74                  assertFalse("Value of "+key+" was \"null\"", "null".equals(value));
75              }
76              if(key != null && value != null){
77                  table.put(key.trim(),value.trim());
78              }
79          }
80          String response = (String) table.get("response");
81          table.put( "methodname", methodName );
82          //System.out.println(auth);
83          String digest = DigestScheme.createDigest(cred.getUserName(),cred.getPassword(), table);
84          assertEquals(response, digest);
85      }
86  
87  
88      // ------------------------------------------------------- TestCase Methods
89  
90      public static Test suite() {
91          return new TestSuite(TestAuthenticator.class);
92      }
93  
94  
95      // ---------------------------------- Test Methods for BasicScheme Authentication
96  
97      public void testBasicAuthenticationWithNoCreds() {
98          String challenge = "Basic realm=\"realm1\"";
99          HttpState state = new HttpState();
100         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
101         try {
102             AuthScheme authscheme = new BasicScheme(challenge);
103             HttpAuthenticator.authenticate(authscheme, method, null, state);
104             fail("Should have thrown HttpException");
105         } catch(HttpException e) {
106             // expected
107         }
108     }
109 
110     public void testBasicAuthenticationWithNoRealm() {
111         String challenge = "Basic";
112         HttpState state = new HttpState();
113         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
114         try {
115             AuthScheme authscheme = new BasicScheme(challenge);
116             HttpAuthenticator.authenticate(authscheme, method, null, state);
117             fail("Should have thrown HttpException");
118         } catch(HttpException e) {
119             // expected
120         }
121     }
122 
123     public void testBasicAuthenticationWithNoRealm2() {
124         String challenge = "Basic ";
125         HttpState state = new HttpState();
126         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
127         try {
128             AuthScheme authscheme = new BasicScheme(challenge);
129             HttpAuthenticator.authenticate(authscheme, method, null, state);
130             fail("Should have thrown HttpException");
131         } catch(HttpException e) {
132             // expected
133         }
134     }
135 
136     public void testBasicAuthenticationWithNullHttpState() throws Exception {
137         String challenge = "Basic realm=\"realm1\"";
138         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
139         try {
140             AuthScheme authscheme = new BasicScheme(challenge);
141             HttpAuthenticator.authenticate(authscheme, method, null, null);
142             fail("Should have thrown IllegalArgumentException");
143         } catch(IllegalArgumentException e) {
144             // expected
145         }
146     }
147 
148     public void testInvalidAuthenticationScheme() throws Exception {
149         String challenge = "invalid realm=\"realm1\"";
150         try{
151             HttpAuthenticator.selectAuthScheme(
152               new Header[] { new Header("WWW-Authenticate", challenge) });
153             fail("Should have thrown UnsupportedOperationException");
154         }catch (UnsupportedOperationException uoe){
155             // expected
156         }
157     }
158 
159     public void testBasicAuthenticationCaseInsensitivity() throws Exception {
160         String challenge = "bAsIc ReAlM=\"realm1\"";
161         HttpState state = new HttpState();
162         state.setCredentials(null, null, new UsernamePasswordCredentials("username","password"));
163         HttpMethod method = new SimpleHttpMethod(new Header("WwW-AuThEnTiCaTe", challenge));
164         AuthScheme authscheme = new BasicScheme(challenge);
165         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
166         assertTrue(null != method.getRequestHeader("Authorization"));
167         String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("username:password")));
168         assertEquals(expected,method.getRequestHeader("Authorization").getValue());
169     }
170 
171 
172     public void testBasicAuthenticationWithDefaultCreds() throws Exception {
173         HttpState state = new HttpState();
174         state.setCredentials(null, null, new UsernamePasswordCredentials("username","password"));
175         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate","Basic realm=\"realm1\""));
176         assertTrue(HttpAuthenticator.authenticateDefault(method, null, state));
177         assertTrue(null != method.getRequestHeader("Authorization"));
178         String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("username:password")));
179         assertEquals(expected,method.getRequestHeader("Authorization").getValue());
180     }
181 
182     public void testBasicAuthentication() throws Exception {
183         String challenge = "Basic realm=\"realm\"";
184         HttpState state = new HttpState();
185         state.setCredentials("realm", null, new UsernamePasswordCredentials("username","password"));
186         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
187         AuthScheme authscheme = new BasicScheme(challenge);
188         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
189         assertTrue(null != method.getRequestHeader("Authorization"));
190         String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("username:password")));
191         assertEquals(expected,method.getRequestHeader("Authorization").getValue());
192     }
193     
194     public void testBasicAuthenticationWith88591Chars() throws Exception {
195         int[] germanChars = { 0xE4, 0x2D, 0xF6, 0x2D, 0xFc };
196         StringBuffer buffer = new StringBuffer();
197         for (int i = 0; i < germanChars.length; i++) {
198             buffer.append((char)germanChars[i]); 
199         }
200         
201         UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("dh", buffer.toString());
202         assertEquals("Basic ZGg65C32Lfw=", BasicScheme.authenticate(credentials));
203     }
204     
205     public void testBasicAuthenticationWithMutlipleRealms() throws Exception {
206         String challenge1 = "Basic realm=\"realm1\"";
207         String challenge2 = "Basic realm=\"realm2\"";
208         HttpState state = new HttpState();
209         state.setCredentials("realm1", null, new UsernamePasswordCredentials("username","password"));
210         state.setCredentials("realm2", null, new UsernamePasswordCredentials("uname2","password2"));
211         AuthScheme authscheme1 = new BasicScheme(challenge1);
212         AuthScheme authscheme2 = new BasicScheme(challenge2);
213         {
214             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate",challenge1));
215             assertTrue(HttpAuthenticator.authenticate(authscheme1, method, null, state));
216             assertTrue(null != method.getRequestHeader("Authorization"));
217             String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("username:password")));
218             assertEquals(expected,method.getRequestHeader("Authorization").getValue());
219         }
220         {
221             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge2));
222             assertTrue(HttpAuthenticator.authenticate(authscheme2, method, null, state));
223             assertTrue(null != method.getRequestHeader("Authorization"));
224             String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("uname2:password2")));
225             assertEquals(expected,method.getRequestHeader("Authorization").getValue());
226         }
227     }
228 
229     public void testPreemptiveAuthorizationTrueNoCreds() throws Exception {
230         HttpState state = new HttpState();
231         HttpMethod method = new SimpleHttpMethod();
232 
233         state.setAuthenticationPreemptive(true);
234         assertTrue(!HttpAuthenticator.authenticateDefault(method, null, state));
235         assertTrue(null == method.getRequestHeader("Authorization"));
236     }
237 
238     public void testPreemptiveAuthorizationTrueWithCreds() throws Exception {
239         HttpState state = new HttpState();
240         HttpMethod method = new SimpleHttpMethod();
241         state.setCredentials(null, null, new UsernamePasswordCredentials("username","password"));
242 
243         state.setAuthenticationPreemptive(true);
244         assertTrue(HttpAuthenticator.authenticateDefault(method, null, state));
245         assertTrue(null != method.getRequestHeader("Authorization"));
246         String expected = "Basic " + HttpConstants.getString(Base64.encode(HttpConstants.getBytes("username:password")));
247         assertEquals(expected, method.getRequestHeader("Authorization").getValue());
248     }
249 
250     // --------------------------------- Test Methods for DigestScheme Authentication
251 
252     public void testDigestAuthenticationWithNoCreds() {
253         String challenge = "Digest realm=\"realm1\", nonce=\"ABC123\"";
254         HttpState state = new HttpState();
255         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
256         try {
257             AuthScheme authscheme = new DigestScheme(challenge);
258             HttpAuthenticator.authenticate(authscheme, method, null, state);
259             fail("Should have thrown HttpException");
260         } catch(HttpException e) {
261             // expected
262         }
263     }
264 
265     public void testDigestAuthenticationWithNoRealm() {
266         String challenge = "Digest";
267         try {
268             AuthScheme authscheme = new DigestScheme(challenge);
269             authscheme.hashCode(); //quiet Eclipse compiler
270             fail("Should have thrown HttpException");
271         } catch(MalformedChallengeException e) {
272             // expected
273         }
274     }
275 
276     public void testDigestAuthenticationWithNoRealm2() {
277         String challenge = "Digest ";
278         try {
279             AuthScheme authscheme = new DigestScheme(challenge);
280             authscheme.hashCode(); //quiet Eclipse compiler
281             fail("Should have thrown HttpException");
282         } catch(MalformedChallengeException e) {
283             // expected
284         }
285     }
286 
287     public void testDigestAuthenticationWithNullHttpState() throws Exception {
288         String challenge = "Digest realm=\"realm1\", nonce=\"ABC123\"";
289         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
290         try {
291             AuthScheme authscheme = new DigestScheme(challenge);
292             HttpAuthenticator.authenticate(authscheme, method, null, null);
293             fail("Should have thrown IllegalArgumentException");
294         } catch(IllegalArgumentException e) {
295             // expected
296         }
297     }
298 
299     public void testDigestAuthenticationCaseInsensitivity() throws Exception {
300         String challenge = "dIgEsT ReAlM=\"realm1\", nONce=\"ABC123\"";
301         HttpState state = new HttpState();
302         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
303         state.setCredentials(null, null, cred);
304         HttpMethod method = new SimpleHttpMethod(new Header("WwW-AuThEnTiCaTe", challenge));
305         AuthScheme authscheme = new DigestScheme(challenge);
306         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
307         assertTrue(null != method.getRequestHeader("Authorization"));
308     }
309 
310 
311     public void testDigestAuthenticationWithDefaultCreds() throws Exception {
312         String challenge = "Digest realm=\"realm1\", nonce=\"ABC123\"";
313         HttpState state = new HttpState();
314         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
315         state.setCredentials(null, null, cred);
316         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
317         AuthScheme authscheme = new DigestScheme(challenge);
318         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
319         assertTrue(null != method.getRequestHeader("Authorization"));
320         checkAuthorization(cred, method.getName(), method.getRequestHeader("Authorization").getValue());
321     }
322 
323     public void testDigestAuthentication() throws Exception {
324         String challenge = "Digest realm=\"realm1\", nonce=\"ABC123\"";
325         HttpState state = new HttpState();
326         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
327         state.setCredentials(null, null, cred);
328         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
329         AuthScheme authscheme = new DigestScheme(challenge);
330         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
331         assertTrue(null != method.getRequestHeader("Authorization"));
332         checkAuthorization(cred, method.getName(), method.getRequestHeader("Authorization").getValue());
333     }
334 
335     public void testDigestAuthenticationWithStaleNonce() throws Exception {
336         
337         String headers =
338             "HTTP/1.1 401 OK\r\n" +
339             "Connection: close\r\n" +
340             "Content-Length: 0\r\n" +
341             "WWW-Authenticate: Digest realm=\"realm1\", nonce=\"ABC123\"\r\n";
342         String headers2 =
343             "HTTP/1.1 401 OK\r\n" +
344             "Connection: close\r\n" +
345             "Content-Length: 0\r\n" +
346             "WWW-Authenticate: Digest realm=\"realm1\", nonce=\"321CBA\", stale=\"true\"\r\n";
347         String headers3 = 
348             "HTTP/1.1 200 OK\r\n" +
349             "Connection: close\r\n" +
350             "Server: HttpClient Test/2.0\r\n\r\n" +
351             "stuff\r\n";
352         
353         SimpleHttpConnection conn = new SimpleHttpConnection();
354         
355         conn.addResponse(headers);
356         conn.addResponse(headers2);
357         conn.addResponse(headers3);
358         HttpState state = new HttpState();
359         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
360         state.setCredentials(null, null, cred);
361 
362         SimpleHttpMethod method = new SimpleHttpMethod();
363         method.setDoAuthentication(true);
364         assertEquals("Authentication failed", 200, method.execute(state, conn));
365         checkAuthorization(cred, method.getName(), method.getRequestHeader("Authorization").getValue());
366     }
367 
368     public void testDigestAuthenticationWithMultipleRealms() throws Exception {
369         String challenge1 = "Digest realm=\"realm1\", nonce=\"ABC123\"";
370         String challenge2 = "Digest realm=\"realm2\", nonce=\"ABC123\"";
371         HttpState state = new HttpState();
372         UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
373         state.setCredentials("realm1", null, cred);
374         UsernamePasswordCredentials cred2 = new UsernamePasswordCredentials("uname2","password2");
375         state.setCredentials("realm2", null, cred2);
376         AuthScheme authscheme1 = new DigestScheme(challenge1);
377         AuthScheme authscheme2 = new DigestScheme(challenge2);
378         {
379             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate",challenge1));
380             assertTrue(HttpAuthenticator.authenticate(authscheme1, method, null, state));
381             assertTrue(null != method.getRequestHeader("Authorization"));
382             checkAuthorization(cred, method.getName(), method.getRequestHeader("Authorization").getValue());
383         }
384         {
385             HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate",challenge2));
386             assertTrue(HttpAuthenticator.authenticate(authscheme2, method, null, state));
387             assertTrue(null != method.getRequestHeader("Authorization"));
388             checkAuthorization(cred2, method.getName(), method.getRequestHeader("Authorization").getValue());
389         }
390     }
391 
392     /*** 
393      * Test digest authentication using the MD5-sess algorithm.
394      */
395     public void testDigestAuthenticationMD5Sess() throws Exception {
396         // Example using Digest auth with MD5-sess
397 
398         String realm="realm";
399         String username="username";
400         String password="password";
401         String nonce="e273f1776275974f1a120d8b92c5b3cb";
402 
403         String challenge="Digest realm=\"" + realm + "\", "
404             + "nonce=\"" + nonce + "\", "
405             + "opaque=\"SomeString\", "
406             + "stale=false, "
407             + "algorithm=MD5-sess, "
408             + "qop=\"auth\"";
409 
410         HttpState state = new HttpState();
411         UsernamePasswordCredentials cred =
412             new UsernamePasswordCredentials(username, password);
413         state.setCredentials(realm, null, cred);
414         AuthScheme authscheme = new DigestScheme(challenge);
415         HttpMethod method =
416             new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
417         assertTrue(HttpAuthenticator.authenticate(
418             authscheme, method, null, state));
419         assertTrue(null != method.getRequestHeader("Authorization"));
420         checkAuthorization(cred, method.getName(),
421             method.getRequestHeader("Authorization").getValue());
422     }
423 
424     // --------------------------------- Test Methods for NTLM Authentication
425 
426     public void testNTLMAuthenticationWithNoCreds() {
427         String challenge = "NTLM";
428         HttpState state = new HttpState();
429         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
430         method.addRequestHeader("Host", "host");
431         try {
432             AuthScheme authscheme = new NTLMScheme(challenge);
433             HttpAuthenticator.authenticate(authscheme, method, null, state);
434             fail("Should have thrown HttpException");
435         } catch(HttpException e) {
436             // expected
437         }
438     }
439 
440     public void testNTLMAuthenticationWithNullHttpState() throws Exception {
441         String challenge = "NTLM";
442         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
443         method.addRequestHeader("Host", "host");
444         try {
445             AuthScheme authscheme = new NTLMScheme(challenge);
446             HttpAuthenticator.authenticate(authscheme, method, null, null);
447             fail("Should have thrown IllegalArgumentException");
448         } catch(IllegalArgumentException e) {
449             // expected
450         }
451     }
452 
453     public void testNTLMAuthenticationCaseInsensitivity() throws Exception {
454         String challenge = "nTlM";
455         HttpState state = new HttpState();
456         NTCredentials cred = new NTCredentials("username","password", "host",
457                 "domain");
458         state.setCredentials(null, null, cred);
459         HttpMethod method = new SimpleHttpMethod(new Header("WwW-AuThEnTiCaTe", challenge));
460         AuthScheme authscheme = new NTLMScheme(challenge);
461         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
462         assertTrue(null != method.getRequestHeader("Authorization"));
463     }
464 
465     public void testNTLMAuthenticationResponse1() throws Exception {
466         String challenge = "NTLM";
467         String expected = "NTLM TlRMTVNTUAABAAAABlIAAAYABgAkAAAABAAEACAAAABIT" +
468             "1NURE9NQUlO";
469         HttpState state = new HttpState();
470         NTCredentials cred = new NTCredentials("username","password", "host",
471                 "domain");
472         state.setCredentials(null, null, cred);
473         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
474         AuthScheme authscheme = new NTLMScheme(challenge);
475         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
476         assertTrue(null != method.getRequestHeader("Authorization"));
477         assertEquals(expected,
478                 method.getRequestHeader("Authorization").getValue());
479     }
480     
481     public void testNTLMAuthenticationResponse2() throws Exception {
482         String challenge = 
483             "NTLM TlRMTVNTUAACAAAACgAKADAAAAAGgoEAPc4kP4LtCV8AAAAAAAAAAJ4AngA" +
484             "6AAAASU5UUkFFUEhPWAIAFABJAE4AVABSAEEARQBQAEgATwBYAAEAEgBCAE8AQQB" +
485             "SAEQAUgBPAE8ATQAEACgAaQBuAHQAcgBhAGUAcABoAG8AeAAuAGUAcABoAG8AeAA" +
486             "uAGMAbwBtAAMAPABCAG8AYQByAGQAcgBvAG8AbQAuAGkAbgB0AHIAYQBlAHAAaAB" +
487             "vAHgALgBlAHAAaABvAHgALgBjAG8AbQAAAAAA";
488 
489         String expected = "NTLM TlRMTVNTUAADAAAAGAAYAFIAAAAAAAAAagAAAAYABgB" +
490             "AAAAACAAIAEYAAAAEAAQATgAAAAAAAABqAAAABlIAAERPTUFJTlVTRVJOQU1FSE" +
491             "9TVAaC+vLxUEHnUtpItj9Dp4kzwQfd61Lztg==";
492         HttpState state = new HttpState();
493         NTCredentials cred = new NTCredentials("username","password", "host",
494                 "domain");
495         state.setCredentials(null, null, cred);
496         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
497         AuthScheme authscheme = new NTLMScheme(challenge);
498         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
499         assertTrue(null != method.getRequestHeader("Authorization"));
500         assertEquals(expected,
501                 method.getRequestHeader("Authorization").getValue());
502     }
503     
504     public void testNTLMAuthenticationWithDefaultCreds() throws Exception {
505         String challenge = 
506             "NTLM TlRMTVNTUAACAAAACgAKADAAAAAGgoEAPc4kP4LtCV8AAAAAAAAAAJ4AngA" +
507             "6AAAASU5UUkFFUEhPWAIAFABJAE4AVABSAEEARQBQAEgATwBYAAEAEgBCAE8AQQB" +
508             "SAEQAUgBPAE8ATQAEACgAaQBuAHQAcgBhAGUAcABoAG8AeAAuAGUAcABoAG8AeAA" +
509             "uAGMAbwBtAAMAPABCAG8AYQByAGQAcgBvAG8AbQAuAGkAbgB0AHIAYQBlAHAAaAB" +
510             "vAHgALgBlAHAAaABvAHgALgBjAG8AbQAAAAAA";
511         String expected = "NTLM TlRMTVNTUAADAAAAGAAYAFIAAAAAAAAAagAAAAYABgB" +
512             "AAAAACAAIAEYAAAAEAAQATgAAAAAAAABqAAAABlIAAERPTUFJTlVTRVJOQU1FSE" +
513             "9TVAaC+vLxUEHnUtpItj9Dp4kzwQfd61Lztg==";
514         HttpState state = new HttpState();
515         NTCredentials cred = new NTCredentials("username","password", "host",
516                 "domain");
517         state.setCredentials(null, null, cred);
518         HttpMethod method = new SimpleHttpMethod(new Header("WWW-Authenticate", challenge));
519         method.addRequestHeader("Host", "host");
520         AuthScheme authscheme = new NTLMScheme(challenge);
521         assertTrue(HttpAuthenticator.authenticate(authscheme, method, null, state));
522         assertTrue(null != method.getRequestHeader("Authorization"));
523         assertEquals(expected,
524                 method.getRequestHeader("Authorization").getValue());
525     }
526     
527     public void testNTLMAuthenticationRetry() throws Exception {
528         NTCredentials cred = new NTCredentials("username", "password", "host", "domain");
529         HttpState state = new HttpState();
530         state.setCredentials(null, null, cred);
531         HttpMethod method = new SimpleHttpMethod();
532         SimpleHttpConnection conn = new SimpleHttpConnection();
533         conn.addResponse(
534             "HTTP/1.1 401 Unauthorized\r\n" +
535             "WWW-Authenticate: NTLM\r\n" +
536             "Connection: close\r\n" +
537             "Server: HttpClient Test/2.0\r\n");
538         conn.addResponse(
539             "HTTP/1.1 401 Unauthorized\r\n" +
540             "WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n" +
541             "Connection: close\r\n" +
542             "Server: HttpClient Test/2.0\r\n");
543         conn.addResponse(
544             "HTTP/1.1 200 OK\r\n" +
545             "Connection: close\r\n" +
546             "Server: HttpClient Test/2.0\r\n\r\n" +
547             "stuff\r\n");
548         method.execute(state, conn);
549         assertNull(method.getResponseHeader("WWW-Authenticate"));
550         assertEquals(200, method.getStatusCode());
551     }
552 
553     /*** 
554      * Test that the Unauthorized response is returned when doAuthentication is false.
555      */
556     public void testDoAuthenticateFalse() throws Exception {
557         HttpState state = new HttpState();
558         state.setCredentials(null, "Protected",
559                 new UsernamePasswordCredentials("name", "pass"));
560         HttpMethod method = new SimpleHttpMethod();
561         method.setDoAuthentication(false);
562         SimpleHttpConnection conn = new SimpleHttpConnection();
563         conn.addResponse(
564             "HTTP/1.1 401 Unauthorized\r\n" + 
565             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
566             "Connection: close\r\n" +
567             "Server: HttpClient Test/2.0\r\n");
568         conn.addResponse( 
569             "HTTP/1.1 200 OK\r\n" +
570             "Connection: close\r\n" +
571             "Server: HttpClient Test/2.0\r\n"); 
572         method.execute(state, conn);
573         assertNotNull(method.getResponseHeader("WWW-Authenticate"));
574         assertNull(method.getRequestHeader("Authorization"));
575         assertEquals(401, method.getStatusCode());
576 
577     }
578 
579 
580     /*** 
581      */
582     public void testInvalidCredentials() throws Exception {
583         HttpState state = new HttpState();
584         state.setCredentials(null, "Protected", new UsernamePasswordCredentials("name", "pass"));
585         HttpMethod method = new SimpleHttpMethod();
586         method.setDoAuthentication(false);
587         SimpleHttpConnection conn = new SimpleHttpConnection();
588         conn.addResponse(
589             "HTTP/1.1 401 Unauthorized\r\n" + 
590             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
591             "Connection: close\r\n" +
592             "Server: HttpClient Test/2.0\r\n"
593                 );
594         method.execute(state, conn);
595         assertEquals(401, method.getStatusCode());
596     }
597 
598 
599     // --------------------------------- Test Methods for Multiple Authentication
600 
601     public void testMultipleChallengeBasic() throws Exception {
602         HttpState state = new HttpState();
603         state.setCredentials("Protected", null, new UsernamePasswordCredentials("name", "pass"));
604         HttpMethod method = new SimpleHttpMethod();
605         SimpleHttpConnection conn = new SimpleHttpConnection();
606         conn.addResponse(
607             "HTTP/1.1 401 Unauthorized\r\n" + 
608             "WWW-Authenticate: Unsupported\r\n" +
609             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
610             "Connection: close\r\n" +
611             "Server: HttpClient Test/2.0\r\n"
612                 );
613         conn.addResponse( 
614             "HTTP/1.1 200 OK\r\n" +
615             "Connection: close\r\n" +
616             "Server: HttpClient Test/2.0\r\n"
617                 ); 
618         method.execute(state, conn);
619         Header authHeader = method.getRequestHeader("Authorization");
620         assertNotNull(authHeader);
621 
622         String authValue = authHeader.getValue();
623         assertTrue(authValue.startsWith("Basic"));
624     }
625 
626     public void testMultipleChallengeBasicLongRealm() throws Exception {
627         HttpState state = new HttpState();
628         state.setCredentials(null, null, new UsernamePasswordCredentials("name", "pass"));
629         HttpMethod method = new SimpleHttpMethod();
630         SimpleHttpConnection conn = new SimpleHttpConnection();
631         conn.addResponse(
632             "HTTP/1.1 401 Unauthorized\r\n" + 
633             "WWW-Authenticate: Unsupported\r\n" +
634             "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" +
635             "Connection: close\r\n" +
636             "Server: HttpClient Test/2.0\r\n"
637                 );
638         conn.addResponse( 
639             "HTTP/1.1 200 OK\r\n" +
640             "Connection: close\r\n" +
641             "Server: HttpClient Test/2.0\r\n"
642                 ); 
643         method.execute(state, conn);
644         Header authHeader = method.getRequestHeader("Authorization");
645         assertNotNull(authHeader);
646 
647         String authValue = authHeader.getValue();
648         assertTrue(authValue.startsWith("Basic"));
649     }
650 
651 
652 
653 
654     public void testMultipleChallengeDigest() throws Exception {
655         HttpState state = new HttpState();
656         state.setCredentials("Protected", null, new UsernamePasswordCredentials("name", "pass"));
657         HttpMethod method = new SimpleHttpMethod();
658         SimpleHttpConnection conn = new SimpleHttpConnection();
659         conn.addResponse(
660             "HTTP/1.1 401 Unauthorized\r\n" + 
661             "WWW-Authenticate: Unsupported\r\n" +
662             "WWW-Authenticate: Digest realm=\"Protected\", nonce=\"ABC123\"\r\n" +
663             "WWW-Authenticate: Basic realm=\"Protected\"\r\n" +
664             "Connection: close\r\n" +
665             "Server: HttpClient Test/2.0\r\n"
666                 );
667         conn.addResponse( 
668             "HTTP/1.1 200 OK\r\n" +
669             "Connection: close\r\n" +
670             "Server: HttpClient Test/2.0\r\n"
671                 ); 
672         method.execute(state, conn);
673         Header authHeader = method.getRequestHeader("Authorization");
674         assertNotNull(authHeader);
675 
676         String authValue = authHeader.getValue();
677         assertTrue(authValue.startsWith("Digest"));
678     }
679 
680 
681     public void testMultipleProxyChallengeBasic() throws Exception {
682         HttpState state = new HttpState();
683         state.setProxyCredentials("Protected", new UsernamePasswordCredentials("name", "pass"));
684         HttpMethod method = new SimpleHttpMethod();
685         SimpleHttpConnection conn = new SimpleHttpConnection();
686         conn.addResponse(
687             "HTTP/1.1 407 Proxy Authentication Required\r\n" + 
688             "Proxy-Authenticate: Basic realm=\"Protected\"\r\n" +
689             "Proxy-Authenticate: Unsupported\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         method.execute(state, conn);
699         Header authHeader = method.getRequestHeader("Proxy-Authorization");
700         assertNotNull(authHeader);
701 
702         String authValue = authHeader.getValue();
703         assertTrue(authValue.startsWith("Basic"));
704     }
705 
706 
707     public void testMultipleProxyChallengeDigest() throws Exception {
708         HttpState state = new HttpState();
709         state.setProxyCredentials("Protected", new UsernamePasswordCredentials("name", "pass"));
710         HttpMethod method = new SimpleHttpMethod();
711         SimpleHttpConnection conn = new SimpleHttpConnection();
712         conn.addResponse(
713             "HTTP/1.1 407 Proxy Authentication Required\r\n" + 
714             "Proxy-Authenticate: Basic realm=\"Protected\"\r\n" +
715             "Proxy-Authenticate: Digest realm=\"Protected\", nonce=\"ABC123\"\r\n" +
716             "Proxy-Authenticate: Unsupported\r\n" +
717             "Connection: close\r\n" +
718             "Server: HttpClient Test/2.0\r\n"
719                 );
720         conn.addResponse( 
721             "HTTP/1.1 200 OK\r\n" +
722             "Connection: close\r\n" +
723             "Server: HttpClient Test/2.0\r\n"
724                 ); 
725         method.execute(state, conn);
726         Header authHeader = method.getRequestHeader("Proxy-Authorization");
727         assertNotNull(authHeader);
728 
729         String authValue = authHeader.getValue();
730         assertTrue(authValue.startsWith("Digest"));
731     }
732 
733 
734     // --------------------------------- Test Methods for Selecting Credentials
735     
736     public void testDefaultCredentials() throws Exception {
737         HttpState state = new HttpState();
738         Credentials expected = new UsernamePasswordCredentials("name", "pass");
739         state.setCredentials(null, null, expected);
740         Credentials got = state.getCredentials("realm", "host");
741         assertEquals(got, expected);
742     }
743     
744     public void testRealmCredentials() throws Exception {
745         HttpState state = new HttpState();
746         Credentials expected = new UsernamePasswordCredentials("name", "pass");
747         state.setCredentials("realm", null, expected);
748         Credentials got = state.getCredentials("realm", "host");
749         assertEquals(expected, got);
750     }
751     
752     public void testHostCredentials() throws Exception {
753         HttpState state = new HttpState();
754         Credentials expected = new UsernamePasswordCredentials("name", "pass");
755         state.setCredentials(null, "host", expected);
756         Credentials got = state.getCredentials("realm", "host");
757         assertEquals(expected, got);
758     }
759     
760     public void testBothCredentials() throws Exception {
761         HttpState state = new HttpState();
762         Credentials expected = new UsernamePasswordCredentials("name", "pass");
763         state.setCredentials("realm", "host", expected);
764         Credentials got = state.getCredentials("realm", "host");
765         assertEquals(expected, got);
766     }
767     
768     public void testWrongHostCredentials() throws Exception {
769         HttpState state = new HttpState();
770         Credentials expected = new UsernamePasswordCredentials("name", "pass");
771         state.setCredentials(null, "host1", expected);
772         Credentials got = state.getCredentials("realm", "host2");
773         assertNotSame(expected, got);
774     }
775     
776     public void testWrongRealmCredentials() throws Exception {
777         HttpState state = new HttpState();
778         Credentials cred = new UsernamePasswordCredentials("name", "pass");
779         state.setCredentials("realm1", "host", cred);
780         Credentials got = state.getCredentials("realm2", "host");
781         assertNotSame(cred, got);
782     }
783     
784     public void testRealmSpoof() throws Exception {
785         HttpState state = new HttpState();
786         Credentials cred = new UsernamePasswordCredentials("name", "pass");
787         state.setCredentials(null, "admin.apache.org", cred);
788         Credentials got = state.getCredentials("admin.apache.org", "myhost");
789         assertNotSame(cred, got);
790     }
791     
792     public void testRealmSpoof2() throws Exception {
793         HttpState state = new HttpState();
794         Credentials cred = new UsernamePasswordCredentials("name", "pass");
795         state.setCredentials(null, "whatever", cred);
796         Credentials got = state.getCredentials("nullwhatever", null);
797         assertNotSame(cred, got);
798     }
799 }