View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.impl.client.integration;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.IOException;
31  import java.util.concurrent.atomic.AtomicLong;
32  
33  import org.apache.http.Consts;
34  import org.apache.http.HttpEntity;
35  import org.apache.http.HttpException;
36  import org.apache.http.HttpHost;
37  import org.apache.http.HttpInetConnection;
38  import org.apache.http.HttpRequest;
39  import org.apache.http.HttpResponse;
40  import org.apache.http.HttpStatus;
41  import org.apache.http.auth.AUTH;
42  import org.apache.http.auth.AuthScope;
43  import org.apache.http.auth.Credentials;
44  import org.apache.http.auth.UsernamePasswordCredentials;
45  import org.apache.http.client.AuthCache;
46  import org.apache.http.client.ClientProtocolException;
47  import org.apache.http.client.CredentialsProvider;
48  import org.apache.http.client.NonRepeatableRequestException;
49  import org.apache.http.client.config.RequestConfig;
50  import org.apache.http.client.methods.HttpGet;
51  import org.apache.http.client.methods.HttpPost;
52  import org.apache.http.client.methods.HttpPut;
53  import org.apache.http.client.protocol.HttpClientContext;
54  import org.apache.http.entity.InputStreamEntity;
55  import org.apache.http.entity.StringEntity;
56  import org.apache.http.impl.auth.BasicScheme;
57  import org.apache.http.impl.client.BasicAuthCache;
58  import org.apache.http.impl.client.BasicCredentialsProvider;
59  import org.apache.http.impl.client.TargetAuthenticationStrategy;
60  import org.apache.http.localserver.BasicAuthTokenExtractor;
61  import org.apache.http.localserver.LocalServerTestBase;
62  import org.apache.http.localserver.RequestBasicAuth;
63  import org.apache.http.localserver.ResponseBasicUnauthorized;
64  import org.apache.http.message.BasicHeader;
65  import org.apache.http.protocol.HTTP;
66  import org.apache.http.protocol.HttpContext;
67  import org.apache.http.protocol.HttpCoreContext;
68  import org.apache.http.protocol.HttpExpectationVerifier;
69  import org.apache.http.protocol.HttpProcessor;
70  import org.apache.http.protocol.HttpProcessorBuilder;
71  import org.apache.http.protocol.HttpRequestHandler;
72  import org.apache.http.protocol.ResponseConnControl;
73  import org.apache.http.protocol.ResponseContent;
74  import org.apache.http.protocol.ResponseDate;
75  import org.apache.http.protocol.ResponseServer;
76  import org.apache.http.util.EntityUtils;
77  import org.junit.Assert;
78  import org.junit.Before;
79  import org.junit.Test;
80  
81  /**
82   * Unit tests for automatic client authentication.
83   */
84  public class TestClientAuthentication extends LocalServerTestBase {
85  
86      @Before @Override
87      public void setUp() throws Exception {
88          super.setUp();
89          final HttpProcessor httpproc = HttpProcessorBuilder.create()
90              .add(new ResponseDate())
91              .add(new ResponseServer(LocalServerTestBase.ORIGIN))
92              .add(new ResponseContent())
93              .add(new ResponseConnControl())
94              .add(new RequestBasicAuth())
95              .add(new ResponseBasicUnauthorized()).build();
96          this.serverBootstrap.setHttpProcessor(httpproc);
97      }
98  
99      static class AuthHandler implements HttpRequestHandler {
100 
101         @Override
102         public void handle(
103                 final HttpRequest request,
104                 final HttpResponse response,
105                 final HttpContext context) throws HttpException, IOException {
106             final String creds = (String) context.getAttribute("creds");
107             if (creds == null || !creds.equals("test:test")) {
108                 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
109             } else {
110                 response.setStatusCode(HttpStatus.SC_OK);
111                 final StringEntity entity = new StringEntity("success", Consts.ASCII);
112                 response.setEntity(entity);
113             }
114         }
115 
116     }
117 
118     static class AuthExpectationVerifier implements HttpExpectationVerifier {
119 
120         private final BasicAuthTokenExtractor authTokenExtractor;
121 
122         public AuthExpectationVerifier() {
123             super();
124             this.authTokenExtractor = new BasicAuthTokenExtractor();
125         }
126 
127         @Override
128         public void verify(
129                 final HttpRequest request,
130                 final HttpResponse response,
131                 final HttpContext context) throws HttpException {
132             final String creds = this.authTokenExtractor.extract(request);
133             if (creds == null || !creds.equals("test:test")) {
134                 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
135             } else {
136                 response.setStatusCode(HttpStatus.SC_CONTINUE);
137             }
138         }
139 
140     }
141 
142     static class TestCredentialsProvider implements CredentialsProvider {
143 
144         private final Credentials creds;
145         private AuthScope authscope;
146 
147         TestCredentialsProvider(final Credentials creds) {
148             super();
149             this.creds = creds;
150         }
151 
152         @Override
153         public void clear() {
154         }
155 
156         @Override
157         public Credentials getCredentials(final AuthScope authscope) {
158             this.authscope = authscope;
159             return this.creds;
160         }
161 
162         @Override
163         public void setCredentials(final AuthScope authscope, final Credentials credentials) {
164         }
165 
166         public AuthScope getAuthScope() {
167             return this.authscope;
168         }
169 
170     }
171 
172     @Test
173     public void testBasicAuthenticationNoCreds() throws Exception {
174         this.serverBootstrap.registerHandler("*", new AuthHandler());
175 
176         final HttpHost target = start();
177 
178         final HttpClientContext context = HttpClientContext.create();
179         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
180         context.setCredentialsProvider(credsProvider);
181         final HttpGet httpget = new HttpGet("/");
182 
183         final HttpResponse response = this.httpclient.execute(target, httpget, context);
184         final HttpEntity entity = response.getEntity();
185         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
186         Assert.assertNotNull(entity);
187         EntityUtils.consume(entity);
188         final AuthScope authscope = credsProvider.getAuthScope();
189         Assert.assertNotNull(authscope);
190         Assert.assertEquals("test realm", authscope.getRealm());
191     }
192 
193     @Test
194     public void testBasicAuthenticationFailure() throws Exception {
195         this.serverBootstrap.registerHandler("*", new AuthHandler());
196 
197         final HttpHost target = start();
198 
199         final HttpClientContext context = HttpClientContext.create();
200         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
201                 new UsernamePasswordCredentials("test", "all-wrong"));
202         context.setCredentialsProvider(credsProvider);
203         final HttpGet httpget = new HttpGet("/");
204 
205         final HttpResponse response = this.httpclient.execute(target, httpget, context);
206         final HttpEntity entity = response.getEntity();
207         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
208         Assert.assertNotNull(entity);
209         EntityUtils.consume(entity);
210         final AuthScope authscope = credsProvider.getAuthScope();
211         Assert.assertNotNull(authscope);
212         Assert.assertEquals("test realm", authscope.getRealm());
213     }
214 
215     @Test
216     public void testBasicAuthenticationSuccess() throws Exception {
217         this.serverBootstrap.registerHandler("*", new AuthHandler());
218 
219         final HttpGet httpget = new HttpGet("/");
220         final HttpClientContext context = HttpClientContext.create();
221         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
222                 new UsernamePasswordCredentials("test", "test"));
223         context.setCredentialsProvider(credsProvider);
224 
225         final HttpHost target = start();
226 
227         final HttpResponse response = this.httpclient.execute(target, httpget, context);
228         final HttpEntity entity = response.getEntity();
229         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
230         Assert.assertNotNull(entity);
231         EntityUtils.consume(entity);
232         final AuthScope authscope = credsProvider.getAuthScope();
233         Assert.assertNotNull(authscope);
234         Assert.assertEquals("test realm", authscope.getRealm());
235     }
236 
237     @Test
238     public void testBasicAuthenticationSuccessOnNonRepeatablePutExpectContinue() throws Exception {
239         final HttpProcessor httpproc = HttpProcessorBuilder.create()
240             .add(new ResponseDate())
241             .add(new ResponseServer(LocalServerTestBase.ORIGIN))
242             .add(new ResponseContent())
243             .add(new ResponseConnControl())
244             .add(new RequestBasicAuth())
245             .add(new ResponseBasicUnauthorized()).build();
246         this.serverBootstrap.setHttpProcessor(httpproc)
247             .setExpectationVerifier(new AuthExpectationVerifier())
248             .registerHandler("*", new AuthHandler());
249 
250         final HttpHost target = start();
251 
252         final RequestConfig config = RequestConfig.custom()
253                 .setExpectContinueEnabled(true)
254                 .build();
255         final HttpPut httpput = new HttpPut("/");
256         httpput.setConfig(config);
257         httpput.setEntity(new InputStreamEntity(
258                 new ByteArrayInputStream(
259                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
260                         -1));
261         final HttpClientContext context = HttpClientContext.create();
262         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
263                 new UsernamePasswordCredentials("test", "test"));
264         context.setCredentialsProvider(credsProvider);
265 
266         final HttpResponse response = this.httpclient.execute(target, httpput, context);
267         final HttpEntity entity = response.getEntity();
268         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
269         Assert.assertNotNull(entity);
270     }
271 
272     @Test(expected=ClientProtocolException.class)
273     public void testBasicAuthenticationFailureOnNonRepeatablePutDontExpectContinue() throws Exception {
274         this.serverBootstrap.registerHandler("*", new AuthHandler());
275 
276         final HttpHost target = start();
277 
278         final RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(true).build();
279         final HttpPut httpput = new HttpPut("/");
280         httpput.setConfig(config);
281         httpput.setEntity(new InputStreamEntity(
282                 new ByteArrayInputStream(
283                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
284                         -1));
285 
286         final HttpClientContext context = HttpClientContext.create();
287         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
288                 new UsernamePasswordCredentials("test", "boom"));
289         context.setCredentialsProvider(credsProvider);
290 
291         try {
292             this.httpclient.execute(target, httpput, context);
293             Assert.fail("ClientProtocolException should have been thrown");
294         } catch (final ClientProtocolException ex) {
295             final Throwable cause = ex.getCause();
296             Assert.assertNotNull(cause);
297             Assert.assertTrue(cause instanceof NonRepeatableRequestException);
298             throw ex;
299         }
300     }
301 
302     @Test
303     public void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception {
304         this.serverBootstrap.registerHandler("*", new AuthHandler());
305 
306         final HttpHost target = start();
307 
308         final HttpPost httppost = new HttpPost("/");
309         httppost.setEntity(new StringEntity("some important stuff", Consts.ASCII));
310 
311         final HttpClientContext context = HttpClientContext.create();
312         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
313                 new UsernamePasswordCredentials("test", "test"));
314         context.setCredentialsProvider(credsProvider);
315 
316         final HttpResponse response = this.httpclient.execute(target, httppost, context);
317         final HttpEntity entity = response.getEntity();
318         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
319         Assert.assertNotNull(entity);
320         EntityUtils.consume(entity);
321         final AuthScope authscope = credsProvider.getAuthScope();
322         Assert.assertNotNull(authscope);
323         Assert.assertEquals("test realm", authscope.getRealm());
324     }
325 
326     @Test(expected=ClientProtocolException.class)
327     public void testBasicAuthenticationFailureOnNonRepeatablePost() throws Exception {
328         this.serverBootstrap.registerHandler("*", new AuthHandler());
329 
330         final HttpHost target = start();
331 
332         final HttpPost httppost = new HttpPost("/");
333         httppost.setEntity(new InputStreamEntity(
334                 new ByteArrayInputStream(
335                         new byte[] { 0,1,2,3,4,5,6,7,8,9 }), -1));
336 
337         final HttpClientContext context = HttpClientContext.create();
338         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
339                 new UsernamePasswordCredentials("test", "test"));
340         context.setCredentialsProvider(credsProvider);
341 
342         try {
343             this.httpclient.execute(target, httppost, context);
344             Assert.fail("ClientProtocolException should have been thrown");
345         } catch (final ClientProtocolException ex) {
346             final Throwable cause = ex.getCause();
347             Assert.assertNotNull(cause);
348             Assert.assertTrue(cause instanceof NonRepeatableRequestException);
349             throw ex;
350         }
351     }
352 
353     static class TestTargetAuthenticationStrategy extends TargetAuthenticationStrategy {
354 
355         private final AtomicLong count;
356 
357         public TestTargetAuthenticationStrategy() {
358             super();
359             this.count = new AtomicLong();
360         }
361 
362         @Override
363         public boolean isAuthenticationRequested(
364                 final HttpHost host,
365                 final HttpResponse response,
366                 final HttpContext context) {
367             final boolean res = super.isAuthenticationRequested(host, response, context);
368             if (res == true) {
369                 this.count.incrementAndGet();
370             }
371             return res;
372         }
373 
374         public long getCount() {
375             return this.count.get();
376         }
377 
378     }
379 
380     @Test
381     public void testBasicAuthenticationCredentialsCaching() throws Exception {
382         this.serverBootstrap.registerHandler("*", new AuthHandler());
383 
384         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
385         this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
386 
387         final HttpHost target = start();
388 
389         final HttpClientContext context = HttpClientContext.create();
390         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
391         credsProvider.setCredentials(AuthScope.ANY,
392                 new UsernamePasswordCredentials("test", "test"));
393         context.setCredentialsProvider(credsProvider);
394 
395         final HttpGet httpget = new HttpGet("/");
396 
397         final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
398         final HttpEntity entity1 = response1.getEntity();
399         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
400         Assert.assertNotNull(entity1);
401         EntityUtils.consume(entity1);
402 
403         final HttpResponse response2 = this.httpclient.execute(target, httpget, context);
404         final HttpEntity entity2 = response1.getEntity();
405         Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
406         Assert.assertNotNull(entity2);
407         EntityUtils.consume(entity2);
408 
409         Assert.assertEquals(1, authStrategy.getCount());
410     }
411 
412     static class RealmAuthHandler implements HttpRequestHandler {
413 
414         final String realm;
415         final String realmCreds;
416 
417         public RealmAuthHandler(final String realm, final String realmCreds) {
418             this.realm = realm;
419             this.realmCreds = realmCreds;
420         }
421 
422         @Override
423         public void handle(
424                 final HttpRequest request,
425                 final HttpResponse response,
426                 final HttpContext context) throws HttpException, IOException {
427             final String givenCreds = (String) context.getAttribute("creds");
428             if (givenCreds == null || !givenCreds.equals(this.realmCreds)) {
429                 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
430                 response.addHeader(AUTH.WWW_AUTH, "Basic realm=\"" + this.realm + "\"");
431             } else {
432                 response.setStatusCode(HttpStatus.SC_OK);
433                 final StringEntity entity = new StringEntity("success", Consts.ASCII);
434                 response.setEntity(entity);
435             }
436         }
437 
438     }
439 
440     @Test
441     public void testAuthenticationCredentialsCachingReauthenticationOnDifferentRealm() throws Exception {
442         this.serverBootstrap.registerHandler("/this", new RealmAuthHandler("this realm", "test:this"));
443         this.serverBootstrap.registerHandler("/that", new RealmAuthHandler("that realm", "test:that"));
444 
445         this.server = this.serverBootstrap.create();
446         this.server.start();
447 
448         final HttpHost target = new HttpHost("localhost", this.server.getLocalPort(), this.scheme.name());
449 
450         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
451         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
452         credsProvider.setCredentials(new AuthScope(target, "this realm", null),
453                 new UsernamePasswordCredentials("test", "this"));
454         credsProvider.setCredentials(new AuthScope(target, "that realm", null),
455                 new UsernamePasswordCredentials("test", "that"));
456 
457         this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
458         this.httpclient = this.clientBuilder.build();
459 
460         final HttpClientContext context = HttpClientContext.create();
461         context.setCredentialsProvider(credsProvider);
462 
463         final HttpGet httpget1 = new HttpGet("/this");
464 
465         final HttpResponse response1 = this.httpclient.execute(target, httpget1, context);
466         final HttpEntity entity1 = response1.getEntity();
467         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
468         Assert.assertNotNull(entity1);
469         EntityUtils.consume(entity1);
470 
471         final HttpGet httpget2 = new HttpGet("/this");
472 
473         final HttpResponse response2 = this.httpclient.execute(target, httpget2, context);
474         final HttpEntity entity2 = response1.getEntity();
475         Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
476         Assert.assertNotNull(entity2);
477         EntityUtils.consume(entity2);
478 
479         final HttpGet httpget3 = new HttpGet("/that");
480 
481         final HttpResponse response3 = this.httpclient.execute(target, httpget3, context);
482         final HttpEntity entity3 = response1.getEntity();
483         Assert.assertEquals(HttpStatus.SC_OK, response3.getStatusLine().getStatusCode());
484         Assert.assertNotNull(entity3);
485         EntityUtils.consume(entity3);
486 
487         Assert.assertEquals(2, authStrategy.getCount());
488     }
489 
490     @Test
491     public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
492         this.serverBootstrap.registerHandler("*", new AuthHandler());
493 
494         final HttpHost target = start();
495         final HttpGet httpget = new HttpGet("http://test:test@" +  target.toHostString() + "/");
496 
497         final HttpClientContext context = HttpClientContext.create();
498         final HttpResponse response = this.httpclient.execute(target, httpget, context);
499         final HttpEntity entity = response.getEntity();
500         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
501         Assert.assertNotNull(entity);
502         EntityUtils.consume(entity);
503     }
504 
505     @Test
506     public void testAuthenticationUserinfoInRequestFailure() throws Exception {
507         this.serverBootstrap.registerHandler("*", new AuthHandler());
508 
509         final HttpHost target = start();
510         final HttpGet httpget = new HttpGet("http://test:all-wrong@" +  target.toHostString() + "/");
511 
512         final HttpClientContext context = HttpClientContext.create();
513         final HttpResponse response = this.httpclient.execute(target, httpget, context);
514         final HttpEntity entity = response.getEntity();
515         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatusLine().getStatusCode());
516         Assert.assertNotNull(entity);
517         EntityUtils.consume(entity);
518     }
519 
520     private static class RedirectHandler implements HttpRequestHandler {
521 
522         public RedirectHandler() {
523             super();
524         }
525 
526         @Override
527         public void handle(
528                 final HttpRequest request,
529                 final HttpResponse response,
530                 final HttpContext context) throws HttpException, IOException {
531             final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
532             final String localhost = conn.getLocalAddress().getHostName();
533             final int port = conn.getLocalPort();
534             response.setStatusCode(HttpStatus.SC_MOVED_PERMANENTLY);
535             response.addHeader(new BasicHeader("Location",
536                     "http://test:test@" + localhost + ":" + port + "/"));
537         }
538 
539     }
540 
541     @Test
542     public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
543         this.serverBootstrap.registerHandler("*", new AuthHandler());
544         this.serverBootstrap.registerHandler("/thatway", new RedirectHandler());
545 
546         final HttpHost target = start();
547 
548         final HttpGet httpget = new HttpGet("http://" +  target.toHostString() + "/thatway");
549         final HttpClientContext context = HttpClientContext.create();
550 
551         final HttpResponse response = this.httpclient.execute(target, httpget, context);
552         final HttpEntity entity = response.getEntity();
553         Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
554         Assert.assertNotNull(entity);
555         EntityUtils.consume(entity);
556     }
557 
558     static class CountingAuthHandler implements HttpRequestHandler {
559 
560         private final AtomicLong count;
561 
562         public CountingAuthHandler() {
563             super();
564             this.count = new AtomicLong();
565         }
566 
567         @Override
568         public void handle(
569                 final HttpRequest request,
570                 final HttpResponse response,
571                 final HttpContext context) throws HttpException, IOException {
572             this.count.incrementAndGet();
573             final String creds = (String) context.getAttribute("creds");
574             if (creds == null || !creds.equals("test:test")) {
575                 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
576             } else {
577                 response.setStatusCode(HttpStatus.SC_OK);
578                 final StringEntity entity = new StringEntity("success", Consts.ASCII);
579                 response.setEntity(entity);
580             }
581         }
582 
583         public long getCount() {
584             return this.count.get();
585         }
586 
587     }
588 
589     @Test
590     public void testPreemptiveAuthentication() throws Exception {
591         final CountingAuthHandler requestHandler = new CountingAuthHandler();
592         this.serverBootstrap.registerHandler("*", requestHandler);
593 
594         final HttpHost target = start();
595 
596         final HttpClientContext context = HttpClientContext.create();
597         final AuthCache authCache = new BasicAuthCache();
598         authCache.put(target, new BasicScheme());
599         context.setAuthCache(authCache);
600         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
601         credsProvider.setCredentials(AuthScope.ANY,
602                 new UsernamePasswordCredentials("test", "test"));
603         context.setCredentialsProvider(credsProvider);
604 
605         final HttpGet httpget = new HttpGet("/");
606         final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
607         final HttpEntity entity1 = response1.getEntity();
608         Assert.assertEquals(HttpStatus.SC_OK, response1.getStatusLine().getStatusCode());
609         Assert.assertNotNull(entity1);
610         EntityUtils.consume(entity1);
611 
612         Assert.assertEquals(1, requestHandler.getCount());
613     }
614 
615     @Test
616     public void testPreemptiveAuthenticationFailure() throws Exception {
617         final CountingAuthHandler requestHandler = new CountingAuthHandler();
618         this.serverBootstrap.registerHandler("*", requestHandler);
619 
620         final HttpHost target = start();
621 
622         final HttpClientContext context = HttpClientContext.create();
623         final AuthCache authCache = new BasicAuthCache();
624         authCache.put(target, new BasicScheme());
625         context.setAuthCache(authCache);
626         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
627         credsProvider.setCredentials(AuthScope.ANY,
628                 new UsernamePasswordCredentials("test", "stuff"));
629         context.setCredentialsProvider(credsProvider);
630 
631         final HttpGet httpget = new HttpGet("/");
632         final HttpResponse response1 = this.httpclient.execute(target, httpget, context);
633         final HttpEntity entity1 = response1.getEntity();
634         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response1.getStatusLine().getStatusCode());
635         Assert.assertNotNull(entity1);
636         EntityUtils.consume(entity1);
637 
638         Assert.assertEquals(1, requestHandler.getCount());
639     }
640 
641     static class ProxyAuthHandler implements HttpRequestHandler {
642 
643         @Override
644         public void handle(
645                 final HttpRequest request,
646                 final HttpResponse response,
647                 final HttpContext context) throws HttpException, IOException {
648             final String creds = (String) context.getAttribute("creds");
649             if (creds == null || !creds.equals("test:test")) {
650                 response.setStatusCode(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);
651             } else {
652                 response.setStatusCode(HttpStatus.SC_OK);
653                 final StringEntity entity = new StringEntity("success", Consts.ASCII);
654                 response.setEntity(entity);
655             }
656         }
657 
658     }
659 
660     @Test
661     public void testAuthenticationTargetAsProxy() throws Exception {
662         this.serverBootstrap.registerHandler("*", new ProxyAuthHandler());
663 
664         final HttpHost target = start();
665 
666         final HttpClientContext context = HttpClientContext.create();
667         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
668         context.setCredentialsProvider(credsProvider);
669 
670         final HttpGet httpget = new HttpGet("/");
671         final HttpResponse response = this.httpclient.execute(target, httpget, context);
672         final HttpEntity entity = response.getEntity();
673         Assert.assertEquals(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED,
674                 response.getStatusLine().getStatusCode());
675         EntityUtils.consume(entity);
676     }
677 
678     static class ClosingAuthHandler implements HttpRequestHandler {
679 
680         @Override
681         public void handle(
682                 final HttpRequest request,
683                 final HttpResponse response,
684                 final HttpContext context) throws HttpException, IOException {
685             final String creds = (String) context.getAttribute("creds");
686             if (creds == null || !creds.equals("test:test")) {
687                 response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
688             } else {
689                 response.setStatusCode(HttpStatus.SC_OK);
690                 final StringEntity entity = new StringEntity("success", Consts.ASCII);
691                 response.setEntity(entity);
692                 response.setHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
693             }
694         }
695 
696     }
697 
698     @Test
699     public void testConnectionCloseAfterAuthenticationSuccess() throws Exception {
700         this.serverBootstrap.registerHandler("*", new ClosingAuthHandler());
701 
702         final HttpHost target = start();
703 
704         final HttpClientContext context = HttpClientContext.create();
705         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
706         credsProvider.setCredentials(AuthScope.ANY,
707                 new UsernamePasswordCredentials("test", "test"));
708         context.setCredentialsProvider(credsProvider);
709 
710         for (int i = 0; i < 2; i++) {
711             final HttpGet httpget = new HttpGet("/");
712 
713             final HttpResponse response = this.httpclient.execute(target, httpget, context);
714             EntityUtils.consume(response.getEntity());
715             Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
716         }
717     }
718 
719 }