Home | History | Annotate | Download | only in http
      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