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.http.impl.auth;
28
29 import java.io.ByteArrayInputStream;
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.ObjectInputStream;
33 import java.io.ObjectOutputStream;
34 import java.nio.charset.StandardCharsets;
35 import java.security.MessageDigest;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39
40 import org.apache.hc.client5.http.auth.AuthChallenge;
41 import org.apache.hc.client5.http.auth.AuthScheme;
42 import org.apache.hc.client5.http.auth.AuthScope;
43 import org.apache.hc.client5.http.auth.AuthenticationException;
44 import org.apache.hc.client5.http.auth.ChallengeType;
45 import org.apache.hc.client5.http.auth.CredentialsProvider;
46 import org.apache.hc.client5.http.auth.MalformedChallengeException;
47 import org.apache.hc.client5.http.auth.StandardAuthScheme;
48 import org.apache.hc.client5.http.protocol.HttpClientContext;
49 import org.apache.hc.core5.http.ClassicHttpRequest;
50 import org.apache.hc.core5.http.ContentType;
51 import org.apache.hc.core5.http.HeaderElement;
52 import org.apache.hc.core5.http.HttpHost;
53 import org.apache.hc.core5.http.HttpRequest;
54 import org.apache.hc.core5.http.ParseException;
55 import org.apache.hc.core5.http.io.entity.InputStreamEntity;
56 import org.apache.hc.core5.http.io.entity.StringEntity;
57 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
58 import org.apache.hc.core5.http.message.BasicHeaderValueParser;
59 import org.apache.hc.core5.http.message.BasicHttpRequest;
60 import org.apache.hc.core5.http.message.ParserCursor;
61 import org.apache.hc.core5.util.CharArrayBuffer;
62 import org.junit.jupiter.api.Assertions;
63 import org.junit.jupiter.api.Test;
64
65
66
67
68 class TestDigestScheme {
69
70 private static AuthChallenge parse(final String s) throws ParseException {
71 final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
72 buffer.append(s);
73 final ParserCursor cursor = new ParserCursor(0, buffer.length());
74 final List<AuthChallenge> authChallenges = AuthChallengeParser.INSTANCE.parse(ChallengeType.TARGET, buffer, cursor);
75 Assertions.assertEquals(1, authChallenges.size());
76 return authChallenges.get(0);
77 }
78
79 @Test
80 void testDigestAuthenticationEmptyChallenge1() throws Exception {
81 final AuthChallenge authChallenge = parse(StandardAuthScheme.DIGEST);
82 final AuthScheme authscheme = new DigestScheme();
83 Assertions.assertThrows(MalformedChallengeException.class, () ->
84 authscheme.processChallenge(authChallenge, null));
85 }
86
87 @Test
88 void testDigestAuthenticationEmptyChallenge2() throws Exception {
89 final AuthChallenge authChallenge = parse(StandardAuthScheme.DIGEST + " ");
90 final AuthScheme authscheme = new DigestScheme();
91 Assertions.assertThrows(MalformedChallengeException.class, () ->
92 authscheme.processChallenge(authChallenge, null));
93 }
94
95 @Test
96 void testDigestAuthenticationWithDefaultCreds() throws Exception {
97 final HttpRequest request = new BasicHttpRequest("Simple", "/");
98 final HttpHost host = new HttpHost("somehost", 80);
99 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
100 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
101 .build();
102
103 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
104 final AuthChallenge authChallenge = parse(challenge);
105 final DigestScheme authscheme = new DigestScheme();
106 authscheme.processChallenge(authChallenge, null);
107
108 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
109 final String authResponse = authscheme.generateAuthResponse(host, request, null);
110 Assertions.assertTrue(authscheme.isChallengeComplete());
111 Assertions.assertFalse(authscheme.isConnectionBased());
112
113 final Map<String, String> table = parseAuthResponse(authResponse);
114 Assertions.assertEquals("username", table.get("username"));
115 Assertions.assertEquals("realm1", table.get("realm"));
116 Assertions.assertEquals("/", table.get("uri"));
117 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
118 Assertions.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
119 }
120
121 @Test
122 void testDigestAuthentication() throws Exception {
123 final HttpRequest request = new BasicHttpRequest("Simple", "/");
124 final HttpHost host = new HttpHost("somehost", 80);
125 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
126 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
127 .build();
128
129 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
130 final AuthChallenge authChallenge = parse(challenge);
131 final DigestScheme authscheme = new DigestScheme();
132 authscheme.processChallenge(authChallenge, null);
133
134 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
135 final String authResponse = authscheme.generateAuthResponse(host, request, null);
136
137 final Map<String, String> table = parseAuthResponse(authResponse);
138 Assertions.assertEquals("username", table.get("username"));
139 Assertions.assertEquals("realm1", table.get("realm"));
140 Assertions.assertEquals("/", table.get("uri"));
141 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
142 Assertions.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
143 }
144
145 @Test
146 void testDigestAuthenticationInvalidInput() throws Exception {
147 final HttpHost host = new HttpHost("somehost", 80);
148 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
149 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
150 .build();
151
152 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
153 final AuthChallenge authChallenge = parse(challenge);
154 final DigestScheme authscheme = new DigestScheme();
155 authscheme.processChallenge(authChallenge, null);
156
157 Assertions.assertThrows(NullPointerException.class, () ->
158 authscheme.isResponseReady(null, credentialsProvider, null));
159 Assertions.assertThrows(NullPointerException.class, () ->
160 authscheme.isResponseReady(host, null, null));
161 Assertions.assertThrows(NullPointerException.class, () ->
162 authscheme.generateAuthResponse(host, null, null));
163 }
164
165 @Test
166 void testDigestAuthenticationWithSHA() throws Exception {
167 final HttpRequest request = new BasicHttpRequest("Simple", "/");
168 final HttpHost host = new HttpHost("somehost", 80);
169 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
170 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
171 .build();
172
173 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", " +
174 "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
175 "algorithm=SHA";
176 final AuthChallenge authChallenge = parse(challenge);
177 final DigestScheme authscheme = new DigestScheme();
178 authscheme.processChallenge(authChallenge, null);
179
180 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
181
182 Assertions.assertThrows(AuthenticationException.class, () ->
183 authscheme.generateAuthResponse(host, request, null), "Expected UnsupportedDigestAlgorithmException for unsupported 'SHA' algorithm");
184 }
185
186 @Test
187 void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
188 final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
189 final HttpHost host = new HttpHost("somehost", 80);
190 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
191 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
192 .build();
193
194 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
195 final AuthChallenge authChallenge = parse(challenge);
196 final DigestScheme authscheme = new DigestScheme();
197 authscheme.processChallenge(authChallenge, null);
198
199 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
200 final String authResponse = authscheme.generateAuthResponse(host, request, null);
201
202 final Map<String, String> table = parseAuthResponse(authResponse);
203 Assertions.assertEquals("username", table.get("username"));
204 Assertions.assertEquals("realm1", table.get("realm"));
205 Assertions.assertEquals("/?param=value", table.get("uri"));
206 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
207 Assertions.assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table.get("response"));
208 }
209
210 @Test
211 void testDigestAuthenticationNoRealm() throws Exception {
212 final HttpRequest request = new BasicHttpRequest("Simple", "/");
213 final HttpHost host = new HttpHost("somehost", 80);
214 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
215 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
216 .build();
217
218 final String challenge = StandardAuthScheme.DIGEST + " no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
219 final AuthChallenge authChallenge = parse(challenge);
220 final DigestScheme authscheme = new DigestScheme();
221 authscheme.processChallenge(authChallenge, null);
222
223 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
224 Assertions.assertThrows(AuthenticationException.class, () ->
225 authscheme.generateAuthResponse(host, request, null));
226 }
227
228 @Test
229 void testDigestAuthenticationNoNonce() throws Exception {
230 final HttpRequest request = new BasicHttpRequest("Simple", "/");
231 final HttpHost host = new HttpHost("somehost", 80);
232 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
233 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
234 .build();
235
236 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
237 final AuthChallenge authChallenge = parse(challenge);
238 final DigestScheme authscheme = new DigestScheme();
239 authscheme.processChallenge(authChallenge, null);
240
241 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
242 Assertions.assertThrows(AuthenticationException.class, () ->
243 authscheme.generateAuthResponse(host, request, null));
244 }
245
246 @Test
247 void testDigestAuthenticationNoAlgorithm() throws Exception {
248 final HttpRequest request = new BasicHttpRequest("Simple", "/");
249 final HttpHost host = new HttpHost("somehost", 80);
250 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
251 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
252 .build();
253
254 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
255 final AuthChallenge authChallenge = parse(challenge);
256 final DigestScheme authscheme = new DigestScheme();
257 authscheme.processChallenge(authChallenge, null);
258
259 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
260 final String authResponse = authscheme.generateAuthResponse(host, request, null);
261
262 final Map<String, String> table = parseAuthResponse(authResponse);
263 Assertions.assertNull(table.get("algorithm"));
264 }
265
266 @Test
267 void testDigestAuthenticationMD5Algorithm() throws Exception {
268 final HttpRequest request = new BasicHttpRequest("Simple", "/");
269 final HttpHost host = new HttpHost("somehost", 80);
270 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
271 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
272 .build();
273
274 final String challenge = StandardAuthScheme.DIGEST
275 + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""
276 + ", algorithm=MD5";
277 final AuthChallenge authChallenge = parse(challenge);
278 final DigestScheme authscheme = new DigestScheme();
279 authscheme.processChallenge(authChallenge, null);
280
281 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
282 final String authResponse = authscheme.generateAuthResponse(host, request, null);
283
284 final Map<String, String> table = parseAuthResponse(authResponse);
285 Assertions.assertEquals("MD5", table.get("algorithm"));
286 }
287
288
289
290
291 @Test
292 void testDigestAuthenticationMD5Sess() throws Exception {
293
294
295 final String realm = "realm";
296 final String username = "username";
297 final String password = "password";
298 final String nonce = "e273f1776275974f1a120d8b92c5b3cb";
299
300 final HttpRequest request = new BasicHttpRequest("Simple", "/");
301 final HttpHost host = new HttpHost("somehost", 80);
302 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
303 .add(new AuthScope(host, realm, null), username, password.toCharArray())
304 .build();
305
306 final String challenge = StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
307 + "nonce=\"" + nonce + "\", "
308 + "opaque=\"SomeString\", "
309 + "stale=false, "
310 + "algorithm=MD5-sess, "
311 + "qop=\"auth,auth-int\"";
312
313 final AuthChallenge authChallenge = parse(challenge);
314
315 final DigestScheme authscheme = new DigestScheme();
316 authscheme.processChallenge(authChallenge, null);
317
318 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
319 final String authResponse = authscheme.generateAuthResponse(host, request, null);
320
321 Assertions.assertTrue(authResponse.indexOf("nc=00000001") > 0);
322 Assertions.assertTrue(authResponse.indexOf("qop=auth") > 0);
323
324 final Map<String, String> table = parseAuthResponse(authResponse);
325 Assertions.assertEquals(username, table.get("username"));
326 Assertions.assertEquals(realm, table.get("realm"));
327 Assertions.assertEquals("MD5-sess", table.get("algorithm"));
328 Assertions.assertEquals("/", table.get("uri"));
329 Assertions.assertEquals(nonce, table.get("nonce"));
330 Assertions.assertEquals(1, Integer.parseInt(table.get("nc"), 16));
331 Assertions.assertNotNull(table.get("cnonce"));
332 Assertions.assertEquals("SomeString", table.get("opaque"));
333 Assertions.assertEquals("auth", table.get("qop"));
334
335 Assertions.assertNotNull(table.get("response"));
336 }
337
338
339
340
341 @Test
342 void testDigestAuthenticationMD5SessNoQop() throws Exception {
343
344
345 final String realm = "realm";
346 final String username = "username";
347 final String password = "password";
348 final String nonce = "e273f1776275974f1a120d8b92c5b3cb";
349
350 final HttpRequest request = new BasicHttpRequest("Simple", "/");
351 final HttpHost host = new HttpHost("somehost", 80);
352 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
353 .add(new AuthScope(host, realm, null), username, password.toCharArray())
354 .build();
355
356 final String challenge = StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
357 + "nonce=\"" + nonce + "\", "
358 + "opaque=\"SomeString\", "
359 + "stale=false, "
360 + "algorithm=MD5-sess";
361
362 final AuthChallenge authChallenge = parse(challenge);
363
364 final DigestScheme authscheme = new DigestScheme();
365 authscheme.processChallenge(authChallenge, null);
366 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
367 final String authResponse = authscheme.generateAuthResponse(host, request, null);
368
369 final Map<String, String> table = parseAuthResponse(authResponse);
370 Assertions.assertEquals(username, table.get("username"));
371 Assertions.assertEquals(realm, table.get("realm"));
372 Assertions.assertEquals("MD5-sess", table.get("algorithm"));
373 Assertions.assertEquals("/", table.get("uri"));
374 Assertions.assertEquals(nonce, table.get("nonce"));
375 Assertions.assertNull(table.get("nc"));
376 Assertions.assertEquals("SomeString", table.get("opaque"));
377 Assertions.assertNull(table.get("qop"));
378
379 Assertions.assertNotNull(table.get("response"));
380 }
381
382
383
384
385 @Test
386 void testDigestAuthenticationMD5SessUnknownQop() throws Exception {
387
388
389 final String realm = "realm";
390 final String username = "username";
391 final String password = "password";
392 final String nonce = "e273f1776275974f1a120d8b92c5b3cb";
393
394 final HttpRequest request = new BasicHttpRequest("Simple", "/");
395 final HttpHost host = new HttpHost("somehost", 80);
396 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
397 .add(new AuthScope(host, realm, null), username, password.toCharArray())
398 .build();
399
400 final String challenge = StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
401 + "nonce=\"" + nonce + "\", "
402 + "opaque=\"SomeString\", "
403 + "stale=false, "
404 + "algorithm=MD5-sess, "
405 + "qop=\"stuff\"";
406
407 final AuthChallenge authChallenge = parse(challenge);
408
409 final DigestScheme authscheme = new DigestScheme();
410 authscheme.processChallenge(authChallenge, null);
411
412 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
413 Assertions.assertThrows(AuthenticationException.class, () ->
414 authscheme.generateAuthResponse(host, request, null));
415 }
416
417
418
419
420 @Test
421 void testDigestAuthenticationUnknownAlgo() throws Exception {
422
423
424 final String realm = "realm";
425 final String username = "username";
426 final String password = "password";
427 final String nonce = "e273f1776275974f1a120d8b92c5b3cb";
428
429 final HttpRequest request = new BasicHttpRequest("Simple", "/");
430 final HttpHost host = new HttpHost("somehost", 80);
431 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
432 .add(new AuthScope(host, realm, null), username, password.toCharArray())
433 .build();
434
435 final String challenge = StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
436 + "nonce=\"" + nonce + "\", "
437 + "opaque=\"SomeString\", "
438 + "stale=false, "
439 + "algorithm=stuff, "
440 + "qop=\"auth\"";
441
442 final AuthChallenge authChallenge = parse(challenge);
443
444 final DigestScheme authscheme = new DigestScheme();
445 authscheme.processChallenge(authChallenge, null);
446
447 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
448 Assertions.assertThrows(AuthenticationException.class, () ->
449 authscheme.generateAuthResponse(host, request, null));
450 }
451
452 @Test
453 void testDigestAuthenticationWithStaleNonce() throws Exception {
454 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", " +
455 "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", stale=\"true\"";
456 final AuthChallenge authChallenge = parse(challenge);
457 final AuthScheme authscheme = new DigestScheme();
458 authscheme.processChallenge(authChallenge, null);
459
460 Assertions.assertFalse(authscheme.isChallengeComplete());
461 }
462
463 private static Map<String, String> parseAuthResponse(final String authResponse) {
464 if (!authResponse.startsWith(StandardAuthScheme.DIGEST + " ")) {
465 return null;
466 }
467 final String s = authResponse.substring(7);
468 final ParserCursor cursor = new ParserCursor(0, s.length());
469 final HeaderElement[] elements = BasicHeaderValueParser.INSTANCE.parseElements(s, cursor);
470 final Map<String, String> map = new HashMap<>(elements.length);
471 for (final HeaderElement element : elements) {
472 map.put(element.getName(), element.getValue());
473 }
474 return map;
475 }
476
477 @Test
478 void testDigestNouceCount() throws Exception {
479 final HttpRequest request = new BasicHttpRequest("GET", "/");
480 final HttpHost host = new HttpHost("somehost", 80);
481 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
482 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
483 .build();
484
485 final String challenge1 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
486 final AuthChallenge authChallenge1 = parse(challenge1);
487
488 final DigestScheme authscheme = new DigestScheme();
489 authscheme.processChallenge(authChallenge1, null);
490 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
491 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
492
493 final Map<String, String> table1 = parseAuthResponse(authResponse1);
494 Assertions.assertEquals("00000001", table1.get("nc"));
495
496 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
497 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
498
499 final Map<String, String> table2 = parseAuthResponse(authResponse2);
500 Assertions.assertEquals("00000002", table2.get("nc"));
501 final String challenge2 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
502 final AuthChallenge authChallenge2 = parse(challenge2);
503 authscheme.processChallenge(authChallenge2, null);
504
505 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
506 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
507
508 final Map<String, String> table3 = parseAuthResponse(authResponse3);
509 Assertions.assertEquals("00000003", table3.get("nc"));
510 final String challenge3 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth";
511 final AuthChallenge authChallenge3 = parse(challenge3);
512 authscheme.processChallenge(authChallenge3, null);
513
514 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
515 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
516
517 final Map<String, String> table4 = parseAuthResponse(authResponse4);
518 Assertions.assertEquals("00000001", table4.get("nc"));
519 }
520
521 @Test
522 void testDigestMD5SessA1AndCnonceConsistency() throws Exception {
523 final HttpHost host = new HttpHost("somehost", 80);
524 final HttpRequest request = new BasicHttpRequest("GET", "/");
525 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
526 .add(new AuthScope(host, "subnet.domain.com", null), "username", "password".toCharArray())
527 .build();
528
529 final String challenge1 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
530 "charset=utf-8, realm=\"subnet.domain.com\"";
531 final AuthChallenge authChallenge1 = parse(challenge1);
532 final DigestScheme authscheme = new DigestScheme();
533 authscheme.processChallenge(authChallenge1, null);
534 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
535 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
536
537 final Map<String, String> table1 = parseAuthResponse(authResponse1);
538 Assertions.assertEquals("00000001", table1.get("nc"));
539 final String cnonce1 = authscheme.getCnonce();
540 final String sessionKey1 = authscheme.getA1();
541
542 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
543 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
544 final Map<String, String> table2 = parseAuthResponse(authResponse2);
545 Assertions.assertEquals("00000002", table2.get("nc"));
546 final String cnonce2 = authscheme.getCnonce();
547 final String sessionKey2 = authscheme.getA1();
548
549 Assertions.assertEquals(cnonce1, cnonce2);
550 Assertions.assertEquals(sessionKey1, sessionKey2);
551
552 final String challenge2 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
553 "charset=utf-8, realm=\"subnet.domain.com\"";
554 final AuthChallenge authChallenge2 = parse(challenge2);
555 authscheme.processChallenge(authChallenge2, null);
556 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
557 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
558 final Map<String, String> table3 = parseAuthResponse(authResponse3);
559 Assertions.assertEquals("00000003", table3.get("nc"));
560
561 final String cnonce3 = authscheme.getCnonce();
562 final String sessionKey3 = authscheme.getA1();
563
564 Assertions.assertEquals(cnonce1, cnonce3);
565 Assertions.assertEquals(sessionKey1, sessionKey3);
566
567 final String challenge3 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"fedcba0987654321\", " +
568 "charset=utf-8, realm=\"subnet.domain.com\"";
569 final AuthChallenge authChallenge3 = parse(challenge3);
570 authscheme.processChallenge(authChallenge3, null);
571 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
572 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
573 final Map<String, String> table4 = parseAuthResponse(authResponse4);
574 Assertions.assertEquals("00000001", table4.get("nc"));
575
576 final String cnonce4 = authscheme.getCnonce();
577 final String sessionKey4 = authscheme.getA1();
578
579 Assertions.assertNotEquals(cnonce1, cnonce4);
580 Assertions.assertNotEquals(sessionKey1, sessionKey4);
581 }
582
583 @Test
584 void testHttpEntityDigest() throws Exception {
585 final HttpEntityDigester digester = new HttpEntityDigester(MessageDigest.getInstance("MD5"));
586 Assertions.assertNull(digester.getDigest());
587 digester.write('a');
588 digester.write('b');
589 digester.write('c');
590 digester.write(0xe4);
591 digester.write(0xf6);
592 digester.write(0xfc);
593 digester.write(new byte[]{'a', 'b', 'c'});
594 Assertions.assertNull(digester.getDigest());
595 digester.close();
596 Assertions.assertEquals("acd2b59cd01c7737d8069015584c6cac", DigestScheme.formatHex(digester.getDigest()));
597 Assertions.assertThrows(IOException.class, () -> digester.write('a'));
598 Assertions.assertThrows(IOException.class, () -> digester.write(new byte[]{'a', 'b', 'c'}));
599 }
600
601 @Test
602 void testDigestAuthenticationQopAuthInt() throws Exception {
603 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
604 request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", StandardCharsets.ISO_8859_1));
605 final HttpHost host = new HttpHost("somehost", 80);
606 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
607 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
608 .build();
609
610 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
611 "qop=\"auth,auth-int\"";
612 final AuthChallenge authChallenge = parse(challenge);
613 final DigestScheme authscheme = new DigestScheme();
614 authscheme.processChallenge(authChallenge, null);
615 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
616 final String authResponse = authscheme.generateAuthResponse(host, request, null);
617
618 Assertions.assertEquals("Post:/:acd2b59cd01c7737d8069015584c6cac", authscheme.getA2());
619
620 final Map<String, String> table = parseAuthResponse(authResponse);
621 Assertions.assertEquals("username", table.get("username"));
622 Assertions.assertEquals("realm1", table.get("realm"));
623 Assertions.assertEquals("/", table.get("uri"));
624 Assertions.assertEquals("auth-int", table.get("qop"));
625 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
626 }
627
628 @Test
629 void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
630 final HttpRequest request = new BasicHttpRequest("Post", "/");
631 final HttpHost host = new HttpHost("somehost", 80);
632 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
633 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
634 .build();
635
636 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
637 "qop=\"auth-int\"";
638 final AuthChallenge authChallenge = parse(challenge);
639 final DigestScheme authscheme = new DigestScheme();
640 authscheme.processChallenge(authChallenge, null);
641 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
642 final String authResponse = authscheme.generateAuthResponse(host, request, null);
643
644 Assertions.assertEquals("Post:/:d41d8cd98f00b204e9800998ecf8427e", authscheme.getA2());
645
646 final Map<String, String> table = parseAuthResponse(authResponse);
647 Assertions.assertEquals("username", table.get("username"));
648 Assertions.assertEquals("realm1", table.get("realm"));
649 Assertions.assertEquals("/", table.get("uri"));
650 Assertions.assertEquals("auth-int", table.get("qop"));
651 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
652 }
653
654 @Test
655 void testDigestAuthenticationQopAuthOrAuthIntNonRepeatableEntity() throws Exception {
656 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
657 request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[]{'a'}), -1, ContentType.DEFAULT_TEXT));
658 final HttpHost host = new HttpHost("somehost", 80);
659 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
660 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
661 .build();
662
663 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
664 "qop=\"auth,auth-int\"";
665 final AuthChallenge authChallenge = parse(challenge);
666 final DigestScheme authscheme = new DigestScheme();
667 authscheme.processChallenge(authChallenge, null);
668 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
669 final String authResponse = authscheme.generateAuthResponse(host, request, null);
670
671 Assertions.assertEquals("Post:/", authscheme.getA2());
672
673 final Map<String, String> table = parseAuthResponse(authResponse);
674 Assertions.assertEquals("username", table.get("username"));
675 Assertions.assertEquals("realm1", table.get("realm"));
676 Assertions.assertEquals("/", table.get("uri"));
677 Assertions.assertEquals("auth", table.get("qop"));
678 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
679 }
680
681 @Test
682 void testParameterCaseSensitivity() throws Exception {
683 final HttpRequest request = new BasicHttpRequest("GET", "/");
684 final HttpHost host = new HttpHost("somehost", 80);
685 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
686 .add(new AuthScope(host, "-", null), "username", "password".toCharArray())
687 .build();
688
689 final String challenge = StandardAuthScheme.DIGEST + " Realm=\"-\", " +
690 "nonce=\"YjYuNGYyYmJhMzUuY2I5ZDhlZDE5M2ZlZDM 1Mjk3NGJkNTIyYjgyNTcwMjQ=\", " +
691 "opaque=\"98700A3D9CE17065E2246B41035C6609\", qop=\"auth\"";
692 final AuthChallenge authChallenge = parse(challenge);
693 final DigestScheme authscheme = new DigestScheme();
694 authscheme.processChallenge(authChallenge, null);
695 Assertions.assertEquals("-", authscheme.getRealm());
696
697 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
698 authscheme.generateAuthResponse(host, request, null);
699 }
700
701 @Test
702 void testDigestAuthenticationQopIntOnlyNonRepeatableEntity() throws Exception {
703 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
704 request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[]{'a'}), -1, ContentType.DEFAULT_TEXT));
705 final HttpHost host = new HttpHost("somehost", 80);
706 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
707 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
708 .build();
709
710 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
711 "qop=\"auth-int\"";
712 final AuthChallenge authChallenge = parse(challenge);
713 final DigestScheme authscheme = new DigestScheme();
714 authscheme.processChallenge(authChallenge, null);
715
716 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
717 Assertions.assertThrows(AuthenticationException.class, () ->
718 authscheme.generateAuthResponse(host, request, null));
719 }
720
721 @Test
722 void testSerialization() throws Exception {
723 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
724 "qop=\"auth,auth-int\"";
725 final AuthChallenge authChallenge = parse(challenge);
726 final DigestScheme digestScheme = new DigestScheme();
727 digestScheme.processChallenge(authChallenge, null);
728
729 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
730 final ObjectOutputStream out = new ObjectOutputStream(buffer);
731 out.writeObject(digestScheme);
732 out.flush();
733 final byte[] raw = buffer.toByteArray();
734 final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
735 final DigestScheme authScheme = (DigestScheme) in.readObject();
736
737 Assertions.assertEquals(digestScheme.getName(), authScheme.getName());
738 Assertions.assertEquals(digestScheme.getRealm(), authScheme.getRealm());
739 Assertions.assertEquals(digestScheme.isChallengeComplete(), authScheme.isChallengeComplete());
740 Assertions.assertEquals(digestScheme.getA1(), authScheme.getA1());
741 Assertions.assertEquals(digestScheme.getA2(), authScheme.getA2());
742 Assertions.assertEquals(digestScheme.getCnonce(), authScheme.getCnonce());
743 }
744
745
746 @Test
747 void testDigestAuthenticationWithUserHash() throws Exception {
748 final HttpRequest request = new BasicHttpRequest("Simple", "/");
749 final HttpHost host = new HttpHost("somehost", 80);
750 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
751 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
752 .build();
753
754
755 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", userhash=true";
756 final AuthChallenge authChallenge = parse(challenge);
757 final DigestScheme authscheme = new DigestScheme();
758 authscheme.processChallenge(authChallenge, null);
759
760 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
761 final String authResponse = authscheme.generateAuthResponse(host, request, null);
762
763 final Map<String, String> table = parseAuthResponse(authResponse);
764
765
766 final MessageDigest md = MessageDigest.getInstance("MD5");
767 md.update("username:realm1".getBytes(StandardCharsets.UTF_8));
768 final String expectedUserhash = bytesToHex(md.digest());
769
770 Assertions.assertEquals(expectedUserhash, table.get("username"));
771 Assertions.assertEquals("realm1", table.get("realm"));
772 Assertions.assertEquals("/", table.get("uri"));
773 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
774 Assertions.assertEquals("3b6561ceb73e5ffe9314a695179f23f9", table.get("response"));
775 }
776
777 private static String bytesToHex(final byte[] bytes) {
778 final StringBuilder hexString = new StringBuilder();
779 for (final byte b : bytes) {
780 final String hex = Integer.toHexString(0xff & b);
781 if (hex.length() == 1) {
782 hexString.append('0');
783 }
784 hexString.append(hex);
785 }
786 return hexString.toString();
787 }
788
789 @Test
790 void testDigestAuthenticationWithQuotedStringsAndWhitespace() throws Exception {
791 final HttpRequest request = new BasicHttpRequest("Simple", "/");
792 final HttpHost host = new HttpHost("somehost", 80);
793 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
794 .add(new AuthScope(host, "\"myhost@example.com\"", null), "\"Mufasa\"", "\"Circle Of Life\"".toCharArray())
795 .build();
796
797
798 final String challenge = StandardAuthScheme.DIGEST + " realm=\"\\\"myhost@example.com\\\"\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", userhash=true";
799 final AuthChallenge authChallenge = parse(challenge);
800 final DigestScheme authscheme = new DigestScheme();
801 authscheme.processChallenge(authChallenge, null);
802
803 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
804
805 final String authResponse = authscheme.generateAuthResponse(host, request, null);
806
807 final Map<String, String> table = parseAuthResponse(authResponse);
808
809
810 final MessageDigest md = MessageDigest.getInstance("MD5");
811 final String a1 = "Mufasa:myhost@example.com:Circle Of Life";
812 md.update(a1.getBytes(StandardCharsets.UTF_8));
813
814
815 final String response = table.get("response");
816 Assertions.assertNotNull(response);
817 }
818
819 @Test
820 void testDigestAuthenticationWithInvalidUsernameAndValidUsernameStar() throws Exception {
821 final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/");
822 final HttpHost host = new HttpHost("somehost", 80);
823 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
824 .add(new AuthScope(host, "realm1", null), "invalid\"username", "password".toCharArray())
825 .build();
826
827 final String encodedUsername = "UTF-8''J%C3%A4s%C3%B8n%20Doe";
828 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
829 "qop=\"auth-int\", username*=\"" + encodedUsername + "\"";
830 final AuthChallenge authChallenge = parse(challenge);
831 final DigestScheme authscheme = new DigestScheme();
832 authscheme.processChallenge(authChallenge, null);
833
834 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
835
836 final String authResponse = authscheme.generateAuthResponse(host, request, null);
837 Assertions.assertNotNull(authResponse);
838 }
839
840 @Test
841 void testDigestAuthenticationWithHighAsciiCharInUsername() throws Exception {
842 final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/");
843 final HttpHost host = new HttpHost("somehost", 80);
844
845 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
846 .add(new AuthScope(host, "realm1", null), "high\u007Fchar", "password".toCharArray())
847 .build();
848
849 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=\"auth-int\"";
850 final AuthChallenge authChallenge = parse(challenge);
851 final DigestScheme authscheme = new DigestScheme();
852 authscheme.processChallenge(authChallenge, null);
853
854 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
855 final String authResponse = authscheme.generateAuthResponse(host, request, null);
856
857
858 Assertions.assertTrue(authResponse.contains("username*"));
859 }
860
861
862 @Test
863 void testDigestAuthenticationWithExtendedAsciiCharInUsername() throws Exception {
864 final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/");
865 final HttpHost host = new HttpHost("somehost", 80);
866
867 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
868 .add(new AuthScope(host, "realm1", null), "username\u0080", "password".toCharArray())
869 .build();
870
871 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=\"auth-int\"";
872 final AuthChallenge authChallenge = parse(challenge);
873 final DigestScheme authscheme = new DigestScheme();
874 authscheme.processChallenge(authChallenge, null);
875
876 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
877 final String authResponse = authscheme.generateAuthResponse(host, request, null);
878
879
880 Assertions.assertTrue(authResponse.contains("username*"));
881 }
882
883
884 @Test
885 void testDigestAuthenticationWithNonAsciiUsername() throws Exception {
886 final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/");
887 final HttpHost host = new HttpHost("somehost", 80);
888
889 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
890 .add(new AuthScope(host, "realm1", null), "Jäsøn Doe", "password".toCharArray())
891 .build();
892
893 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=\"auth-int\"";
894 final AuthChallenge authChallenge = parse(challenge);
895 final DigestScheme authscheme = new DigestScheme();
896 authscheme.processChallenge(authChallenge, null);
897
898 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
899 final String authResponse = authscheme.generateAuthResponse(host, request, null);
900
901
902 Assertions.assertTrue(authResponse.contains("username*"));
903 }
904
905 @Test
906 void testRspAuthFieldAndQuoting() throws Exception {
907 final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/");
908 final HttpHost host = new HttpHost("somehost", 80);
909 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
910 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
911 .build();
912
913
914 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=\"auth-int\"";
915 final AuthChallenge authChallenge = parse(challenge);
916 final DigestScheme authscheme = new DigestScheme();
917 authscheme.processChallenge(authChallenge, null);
918
919 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
920 final String authResponse = authscheme.generateAuthResponse(host, request, null);
921
922 final Map<String, String> table = parseAuthResponse(authResponse);
923
924 Assertions.assertNotNull(table.get("rspauth"));
925 }
926
927 @Test
928 void testNextNonceUsageFromContext() throws Exception {
929 final HttpRequest request = new BasicHttpRequest("GET", "/");
930 final HttpHost host = new HttpHost("somehost", 80);
931 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
932 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
933 .build();
934
935 final HttpClientContext context = HttpClientContext.create();
936 context.setNextNonce("sampleNextNonce");
937
938 final DigestScheme authscheme = new DigestScheme();
939 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"initialNonce\"";
940 final AuthChallenge authChallenge = parse(challenge);
941 authscheme.processChallenge(authChallenge, context);
942
943
944 authscheme.isResponseReady(host, credentialsProvider, context);
945 final String authResponse = authscheme.generateAuthResponse(host, request, context);
946
947
948 final Map<String, String> paramMap = parseAuthResponse(authResponse);
949 Assertions.assertEquals("sampleNextNonce", paramMap.get("nonce"), "The nonce should match 'auth-nextnonce' from the context.");
950
951
952 Assertions.assertNull(context.getAttribute("auth-nextnonce"), "The next nonce should be removed from the context after use.");
953 }
954
955
956 @Test
957 void testNoNextNonceUsageFromContext() throws Exception {
958 final HttpRequest request = new BasicHttpRequest("GET", "/");
959 final HttpHost host = new HttpHost("somehost", 80);
960 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
961 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
962 .build();
963
964 final HttpClientContext context = HttpClientContext.create();
965
966
967 final DigestScheme authscheme = new DigestScheme();
968 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"initialNonce\"";
969 final AuthChallenge authChallenge = parse(challenge);
970 authscheme.processChallenge(authChallenge, context);
971
972
973 authscheme.isResponseReady(host, credentialsProvider, context);
974 final String authResponse = authscheme.generateAuthResponse(host, request, context);
975
976
977 final Map<String, String> paramMap = parseAuthResponse(authResponse);
978 Assertions.assertEquals("initialNonce", paramMap.get("nonce"), "The nonce should match the initial nonce provided in the challenge.");
979
980
981 Assertions.assertNull(context.getAttribute("auth-nextnonce"), "The context should not contain a nextNonce attribute.");
982 }
983
984
985 @Test
986 void testDigestAuthenticationWithSHA256() throws Exception {
987 final HttpRequest request = new BasicHttpRequest("Simple", "/");
988 final HttpHost host = new HttpHost("somehost", 80);
989 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
990 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
991 .build();
992
993 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", algorithm=SHA-256";
994 final AuthChallenge authChallenge = parse(challenge);
995 final DigestScheme authscheme = new DigestScheme();
996 authscheme.processChallenge(authChallenge, null);
997
998 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
999 final String authResponse = authscheme.generateAuthResponse(host, request, null);
1000
1001 final Map<String, String> table = parseAuthResponse(authResponse);
1002 Assertions.assertEquals("username", table.get("username"));
1003 Assertions.assertEquals("realm1", table.get("realm"));
1004 Assertions.assertEquals("/", table.get("uri"));
1005 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
1006 Assertions.assertEquals("SHA-256", table.get("algorithm"));
1007 Assertions.assertNotNull(table.get("response"));
1008
1009 }
1010
1011 @Test
1012 void testDigestAuthenticationWithSHA512_256() throws Exception {
1013 final HttpRequest request = new BasicHttpRequest("Simple", "/");
1014 final HttpHost host = new HttpHost("somehost", 80);
1015 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
1016 .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
1017 .build();
1018
1019 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", algorithm=SHA-512-256";
1020 final AuthChallenge authChallenge = parse(challenge);
1021 final DigestScheme authscheme = new DigestScheme();
1022 authscheme.processChallenge(authChallenge, null);
1023
1024 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1025 final String authResponse = authscheme.generateAuthResponse(host, request, null);
1026
1027 final Map<String, String> table = parseAuthResponse(authResponse);
1028 Assertions.assertEquals("username", table.get("username"));
1029 Assertions.assertEquals("realm1", table.get("realm"));
1030 Assertions.assertEquals("/", table.get("uri"));
1031 Assertions.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
1032 Assertions.assertEquals("SHA-512-256", table.get("algorithm"));
1033 Assertions.assertNotNull(table.get("response"));
1034 }
1035
1036 @Test
1037 void testDigestSHA256SessA1AndCnonceConsistency() throws Exception {
1038 final HttpHost host = new HttpHost("somehost", 80);
1039 final HttpRequest request = new BasicHttpRequest("GET", "/");
1040 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
1041 .add(new AuthScope(host, "subnet.domain.com", null), "username", "password".toCharArray())
1042 .build();
1043
1044 final String challenge1 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-256-sess, nonce=\"1234567890abcdef\", " +
1045 "charset=utf-8, realm=\"subnet.domain.com\"";
1046 final AuthChallenge authChallenge1 = parse(challenge1);
1047 final DigestScheme authscheme = new DigestScheme();
1048 authscheme.processChallenge(authChallenge1, null);
1049 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1050 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
1051
1052 final Map<String, String> table1 = parseAuthResponse(authResponse1);
1053 Assertions.assertEquals("00000001", table1.get("nc"));
1054 final String cnonce1 = authscheme.getCnonce();
1055 final String sessionKey1 = authscheme.getA1();
1056
1057 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1058 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
1059 final Map<String, String> table2 = parseAuthResponse(authResponse2);
1060 Assertions.assertEquals("00000002", table2.get("nc"));
1061 final String cnonce2 = authscheme.getCnonce();
1062 final String sessionKey2 = authscheme.getA1();
1063
1064 Assertions.assertEquals(cnonce1, cnonce2);
1065 Assertions.assertEquals(sessionKey1, sessionKey2);
1066
1067 final String challenge2 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-256-sess, nonce=\"1234567890abcdef\", " +
1068 "charset=utf-8, realm=\"subnet.domain.com\"";
1069 final AuthChallenge authChallenge2 = parse(challenge2);
1070 authscheme.processChallenge(authChallenge2, null);
1071 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1072 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
1073 final Map<String, String> table3 = parseAuthResponse(authResponse3);
1074 Assertions.assertEquals("00000003", table3.get("nc"));
1075
1076 final String cnonce3 = authscheme.getCnonce();
1077 final String sessionKey3 = authscheme.getA1();
1078
1079 Assertions.assertEquals(cnonce1, cnonce3);
1080 Assertions.assertEquals(sessionKey1, sessionKey3);
1081
1082 final String challenge3 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-256-sess, nonce=\"fedcba0987654321\", " +
1083 "charset=utf-8, realm=\"subnet.domain.com\"";
1084 final AuthChallenge authChallenge3 = parse(challenge3);
1085 authscheme.processChallenge(authChallenge3, null);
1086 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1087 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
1088 final Map<String, String> table4 = parseAuthResponse(authResponse4);
1089 Assertions.assertEquals("00000001", table4.get("nc"));
1090
1091 final String cnonce4 = authscheme.getCnonce();
1092 final String sessionKey4 = authscheme.getA1();
1093
1094 Assertions.assertNotEquals(cnonce1, cnonce4);
1095 Assertions.assertNotEquals(sessionKey1, sessionKey4);
1096 }
1097
1098
1099 @Test
1100 void testDigestSHA512256SessA1AndCnonceConsistency() throws Exception {
1101 final HttpHost host = new HttpHost("somehost", 80);
1102 final HttpRequest request = new BasicHttpRequest("GET", "/");
1103 final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
1104 .add(new AuthScope(host, "subnet.domain.com", null), "username", "password".toCharArray())
1105 .build();
1106
1107 final String challenge1 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-512-256-sess, nonce=\"1234567890abcdef\", " +
1108 "charset=utf-8, realm=\"subnet.domain.com\"";
1109 final AuthChallenge authChallenge1 = parse(challenge1);
1110 final DigestScheme authscheme = new DigestScheme();
1111 authscheme.processChallenge(authChallenge1, null);
1112 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1113 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
1114
1115 final Map<String, String> table1 = parseAuthResponse(authResponse1);
1116 Assertions.assertEquals("00000001", table1.get("nc"));
1117 final String cnonce1 = authscheme.getCnonce();
1118 final String sessionKey1 = authscheme.getA1();
1119
1120 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1121 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
1122 final Map<String, String> table2 = parseAuthResponse(authResponse2);
1123 Assertions.assertEquals("00000002", table2.get("nc"));
1124 final String cnonce2 = authscheme.getCnonce();
1125 final String sessionKey2 = authscheme.getA1();
1126
1127 Assertions.assertEquals(cnonce1, cnonce2);
1128 Assertions.assertEquals(sessionKey1, sessionKey2);
1129
1130 final String challenge2 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-512-256-sess, nonce=\"1234567890abcdef\", " +
1131 "charset=utf-8, realm=\"subnet.domain.com\"";
1132 final AuthChallenge authChallenge2 = parse(challenge2);
1133 authscheme.processChallenge(authChallenge2, null);
1134 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1135 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
1136 final Map<String, String> table3 = parseAuthResponse(authResponse3);
1137 Assertions.assertEquals("00000003", table3.get("nc"));
1138
1139 final String cnonce3 = authscheme.getCnonce();
1140 final String sessionKey3 = authscheme.getA1();
1141
1142 Assertions.assertEquals(cnonce1, cnonce3);
1143 Assertions.assertEquals(sessionKey1, sessionKey3);
1144
1145 final String challenge3 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=SHA-512-256-sess, nonce=\"fedcba0987654321\", " +
1146 "charset=utf-8, realm=\"subnet.domain.com\"";
1147 final AuthChallenge authChallenge3 = parse(challenge3);
1148 authscheme.processChallenge(authChallenge3, null);
1149 Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
1150 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
1151 final Map<String, String> table4 = parseAuthResponse(authResponse4);
1152 Assertions.assertEquals("00000001", table4.get("nc"));
1153
1154 final String cnonce4 = authscheme.getCnonce();
1155 final String sessionKey4 = authscheme.getA1();
1156
1157 Assertions.assertNotEquals(cnonce1, cnonce4);
1158 Assertions.assertNotEquals(sessionKey1, sessionKey4);
1159 }
1160
1161
1162
1163 }