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.Arrays;
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.SimpleHttpRequests;
38 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
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.CredentialsStore;
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(SimpleHttpRequests.get(target, "/"), context, null);
168 final HttpResponse response = future.get();
169
170 Assert.assertNotNull(response);
171 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
172 final AuthScope authscope = credsProvider.getAuthScope();
173 Assert.assertNotNull(authscope);
174 Assert.assertEquals("test realm", authscope.getRealm());
175 }
176
177 @Test
178 public void testBasicAuthenticationFailure() throws Exception {
179 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
180
181 @Override
182 public AsyncServerExchangeHandler get() {
183 return new AsyncEchoHandler();
184 }
185
186 });
187 final HttpHost target = start();
188
189 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
190 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
191 final HttpClientContext context = HttpClientContext.create();
192 context.setCredentialsProvider(credsProvider);
193
194 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequests.get(target, "/"), context, null);
195 final HttpResponse response = future.get();
196
197 Assert.assertNotNull(response);
198 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
199 final AuthScope authscope = credsProvider.getAuthScope();
200 Assert.assertNotNull(authscope);
201 Assert.assertEquals("test realm", authscope.getRealm());
202 }
203
204 @Test
205 public void testBasicAuthenticationSuccess() throws Exception {
206 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
207
208 @Override
209 public AsyncServerExchangeHandler get() {
210 return new AsyncEchoHandler();
211 }
212
213 });
214 final HttpHost target = start();
215
216 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
217 new UsernamePasswordCredentials("test", "test".toCharArray()));
218 final HttpClientContext context = HttpClientContext.create();
219 context.setCredentialsProvider(credsProvider);
220
221 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequests.get(target, "/"), context, null);
222 final HttpResponse response = future.get();
223
224 Assert.assertNotNull(response);
225 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
226 final AuthScope authscope = credsProvider.getAuthScope();
227 Assert.assertNotNull(authscope);
228 Assert.assertEquals("test realm", authscope.getRealm());
229 }
230
231 @Test
232 public void testBasicAuthenticationWithEntitySuccess() throws Exception {
233 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
234
235 @Override
236 public AsyncServerExchangeHandler get() {
237 return new AsyncEchoHandler();
238 }
239
240 });
241 final HttpHost target = start();
242
243 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
244 new UsernamePasswordCredentials("test", "test".toCharArray()));
245 final HttpClientContext context = HttpClientContext.create();
246 context.setCredentialsProvider(credsProvider);
247
248 final SimpleHttpRequest put = SimpleHttpRequests.put(target, "/");
249 put.setBody("Some important stuff", ContentType.TEXT_PLAIN);
250 final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
251 final HttpResponse response = future.get();
252
253 Assert.assertNotNull(response);
254 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
255 final AuthScope authscope = credsProvider.getAuthScope();
256 Assert.assertNotNull(authscope);
257 Assert.assertEquals("test realm", authscope.getRealm());
258 }
259
260 @Test
261 public void testBasicAuthenticationExpectationFailure() throws Exception {
262 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
263
264 @Override
265 public AsyncServerExchangeHandler get() {
266 return new AsyncEchoHandler();
267 }
268
269 });
270 final HttpHost target = start();
271
272 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
273 new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
274 final HttpClientContext context = HttpClientContext.create();
275 context.setCredentialsProvider(credsProvider);
276 context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
277
278 final SimpleHttpRequest put = SimpleHttpRequests.put(target, "/");
279 put.setBody("Some important stuff", ContentType.TEXT_PLAIN);
280 final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
281 final HttpResponse response = future.get();
282
283 Assert.assertNotNull(response);
284 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
285 }
286
287 @Test
288 public void testBasicAuthenticationExpectationSuccess() throws Exception {
289 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
290
291 @Override
292 public AsyncServerExchangeHandler get() {
293 return new AsyncEchoHandler();
294 }
295
296 });
297 final HttpHost target = start();
298
299 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
300 new UsernamePasswordCredentials("test", "test".toCharArray()));
301 final HttpClientContext context = HttpClientContext.create();
302 context.setCredentialsProvider(credsProvider);
303 context.setRequestConfig(RequestConfig.custom().setExpectContinueEnabled(true).build());
304
305 final SimpleHttpRequest put = SimpleHttpRequests.put(target, "/");
306 put.setBody("Some important stuff", ContentType.TEXT_PLAIN);
307 final Future<SimpleHttpResponse> future = httpclient.execute(put, context, null);
308 final HttpResponse response = future.get();
309
310 Assert.assertNotNull(response);
311 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
312 final AuthScope authscope = credsProvider.getAuthScope();
313 Assert.assertNotNull(authscope);
314 Assert.assertEquals("test realm", authscope.getRealm());
315 }
316
317 @Test
318 public void testBasicAuthenticationCredentialsCaching() throws Exception {
319 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
320
321 @Override
322 public AsyncServerExchangeHandler get() {
323 return new AsyncEchoHandler();
324 }
325
326 });
327
328 final AtomicLong count = new AtomicLong(0);
329 setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy() {
330
331 @Override
332 public List<AuthScheme> select(
333 final ChallengeType challengeType,
334 final Map<String, AuthChallenge> challenges,
335 final HttpContext context) {
336 count.incrementAndGet();
337 return super.select(challengeType, challenges, context);
338 }
339 });
340 final HttpHost target = start();
341
342 final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
343 credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
344 new UsernamePasswordCredentials("test", "test".toCharArray()));
345 final HttpClientContext context = HttpClientContext.create();
346 context.setCredentialsProvider(credsProvider);
347
348 final Future<SimpleHttpResponse> future1 = httpclient.execute(SimpleHttpRequests.get(target, "/"), context, null);
349 final HttpResponse response1 = future1.get();
350 Assert.assertNotNull(response1);
351 Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
352
353 final Future<SimpleHttpResponse> future2 = httpclient.execute(SimpleHttpRequests.get(target, "/"), context, null);
354 final HttpResponse response2 = future2.get();
355 Assert.assertNotNull(response2);
356 Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
357
358 Assert.assertEquals(1, count.get());
359 }
360
361 @Test
362 public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
363 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
364
365 @Override
366 public AsyncServerExchangeHandler get() {
367 return new AsyncEchoHandler();
368 }
369
370 });
371 final HttpHost target = start();
372
373 final HttpClientContext context = HttpClientContext.create();
374 final Future<SimpleHttpResponse> future = httpclient.execute(
375 SimpleHttpRequests.get(target.getSchemeName() + "://test:test@" + target.toHostString() + "/"), context, null);
376 final SimpleHttpResponse response = future.get();
377
378 Assert.assertNotNull(response);
379 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
380 }
381
382 @Test
383 public void testAuthenticationUserinfoInRequestFailure() throws Exception {
384 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
385
386 @Override
387 public AsyncServerExchangeHandler get() {
388 return new AsyncEchoHandler();
389 }
390
391 });
392 final HttpHost target = start();
393
394 final HttpClientContext context = HttpClientContext.create();
395 final Future<SimpleHttpResponse> future = httpclient.execute(
396 SimpleHttpRequests.get(target.getSchemeName() + "://test:all-worng@" + target.toHostString() + "/"), context, null);
397 final SimpleHttpResponse response = future.get();
398
399 Assert.assertNotNull(response);
400 Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
401 }
402
403 @Test
404 public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
405 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
406
407 @Override
408 public AsyncServerExchangeHandler get() {
409 return new AsyncEchoHandler();
410 }
411
412 });
413 final HttpHost target = start();
414 server.register("/thatway", new Supplier<AsyncServerExchangeHandler>() {
415
416 @Override
417 public AsyncServerExchangeHandler get() {
418 return new AbstractSimpleServerExchangeHandler() {
419
420 @Override
421 protected SimpleHttpResponse handle(
422 final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException {
423 final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_PERMANENTLY);
424 response.addHeader(new BasicHeader("Location", target.getSchemeName() + "://test:test@" + target.toHostString() + "/"));
425 return response;
426 }
427 };
428 }
429
430 });
431
432 final HttpClientContext context = HttpClientContext.create();
433 final Future<SimpleHttpResponse> future = httpclient.execute(
434 SimpleHttpRequests.get(target.getSchemeName() + "://test:test@" + target.toHostString() + "/thatway"), context, null);
435 final SimpleHttpResponse response = future.get();
436
437 Assert.assertNotNull(response);
438 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
439 }
440
441 @Test
442 public void testReauthentication() throws Exception {
443 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
444
445 @Override
446 public AsyncServerExchangeHandler get() {
447 return new AsyncEchoHandler();
448 }
449
450 });
451 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
452 new UsernamePasswordCredentials("test", "test".toCharArray()));
453
454 final Registry<AuthSchemeFactory> authSchemeRegistry = RegistryBuilder.<AuthSchemeFactory>create()
455 .register("MyBasic", new AuthSchemeFactory() {
456
457 @Override
458 public AuthScheme create(final HttpContext context) {
459 return new BasicScheme() {
460
461 private static final long serialVersionUID = 1L;
462
463 @Override
464 public String getName() {
465 return "MyBasic";
466 }
467
468 };
469 }
470
471 })
472 .build();
473 setDefaultAuthSchemeRegistry(authSchemeRegistry);
474
475 final Authenticator authenticator = new BasicTestAuthenticator("test:test", "test realm") {
476
477 private final AtomicLong count = new AtomicLong(0);
478
479 @Override
480 public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) {
481 final boolean authenticated = super.authenticate(authority, requestUri, credentials);
482 if (authenticated) {
483 return this.count.incrementAndGet() % 4 != 0;
484 }
485 return false;
486 }
487 };
488
489 final HttpHost target = start(
490 new Decorator<AsyncServerExchangeHandler>() {
491
492 @Override
493 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
494 return new AuthenticatingAsyncDecorator(exchangeHandler, authenticator) {
495
496 @Override
497 protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
498 unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE);
499 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
500 }
501
502 };
503 }
504
505 });
506
507 final RequestConfig config = RequestConfig.custom()
508 .setTargetPreferredAuthSchemes(Arrays.asList("MyBasic"))
509 .build();
510 final HttpClientContext context = HttpClientContext.create();
511 context.setCredentialsProvider(credsProvider);
512
513 for (int i = 0; i < 10; i++) {
514 final SimpleHttpRequest request = SimpleHttpRequests.get(target, "/");
515 request.setConfig(config);
516 final Future<SimpleHttpResponse> future = httpclient.execute(request, context, null);
517 final SimpleHttpResponse response = future.get();
518 Assert.assertNotNull(response);
519 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
520 }
521 }
522
523 @Test
524 public void testAuthenticationFallback() throws Exception {
525 server.register("*", new Supplier<AsyncServerExchangeHandler>() {
526
527 @Override
528 public AsyncServerExchangeHandler get() {
529 return new AsyncEchoHandler();
530 }
531
532 });
533 final HttpHost target = start(
534 new Decorator<AsyncServerExchangeHandler>() {
535
536 @Override
537 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
538 return new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) {
539
540 @Override
541 protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
542 unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid");
543 }
544
545 };
546 }
547
548 });
549
550 final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
551 new UsernamePasswordCredentials("test", "test".toCharArray()));
552 final HttpClientContext context = HttpClientContext.create();
553 context.setCredentialsProvider(credsProvider);
554
555 final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequests.get(target, "/"), context, null);
556 final SimpleHttpResponse response = future.get();
557 Assert.assertNotNull(response);
558 Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
559 final AuthScope authscope = credsProvider.getAuthScope();
560 Assert.assertNotNull(authscope);
561 Assert.assertEquals("test realm", authscope.getRealm());
562 }
563
564 }