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