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.hc.client5.testing.sync;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.IOException;
31  import java.net.InetSocketAddress;
32  import java.nio.charset.StandardCharsets;
33  import java.util.Collections;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.concurrent.atomic.AtomicLong;
37  
38  import org.apache.hc.client5.http.auth.AuthCache;
39  import org.apache.hc.client5.http.auth.AuthChallenge;
40  import org.apache.hc.client5.http.auth.AuthScheme;
41  import org.apache.hc.client5.http.auth.AuthSchemeFactory;
42  import org.apache.hc.client5.http.auth.StandardAuthScheme;
43  import org.apache.hc.client5.http.auth.AuthScope;
44  import org.apache.hc.client5.http.auth.ChallengeType;
45  import org.apache.hc.client5.http.auth.Credentials;
46  import org.apache.hc.client5.http.auth.CredentialsProvider;
47  import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
48  import org.apache.hc.client5.http.classic.methods.HttpGet;
49  import org.apache.hc.client5.http.classic.methods.HttpPost;
50  import org.apache.hc.client5.http.classic.methods.HttpPut;
51  import org.apache.hc.client5.http.config.RequestConfig;
52  import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
53  import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
54  import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
55  import org.apache.hc.client5.http.impl.auth.BasicScheme;
56  import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
57  import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
58  import org.apache.hc.client5.http.protocol.HttpClientContext;
59  import org.apache.hc.client5.testing.BasicTestAuthenticator;
60  import org.apache.hc.client5.testing.auth.Authenticator;
61  import org.apache.hc.client5.testing.classic.AuthenticatingDecorator;
62  import org.apache.hc.client5.testing.classic.EchoHandler;
63  import org.apache.hc.core5.function.Decorator;
64  import org.apache.hc.core5.http.ClassicHttpRequest;
65  import org.apache.hc.core5.http.ClassicHttpResponse;
66  import org.apache.hc.core5.http.EndpointDetails;
67  import org.apache.hc.core5.http.HeaderElements;
68  import org.apache.hc.core5.http.HttpEntity;
69  import org.apache.hc.core5.http.HttpException;
70  import org.apache.hc.core5.http.HttpHeaders;
71  import org.apache.hc.core5.http.HttpHost;
72  import org.apache.hc.core5.http.HttpStatus;
73  import org.apache.hc.core5.http.config.Registry;
74  import org.apache.hc.core5.http.config.RegistryBuilder;
75  import org.apache.hc.core5.http.impl.HttpProcessors;
76  import org.apache.hc.core5.http.io.HttpRequestHandler;
77  import org.apache.hc.core5.http.io.HttpServerRequestHandler;
78  import org.apache.hc.core5.http.io.entity.EntityUtils;
79  import org.apache.hc.core5.http.io.entity.InputStreamEntity;
80  import org.apache.hc.core5.http.io.entity.StringEntity;
81  import org.apache.hc.core5.http.message.BasicHeader;
82  import org.apache.hc.core5.http.protocol.HttpContext;
83  import org.apache.hc.core5.http.protocol.HttpCoreContext;
84  import org.apache.hc.core5.net.URIAuthority;
85  import org.junit.Assert;
86  import org.junit.Test;
87  
88  /**
89   * Unit tests for automatic client authentication.
90   */
91  public class TestClientAuthentication extends LocalServerTestBase {
92  
93      public HttpHost start(final Authenticator authenticator) throws IOException {
94          return super.start(null, new Decorator<HttpServerRequestHandler>() {
95  
96              @Override
97              public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) {
98                  return new AuthenticatingDecorator(requestHandler, authenticator);
99              }
100 
101         });
102     }
103 
104     @Override
105     public HttpHost start() throws IOException {
106         return start(new BasicTestAuthenticator("test:test", "test realm"));
107     }
108 
109     static class TestCredentialsProvider implements CredentialsProvider {
110 
111         private final Credentials creds;
112         private AuthScope authscope;
113 
114         TestCredentialsProvider(final Credentials creds) {
115             super();
116             this.creds = creds;
117         }
118 
119         @Override
120         public Credentials getCredentials(final AuthScope authscope, final HttpContext context) {
121             this.authscope = authscope;
122             return this.creds;
123         }
124 
125         public AuthScope getAuthScope() {
126             return this.authscope;
127         }
128 
129     }
130 
131     @Test
132     public void testBasicAuthenticationNoCreds() throws Exception {
133         this.server.registerHandler("*", new EchoHandler());
134         final HttpHost target = start();
135 
136         final HttpClientContext context = HttpClientContext.create();
137         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
138         context.setCredentialsProvider(credsProvider);
139         final HttpGet httpget = new HttpGet("/");
140 
141         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
142         final HttpEntity entity = response.getEntity();
143         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
144         Assert.assertNotNull(entity);
145         EntityUtils.consume(entity);
146         final AuthScope authscope = credsProvider.getAuthScope();
147         Assert.assertNotNull(authscope);
148         Assert.assertEquals("test realm", authscope.getRealm());
149     }
150 
151     @Test
152     public void testBasicAuthenticationFailure() throws Exception {
153         this.server.registerHandler("*", new EchoHandler());
154         final HttpHost target = start();
155 
156         final HttpClientContext context = HttpClientContext.create();
157         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
158                 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
159         context.setCredentialsProvider(credsProvider);
160         final HttpGet httpget = new HttpGet("/");
161 
162         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
163         final HttpEntity entity = response.getEntity();
164         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
165         Assert.assertNotNull(entity);
166         EntityUtils.consume(entity);
167         final AuthScope authscope = credsProvider.getAuthScope();
168         Assert.assertNotNull(authscope);
169         Assert.assertEquals("test realm", authscope.getRealm());
170     }
171 
172     @Test
173     public void testBasicAuthenticationSuccess() throws Exception {
174         this.server.registerHandler("*", new EchoHandler());
175         final HttpGet httpget = new HttpGet("/");
176         final HttpClientContext context = HttpClientContext.create();
177         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
178                 new UsernamePasswordCredentials("test", "test".toCharArray()));
179         context.setCredentialsProvider(credsProvider);
180 
181         final HttpHost target = start();
182 
183         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
184         final HttpEntity entity = response.getEntity();
185         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
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 testBasicAuthenticationSuccessOnNonRepeatablePutExpectContinue() throws Exception {
195         this.server.registerHandler("*", new EchoHandler());
196         final HttpHost target = start();
197 
198         final RequestConfig config = RequestConfig.custom()
199                 .setExpectContinueEnabled(true)
200                 .build();
201         final HttpPut httpput = new HttpPut("/");
202         httpput.setConfig(config);
203         httpput.setEntity(new InputStreamEntity(
204                 new ByteArrayInputStream(
205                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
206                         -1, null));
207         final HttpClientContext context = HttpClientContext.create();
208         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
209                 new UsernamePasswordCredentials("test", "test".toCharArray()));
210         context.setCredentialsProvider(credsProvider);
211 
212         final ClassicHttpResponse response = this.httpclient.execute(target, httpput, context);
213         final HttpEntity entity = response.getEntity();
214         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
215         Assert.assertNotNull(entity);
216     }
217 
218     @Test
219     public void testBasicAuthenticationFailureOnNonRepeatablePutDontExpectContinue() throws Exception {
220         this.server.registerHandler("*", new EchoHandler());
221         final HttpHost target = start();
222 
223         final RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(false).build();
224         final HttpPut httpput = new HttpPut("/");
225         httpput.setConfig(config);
226         httpput.setEntity(new InputStreamEntity(
227                 new ByteArrayInputStream(
228                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
229                         -1, null));
230 
231         final HttpClientContext context = HttpClientContext.create();
232         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
233                 new UsernamePasswordCredentials("test", "boom".toCharArray()));
234         context.setCredentialsProvider(credsProvider);
235 
236         final CloseableHttpResponse response = this.httpclient.execute(target, httpput, context);
237         final HttpEntity entity = response.getEntity();
238         Assert.assertEquals(401, response.getCode());
239         Assert.assertNotNull(entity);
240         EntityUtils.consume(entity);
241     }
242 
243     @Test
244     public void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception {
245         this.server.registerHandler("*", new EchoHandler());
246         final HttpHost target = start();
247 
248         final HttpPost httppost = new HttpPost("/");
249         httppost.setEntity(new StringEntity("some important stuff", StandardCharsets.US_ASCII));
250 
251         final HttpClientContext context = HttpClientContext.create();
252         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
253                 new UsernamePasswordCredentials("test", "test".toCharArray()));
254         context.setCredentialsProvider(credsProvider);
255 
256         final ClassicHttpResponse response = this.httpclient.execute(target, httppost, context);
257         final HttpEntity entity = response.getEntity();
258         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
259         Assert.assertNotNull(entity);
260         EntityUtils.consume(entity);
261         final AuthScope authscope = credsProvider.getAuthScope();
262         Assert.assertNotNull(authscope);
263         Assert.assertEquals("test realm", authscope.getRealm());
264     }
265 
266     @Test
267     public void testBasicAuthenticationFailureOnNonRepeatablePost() throws Exception {
268         this.server.registerHandler("*", new EchoHandler());
269         final HttpHost target = start();
270 
271         final HttpPost httppost = new HttpPost("/");
272         httppost.setEntity(new InputStreamEntity(
273                 new ByteArrayInputStream(
274                         new byte[] { 0,1,2,3,4,5,6,7,8,9 }), -1, null));
275 
276         final HttpClientContext context = HttpClientContext.create();
277         context.setRequestConfig(RequestConfig.custom()
278                 .setExpectContinueEnabled(false)
279                 .build());
280         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
281                 new UsernamePasswordCredentials("test", "test".toCharArray()));
282         context.setCredentialsProvider(credsProvider);
283 
284         final CloseableHttpResponse response = this.httpclient.execute(target, httppost, context);
285         final HttpEntity entity = response.getEntity();
286         Assert.assertEquals(401, response.getCode());
287         Assert.assertNotNull(entity);
288         EntityUtils.consume(entity);
289     }
290 
291     static class TestTargetAuthenticationStrategy extends DefaultAuthenticationStrategy {
292 
293         private final AtomicLong count;
294 
295         public TestTargetAuthenticationStrategy() {
296             super();
297             this.count = new AtomicLong();
298         }
299 
300         @Override
301         public List<AuthScheme> select(
302                 final ChallengeType challengeType,
303                 final Map<String, AuthChallenge> challenges,
304                 final HttpContext context) {
305             final List<AuthScheme> authSchemes = super.select(challengeType, challenges, context);
306             this.count.incrementAndGet();
307             return authSchemes;
308         }
309 
310         public long getCount() {
311             return this.count.get();
312         }
313 
314     }
315 
316     @Test
317     public void testBasicAuthenticationCredentialsCaching() throws Exception {
318         this.server.registerHandler("*", new EchoHandler());
319         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
320         this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
321 
322         final HttpHost target = start();
323 
324         final HttpClientContext context = HttpClientContext.create();
325         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
326         credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
327                 new UsernamePasswordCredentials("test", "test".toCharArray()));
328         context.setCredentialsProvider(credsProvider);
329 
330         final HttpGet httpget = new HttpGet("/");
331 
332         final ClassicHttpResponse response1 = this.httpclient.execute(target, httpget, context);
333         final HttpEntity entity1 = response1.getEntity();
334         Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
335         Assert.assertNotNull(entity1);
336         EntityUtils.consume(entity1);
337 
338         final ClassicHttpResponse response2 = this.httpclient.execute(target, httpget, context);
339         final HttpEntity entity2 = response1.getEntity();
340         Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
341         Assert.assertNotNull(entity2);
342         EntityUtils.consume(entity2);
343 
344         Assert.assertEquals(1, authStrategy.getCount());
345     }
346 
347     @Test
348     public void testAuthenticationCredentialsCachingReauthenticationOnDifferentRealm() throws Exception {
349         this.server.registerHandler("*", new EchoHandler());
350         final HttpHost target = start(new Authenticator() {
351 
352             @Override
353             public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
354                 if (requestUri.equals("/this")) {
355                     return "test:this".equals(credentials);
356                 } else if (requestUri.equals("/that")) {
357                     return "test:that".equals(credentials);
358                 } else {
359                     return "test:test".equals(credentials);
360                 }
361             }
362 
363             @Override
364             public String getRealm(final URIAuthority authority, final String requestUri) {
365                 if (requestUri.equals("/this")) {
366                     return "this realm";
367                 } else if (requestUri.equals("/that")) {
368                     return "that realm";
369                 } else {
370                     return "test realm";
371                 }
372             }
373 
374         });
375 
376         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
377         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
378         credsProvider.setCredentials(new AuthScope(target, "this realm", null),
379                 new UsernamePasswordCredentials("test", "this".toCharArray()));
380         credsProvider.setCredentials(new AuthScope(target, "that realm", null),
381                 new UsernamePasswordCredentials("test", "that".toCharArray()));
382 
383         this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
384         this.httpclient = this.clientBuilder.build();
385 
386         final HttpClientContext context = HttpClientContext.create();
387         context.setCredentialsProvider(credsProvider);
388 
389         final HttpGet httpget1 = new HttpGet("/this");
390 
391         final ClassicHttpResponse response1 = this.httpclient.execute(target, httpget1, context);
392         final HttpEntity entity1 = response1.getEntity();
393         Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
394         Assert.assertNotNull(entity1);
395         EntityUtils.consume(entity1);
396 
397         final HttpGet httpget2 = new HttpGet("/this");
398 
399         final ClassicHttpResponse response2 = this.httpclient.execute(target, httpget2, context);
400         final HttpEntity entity2 = response1.getEntity();
401         Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
402         Assert.assertNotNull(entity2);
403         EntityUtils.consume(entity2);
404 
405         final HttpGet httpget3 = new HttpGet("/that");
406 
407         final ClassicHttpResponse response3 = this.httpclient.execute(target, httpget3, context);
408         final HttpEntity entity3 = response1.getEntity();
409         Assert.assertEquals(HttpStatus.SC_OK, response3.getCode());
410         Assert.assertNotNull(entity3);
411         EntityUtils.consume(entity3);
412 
413         Assert.assertEquals(2, authStrategy.getCount());
414     }
415 
416     @Test
417     public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
418         this.server.registerHandler("*", new EchoHandler());
419         final HttpHost target = start();
420         final HttpGet httpget = new HttpGet("http://test:test@" +  target.toHostString() + "/");
421 
422         final HttpClientContext context = HttpClientContext.create();
423         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
424         final HttpEntity entity = response.getEntity();
425         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
426         Assert.assertNotNull(entity);
427         EntityUtils.consume(entity);
428     }
429 
430     @Test
431     public void testAuthenticationUserinfoInRequestFailure() throws Exception {
432         this.server.registerHandler("*", new EchoHandler());
433         final HttpHost target = start();
434         final HttpGet httpget = new HttpGet("http://test:all-wrong@" +  target.toHostString() + "/");
435 
436         final HttpClientContext context = HttpClientContext.create();
437         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
438         final HttpEntity entity = response.getEntity();
439         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
440         Assert.assertNotNull(entity);
441         EntityUtils.consume(entity);
442     }
443 
444     @Test
445     public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
446         this.server.registerHandler("/*", new EchoHandler());
447         this.server.registerHandler("/thatway", new HttpRequestHandler() {
448 
449             @Override
450             public void handle(
451                     final ClassicHttpRequest request,
452                     final ClassicHttpResponse response,
453                     final HttpContext context) throws HttpException, IOException {
454                 final EndpointDetails endpoint = (EndpointDetails) context.getAttribute(HttpCoreContext.CONNECTION_ENDPOINT);
455                 final InetSocketAddress socketAddress = (InetSocketAddress) endpoint.getLocalAddress();
456                 final int port = socketAddress.getPort();
457                 response.setCode(HttpStatus.SC_MOVED_PERMANENTLY);
458                 response.addHeader(new BasicHeader("Location", "http://test:test@localhost:" + port + "/secure"));
459             }
460 
461         });
462 
463         final HttpHost target = start(new BasicTestAuthenticator("test:test", "test realm") {
464 
465             @Override
466             public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
467                 if (requestUri.equals("/secure") || requestUri.startsWith("/secure/")) {
468                     return super.authenticate(authority, requestUri, credentials);
469                 }
470                 return true;
471             }
472         });
473 
474         final HttpGet httpget = new HttpGet("/thatway");
475         final HttpClientContext context = HttpClientContext.create();
476 
477         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
478         final HttpEntity entity = response.getEntity();
479         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
480         Assert.assertNotNull(entity);
481         EntityUtils.consume(entity);
482     }
483 
484     static class CountingAuthenticator extends BasicTestAuthenticator {
485 
486         private final AtomicLong count;
487 
488         public CountingAuthenticator(final String userToken, final String realm) {
489             super(userToken, realm);
490             this.count = new AtomicLong();
491         }
492 
493         @Override
494         public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
495             this.count.incrementAndGet();
496             return super.authenticate(authority, requestUri, credentials);
497         }
498 
499         public long getCount() {
500             return this.count.get();
501         }
502 
503     }
504 
505     @Test
506     public void testPreemptiveAuthentication() throws Exception {
507         this.server.registerHandler("*", new EchoHandler());
508         final CountingAuthenticator countingAuthenticator = new CountingAuthenticator("test:test", "test realm");
509         final HttpHost target = start(countingAuthenticator);
510 
511         final BasicScheme basicScheme = new BasicScheme();
512         basicScheme.initPreemptive(new UsernamePasswordCredentials("test", "test".toCharArray()));
513         final HttpClientContext context = HttpClientContext.create();
514         final AuthCache authCache = new BasicAuthCache();
515         authCache.put(target, basicScheme);
516         context.setAuthCache(authCache);
517 
518         final HttpGet httpget = new HttpGet("/");
519         final ClassicHttpResponse response1 = this.httpclient.execute(target, httpget, context);
520         final HttpEntity entity1 = response1.getEntity();
521         Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
522         Assert.assertNotNull(entity1);
523         EntityUtils.consume(entity1);
524 
525         Assert.assertEquals(1, countingAuthenticator.getCount());
526     }
527 
528     @Test
529     public void testPreemptiveAuthenticationFailure() throws Exception {
530         this.server.registerHandler("*", new EchoHandler());
531         final CountingAuthenticator countingAuthenticator = new CountingAuthenticator("test:test", "test realm");
532 
533         final HttpHost target = start(countingAuthenticator);
534 
535         final HttpClientContext context = HttpClientContext.create();
536         final AuthCache authCache = new BasicAuthCache();
537         authCache.put(target, new BasicScheme());
538         context.setAuthCache(authCache);
539         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
540         credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
541                 new UsernamePasswordCredentials("test", "stuff".toCharArray()));
542         context.setCredentialsProvider(credsProvider);
543 
544         final HttpGet httpget = new HttpGet("/");
545         final ClassicHttpResponse response1 = this.httpclient.execute(target, httpget, context);
546         final HttpEntity entity1 = response1.getEntity();
547         Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response1.getCode());
548         Assert.assertNotNull(entity1);
549         EntityUtils.consume(entity1);
550 
551         Assert.assertEquals(1, countingAuthenticator.getCount());
552     }
553 
554     static class ProxyAuthHandler implements HttpRequestHandler {
555 
556         @Override
557         public void handle(
558                 final ClassicHttpRequest request,
559                 final ClassicHttpResponse response,
560                 final HttpContext context) throws HttpException, IOException {
561             final String creds = (String) context.getAttribute("creds");
562             if (creds == null || !creds.equals("test:test")) {
563                 response.setCode(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);
564             } else {
565                 response.setCode(HttpStatus.SC_OK);
566                 final StringEntity entity = new StringEntity("success", StandardCharsets.US_ASCII);
567                 response.setEntity(entity);
568             }
569         }
570 
571     }
572 
573     @Test
574     public void testAuthenticationTargetAsProxy() throws Exception {
575         this.server.registerHandler("*", new ProxyAuthHandler());
576 
577         final HttpHost target = super.start();
578 
579         final HttpClientContext context = HttpClientContext.create();
580         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
581         context.setCredentialsProvider(credsProvider);
582 
583         final HttpGet httpget = new HttpGet("/");
584         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
585         final HttpEntity entity = response.getEntity();
586         Assert.assertEquals(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED,
587                 response.getCode());
588         EntityUtils.consume(entity);
589     }
590 
591     @Test
592     public void testConnectionCloseAfterAuthenticationSuccess() throws Exception {
593         this.server.registerHandler("*", new EchoHandler());
594 
595         final HttpHost target = start(
596                 HttpProcessors.server(),
597                 new Decorator<HttpServerRequestHandler>() {
598 
599                     @Override
600                     public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) {
601                         return new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) {
602 
603                             @Override
604                             protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) {
605                                 unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE);
606                             }
607 
608                         };
609                     }
610 
611                 });
612 
613         final HttpClientContext context = HttpClientContext.create();
614         final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
615         credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
616                 new UsernamePasswordCredentials("test", "test".toCharArray()));
617         context.setCredentialsProvider(credsProvider);
618 
619         for (int i = 0; i < 2; i++) {
620             final HttpGet httpget = new HttpGet("/");
621 
622             final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
623             EntityUtils.consume(response.getEntity());
624             Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
625         }
626     }
627 
628     @Test
629     public void testReauthentication() throws Exception {
630         this.server.registerHandler("*", new EchoHandler());
631 
632         final BasicSchemeFactory myBasicAuthSchemeFactory = new BasicSchemeFactory() {
633 
634             @Override
635             public AuthScheme create(final HttpContext context) {
636                 return new BasicScheme() {
637                     private static final long serialVersionUID = 1L;
638 
639                     @Override
640                     public String getName() {
641                         return "MyBasic";
642                     }
643 
644                 };
645             }
646 
647         };
648 
649         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
650                 new UsernamePasswordCredentials("test", "test".toCharArray()));
651 
652         final RequestConfig config = RequestConfig.custom()
653                 .setTargetPreferredAuthSchemes(Collections.singletonList("MyBasic"))
654                 .build();
655         final Registry<AuthSchemeFactory> authSchemeRegistry = RegistryBuilder.<AuthSchemeFactory>create()
656                 .register("MyBasic", myBasicAuthSchemeFactory)
657                 .build();
658         this.httpclient = this.clientBuilder
659                 .setDefaultAuthSchemeRegistry(authSchemeRegistry)
660                 .setDefaultCredentialsProvider(credsProvider)
661                 .build();
662 
663         final Authenticator authenticator = new BasicTestAuthenticator("test:test", "test realm") {
664 
665             private final AtomicLong count = new AtomicLong(0);
666 
667             @Override
668             public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
669                 final boolean authenticated = super.authenticate(authority, requestUri, credentials);
670                 if (authenticated) {
671                     return this.count.incrementAndGet() % 4 != 0;
672                 }
673                 return false;
674             }
675         };
676 
677         final HttpHost target = start(
678                 HttpProcessors.server(),
679                 new Decorator<HttpServerRequestHandler>() {
680 
681                     @Override
682                     public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) {
683                         return new AuthenticatingDecorator(requestHandler, authenticator) {
684 
685                             @Override
686                             protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) {
687                                 unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE);
688                                 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
689                             }
690 
691                         };
692                     }
693 
694                 });
695 
696         final HttpClientContext context = HttpClientContext.create();
697         for (int i = 0; i < 10; i++) {
698             final HttpGet httpget = new HttpGet("/");
699             httpget.setConfig(config);
700             try (final CloseableHttpResponse response = this.httpclient.execute(target, httpget, context)) {
701                 final HttpEntity entity = response.getEntity();
702                 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
703                 Assert.assertNotNull(entity);
704                 EntityUtils.consume(entity);
705             }
706         }
707     }
708 
709     @Test
710     public void testAuthenticationFallback() throws Exception {
711         this.server.registerHandler("*", new EchoHandler());
712 
713         final HttpHost target = start(
714                 HttpProcessors.server(),
715                 new Decorator<HttpServerRequestHandler>() {
716 
717                     @Override
718                     public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) {
719                         return new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) {
720 
721                             @Override
722                             protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) {
723                                 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid");
724                             }
725 
726                         };
727                     }
728 
729                 });
730 
731         final HttpClientContext context = HttpClientContext.create();
732         final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
733                 new UsernamePasswordCredentials("test", "test".toCharArray()));
734         context.setCredentialsProvider(credsProvider);
735         final HttpGet httpget = new HttpGet("/");
736 
737         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
738         final HttpEntity entity = response.getEntity();
739         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
740         Assert.assertNotNull(entity);
741         EntityUtils.consume(entity);
742         final AuthScope authscope = credsProvider.getAuthScope();
743         Assert.assertNotNull(authscope);
744         Assert.assertEquals("test realm", authscope.getRealm());
745     }
746 
747 }