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.StandardAuthScheme;
43 import org.apache.hc.client5.http.auth.AuthScope;
44 import org.apache.hc.client5.http.auth.AuthenticationException;
45 import org.apache.hc.client5.http.auth.ChallengeType;
46 import org.apache.hc.client5.http.auth.Credentials;
47 import org.apache.hc.client5.http.auth.MalformedChallengeException;
48 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
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.Assert;
63 import org.junit.Test;
64
65
66
67
68 public 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 Assert.assertEquals(1, authChallenges.size());
76 return authChallenges.get(0);
77 }
78
79 @Test(expected=MalformedChallengeException.class)
80 public void testDigestAuthenticationEmptyChallenge1() throws Exception {
81 final AuthChallenge authChallenge = parse(StandardAuthScheme.DIGEST);
82 final AuthScheme authscheme = new DigestScheme();
83 authscheme.processChallenge(authChallenge, null);
84 }
85
86 @Test(expected=MalformedChallengeException.class)
87 public void testDigestAuthenticationEmptyChallenge2() throws Exception {
88 final AuthChallenge authChallenge = parse(StandardAuthScheme.DIGEST + " ");
89 final AuthScheme authscheme = new DigestScheme();
90 authscheme.processChallenge(authChallenge, null);
91 }
92
93 @Test
94 public void testDigestAuthenticationWithDefaultCreds() throws Exception {
95 final HttpRequest request = new BasicHttpRequest("Simple", "/");
96 final HttpHost host = new HttpHost("somehost", 80);
97 final AuthScope authScope = new AuthScope(host, "realm1", null);
98 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
99 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
100 credentialsProvider.setCredentials(authScope, creds);
101
102 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
103 final AuthChallenge authChallenge = parse(challenge);
104 final DigestScheme authscheme = new DigestScheme();
105 authscheme.processChallenge(authChallenge, null);
106
107 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
108 final String authResponse = authscheme.generateAuthResponse(host, request, null);
109 Assert.assertTrue(authscheme.isChallengeComplete());
110 Assert.assertFalse(authscheme.isConnectionBased());
111
112 final Map<String, String> table = parseAuthResponse(authResponse);
113 Assert.assertEquals("username", table.get("username"));
114 Assert.assertEquals("realm1", table.get("realm"));
115 Assert.assertEquals("/", table.get("uri"));
116 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
117 Assert.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
118 }
119
120 @Test
121 public void testDigestAuthentication() throws Exception {
122 final HttpRequest request = new BasicHttpRequest("Simple", "/");
123 final HttpHost host = new HttpHost("somehost", 80);
124 final AuthScope authScope = new AuthScope(host, "realm1", null);
125 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
126 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
127 credentialsProvider.setCredentials(authScope, creds);
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 Assert.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 Assert.assertEquals("username", table.get("username"));
139 Assert.assertEquals("realm1", table.get("realm"));
140 Assert.assertEquals("/", table.get("uri"));
141 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
142 Assert.assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
143 }
144
145 @Test
146 public void testDigestAuthenticationInvalidInput() throws Exception {
147 final HttpHost host = new HttpHost("somehost", 80);
148 final AuthScope authScope = new AuthScope(host, "realm1", null);
149 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
150 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
151 credentialsProvider.setCredentials(authScope, creds);
152
153 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
154 final AuthChallenge authChallenge = parse(challenge);
155 final DigestScheme authscheme = new DigestScheme();
156 authscheme.processChallenge(authChallenge, null);
157
158 try {
159 authscheme.isResponseReady(null, credentialsProvider, null);
160 Assert.fail("NullPointerException should have been thrown");
161 } catch (final NullPointerException ex) {
162 }
163 try {
164 authscheme.isResponseReady(host, null, null);
165 Assert.fail("NullPointerException should have been thrown");
166 } catch (final NullPointerException ex) {
167 }
168 try {
169 authscheme.generateAuthResponse(host, null, null);
170 Assert.fail("NullPointerException should have been thrown");
171 } catch (final NullPointerException ex) {
172 }
173 }
174
175 @Test
176 public void testDigestAuthenticationWithSHA() throws Exception {
177 final HttpRequest request = new BasicHttpRequest("Simple", "/");
178 final HttpHost host = new HttpHost("somehost", 80);
179 final AuthScope authScope = new AuthScope(host, "realm1", null);
180 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
181 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
182 credentialsProvider.setCredentials(authScope, creds);
183
184 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", " +
185 "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
186 "algorithm=SHA";
187 final AuthChallenge authChallenge = parse(challenge);
188 final DigestScheme authscheme = new DigestScheme();
189 authscheme.processChallenge(authChallenge, null);
190
191 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
192 final String authResponse = authscheme.generateAuthResponse(host, request, null);
193
194 final Map<String, String> table = parseAuthResponse(authResponse);
195 Assert.assertEquals("username", table.get("username"));
196 Assert.assertEquals("realm1", table.get("realm"));
197 Assert.assertEquals("/", table.get("uri"));
198 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
199 Assert.assertEquals("8769e82e4e28ecc040b969562b9050580c6d186d", table.get("response"));
200 }
201
202 @Test
203 public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
204 final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
205 final HttpHost host = new HttpHost("somehost", 80);
206 final AuthScope authScope = new AuthScope(host, "realm1", null);
207 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
208 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
209 credentialsProvider.setCredentials(authScope, creds);
210
211 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
212 final AuthChallenge authChallenge = parse(challenge);
213 final DigestScheme authscheme = new DigestScheme();
214 authscheme.processChallenge(authChallenge, null);
215
216 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
217 final String authResponse = authscheme.generateAuthResponse(host, request, null);
218
219 final Map<String, String> table = parseAuthResponse(authResponse);
220 Assert.assertEquals("username", table.get("username"));
221 Assert.assertEquals("realm1", table.get("realm"));
222 Assert.assertEquals("/?param=value", table.get("uri"));
223 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
224 Assert.assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table.get("response"));
225 }
226
227 @Test(expected=AuthenticationException.class)
228 public void testDigestAuthenticationNoRealm() throws Exception {
229 final HttpRequest request = new BasicHttpRequest("Simple", "/");
230 final HttpHost host = new HttpHost("somehost", 80);
231 final AuthScope authScope = new AuthScope(host, "realm1", null);
232 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
233 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
234 credentialsProvider.setCredentials(authScope, creds);
235
236 final String challenge = StandardAuthScheme.DIGEST + " no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
237 final AuthChallenge authChallenge = parse(challenge);
238 final DigestScheme authscheme = new DigestScheme();
239 authscheme.processChallenge(authChallenge, null);
240
241 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
242 authscheme.generateAuthResponse(host, request, null);
243 }
244
245 @Test(expected=AuthenticationException.class)
246 public void testDigestAuthenticationNoNonce() throws Exception {
247 final HttpRequest request = new BasicHttpRequest("Simple", "/");
248 final HttpHost host = new HttpHost("somehost", 80);
249 final AuthScope authScope = new AuthScope(host, "realm1", null);
250 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
251 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
252 credentialsProvider.setCredentials(authScope, creds);
253
254 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
255 final AuthChallenge authChallenge = parse(challenge);
256 final DigestScheme authscheme = new DigestScheme();
257 authscheme.processChallenge(authChallenge, null);
258
259 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
260 authscheme.generateAuthResponse(host, request, null);
261 }
262
263
264
265
266 @Test
267 public void testDigestAuthenticationMD5Sess() throws Exception {
268
269
270 final String realm="realm";
271 final String username="username";
272 final String password="password";
273 final String nonce="e273f1776275974f1a120d8b92c5b3cb";
274
275 final HttpRequest request = new BasicHttpRequest("Simple", "/");
276 final HttpHost host = new HttpHost("somehost", 80);
277 final AuthScope authScope = new AuthScope(host, realm, null);
278 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
279 final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
280 credentialsProvider.setCredentials(authScope, creds);
281
282 final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
283 + "nonce=\"" + nonce + "\", "
284 + "opaque=\"SomeString\", "
285 + "stale=false, "
286 + "algorithm=MD5-sess, "
287 + "qop=\"auth,auth-int\"";
288
289 final AuthChallenge authChallenge = parse(challenge);
290
291 final DigestScheme authscheme = new DigestScheme();
292 authscheme.processChallenge(authChallenge, null);
293
294 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
295 final String authResponse = authscheme.generateAuthResponse(host, request, null);
296
297 Assert.assertTrue(authResponse.indexOf("nc=00000001") > 0);
298 Assert.assertTrue(authResponse.indexOf("qop=auth") > 0);
299
300 final Map<String, String> table = parseAuthResponse(authResponse);
301 Assert.assertEquals(username, table.get("username"));
302 Assert.assertEquals(realm, table.get("realm"));
303 Assert.assertEquals("MD5-sess", table.get("algorithm"));
304 Assert.assertEquals("/", table.get("uri"));
305 Assert.assertEquals(nonce, table.get("nonce"));
306 Assert.assertEquals(1, Integer.parseInt(table.get("nc"),16));
307 Assert.assertTrue(null != table.get("cnonce"));
308 Assert.assertEquals("SomeString", table.get("opaque"));
309 Assert.assertEquals("auth", table.get("qop"));
310
311 Assert.assertTrue(null != table.get("response"));
312 }
313
314
315
316
317 @Test
318 public void testDigestAuthenticationMD5SessNoQop() throws Exception {
319
320
321 final String realm="realm";
322 final String username="username";
323 final String password="password";
324 final String nonce="e273f1776275974f1a120d8b92c5b3cb";
325
326 final HttpRequest request = new BasicHttpRequest("Simple", "/");
327 final HttpHost host = new HttpHost("somehost", 80);
328 final AuthScope authScope = new AuthScope(host, realm, null);
329 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
330 final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
331 credentialsProvider.setCredentials(authScope, creds);
332
333 final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
334 + "nonce=\"" + nonce + "\", "
335 + "opaque=\"SomeString\", "
336 + "stale=false, "
337 + "algorithm=MD5-sess";
338
339 final AuthChallenge authChallenge = parse(challenge);
340
341 final DigestScheme authscheme = new DigestScheme();
342 authscheme.processChallenge(authChallenge, null);
343 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
344 final String authResponse = authscheme.generateAuthResponse(host, request, null);
345
346 final Map<String, String> table = parseAuthResponse(authResponse);
347 Assert.assertEquals(username, table.get("username"));
348 Assert.assertEquals(realm, table.get("realm"));
349 Assert.assertEquals("MD5-sess", table.get("algorithm"));
350 Assert.assertEquals("/", table.get("uri"));
351 Assert.assertEquals(nonce, table.get("nonce"));
352 Assert.assertTrue(null == table.get("nc"));
353 Assert.assertEquals("SomeString", table.get("opaque"));
354 Assert.assertTrue(null == table.get("qop"));
355
356 Assert.assertTrue(null != table.get("response"));
357 }
358
359
360
361
362 @Test(expected=AuthenticationException.class)
363 public void testDigestAuthenticationMD5SessUnknownQop() throws Exception {
364
365
366 final String realm="realm";
367 final String username="username";
368 final String password="password";
369 final String nonce="e273f1776275974f1a120d8b92c5b3cb";
370
371 final HttpRequest request = new BasicHttpRequest("Simple", "/");
372 final HttpHost host = new HttpHost("somehost", 80);
373 final AuthScope authScope = new AuthScope(host, realm, null);
374 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
375 final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
376 credentialsProvider.setCredentials(authScope, creds);
377
378 final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
379 + "nonce=\"" + nonce + "\", "
380 + "opaque=\"SomeString\", "
381 + "stale=false, "
382 + "algorithm=MD5-sess, "
383 + "qop=\"stuff\"";
384
385 final AuthChallenge authChallenge = parse(challenge);
386
387 final DigestScheme authscheme = new DigestScheme();
388 authscheme.processChallenge(authChallenge, null);
389
390 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
391 authscheme.generateAuthResponse(host, request, null);
392 }
393
394
395
396
397 @Test(expected=AuthenticationException.class)
398 public void testDigestAuthenticationUnknownAlgo() throws Exception {
399
400
401 final String realm="realm";
402 final String username="username";
403 final String password="password";
404 final String nonce="e273f1776275974f1a120d8b92c5b3cb";
405
406 final HttpRequest request = new BasicHttpRequest("Simple", "/");
407 final HttpHost host = new HttpHost("somehost", 80);
408 final AuthScope authScope = new AuthScope(host, realm, null);
409 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
410 final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
411 credentialsProvider.setCredentials(authScope, creds);
412
413 final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
414 + "nonce=\"" + nonce + "\", "
415 + "opaque=\"SomeString\", "
416 + "stale=false, "
417 + "algorithm=stuff, "
418 + "qop=\"auth\"";
419
420 final AuthChallenge authChallenge = parse(challenge);
421
422 final DigestScheme authscheme = new DigestScheme();
423 authscheme.processChallenge(authChallenge, null);
424
425 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
426 authscheme.generateAuthResponse(host, request, null);
427 }
428
429 @Test
430 public void testDigestAuthenticationWithStaleNonce() throws Exception {
431 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", " +
432 "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", stale=\"true\"";
433 final AuthChallenge authChallenge = parse(challenge);
434 final AuthScheme authscheme = new DigestScheme();
435 authscheme.processChallenge(authChallenge, null);
436
437 Assert.assertFalse(authscheme.isChallengeComplete());
438 }
439
440 private static Map<String, String> parseAuthResponse(final String authResponse) {
441 if (!authResponse.startsWith(StandardAuthScheme.DIGEST + " ")) {
442 return null;
443 }
444 final String s = authResponse.substring(7);
445 final ParserCursor cursor = new ParserCursor(0, s.length());
446 final HeaderElement[] elements = BasicHeaderValueParser.INSTANCE.parseElements(s, cursor);
447 final Map<String, String> map = new HashMap<>(elements.length);
448 for (final HeaderElement element : elements) {
449 map.put(element.getName(), element.getValue());
450 }
451 return map;
452 }
453
454 @Test
455 public void testDigestNouceCount() throws Exception {
456 final HttpRequest request = new BasicHttpRequest("GET", "/");
457 final HttpHost host = new HttpHost("somehost", 80);
458 final AuthScope authScope = new AuthScope(host, "realm1", null);
459 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
460 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
461 credentialsProvider.setCredentials(authScope, creds);
462
463 final String challenge1 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
464 final AuthChallenge authChallenge1 = parse(challenge1);
465
466 final DigestScheme authscheme = new DigestScheme();
467 authscheme.processChallenge(authChallenge1, null);
468 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
469 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
470
471 final Map<String, String> table1 = parseAuthResponse(authResponse1);
472 Assert.assertEquals("00000001", table1.get("nc"));
473
474 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
475 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
476
477 final Map<String, String> table2 = parseAuthResponse(authResponse2);
478 Assert.assertEquals("00000002", table2.get("nc"));
479 final String challenge2 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
480 final AuthChallenge authChallenge2 = parse(challenge2);
481 authscheme.processChallenge(authChallenge2, null);
482
483 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
484 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
485
486 final Map<String, String> table3 = parseAuthResponse(authResponse3);
487 Assert.assertEquals("00000003", table3.get("nc"));
488 final String challenge3 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth";
489 final AuthChallenge authChallenge3 = parse(challenge3);
490 authscheme.processChallenge(authChallenge3, null);
491
492 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
493 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
494
495 final Map<String, String> table4 = parseAuthResponse(authResponse4);
496 Assert.assertEquals("00000001", table4.get("nc"));
497 }
498
499 @Test
500 public void testDigestMD5SessA1AndCnonceConsistency() throws Exception {
501 final HttpHost host = new HttpHost("somehost", 80);
502 final AuthScope authScope = new AuthScope(host, "subnet.domain.com", null);
503 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
504 final HttpRequest request = new BasicHttpRequest("GET", "/");
505 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
506 credentialsProvider.setCredentials(authScope, creds);
507
508 final String challenge1 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
509 "charset=utf-8, realm=\"subnet.domain.com\"";
510 final AuthChallenge authChallenge1 = parse(challenge1);
511 final DigestScheme authscheme = new DigestScheme();
512 authscheme.processChallenge(authChallenge1, null);
513 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
514 final String authResponse1 = authscheme.generateAuthResponse(host, request, null);
515
516 final Map<String, String> table1 = parseAuthResponse(authResponse1);
517 Assert.assertEquals("00000001", table1.get("nc"));
518 final String cnonce1 = authscheme.getCnonce();
519 final String sessionKey1 = authscheme.getA1();
520
521 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
522 final String authResponse2 = authscheme.generateAuthResponse(host, request, null);
523 final Map<String, String> table2 = parseAuthResponse(authResponse2);
524 Assert.assertEquals("00000002", table2.get("nc"));
525 final String cnonce2 = authscheme.getCnonce();
526 final String sessionKey2 = authscheme.getA1();
527
528 Assert.assertEquals(cnonce1, cnonce2);
529 Assert.assertEquals(sessionKey1, sessionKey2);
530
531 final String challenge2 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
532 "charset=utf-8, realm=\"subnet.domain.com\"";
533 final AuthChallenge authChallenge2 = parse(challenge2);
534 authscheme.processChallenge(authChallenge2, null);
535 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
536 final String authResponse3 = authscheme.generateAuthResponse(host, request, null);
537 final Map<String, String> table3 = parseAuthResponse(authResponse3);
538 Assert.assertEquals("00000003", table3.get("nc"));
539
540 final String cnonce3 = authscheme.getCnonce();
541 final String sessionKey3 = authscheme.getA1();
542
543 Assert.assertEquals(cnonce1, cnonce3);
544 Assert.assertEquals(sessionKey1, sessionKey3);
545
546 final String challenge3 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"fedcba0987654321\", " +
547 "charset=utf-8, realm=\"subnet.domain.com\"";
548 final AuthChallenge authChallenge3 = parse(challenge3);
549 authscheme.processChallenge(authChallenge3, null);
550 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
551 final String authResponse4 = authscheme.generateAuthResponse(host, request, null);
552 final Map<String, String> table4 = parseAuthResponse(authResponse4);
553 Assert.assertEquals("00000001", table4.get("nc"));
554
555 final String cnonce4 = authscheme.getCnonce();
556 final String sessionKey4 = authscheme.getA1();
557
558 Assert.assertFalse(cnonce1.equals(cnonce4));
559 Assert.assertFalse(sessionKey1.equals(sessionKey4));
560 }
561
562 @Test
563 public void testHttpEntityDigest() throws Exception {
564 final HttpEntityDigester digester = new HttpEntityDigester(MessageDigest.getInstance("MD5"));
565 Assert.assertNull(digester.getDigest());
566 digester.write('a');
567 digester.write('b');
568 digester.write('c');
569 digester.write(0xe4);
570 digester.write(0xf6);
571 digester.write(0xfc);
572 digester.write(new byte[] { 'a', 'b', 'c'});
573 Assert.assertNull(digester.getDigest());
574 digester.close();
575 Assert.assertEquals("acd2b59cd01c7737d8069015584c6cac", DigestScheme.formatHex(digester.getDigest()));
576 try {
577 digester.write('a');
578 Assert.fail("IOException should have been thrown");
579 } catch (final IOException ex) {
580 }
581 try {
582 digester.write(new byte[] { 'a', 'b', 'c'});
583 Assert.fail("IOException should have been thrown");
584 } catch (final IOException ex) {
585 }
586 }
587
588 @Test
589 public void testDigestAuthenticationQopAuthInt() throws Exception {
590 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
591 request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", StandardCharsets.ISO_8859_1));
592 final HttpHost host = new HttpHost("somehost", 80);
593 final AuthScope authScope = new AuthScope(host, "realm1", null);
594 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
595 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
596 credentialsProvider.setCredentials(authScope, creds);
597
598 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
599 "qop=\"auth,auth-int\"";
600 final AuthChallenge authChallenge = parse(challenge);
601 final DigestScheme authscheme = new DigestScheme();
602 authscheme.processChallenge(authChallenge, null);
603 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
604 final String authResponse = authscheme.generateAuthResponse(host, request, null);
605
606 Assert.assertEquals("Post:/:acd2b59cd01c7737d8069015584c6cac", authscheme.getA2());
607
608 final Map<String, String> table = parseAuthResponse(authResponse);
609 Assert.assertEquals("username", table.get("username"));
610 Assert.assertEquals("realm1", table.get("realm"));
611 Assert.assertEquals("/", table.get("uri"));
612 Assert.assertEquals("auth-int", table.get("qop"));
613 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
614 }
615
616 @Test
617 public void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
618 final HttpRequest request = new BasicHttpRequest("Post", "/");
619 final HttpHost host = new HttpHost("somehost", 80);
620 final AuthScope authScope = new AuthScope(host, "realm1", null);
621 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
622 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
623 credentialsProvider.setCredentials(authScope, creds);
624
625 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
626 "qop=\"auth-int\"";
627 final AuthChallenge authChallenge = parse(challenge);
628 final DigestScheme authscheme = new DigestScheme();
629 authscheme.processChallenge(authChallenge, null);
630 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
631 final String authResponse = authscheme.generateAuthResponse(host, request, null);
632
633 Assert.assertEquals("Post:/:d41d8cd98f00b204e9800998ecf8427e", authscheme.getA2());
634
635 final Map<String, String> table = parseAuthResponse(authResponse);
636 Assert.assertEquals("username", table.get("username"));
637 Assert.assertEquals("realm1", table.get("realm"));
638 Assert.assertEquals("/", table.get("uri"));
639 Assert.assertEquals("auth-int", table.get("qop"));
640 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
641 }
642
643 @Test
644 public void testDigestAuthenticationQopAuthOrAuthIntNonRepeatableEntity() throws Exception {
645 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
646 request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1, ContentType.DEFAULT_TEXT));
647 final HttpHost host = new HttpHost("somehost", 80);
648 final AuthScope authScope = new AuthScope(host, "realm1", null);
649 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
650 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
651 credentialsProvider.setCredentials(authScope, creds);
652
653 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
654 "qop=\"auth,auth-int\"";
655 final AuthChallenge authChallenge = parse(challenge);
656 final DigestScheme authscheme = new DigestScheme();
657 authscheme.processChallenge(authChallenge, null);
658 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
659 final String authResponse = authscheme.generateAuthResponse(host, request, null);
660
661 Assert.assertEquals("Post:/", authscheme.getA2());
662
663 final Map<String, String> table = parseAuthResponse(authResponse);
664 Assert.assertEquals("username", table.get("username"));
665 Assert.assertEquals("realm1", table.get("realm"));
666 Assert.assertEquals("/", table.get("uri"));
667 Assert.assertEquals("auth", table.get("qop"));
668 Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
669 }
670
671 @Test
672 public void testParameterCaseSensitivity() throws Exception {
673 final HttpRequest request = new BasicHttpRequest("GET", "/");
674 final HttpHost host = new HttpHost("somehost", 80);
675 final AuthScope authScope = new AuthScope(host, "-", null);
676 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
677 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
678 credentialsProvider.setCredentials(authScope, creds);
679
680 final String challenge = StandardAuthScheme.DIGEST + " Realm=\"-\", " +
681 "nonce=\"YjYuNGYyYmJhMzUuY2I5ZDhlZDE5M2ZlZDM 1Mjk3NGJkNTIyYjgyNTcwMjQ=\", " +
682 "opaque=\"98700A3D9CE17065E2246B41035C6609\", qop=\"auth\"";
683 final AuthChallenge authChallenge = parse(challenge);
684 final DigestScheme authscheme = new DigestScheme();
685 authscheme.processChallenge(authChallenge, null);
686 Assert.assertEquals("-", authscheme.getRealm());
687
688 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
689 authscheme.generateAuthResponse(host, request, null);
690 }
691
692 @Test(expected=AuthenticationException.class)
693 public void testDigestAuthenticationQopIntOnlyNonRepeatableEntity() throws Exception {
694 final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
695 request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1, ContentType.DEFAULT_TEXT));
696 final HttpHost host = new HttpHost("somehost", 80);
697 final AuthScope authScope = new AuthScope(host, "realm1", null);
698 final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
699 final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
700 credentialsProvider.setCredentials(authScope, creds);
701
702 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
703 "qop=\"auth-int\"";
704 final AuthChallenge authChallenge = parse(challenge);
705 final DigestScheme authscheme = new DigestScheme();
706 authscheme.processChallenge(authChallenge, null);
707
708 Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
709 authscheme.generateAuthResponse(host, request, null);
710 }
711
712 @Test
713 public void testSerialization() throws Exception {
714 final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
715 "qop=\"auth,auth-int\"";
716 final AuthChallenge authChallenge = parse(challenge);
717 final DigestScheme digestScheme = new DigestScheme();
718 digestScheme.processChallenge(authChallenge, null);
719
720 final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
721 final ObjectOutputStream out = new ObjectOutputStream(buffer);
722 out.writeObject(digestScheme);
723 out.flush();
724 final byte[] raw = buffer.toByteArray();
725 final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
726 final DigestScheme authScheme = (DigestScheme) in.readObject();
727
728 Assert.assertEquals(digestScheme.getName(), authScheme.getName());
729 Assert.assertEquals(digestScheme.getRealm(), authScheme.getRealm());
730 Assert.assertEquals(digestScheme.isChallengeComplete(), authScheme.isChallengeComplete());
731 Assert.assertEquals(digestScheme.getA1(), authScheme.getA1());
732 Assert.assertEquals(digestScheme.getA2(), authScheme.getA2());
733 Assert.assertEquals(digestScheme.getCnonce(), authScheme.getCnonce());
734 }
735
736 }