1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_auth_handler_digest.h"
6
7 #include <string>
8
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/network_anonymization_key.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/dns/mock_host_resolver.h"
15 #include "net/http/http_auth_challenge_tokenizer.h"
16 #include "net/http/http_request_info.h"
17 #include "net/log/net_log_with_source.h"
18 #include "net/ssl/ssl_info.h"
19 #include "net/test/gtest_util.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "url/gurl.h"
23 #include "url/scheme_host_port.h"
24
25 using net::test::IsOk;
26
27 namespace net {
28
29 namespace {
30
31 const char* const kSimpleChallenge =
32 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
33
34 // RespondToChallenge creates an HttpAuthHandlerDigest for the specified
35 // |challenge|, and generates a response to the challenge which is returned in
36 // |token|.
37 //
38 // The return value indicates whether the |token| was successfully created.
39 //
40 // If |target| is HttpAuth::AUTH_PROXY, then |proxy_name| specifies the source
41 // of the |challenge|. Otherwise, the scheme and host and port of |request_url|
42 // indicates the origin of the challenge.
RespondToChallenge(HttpAuth::Target target,const std::string & proxy_name,const std::string & request_url,const std::string & challenge,std::string * token)43 bool RespondToChallenge(HttpAuth::Target target,
44 const std::string& proxy_name,
45 const std::string& request_url,
46 const std::string& challenge,
47 std::string* token) {
48 // Input validation.
49 if (token == nullptr) {
50 ADD_FAILURE() << "|token| must be valid";
51 return false;
52 }
53 EXPECT_TRUE(target != HttpAuth::AUTH_PROXY || !proxy_name.empty());
54 EXPECT_FALSE(request_url.empty());
55 EXPECT_FALSE(challenge.empty());
56
57 token->clear();
58 auto factory = std::make_unique<HttpAuthHandlerDigest::Factory>();
59 auto nonce_generator =
60 std::make_unique<HttpAuthHandlerDigest::FixedNonceGenerator>(
61 "client_nonce");
62 factory->set_nonce_generator(std::move(nonce_generator));
63 auto host_resolver = std::make_unique<MockHostResolver>();
64 std::unique_ptr<HttpAuthHandler> handler;
65
66 // Create a handler for a particular challenge.
67 SSLInfo null_ssl_info;
68 url::SchemeHostPort scheme_host_port(
69 target == HttpAuth::AUTH_SERVER ? GURL(request_url) : GURL(proxy_name));
70 int rv_create = factory->CreateAuthHandlerFromString(
71 challenge, target, null_ssl_info, NetworkAnonymizationKey(),
72 scheme_host_port, NetLogWithSource(), host_resolver.get(), &handler);
73 if (rv_create != OK || handler.get() == nullptr) {
74 ADD_FAILURE() << "Unable to create auth handler.";
75 return false;
76 }
77
78 // Create a token in response to the challenge.
79 // NOTE: HttpAuthHandlerDigest's implementation of GenerateAuthToken always
80 // completes synchronously. That's why this test can get away with a
81 // TestCompletionCallback without an IO thread.
82 TestCompletionCallback callback;
83 auto request = std::make_unique<HttpRequestInfo>();
84 request->url = GURL(request_url);
85 AuthCredentials credentials(u"foo", u"bar");
86 int rv_generate = handler->GenerateAuthToken(
87 &credentials, request.get(), callback.callback(), token);
88 if (rv_generate != OK) {
89 ADD_FAILURE() << "Problems generating auth token";
90 return false;
91 }
92
93 return true;
94 }
95
96 } // namespace
97
98
TEST(HttpAuthHandlerDigestTest,ParseChallenge)99 TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
100 static const struct {
101 // The challenge string.
102 const char* challenge;
103 // Expected return value of ParseChallenge.
104 bool parsed_success;
105 // The expected values that were parsed.
106 const char* parsed_realm;
107 const char* parsed_nonce;
108 const char* parsed_domain;
109 const char* parsed_opaque;
110 bool parsed_stale;
111 int parsed_algorithm;
112 int parsed_qop;
113 } tests[] = {
114 { // Check that a minimal challenge works correctly.
115 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\"",
116 true,
117 "Thunder Bluff",
118 "xyz",
119 "",
120 "",
121 false,
122 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
123 HttpAuthHandlerDigest::QOP_UNSPECIFIED
124 },
125
126 { // Realm does not need to be quoted, even though RFC2617 requires it.
127 "Digest nonce=\"xyz\", realm=ThunderBluff",
128 true,
129 "ThunderBluff",
130 "xyz",
131 "",
132 "",
133 false,
134 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
135 HttpAuthHandlerDigest::QOP_UNSPECIFIED
136 },
137
138 { // We allow the realm to be omitted, and will default it to empty string.
139 // See http://crbug.com/20984.
140 "Digest nonce=\"xyz\"",
141 true,
142 "",
143 "xyz",
144 "",
145 "",
146 false,
147 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
148 HttpAuthHandlerDigest::QOP_UNSPECIFIED
149 },
150
151 { // Try with realm set to empty string.
152 "Digest realm=\"\", nonce=\"xyz\"",
153 true,
154 "",
155 "xyz",
156 "",
157 "",
158 false,
159 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
160 HttpAuthHandlerDigest::QOP_UNSPECIFIED
161 },
162
163 // Handle ISO-8859-1 character as part of the realm. The realm is converted
164 // to UTF-8. However, the credentials will still use the original encoding.
165 {
166 "Digest nonce=\"xyz\", realm=\"foo-\xE5\"",
167 true,
168 "foo-\xC3\xA5",
169 "xyz",
170 "",
171 "",
172 false,
173 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
174 HttpAuthHandlerDigest::QOP_UNSPECIFIED,
175 },
176
177 { // At a minimum, a nonce must be provided.
178 "Digest realm=\"Thunder Bluff\"",
179 false,
180 "",
181 "",
182 "",
183 "",
184 false,
185 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
186 HttpAuthHandlerDigest::QOP_UNSPECIFIED
187 },
188
189 { // The nonce does not need to be quoted, even though RFC2617
190 // requires it.
191 "Digest nonce=xyz, realm=\"Thunder Bluff\"",
192 true,
193 "Thunder Bluff",
194 "xyz",
195 "",
196 "",
197 false,
198 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
199 HttpAuthHandlerDigest::QOP_UNSPECIFIED
200 },
201
202 { // Unknown authentication parameters are ignored.
203 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", foo=\"bar\"",
204 true,
205 "Thunder Bluff",
206 "xyz",
207 "",
208 "",
209 false,
210 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
211 HttpAuthHandlerDigest::QOP_UNSPECIFIED
212 },
213
214 { // Check that when algorithm has an unsupported value, parsing fails.
215 "Digest nonce=\"xyz\", algorithm=\"awezum\", realm=\"Thunder\"",
216 false,
217 // The remaining values don't matter (but some have been set already).
218 "",
219 "xyz",
220 "",
221 "",
222 false,
223 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
224 HttpAuthHandlerDigest::QOP_UNSPECIFIED
225 },
226
227 { // Check that algorithm's value is case insensitive, and that MD5 is
228 // a supported algorithm.
229 "Digest nonce=\"xyz\", algorithm=\"mD5\", realm=\"Oblivion\"",
230 true,
231 "Oblivion",
232 "xyz",
233 "",
234 "",
235 false,
236 HttpAuthHandlerDigest::ALGORITHM_MD5,
237 HttpAuthHandlerDigest::QOP_UNSPECIFIED
238 },
239
240 { // Check that md5-sess is a supported algorithm.
241 "Digest nonce=\"xyz\", algorithm=\"md5-sess\", realm=\"Oblivion\"",
242 true,
243 "Oblivion",
244 "xyz",
245 "",
246 "",
247 false,
248 HttpAuthHandlerDigest::ALGORITHM_MD5_SESS,
249 HttpAuthHandlerDigest::QOP_UNSPECIFIED,
250 },
251
252 { // Check that qop's value is case insensitive, and that auth is known.
253 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"aUth\"",
254 true,
255 "Oblivion",
256 "xyz",
257 "",
258 "",
259 false,
260 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
261 HttpAuthHandlerDigest::QOP_AUTH
262 },
263
264 { // auth-int is not handled, but will fall back to default qop.
265 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth-int\"",
266 true,
267 "Oblivion",
268 "xyz",
269 "",
270 "",
271 false,
272 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
273 HttpAuthHandlerDigest::QOP_UNSPECIFIED
274 },
275
276 { // Unknown qop values are ignored.
277 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,foo\"",
278 true,
279 "Oblivion",
280 "xyz",
281 "",
282 "",
283 false,
284 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
285 HttpAuthHandlerDigest::QOP_AUTH
286 },
287
288 { // If auth-int is included with auth, then use auth.
289 "Digest nonce=\"xyz\", realm=\"Oblivion\", qop=\"auth,auth-int\"",
290 true,
291 "Oblivion",
292 "xyz",
293 "",
294 "",
295 false,
296 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
297 HttpAuthHandlerDigest::QOP_AUTH
298 },
299
300 { // Opaque parameter parsing should work correctly.
301 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=\"foobar\"",
302 true,
303 "Thunder Bluff",
304 "xyz",
305 "",
306 "foobar",
307 false,
308 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
309 HttpAuthHandlerDigest::QOP_UNSPECIFIED
310 },
311
312 { // Opaque parameters do not need to be quoted, even though RFC2617
313 // seems to require it.
314 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", opaque=foobar",
315 true,
316 "Thunder Bluff",
317 "xyz",
318 "",
319 "foobar",
320 false,
321 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
322 HttpAuthHandlerDigest::QOP_UNSPECIFIED
323 },
324
325 { // Domain can be parsed.
326 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", "
327 "domain=\"http://intranet.example.com/protection\"",
328 true,
329 "Thunder Bluff",
330 "xyz",
331 "http://intranet.example.com/protection",
332 "",
333 false,
334 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
335 HttpAuthHandlerDigest::QOP_UNSPECIFIED
336 },
337
338 { // Multiple domains can be parsed.
339 "Digest nonce=\"xyz\", realm=\"Thunder Bluff\", "
340 "domain=\"http://intranet.example.com/protection http://www.google.com\"",
341 true,
342 "Thunder Bluff",
343 "xyz",
344 "http://intranet.example.com/protection http://www.google.com",
345 "",
346 false,
347 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
348 HttpAuthHandlerDigest::QOP_UNSPECIFIED
349 },
350
351 { // If a non-Digest scheme is somehow passed in, it should be rejected.
352 "Basic realm=\"foo\"",
353 false,
354 "",
355 "",
356 "",
357 "",
358 false,
359 HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
360 HttpAuthHandlerDigest::QOP_UNSPECIFIED
361 },
362 };
363
364 url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
365 auto factory = std::make_unique<HttpAuthHandlerDigest::Factory>();
366 for (const auto& test : tests) {
367 SSLInfo null_ssl_info;
368 auto host_resolver = std::make_unique<MockHostResolver>();
369 std::unique_ptr<HttpAuthHandler> handler;
370 int rv = factory->CreateAuthHandlerFromString(
371 test.challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
372 NetworkAnonymizationKey(), scheme_host_port, NetLogWithSource(),
373 host_resolver.get(), &handler);
374 if (test.parsed_success) {
375 EXPECT_THAT(rv, IsOk());
376 } else {
377 EXPECT_NE(OK, rv);
378 EXPECT_TRUE(handler.get() == nullptr);
379 continue;
380 }
381 ASSERT_TRUE(handler.get() != nullptr);
382 HttpAuthHandlerDigest* digest =
383 static_cast<HttpAuthHandlerDigest*>(handler.get());
384 EXPECT_STREQ(test.parsed_realm, digest->realm_.c_str());
385 EXPECT_STREQ(test.parsed_nonce, digest->nonce_.c_str());
386 EXPECT_STREQ(test.parsed_domain, digest->domain_.c_str());
387 EXPECT_STREQ(test.parsed_opaque, digest->opaque_.c_str());
388 EXPECT_EQ(test.parsed_stale, digest->stale_);
389 EXPECT_EQ(test.parsed_algorithm, digest->algorithm_);
390 EXPECT_EQ(test.parsed_qop, digest->qop_);
391 EXPECT_TRUE(handler->encrypts_identity());
392 EXPECT_FALSE(handler->is_connection_based());
393 EXPECT_TRUE(handler->NeedsIdentity());
394 EXPECT_FALSE(handler->AllowsDefaultCredentials());
395 }
396 }
397
TEST(HttpAuthHandlerDigestTest,AssembleCredentials)398 TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
399 static const struct {
400 const char* req_method;
401 const char* req_path;
402 const char* challenge;
403 const char* username;
404 const char* password;
405 const char* cnonce;
406 int nonce_count;
407 const char* expected_creds;
408 } tests[] = {
409 { // MD5 with username/password
410 "GET",
411 "/test/drealm1",
412
413 // Challenge
414 "Digest realm=\"DRealm1\", "
415 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
416 "algorithm=MD5, qop=\"auth\"",
417
418 "foo", "bar", // username/password
419 "082c875dcb2ca740", // cnonce
420 1, // nc
421
422 // Authorization
423 "Digest username=\"foo\", realm=\"DRealm1\", "
424 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
425 "uri=\"/test/drealm1\", algorithm=MD5, "
426 "response=\"bcfaa62f1186a31ff1b474a19a17cf57\", "
427 "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
428 },
429
430 { // MD5 with username but empty password. username has space in it.
431 "GET",
432 "/test/drealm1/",
433
434 // Challenge
435 "Digest realm=\"DRealm1\", "
436 "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
437 "algorithm=MD5, qop=\"auth\"",
438
439 "foo bar", "", // Username/password
440 "082c875dcb2ca740", // cnonce
441 1, // nc
442
443 // Authorization
444 "Digest username=\"foo bar\", realm=\"DRealm1\", "
445 "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
446 "uri=\"/test/drealm1/\", algorithm=MD5, "
447 "response=\"93c9c6d5930af3b0eb26c745e02b04a0\", "
448 "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
449 },
450
451 { // MD5 with no username.
452 "GET",
453 "/test/drealm1/",
454
455 // Challenge
456 "Digest realm=\"DRealm1\", "
457 "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
458 "algorithm=MD5, qop=\"auth\"",
459
460 "", "pass", // Username/password
461 "6509bc74daed8263", // cnonce
462 1, // nc
463
464 // Authorization
465 "Digest username=\"\", realm=\"DRealm1\", "
466 "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
467 "uri=\"/test/drealm1/\", algorithm=MD5, "
468 "response=\"bc597110f41a62d07f8b70b6977fcb61\", "
469 "qop=auth, nc=00000001, cnonce=\"6509bc74daed8263\""
470 },
471
472 { // MD5 with no username and no password.
473 "GET",
474 "/test/drealm1/",
475
476 // Challenge
477 "Digest realm=\"DRealm1\", "
478 "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
479 "algorithm=MD5, qop=\"auth\"",
480
481 "", "", // Username/password
482 "1522e61005789929", // cnonce
483 1, // nc
484
485 // Authorization
486 "Digest username=\"\", realm=\"DRealm1\", "
487 "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
488 "uri=\"/test/drealm1/\", algorithm=MD5, "
489 "response=\"22cfa2b30cb500a9591c6d55ec5590a8\", "
490 "qop=auth, nc=00000001, cnonce=\"1522e61005789929\""
491 },
492
493 { // No algorithm, and no qop.
494 "GET",
495 "/",
496
497 // Challenge
498 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"",
499
500 "FooBar", "pass", // Username/password
501 "", // cnonce
502 1, // nc
503
504 // Authorization
505 "Digest username=\"FooBar\", realm=\"Oblivion\", "
506 "nonce=\"nonce-value\", uri=\"/\", "
507 "response=\"f72ff54ebde2f928860f806ec04acd1b\""
508 },
509
510 { // MD5-sess
511 "GET",
512 "/",
513
514 // Challenge
515 "Digest realm=\"Baztastic\", nonce=\"AAAAAAAA\", "
516 "algorithm=\"md5-sess\", qop=auth",
517
518 "USER", "123", // Username/password
519 "15c07961ed8575c4", // cnonce
520 1, // nc
521
522 // Authorization
523 "Digest username=\"USER\", realm=\"Baztastic\", "
524 "nonce=\"AAAAAAAA\", uri=\"/\", algorithm=MD5-sess, "
525 "response=\"cbc1139821ee7192069580570c541a03\", "
526 "qop=auth, nc=00000001, cnonce=\"15c07961ed8575c4\""
527 }
528 };
529 url::SchemeHostPort scheme_host_port(GURL("http://www.example.com"));
530 auto factory = std::make_unique<HttpAuthHandlerDigest::Factory>();
531 for (const auto& test : tests) {
532 SSLInfo null_ssl_info;
533 auto host_resolver = std::make_unique<MockHostResolver>();
534 std::unique_ptr<HttpAuthHandler> handler;
535 int rv = factory->CreateAuthHandlerFromString(
536 test.challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
537 NetworkAnonymizationKey(), scheme_host_port, NetLogWithSource(),
538 host_resolver.get(), &handler);
539 EXPECT_THAT(rv, IsOk());
540 ASSERT_TRUE(handler != nullptr);
541
542 HttpAuthHandlerDigest* digest =
543 static_cast<HttpAuthHandlerDigest*>(handler.get());
544 std::string creds = digest->AssembleCredentials(
545 test.req_method, test.req_path,
546 AuthCredentials(base::ASCIIToUTF16(test.username),
547 base::ASCIIToUTF16(test.password)),
548 test.cnonce, test.nonce_count);
549
550 EXPECT_STREQ(test.expected_creds, creds.c_str());
551 }
552 }
553
TEST(HttpAuthHandlerDigest,HandleAnotherChallenge)554 TEST(HttpAuthHandlerDigest, HandleAnotherChallenge) {
555 auto factory = std::make_unique<HttpAuthHandlerDigest::Factory>();
556 auto host_resolver = std::make_unique<MockHostResolver>();
557 std::unique_ptr<HttpAuthHandler> handler;
558 std::string default_challenge =
559 "Digest realm=\"Oblivion\", nonce=\"nonce-value\"";
560 url::SchemeHostPort scheme_host_port(GURL("http://intranet.google.com"));
561 SSLInfo null_ssl_info;
562 int rv = factory->CreateAuthHandlerFromString(
563 default_challenge, HttpAuth::AUTH_SERVER, null_ssl_info,
564 NetworkAnonymizationKey(), scheme_host_port, NetLogWithSource(),
565 host_resolver.get(), &handler);
566 EXPECT_THAT(rv, IsOk());
567 ASSERT_TRUE(handler.get() != nullptr);
568 HttpAuthChallengeTokenizer tok_default(default_challenge.begin(),
569 default_challenge.end());
570 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
571 handler->HandleAnotherChallenge(&tok_default));
572
573 std::string stale_challenge = default_challenge + ", stale=true";
574 HttpAuthChallengeTokenizer tok_stale(stale_challenge.begin(),
575 stale_challenge.end());
576 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_STALE,
577 handler->HandleAnotherChallenge(&tok_stale));
578
579 std::string stale_false_challenge = default_challenge + ", stale=false";
580 HttpAuthChallengeTokenizer tok_stale_false(stale_false_challenge.begin(),
581 stale_false_challenge.end());
582 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_REJECT,
583 handler->HandleAnotherChallenge(&tok_stale_false));
584
585 std::string realm_change_challenge =
586 "Digest realm=\"SomethingElse\", nonce=\"nonce-value2\"";
587 HttpAuthChallengeTokenizer tok_realm_change(realm_change_challenge.begin(),
588 realm_change_challenge.end());
589 EXPECT_EQ(HttpAuth::AUTHORIZATION_RESULT_DIFFERENT_REALM,
590 handler->HandleAnotherChallenge(&tok_realm_change));
591 }
592
TEST(HttpAuthHandlerDigest,RespondToServerChallenge)593 TEST(HttpAuthHandlerDigest, RespondToServerChallenge) {
594 std::string auth_token;
595 EXPECT_TRUE(RespondToChallenge(
596 HttpAuth::AUTH_SERVER,
597 std::string(),
598 "http://www.example.com/path/to/resource",
599 kSimpleChallenge,
600 &auth_token));
601 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
602 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
603 "response=\"6779f90bd0d658f937c1af967614fe84\"",
604 auth_token);
605 }
606
TEST(HttpAuthHandlerDigest,RespondToHttpsServerChallenge)607 TEST(HttpAuthHandlerDigest, RespondToHttpsServerChallenge) {
608 std::string auth_token;
609 EXPECT_TRUE(RespondToChallenge(
610 HttpAuth::AUTH_SERVER,
611 std::string(),
612 "https://www.example.com/path/to/resource",
613 kSimpleChallenge,
614 &auth_token));
615 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
616 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
617 "response=\"6779f90bd0d658f937c1af967614fe84\"",
618 auth_token);
619 }
620
TEST(HttpAuthHandlerDigest,RespondToProxyChallenge)621 TEST(HttpAuthHandlerDigest, RespondToProxyChallenge) {
622 std::string auth_token;
623 EXPECT_TRUE(RespondToChallenge(
624 HttpAuth::AUTH_PROXY,
625 "http://proxy.intranet.corp.com:3128",
626 "http://www.example.com/path/to/resource",
627 kSimpleChallenge,
628 &auth_token));
629 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
630 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
631 "response=\"6779f90bd0d658f937c1af967614fe84\"",
632 auth_token);
633 }
634
TEST(HttpAuthHandlerDigest,RespondToProxyChallengeHttps)635 TEST(HttpAuthHandlerDigest, RespondToProxyChallengeHttps) {
636 std::string auth_token;
637 EXPECT_TRUE(RespondToChallenge(
638 HttpAuth::AUTH_PROXY,
639 "http://proxy.intranet.corp.com:3128",
640 "https://www.example.com/path/to/resource",
641 kSimpleChallenge,
642 &auth_token));
643 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
644 "nonce=\"nonce-value\", uri=\"www.example.com:443\", "
645 "response=\"3270da8467afbe9ddf2334a48d46e9b9\"",
646 auth_token);
647 }
648
TEST(HttpAuthHandlerDigest,RespondToProxyChallengeWs)649 TEST(HttpAuthHandlerDigest, RespondToProxyChallengeWs) {
650 std::string auth_token;
651 EXPECT_TRUE(RespondToChallenge(
652 HttpAuth::AUTH_PROXY,
653 "http://proxy.intranet.corp.com:3128",
654 "ws://www.example.com/echo",
655 kSimpleChallenge,
656 &auth_token));
657 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
658 "nonce=\"nonce-value\", uri=\"www.example.com:80\", "
659 "response=\"aa1df184f68d5b6ab9d9aa4f88e41b4c\"",
660 auth_token);
661 }
662
TEST(HttpAuthHandlerDigest,RespondToProxyChallengeWss)663 TEST(HttpAuthHandlerDigest, RespondToProxyChallengeWss) {
664 std::string auth_token;
665 EXPECT_TRUE(RespondToChallenge(
666 HttpAuth::AUTH_PROXY,
667 "http://proxy.intranet.corp.com:3128",
668 "wss://www.example.com/echo",
669 kSimpleChallenge,
670 &auth_token));
671 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
672 "nonce=\"nonce-value\", uri=\"www.example.com:443\", "
673 "response=\"3270da8467afbe9ddf2334a48d46e9b9\"",
674 auth_token);
675 }
676
TEST(HttpAuthHandlerDigest,RespondToChallengeAuthQop)677 TEST(HttpAuthHandlerDigest, RespondToChallengeAuthQop) {
678 std::string auth_token;
679 EXPECT_TRUE(RespondToChallenge(
680 HttpAuth::AUTH_SERVER,
681 std::string(),
682 "http://www.example.com/path/to/resource",
683 "Digest realm=\"Oblivion\", nonce=\"nonce-value\", qop=\"auth\"",
684 &auth_token));
685 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
686 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
687 "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
688 "qop=auth, nc=00000001, cnonce=\"client_nonce\"",
689 auth_token);
690 }
691
TEST(HttpAuthHandlerDigest,RespondToChallengeOpaque)692 TEST(HttpAuthHandlerDigest, RespondToChallengeOpaque) {
693 std::string auth_token;
694 EXPECT_TRUE(RespondToChallenge(
695 HttpAuth::AUTH_SERVER,
696 std::string(),
697 "http://www.example.com/path/to/resource",
698 "Digest realm=\"Oblivion\", nonce=\"nonce-value\", "
699 "qop=\"auth\", opaque=\"opaque text\"",
700 &auth_token));
701 EXPECT_EQ("Digest username=\"foo\", realm=\"Oblivion\", "
702 "nonce=\"nonce-value\", uri=\"/path/to/resource\", "
703 "response=\"5b1459beda5cee30d6ff9e970a69c0ea\", "
704 "opaque=\"opaque text\", "
705 "qop=auth, nc=00000001, cnonce=\"client_nonce\"",
706 auth_token);
707 }
708
709
710 } // namespace net
711