Home | History | Annotate | Download | only in http
      1 // Copyright (c) 2006-2008 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 "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "net/http/http_auth_handler_digest.h"
      9 
     10 namespace net {
     11 
     12 TEST(HttpAuthHandlerDigestTest, ParseChallenge) {
     13   static const struct {
     14     // The challenge string.
     15     const char* challenge;
     16     // Expected return value of ParseChallenge.
     17     bool parsed_success;
     18     // The expected values that were parsed.
     19     const char* parsed_realm;
     20     const char* parsed_nonce;
     21     const char* parsed_domain;
     22     const char* parsed_opaque;
     23     bool parsed_stale;
     24     int parsed_algorithm;
     25     int parsed_qop;
     26   } tests[] = {
     27     {
     28       "Digest nonce=\"xyz\", realm=\"Thunder Bluff\"",
     29       true,
     30       "Thunder Bluff",
     31       "xyz",
     32       "",
     33       "",
     34       false,
     35       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
     36       HttpAuthHandlerDigest::QOP_UNSPECIFIED
     37     },
     38 
     39     { // Check that when algorithm has an unsupported value, parsing fails.
     40       "Digest nonce=\"xyz\", algorithm=\"awezum\", realm=\"Thunder\"",
     41       false,
     42       // The remaining values don't matter (but some have been set already).
     43       "",
     44       "xyz",
     45       "",
     46       "",
     47       false,
     48       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
     49       HttpAuthHandlerDigest::QOP_UNSPECIFIED
     50     },
     51 
     52     { // Check that algorithm's value is case insensitive.
     53       "Digest nonce=\"xyz\", algorithm=\"mD5\", realm=\"Oblivion\"",
     54       true,
     55       "Oblivion",
     56       "xyz",
     57       "",
     58       "",
     59       false,
     60       HttpAuthHandlerDigest::ALGORITHM_MD5,
     61       HttpAuthHandlerDigest::QOP_UNSPECIFIED
     62     },
     63 
     64     { // Check that md5-sess is recognized, as is single QOP
     65       "Digest nonce=\"xyz\", algorithm=\"md5-sess\", "
     66           "realm=\"Oblivion\", qop=\"auth\"",
     67       true,
     68       "Oblivion",
     69       "xyz",
     70       "",
     71       "",
     72       false,
     73       HttpAuthHandlerDigest::ALGORITHM_MD5_SESS,
     74       HttpAuthHandlerDigest::QOP_AUTH
     75     },
     76 
     77     { // We allow the realm to be omitted, and will default it to empty string.
     78       // See http://crbug.com/20984.
     79       "Digest nonce=\"xyz\"",
     80       true,
     81       "",
     82       "xyz",
     83       "",
     84       "",
     85       false,
     86       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
     87       HttpAuthHandlerDigest::QOP_UNSPECIFIED
     88     },
     89 
     90     { // Try with realm set to empty string.
     91       "Digest realm=\"\", nonce=\"xyz\"",
     92       true,
     93       "",
     94       "xyz",
     95       "",
     96       "",
     97       false,
     98       HttpAuthHandlerDigest::ALGORITHM_UNSPECIFIED,
     99       HttpAuthHandlerDigest::QOP_UNSPECIFIED
    100     }
    101   };
    102 
    103   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    104     std::string challenge(tests[i].challenge);
    105 
    106     scoped_refptr<HttpAuthHandlerDigest> digest = new HttpAuthHandlerDigest;
    107     bool ok = digest->ParseChallenge(challenge.begin(), challenge.end());
    108 
    109     EXPECT_EQ(tests[i].parsed_success, ok);
    110     EXPECT_STREQ(tests[i].parsed_realm, digest->realm_.c_str());
    111     EXPECT_STREQ(tests[i].parsed_nonce, digest->nonce_.c_str());
    112     EXPECT_STREQ(tests[i].parsed_domain, digest->domain_.c_str());
    113     EXPECT_STREQ(tests[i].parsed_opaque, digest->opaque_.c_str());
    114     EXPECT_EQ(tests[i].parsed_stale, digest->stale_);
    115     EXPECT_EQ(tests[i].parsed_algorithm, digest->algorithm_);
    116     EXPECT_EQ(tests[i].parsed_qop, digest->qop_);
    117   }
    118 }
    119 
    120 TEST(HttpAuthHandlerDigestTest, AssembleCredentials) {
    121   static const struct {
    122     const char* req_method;
    123     const char* req_path;
    124     const char* challenge;
    125     const char* username;
    126     const char* password;
    127     const char* cnonce;
    128     int nonce_count;
    129     const char* expected_creds;
    130   } tests[] = {
    131     { // MD5 with username/password
    132       "GET",
    133       "/test/drealm1",
    134 
    135       // Challenge
    136       "Digest realm=\"DRealm1\", "
    137       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
    138       "algorithm=MD5, qop=\"auth\"",
    139 
    140       "foo", "bar", // username/password
    141       "082c875dcb2ca740", // cnonce
    142       1, // nc
    143 
    144       // Authorization
    145       "Digest username=\"foo\", realm=\"DRealm1\", "
    146       "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\", "
    147       "uri=\"/test/drealm1\", algorithm=MD5, "
    148       "response=\"bcfaa62f1186a31ff1b474a19a17cf57\", "
    149       "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
    150     },
    151 
    152     { // MD5 with username but empty password. username has space in it.
    153       "GET",
    154       "/test/drealm1/",
    155 
    156       // Challenge
    157       "Digest realm=\"DRealm1\", "
    158       "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
    159       "algorithm=MD5, qop=\"auth\"",
    160 
    161       "foo bar", "", // Username/password
    162       "082c875dcb2ca740", // cnonce
    163       1, // nc
    164 
    165       // Authorization
    166       "Digest username=\"foo bar\", realm=\"DRealm1\", "
    167       "nonce=\"Ure30oRXBAA=7eca98bbf521ac6642820b11b86bd2d9ed7edc70\", "
    168       "uri=\"/test/drealm1/\", algorithm=MD5, "
    169       "response=\"93c9c6d5930af3b0eb26c745e02b04a0\", "
    170       "qop=auth, nc=00000001, cnonce=\"082c875dcb2ca740\""
    171     },
    172 
    173     { // MD5 with no username.
    174       "GET",
    175       "/test/drealm1/",
    176 
    177       // Challenge
    178       "Digest realm=\"DRealm1\", "
    179       "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
    180       "algorithm=MD5, qop=\"auth\"",
    181 
    182       "", "pass", // Username/password
    183       "6509bc74daed8263", // cnonce
    184       1, // nc
    185 
    186       // Authorization
    187       "Digest username=\"\", realm=\"DRealm1\", "
    188       "nonce=\"7thGplhaBAA=41fb92453c49799cf353c8cd0aabee02d61a98a8\", "
    189       "uri=\"/test/drealm1/\", algorithm=MD5, "
    190       "response=\"bc597110f41a62d07f8b70b6977fcb61\", "
    191       "qop=auth, nc=00000001, cnonce=\"6509bc74daed8263\""
    192     },
    193 
    194     { // MD5 with no username and no password.
    195       "GET",
    196       "/test/drealm1/",
    197 
    198       // Challenge
    199       "Digest realm=\"DRealm1\", "
    200       "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
    201       "algorithm=MD5, qop=\"auth\"",
    202 
    203       "", "", // Username/password
    204       "1522e61005789929", // cnonce
    205       1, // nc
    206 
    207       // Authorization
    208       "Digest username=\"\", realm=\"DRealm1\", "
    209       "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\", "
    210       "uri=\"/test/drealm1/\", algorithm=MD5, "
    211       "response=\"22cfa2b30cb500a9591c6d55ec5590a8\", "
    212       "qop=auth, nc=00000001, cnonce=\"1522e61005789929\""
    213     },
    214 
    215     { // No algorithm, and no qop.
    216       "GET",
    217       "/",
    218 
    219       // Challenge
    220       "Digest realm=\"Oblivion\", nonce=\"nonce-value\"",
    221 
    222       "FooBar", "pass", // Username/password
    223       "", // cnonce
    224       1, // nc
    225 
    226       // Authorization
    227       "Digest username=\"FooBar\", realm=\"Oblivion\", "
    228       "nonce=\"nonce-value\", uri=\"/\", "
    229       "response=\"f72ff54ebde2f928860f806ec04acd1b\""
    230     },
    231 
    232     { // MD5-sess
    233       "GET",
    234       "/",
    235 
    236       // Challenge
    237       "Digest realm=\"Baztastic\", nonce=\"AAAAAAAA\", "
    238       "algorithm=\"md5-sess\", qop=auth",
    239 
    240       "USER", "123", // Username/password
    241       "15c07961ed8575c4", // cnonce
    242       1, // nc
    243 
    244       // Authorization
    245       "Digest username=\"USER\", realm=\"Baztastic\", "
    246       "nonce=\"AAAAAAAA\", uri=\"/\", algorithm=MD5-sess, "
    247       "response=\"cbc1139821ee7192069580570c541a03\", "
    248       "qop=auth, nc=00000001, cnonce=\"15c07961ed8575c4\""
    249     }
    250   };
    251   GURL origin("http://www.example.com");
    252   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    253     scoped_refptr<HttpAuthHandlerDigest> digest = new HttpAuthHandlerDigest;
    254     std::string challenge = tests[i].challenge;
    255     EXPECT_TRUE(digest->InitFromChallenge(
    256         challenge.begin(), challenge.end(), HttpAuth::AUTH_SERVER, origin));
    257 
    258     std::string creds = digest->AssembleCredentials(tests[i].req_method,
    259         tests[i].req_path, tests[i].username, tests[i].password,
    260         tests[i].cnonce, tests[i].nonce_count);
    261 
    262     EXPECT_STREQ(tests[i].expected_creds, creds.c_str());
    263   }
    264 }
    265 
    266 } // namespace net
    267