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