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