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.async;
28
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import org.apache.hc.client5.http.AuthenticationStrategy;
36 import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
37 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
38 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
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.AuthScope;
43 import org.apache.hc.client5.http.auth.ChallengeType;
44 import org.apache.hc.client5.http.auth.Credentials;
45 import org.apache.hc.client5.http.auth.CredentialsStore;
46 import org.apache.hc.client5.http.auth.StandardAuthScheme;
47 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
48 import org.apache.hc.client5.http.config.RequestConfig;
49 import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
50 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
51 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
52 import org.apache.hc.client5.http.impl.auth.BasicScheme;
53 import org.apache.hc.client5.http.protocol.HttpClientContext;
54 import org.apache.hc.client5.testing.BasicTestAuthenticator;
55 import org.apache.hc.client5.testing.auth.Authenticator;
56 import org.apache.hc.core5.function.Decorator;
57 import org.apache.hc.core5.function.Supplier;
58 import org.apache.hc.core5.http.ContentType;
59 import org.apache.hc.core5.http.HttpException;
60 import org.apache.hc.core5.http.HttpHeaders;
61 import org.apache.hc.core5.http.HttpHost;
62 import org.apache.hc.core5.http.HttpResponse;
63 import org.apache.hc.core5.http.HttpStatus;
64 import org.apache.hc.core5.http.HttpVersion;
65 import org.apache.hc.core5.http.URIScheme;
66 import org.apache.hc.core5.http.config.Http1Config;
67 import org.apache.hc.core5.http.config.Lookup;
68 import org.apache.hc.core5.http.config.Registry;
69 import org.apache.hc.core5.http.config.RegistryBuilder;
70 import org.apache.hc.core5.http.impl.HttpProcessors;
71 import org.apache.hc.core5.http.message.BasicHeader;
72 import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
73 import org.apache.hc.core5.http.protocol.HttpContext;
74 import org.apache.hc.core5.http.protocol.HttpCoreContext;
75 import org.apache.hc.core5.http2.config.H2Config;
76 import org.apache.hc.core5.http2.impl.H2Processors;
77 import org.apache.hc.core5.net.URIAuthority;
78 import org.junit.Assert;
79 import org.junit.Test;
80
81 public abstract class AbstractHttpAsyncClientAuthentication<T extends CloseableHttpAsyncClient> extends AbstractIntegrationTestBase<T> {
82
83 protected final HttpVersion protocolVersion;
84
85 public AbstractHttpAsyncClientAuthentication(final URIScheme scheme, final HttpVersion protocolVersion) {
86 super(scheme);
87 this.protocolVersion = protocolVersion;
88 }
89
90 @Override
91 public final HttpHost start() throws Exception {
92 return start(new Decorator<AsyncServerExchangeHandler>() {
93
94 @Override
95 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler requestHandler) {
96 return new AuthenticatingAsyncDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm"));
97 }
98
99 });
100 }
101
102 public final HttpHost start(
103 final Decorator<AsyncServerExchangeHandler> exchangeHandlerDecorator) throws Exception {
104 if (protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) {
105 return super.start(
106 H2Processors.server(),
107 exchangeHandlerDecorator,
108 H2Config.DEFAULT);
109 } else {
110 return super.start(
111 HttpProcessors.server(),
112 exchangeHandlerDecorator,
113 Http1Config.DEFAULT);
114 }
115 }
116
117 abstract void setDefaultAuthSchemeRegistry(Lookup<AuthSchemeFactory> authSchemeRegistry);
118
119 abstract void setTargetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy);
120
121 static class TestCredentialsProvider implements CredentialsStore {
122
123 private final Credentials creds;
124 private AuthScope authscope;
125
126 TestCredentialsProvider(final Credentials creds) {
127 super();
128 this.creds = creds;
129 }
130
131 @Override
132 public void clear() {
133 }
134
135 @Override
136 public Credentials getCredentials(final AuthScope authscope, final HttpContext context) {
137 this.authscope = authscope;
138 return this.creds;
139 }
140
141 @Override
142 public void setCredentials(final AuthScope authscope, final Credentials credentials) {
143 }
144
145 public AuthScope getAuthScope() {
146 return this.authscope;
147 }
148
149 }
150
151 @Test
152 public void testBasicAuthenticationNoCreds() throws Exception {
153 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
154
155 @Override
156 public AsyncServerExchangeHandler get() {
157 return new AsyncEchoHandler();
158 }
159
160 });
161 final HttpHost target = start();
162
163 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
164 final HttpClientContext context = HttpClientContext.create();
165 context.setCredentialsProvider(credsProvider);
166
167 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleRequestBuilder.get()
168 .setHttpHost(target)
169 .setPath("/")
170 .build(), context, null);
171 final HttpResponse response = future.get();
172
173 Assert.assertNotNull(response);
174 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
175 final AuthScope authscope = credsProvider.getAuthScope();
176 Assert.assertNotNull(authscope);
177 Assert.assertEquals("test realm", authscope.getRealm());
178 }
179
180 @Test
181 public void testBasicAuthenticationFailure() throws Exception {
182 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
183
184 @Override
185 public AsyncServerExchangeHandler get() {
186 return new AsyncEchoHandler();
187 }
188
189 });
190 final HttpHost target = start();
191
192 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
193 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
194 final HttpClientContext context = HttpClientContext.create();
195 context.setCredentialsProvider(credsProvider);
196
197 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleRequestBuilder.get()
198 .setHttpHost(target)
199 .setPath("/")
200 .build(), context, null);
201 final HttpResponse response = future.get();
202
203 Assert.assertNotNull(response);
204 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
205 final AuthScope authscope = credsProvider.getAuthScope();
206 Assert.assertNotNull(authscope);
207 Assert.assertEquals("test realm", authscope.getRealm());
208 }
209
210 @Test
211 public void testBasicAuthenticationSuccess() throws Exception {
212 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
213
214 @Override
215 public AsyncServerExchangeHandler get() {
216 return new AsyncEchoHandler();
217 }
218
219 });
220 final HttpHost target = start();
221
222 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
223 new UsernamePasswordCredentials("test", "test".toCharArray()));
224 final HttpClientContext context = HttpClientContext.create();
225 context.setCredentialsProvider(credsProvider);
226
227 final Future<SimpleHttpResponse> future = httpclient.execute(
228 SimpleRequestBuilder.get()
229 .setHttpHost(target)
230 .setPath("/")
231 .build(), context, null);
232 final HttpResponse response = future.get();
233
234 Assert.assertNotNull(response);
235 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
236 final AuthScope authscope = credsProvider.getAuthScope();
237 Assert.assertNotNull(authscope);
238 Assert.assertEquals("test realm", authscope.getRealm());
239 }
240
241 @Test
242 public void testBasicAuthenticationWithEntitySuccess() throws Exception {
243 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
244
245 @Override
246 public AsyncServerExchangeHandler get() {
247 return new AsyncEchoHandler();
248 }
249
250 });
251 final HttpHost target = start();
252
253 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
254 new UsernamePasswordCredentials("test", "test".toCharArray()));
255 final HttpClientContext context = HttpClientContext.create();
256 context.setCredentialsProvider(credsProvider);
257 final Future<SimpleHttpResponse> future = httpclient.execute(
258 SimpleRequestBuilder.put()
259 .setHttpHost(target)
260 .setPath("/")
261 .setBody("Some important stuff", ContentType.TEXT_PLAIN)
262 .build(), context, null);
263 final HttpResponse response = future.get();
264
265 Assert.assertNotNull(response);
266 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
267 final AuthScope authscope = credsProvider.getAuthScope();
268 Assert.assertNotNull(authscope);
269 Assert.assertEquals("test realm", authscope.getRealm());
270 }
271
272 @Test
273 public void testBasicAuthenticationExpectationFailure() throws Exception {
274 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
275
276 @Override
277 public AsyncServerExchangeHandler get() {
278 return new AsyncEchoHandler();
279 }
280
281 });
282 final HttpHost target = start();
283
284 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
285 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
286 final HttpClientContext context = HttpClientContext.create();
287 context.setCredentialsProvider(credsProvider);
288 context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
289 final Future<SimpleHttpResponse> future = httpclient.execute(
290 SimpleRequestBuilder.put()
291 .setHttpHost(target)
292 .setPath("/")
293 .setBody("Some important stuff", ContentType.TEXT_PLAIN)
294 .build(), context, null);
295 final HttpResponse response = future.get();
296
297 Assert.assertNotNull(response);
298 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
299 }
300
301 @Test
302 public void testBasicAuthenticationExpectationSuccess() throws Exception {
303 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
304
305 @Override
306 public AsyncServerExchangeHandler get() {
307 return new AsyncEchoHandler();
308 }
309
310 });
311 final HttpHost target = start();
312
313 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
314 new UsernamePasswordCredentials("test", "test".toCharArray()));
315 final HttpClientContext context = HttpClientContext.create();
316 context.setCredentialsProvider(credsProvider);
317 context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
318 final Future<SimpleHttpResponse> future = httpclient.execute(
319 SimpleRequestBuilder.put()
320 .setHttpHost(target)
321 .setPath("/")
322 .setBody("Some important stuff", ContentType.TEXT_PLAIN)
323 .build(), context, null);
324 final HttpResponse response = future.get();
325
326 Assert.assertNotNull(response);
327 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
328 final AuthScope authscope = credsProvider.getAuthScope();
329 Assert.assertNotNull(authscope);
330 Assert.assertEquals("test realm", authscope.getRealm());
331 }
332
333 @Test
334 public void testBasicAuthenticationCredentialsCaching() throws Exception {
335 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
336
337 @Override
338 public AsyncServerExchangeHandler get() {
339 return new AsyncEchoHandler();
340 }
341
342 });
343
344 final AtomicLong count = new AtomicLong(0);
345 setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy() {
346
347 @Override
348 public List<AuthScheme> select(
349 final ChallengeType challengeType,
350 final Map<String, AuthChallenge> challenges,
351 final HttpContext context) {
352 count.incrementAndGet();
353 return super.select(challengeType, challenges, context);
354 }
355 });
356 final HttpHost target = start();
357
358 final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
359 credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
360 new UsernamePasswordCredentials("test", "test".toCharArray()));
361 final HttpClientContext context = HttpClientContext.create();
362 context.setCredentialsProvider(credsProvider);
363
364 final Future<SimpleHttpResponse> future1 = httpclient.execute(SimpleRequestBuilder.get()
365 .setHttpHost(target)
366 .setPath("/")
367 .build(), context, null);
368 final HttpResponse response1 = future1.get();
369 Assert.assertNotNull(response1);
370 Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
371
372 final Future<SimpleHttpResponse> future2 = httpclient.execute(SimpleRequestBuilder.get()
373 .setHttpHost(target)
374 .setPath("/")
375 .build(), context, null);
376 final HttpResponse response2 = future2.get();
377 Assert.assertNotNull(response2);
378 Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
379
380 Assert.assertEquals(1, count.get());
381 }
382
383 @Test
384 public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
385 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
386
387 @Override
388 public AsyncServerExchangeHandler get() {
389 return new AsyncEchoHandler();
390 }
391
392 });
393 final HttpHost target = start();
394
395 final HttpClientContext context = HttpClientContext.create();
396 final Future<SimpleHttpResponse> future = httpclient.execute(
397 SimpleRequestBuilder.get()
398 .setScheme(target.getSchemeName())
399 .setAuthority(new URIAuthority("test:test", target.getHostName(), target.getPort()))
400 .setPath("/")
401 .build(), context, null);
402 final SimpleHttpResponse response = future.get();
403
404 Assert.assertNotNull(response);
405 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
406 }
407
408 @Test
409 public void testAuthenticationUserinfoInRequestFailure() throws Exception {
410 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
411
412 @Override
413 public AsyncServerExchangeHandler get() {
414 return new AsyncEchoHandler();
415 }
416
417 });
418 final HttpHost target = start();
419
420 final HttpClientContext context = HttpClientContext.create();
421 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleRequestBuilder.get()
422 .setScheme(target.getSchemeName())
423 .setAuthority(new URIAuthority("test:all-worng", target.getHostName(), target.getPort()))
424 .setPath("/")
425 .build(), context, null);
426 final SimpleHttpResponse response = future.get();
427
428 Assert.assertNotNull(response);
429 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
430 }
431
432 @Test
433 public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
434 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
435
436 @Override
437 public AsyncServerExchangeHandler get() {
438 return new AsyncEchoHandler();
439 }
440
441 });
442 final HttpHost target = start();
443 server.register("/thatway", new Supplier<AsyncServerExchangeHandler>() {
444
445 @Override
446 public AsyncServerExchangeHandler get() {
447 return new AbstractSimpleServerExchangeHandler() {
448
449 @Override
450 protected SimpleHttpResponse handle(
451 final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException {
452 final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_PERMANENTLY);
453 response.addHeader(new BasicHeader("Location", target.getSchemeName() + "://test:test@" + target.toHostString() + "/"));
454 return response;
455 }
456 };
457 }
458
459 });
460
461 final HttpClientContext context = HttpClientContext.create();
462 final Future<SimpleHttpResponse> future = httpclient.execute(
463 SimpleRequestBuilder.get()
464 .setScheme(target.getSchemeName())
465 .setAuthority(new URIAuthority("test:test", target.getHostName(), target.getPort()))
466 .setPath("/thatway")
467 .build(), context, null);
468 final SimpleHttpResponse response = future.get();
469
470 Assert.assertNotNull(response);
471 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
472 }
473
474 @Test
475 public void testReauthentication() throws Exception {
476 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
477
478 @Override
479 public AsyncServerExchangeHandler get() {
480 return new AsyncEchoHandler();
481 }
482
483 });
484 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
485 new UsernamePasswordCredentials("test", "test".toCharArray()));
486
487 final Registry<AuthSchemeFactory> authSchemeRegistry = RegistryBuilder.<AuthSchemeFactory>create()
488 .register("MyBasic", new AuthSchemeFactory() {
489
490 @Override
491 public AuthScheme create(final HttpContext context) {
492 return new BasicScheme() {
493
494 private static final long serialVersionUID = 1L;
495
496 @Override
497 public String getName() {
498 return "MyBasic";
499 }
500
501 };
502 }
503
504 })
505 .build();
506 setDefaultAuthSchemeRegistry(authSchemeRegistry);
507
508 final Authenticator authenticator = new BasicTestAuthenticator("test:test", "test realm") {
509
510 private final AtomicLong count = new AtomicLong(0);
511
512 @Override
513 public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
514 final boolean authenticated = super.authenticate(authority, requestUri, credentials);
515 if (authenticated) {
516 return this.count.incrementAndGet() % 4 != 0;
517 }
518 return false;
519 }
520 };
521
522 final HttpHost target = start(
523 new Decorator<AsyncServerExchangeHandler>() {
524
525 @Override
526 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
527 return new AuthenticatingAsyncDecorator(exchangeHandler, authenticator) {
528
529 @Override
530 protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
531 unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE);
532 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
533 }
534
535 };
536 }
537
538 });
539
540 final RequestConfig config = RequestConfig.custom()
541 .setTargetPreferredAuthSchemes(Collections.singletonList("MyBasic"))
542 .build();
543 final HttpClientContext context = HttpClientContext.create();
544 context.setCredentialsProvider(credsProvider);
545
546 for (int i = 0; i < 10; i++) {
547 final SimpleHttpRequest request = SimpleRequestBuilder.get()
548 .setHttpHost(target)
549 .setPath("/")
550 .build();
551 request.setConfig(config);
552 final Future<SimpleHttpResponse> future = httpclient.execute(request, context, null);
553 final SimpleHttpResponse response = future.get();
554 Assert.assertNotNull(response);
555 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
556 }
557 }
558
559 @Test
560 public void testAuthenticationFallback() throws Exception {
561 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
562
563 @Override
564 public AsyncServerExchangeHandler get() {
565 return new AsyncEchoHandler();
566 }
567
568 });
569 final HttpHost target = start(
570 new Decorator<AsyncServerExchangeHandler>() {
571
572 @Override
573 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
574 return new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) {
575
576 @Override
577 protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
578 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid");
579 }
580
581 };
582 }
583
584 });
585
586 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
587 new UsernamePasswordCredentials("test", "test".toCharArray()));
588 final HttpClientContext context = HttpClientContext.create();
589 context.setCredentialsProvider(credsProvider);
590
591 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleRequestBuilder.get()
592 .setHttpHost(target)
593 .setPath("/")
594 .build(), context, null);
595 final SimpleHttpResponse response = future.get();
596 Assert.assertNotNull(response);
597 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
598 final AuthScope authscope = credsProvider.getAuthScope();
599 Assert.assertNotNull(authscope);
600 Assert.assertEquals("test realm", authscope.getRealm());
601 }
602
603 }