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