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