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