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/strings/string16.h" 8 #include "base/strings/string_util.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "net/base/net_errors.h" 12 #include "net/http/http_auth_cache.h" 13 #include "net/http/http_auth_handler.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 using base::ASCIIToUTF16; 17 18 namespace net { 19 20 namespace { 21 22 class MockAuthHandler : public HttpAuthHandler { 23 public: 24 MockAuthHandler(HttpAuth::Scheme scheme, 25 const std::string& realm, 26 HttpAuth::Target target) { 27 // Can't use initializer list since these are members of the base class. 28 auth_scheme_ = scheme; 29 realm_ = realm; 30 score_ = 1; 31 target_ = target; 32 properties_ = 0; 33 } 34 35 virtual HttpAuth::AuthorizationResult HandleAnotherChallenge( 36 HttpAuthChallengeTokenizer* challenge) OVERRIDE { 37 return HttpAuth::AUTHORIZATION_RESULT_REJECT; 38 } 39 40 protected: 41 virtual bool Init(HttpAuthChallengeTokenizer* challenge) OVERRIDE { 42 return false; // Unused. 43 } 44 45 virtual int GenerateAuthTokenImpl(const AuthCredentials*, 46 const HttpRequestInfo*, 47 const CompletionCallback& callback, 48 std::string* auth_token) OVERRIDE { 49 *auth_token = "mock-credentials"; 50 return OK; 51 } 52 53 54 private: 55 virtual ~MockAuthHandler() {} 56 }; 57 58 const char* kRealm1 = "Realm1"; 59 const char* kRealm2 = "Realm2"; 60 const char* kRealm3 = "Realm3"; 61 const char* kRealm4 = "Realm4"; 62 const char* kRealm5 = "Realm5"; 63 const base::string16 k123(ASCIIToUTF16("123")); 64 const base::string16 k1234(ASCIIToUTF16("1234")); 65 const base::string16 kAdmin(ASCIIToUTF16("admin")); 66 const base::string16 kAlice(ASCIIToUTF16("alice")); 67 const base::string16 kAlice2(ASCIIToUTF16("alice2")); 68 const base::string16 kPassword(ASCIIToUTF16("password")); 69 const base::string16 kRoot(ASCIIToUTF16("root")); 70 const base::string16 kUsername(ASCIIToUTF16("username")); 71 const base::string16 kWileCoyote(ASCIIToUTF16("wilecoyote")); 72 73 AuthCredentials CreateASCIICredentials(const char* username, 74 const char* password) { 75 return AuthCredentials(ASCIIToUTF16(username), ASCIIToUTF16(password)); 76 } 77 78 } // namespace 79 80 // Test adding and looking-up cache entries (both by realm and by path). 81 TEST(HttpAuthCacheTest, Basic) { 82 GURL origin("http://www.google.com"); 83 HttpAuthCache cache; 84 HttpAuthCache::Entry* entry; 85 86 // Add cache entries for 4 realms: "Realm1", "Realm2", "Realm3" and 87 // "Realm4" 88 89 scoped_ptr<HttpAuthHandler> realm1_handler( 90 new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC, 91 kRealm1, 92 HttpAuth::AUTH_SERVER)); 93 cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(), 94 "Basic realm=Realm1", 95 CreateASCIICredentials("realm1-user", "realm1-password"), 96 "/foo/bar/index.html"); 97 98 scoped_ptr<HttpAuthHandler> realm2_handler( 99 new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC, 100 kRealm2, 101 HttpAuth::AUTH_SERVER)); 102 cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(), 103 "Basic realm=Realm2", 104 CreateASCIICredentials("realm2-user", "realm2-password"), 105 "/foo2/index.html"); 106 107 scoped_ptr<HttpAuthHandler> realm3_basic_handler( 108 new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC, 109 kRealm3, 110 HttpAuth::AUTH_PROXY)); 111 cache.Add( 112 origin, 113 realm3_basic_handler->realm(), 114 realm3_basic_handler->auth_scheme(), 115 "Basic realm=Realm3", 116 CreateASCIICredentials("realm3-basic-user", "realm3-basic-password"), 117 std::string()); 118 119 scoped_ptr<HttpAuthHandler> realm3_digest_handler( 120 new MockAuthHandler(HttpAuth::AUTH_SCHEME_DIGEST, 121 kRealm3, 122 HttpAuth::AUTH_PROXY)); 123 cache.Add(origin, realm3_digest_handler->realm(), 124 realm3_digest_handler->auth_scheme(), "Digest realm=Realm3", 125 CreateASCIICredentials("realm3-digest-user", 126 "realm3-digest-password"), 127 "/baz/index.html"); 128 129 scoped_ptr<HttpAuthHandler> realm4_basic_handler( 130 new MockAuthHandler(HttpAuth::AUTH_SCHEME_BASIC, 131 kRealm4, 132 HttpAuth::AUTH_SERVER)); 133 cache.Add(origin, realm4_basic_handler->realm(), 134 realm4_basic_handler->auth_scheme(), "Basic realm=Realm4", 135 CreateASCIICredentials("realm4-basic-user", 136 "realm4-basic-password"), 137 "/"); 138 139 // There is no Realm5 140 entry = cache.Lookup(origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC); 141 EXPECT_TRUE(NULL == entry); 142 143 // While Realm3 does exist, the origin scheme is wrong. 144 entry = cache.Lookup(GURL("https://www.google.com"), kRealm3, 145 HttpAuth::AUTH_SCHEME_BASIC); 146 EXPECT_TRUE(NULL == entry); 147 148 // Realm, origin scheme ok, authentication scheme wrong 149 entry = cache.Lookup 150 (GURL("http://www.google.com"), kRealm1, HttpAuth::AUTH_SCHEME_DIGEST); 151 EXPECT_TRUE(NULL == entry); 152 153 // Valid lookup by origin, realm, scheme. 154 entry = cache.Lookup( 155 GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_BASIC); 156 ASSERT_FALSE(NULL == entry); 157 EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); 158 EXPECT_EQ(kRealm3, entry->realm()); 159 EXPECT_EQ("Basic realm=Realm3", entry->auth_challenge()); 160 EXPECT_EQ(ASCIIToUTF16("realm3-basic-user"), entry->credentials().username()); 161 EXPECT_EQ(ASCIIToUTF16("realm3-basic-password"), 162 entry->credentials().password()); 163 164 // Valid lookup by origin, realm, scheme when there's a duplicate 165 // origin, realm in the cache 166 entry = cache.Lookup( 167 GURL("http://www.google.com:80"), kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); 168 ASSERT_FALSE(NULL == entry); 169 EXPECT_EQ(HttpAuth::AUTH_SCHEME_DIGEST, entry->scheme()); 170 EXPECT_EQ(kRealm3, entry->realm()); 171 EXPECT_EQ("Digest realm=Realm3", entry->auth_challenge()); 172 EXPECT_EQ(ASCIIToUTF16("realm3-digest-user"), 173 entry->credentials().username()); 174 EXPECT_EQ(ASCIIToUTF16("realm3-digest-password"), 175 entry->credentials().password()); 176 177 // Valid lookup by realm. 178 entry = cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC); 179 ASSERT_FALSE(NULL == entry); 180 EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); 181 EXPECT_EQ(kRealm2, entry->realm()); 182 EXPECT_EQ("Basic realm=Realm2", entry->auth_challenge()); 183 EXPECT_EQ(ASCIIToUTF16("realm2-user"), entry->credentials().username()); 184 EXPECT_EQ(ASCIIToUTF16("realm2-password"), entry->credentials().password()); 185 186 // Check that subpaths are recognized. 187 HttpAuthCache::Entry* realm2_entry = cache.Lookup( 188 origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC); 189 HttpAuthCache::Entry* realm4_entry = cache.Lookup( 190 origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC); 191 EXPECT_FALSE(NULL == realm2_entry); 192 EXPECT_FALSE(NULL == realm4_entry); 193 // Realm4 applies to '/' and Realm2 applies to '/foo2/'. 194 // LookupByPath() should return the closest enclosing path. 195 // Positive tests: 196 entry = cache.LookupByPath(origin, "/foo2/index.html"); 197 EXPECT_TRUE(realm2_entry == entry); 198 entry = cache.LookupByPath(origin, "/foo2/foobar.html"); 199 EXPECT_TRUE(realm2_entry == entry); 200 entry = cache.LookupByPath(origin, "/foo2/bar/index.html"); 201 EXPECT_TRUE(realm2_entry == entry); 202 entry = cache.LookupByPath(origin, "/foo2/"); 203 EXPECT_TRUE(realm2_entry == entry); 204 entry = cache.LookupByPath(origin, "/foo2"); 205 EXPECT_TRUE(realm4_entry == entry); 206 entry = cache.LookupByPath(origin, "/"); 207 EXPECT_TRUE(realm4_entry == entry); 208 209 // Negative tests: 210 entry = cache.LookupByPath(origin, "/foo3/index.html"); 211 EXPECT_FALSE(realm2_entry == entry); 212 entry = cache.LookupByPath(origin, std::string()); 213 EXPECT_FALSE(realm2_entry == entry); 214 215 // Confirm we find the same realm, different auth scheme by path lookup 216 HttpAuthCache::Entry* realm3_digest_entry = 217 cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); 218 EXPECT_FALSE(NULL == realm3_digest_entry); 219 entry = cache.LookupByPath(origin, "/baz/index.html"); 220 EXPECT_TRUE(realm3_digest_entry == entry); 221 entry = cache.LookupByPath(origin, "/baz/"); 222 EXPECT_TRUE(realm3_digest_entry == entry); 223 entry = cache.LookupByPath(origin, "/baz"); 224 EXPECT_FALSE(realm3_digest_entry == entry); 225 226 // Confirm we find the same realm, different auth scheme by path lookup 227 HttpAuthCache::Entry* realm3DigestEntry = 228 cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); 229 EXPECT_FALSE(NULL == realm3DigestEntry); 230 entry = cache.LookupByPath(origin, "/baz/index.html"); 231 EXPECT_TRUE(realm3DigestEntry == entry); 232 entry = cache.LookupByPath(origin, "/baz/"); 233 EXPECT_TRUE(realm3DigestEntry == entry); 234 entry = cache.LookupByPath(origin, "/baz"); 235 EXPECT_FALSE(realm3DigestEntry == entry); 236 237 // Lookup using empty path (may be used for proxy). 238 entry = cache.LookupByPath(origin, std::string()); 239 EXPECT_FALSE(NULL == entry); 240 EXPECT_EQ(HttpAuth::AUTH_SCHEME_BASIC, entry->scheme()); 241 EXPECT_EQ(kRealm3, entry->realm()); 242 } 243 244 TEST(HttpAuthCacheTest, AddPath) { 245 HttpAuthCache::Entry entry; 246 247 // All of these paths have a common root /1/2/2/4/5/ 248 entry.AddPath("/1/2/3/4/5/x.txt"); 249 entry.AddPath("/1/2/3/4/5/y.txt"); 250 entry.AddPath("/1/2/3/4/5/z.txt"); 251 252 EXPECT_EQ(1U, entry.paths_.size()); 253 EXPECT_EQ("/1/2/3/4/5/", entry.paths_.front()); 254 255 // Add a new entry (not a subpath). 256 entry.AddPath("/1/XXX/q"); 257 EXPECT_EQ(2U, entry.paths_.size()); 258 EXPECT_EQ("/1/XXX/", entry.paths_.front()); 259 EXPECT_EQ("/1/2/3/4/5/", entry.paths_.back()); 260 261 // Add containing paths of /1/2/3/4/5/ -- should swallow up the deeper paths. 262 entry.AddPath("/1/2/3/4/x.txt"); 263 EXPECT_EQ(2U, entry.paths_.size()); 264 EXPECT_EQ("/1/2/3/4/", entry.paths_.front()); 265 EXPECT_EQ("/1/XXX/", entry.paths_.back()); 266 entry.AddPath("/1/2/3/x"); 267 EXPECT_EQ(2U, entry.paths_.size()); 268 EXPECT_EQ("/1/2/3/", entry.paths_.front()); 269 EXPECT_EQ("/1/XXX/", entry.paths_.back()); 270 271 entry.AddPath("/index.html"); 272 EXPECT_EQ(1U, entry.paths_.size()); 273 EXPECT_EQ("/", entry.paths_.front()); 274 } 275 276 // Calling Add when the realm entry already exists, should append that 277 // path. 278 TEST(HttpAuthCacheTest, AddToExistingEntry) { 279 HttpAuthCache cache; 280 GURL origin("http://www.foobar.com:70"); 281 const std::string auth_challenge = "Basic realm=MyRealm"; 282 283 scoped_ptr<HttpAuthHandler> handler( 284 new MockAuthHandler( 285 HttpAuth::AUTH_SCHEME_BASIC, "MyRealm", HttpAuth::AUTH_SERVER)); 286 HttpAuthCache::Entry* orig_entry = cache.Add( 287 origin, handler->realm(), handler->auth_scheme(), auth_challenge, 288 CreateASCIICredentials("user1", "password1"), "/x/y/z/"); 289 cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge, 290 CreateASCIICredentials("user2", "password2"), "/z/y/x/"); 291 cache.Add(origin, handler->realm(), handler->auth_scheme(), auth_challenge, 292 CreateASCIICredentials("user3", "password3"), "/z/y"); 293 294 HttpAuthCache::Entry* entry = cache.Lookup( 295 origin, "MyRealm", HttpAuth::AUTH_SCHEME_BASIC); 296 297 EXPECT_TRUE(entry == orig_entry); 298 EXPECT_EQ(ASCIIToUTF16("user3"), entry->credentials().username()); 299 EXPECT_EQ(ASCIIToUTF16("password3"), entry->credentials().password()); 300 301 EXPECT_EQ(2U, entry->paths_.size()); 302 EXPECT_EQ("/z/", entry->paths_.front()); 303 EXPECT_EQ("/x/y/z/", entry->paths_.back()); 304 } 305 306 TEST(HttpAuthCacheTest, Remove) { 307 GURL origin("http://foobar2.com"); 308 309 scoped_ptr<HttpAuthHandler> realm1_handler( 310 new MockAuthHandler( 311 HttpAuth::AUTH_SCHEME_BASIC, kRealm1, HttpAuth::AUTH_SERVER)); 312 313 scoped_ptr<HttpAuthHandler> realm2_handler( 314 new MockAuthHandler( 315 HttpAuth::AUTH_SCHEME_BASIC, kRealm2, HttpAuth::AUTH_SERVER)); 316 317 scoped_ptr<HttpAuthHandler> realm3_basic_handler( 318 new MockAuthHandler( 319 HttpAuth::AUTH_SCHEME_BASIC, kRealm3, HttpAuth::AUTH_SERVER)); 320 321 scoped_ptr<HttpAuthHandler> realm3_digest_handler( 322 new MockAuthHandler( 323 HttpAuth::AUTH_SCHEME_DIGEST, kRealm3, HttpAuth::AUTH_SERVER)); 324 325 HttpAuthCache cache; 326 cache.Add(origin, realm1_handler->realm(), realm1_handler->auth_scheme(), 327 "basic realm=Realm1", AuthCredentials(kAlice, k123), "/"); 328 cache.Add(origin, realm2_handler->realm(), realm2_handler->auth_scheme(), 329 "basic realm=Realm2", CreateASCIICredentials("bob", "princess"), 330 "/"); 331 cache.Add(origin, realm3_basic_handler->realm(), 332 realm3_basic_handler->auth_scheme(), "basic realm=Realm3", 333 AuthCredentials(kAdmin, kPassword), "/"); 334 cache.Add(origin, realm3_digest_handler->realm(), 335 realm3_digest_handler->auth_scheme(), "digest realm=Realm3", 336 AuthCredentials(kRoot, kWileCoyote), "/"); 337 338 // Fails, because there is no realm "Realm5". 339 EXPECT_FALSE(cache.Remove( 340 origin, kRealm5, HttpAuth::AUTH_SCHEME_BASIC, 341 AuthCredentials(kAlice, k123))); 342 343 // Fails because the origin is wrong. 344 EXPECT_FALSE(cache.Remove(GURL("http://foobar2.com:100"), 345 kRealm1, 346 HttpAuth::AUTH_SCHEME_BASIC, 347 AuthCredentials(kAlice, k123))); 348 349 // Fails because the username is wrong. 350 EXPECT_FALSE(cache.Remove( 351 origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, 352 AuthCredentials(kAlice2, k123))); 353 354 // Fails because the password is wrong. 355 EXPECT_FALSE(cache.Remove( 356 origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, 357 AuthCredentials(kAlice, k1234))); 358 359 // Fails because the authentication type is wrong. 360 EXPECT_FALSE(cache.Remove( 361 origin, kRealm1, HttpAuth::AUTH_SCHEME_DIGEST, 362 AuthCredentials(kAlice, k123))); 363 364 // Succeeds. 365 EXPECT_TRUE(cache.Remove( 366 origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, 367 AuthCredentials(kAlice, k123))); 368 369 // Fails because we just deleted the entry! 370 EXPECT_FALSE(cache.Remove( 371 origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC, 372 AuthCredentials(kAlice, k123))); 373 374 // Succeed when there are two authentication types for the same origin,realm. 375 EXPECT_TRUE(cache.Remove( 376 origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST, 377 AuthCredentials(kRoot, kWileCoyote))); 378 379 // Succeed as above, but when entries were added in opposite order 380 cache.Add(origin, realm3_digest_handler->realm(), 381 realm3_digest_handler->auth_scheme(), "digest realm=Realm3", 382 AuthCredentials(kRoot, kWileCoyote), "/"); 383 EXPECT_TRUE(cache.Remove( 384 origin, kRealm3, HttpAuth::AUTH_SCHEME_BASIC, 385 AuthCredentials(kAdmin, kPassword))); 386 387 // Make sure that removing one entry still leaves the other available for 388 // lookup. 389 HttpAuthCache::Entry* entry = cache.Lookup( 390 origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); 391 EXPECT_FALSE(NULL == entry); 392 } 393 394 TEST(HttpAuthCacheTest, UpdateStaleChallenge) { 395 HttpAuthCache cache; 396 GURL origin("http://foobar2.com"); 397 scoped_ptr<HttpAuthHandler> digest_handler( 398 new MockAuthHandler( 399 HttpAuth::AUTH_SCHEME_DIGEST, kRealm1, HttpAuth::AUTH_PROXY)); 400 HttpAuthCache::Entry* entry_pre = cache.Add( 401 origin, 402 digest_handler->realm(), 403 digest_handler->auth_scheme(), 404 "Digest realm=Realm1," 405 "nonce=\"s3MzvFhaBAA=4c520af5acd9d8d7ae26947529d18c8eae1e98f4\"", 406 CreateASCIICredentials("realm-digest-user", "realm-digest-password"), 407 "/baz/index.html"); 408 ASSERT_TRUE(entry_pre != NULL); 409 410 EXPECT_EQ(2, entry_pre->IncrementNonceCount()); 411 EXPECT_EQ(3, entry_pre->IncrementNonceCount()); 412 EXPECT_EQ(4, entry_pre->IncrementNonceCount()); 413 414 bool update_success = cache.UpdateStaleChallenge( 415 origin, 416 digest_handler->realm(), 417 digest_handler->auth_scheme(), 418 "Digest realm=Realm1," 419 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\"," 420 "stale=\"true\""); 421 EXPECT_TRUE(update_success); 422 423 // After the stale update, the entry should still exist in the cache and 424 // the nonce count should be reset to 0. 425 HttpAuthCache::Entry* entry_post = cache.Lookup( 426 origin, 427 digest_handler->realm(), 428 digest_handler->auth_scheme()); 429 ASSERT_TRUE(entry_post != NULL); 430 EXPECT_EQ(2, entry_post->IncrementNonceCount()); 431 432 // UpdateStaleChallenge will fail if an entry doesn't exist in the cache. 433 bool update_failure = cache.UpdateStaleChallenge( 434 origin, 435 kRealm2, 436 digest_handler->auth_scheme(), 437 "Digest realm=Realm2," 438 "nonce=\"claGgoRXBAA=7583377687842fdb7b56ba0555d175baa0b800e3\"," 439 "stale=\"true\""); 440 EXPECT_FALSE(update_failure); 441 } 442 443 TEST(HttpAuthCacheTest, UpdateAllFrom) { 444 GURL origin("http://example.com"); 445 std::string path("/some/path"); 446 std::string another_path("/another/path"); 447 448 scoped_ptr<HttpAuthHandler> realm1_handler( 449 new MockAuthHandler( 450 HttpAuth::AUTH_SCHEME_BASIC, kRealm1, HttpAuth::AUTH_SERVER)); 451 452 scoped_ptr<HttpAuthHandler> realm2_handler( 453 new MockAuthHandler( 454 HttpAuth::AUTH_SCHEME_BASIC, kRealm2, HttpAuth::AUTH_PROXY)); 455 456 scoped_ptr<HttpAuthHandler> realm3_digest_handler( 457 new MockAuthHandler( 458 HttpAuth::AUTH_SCHEME_DIGEST, kRealm3, HttpAuth::AUTH_SERVER)); 459 460 scoped_ptr<HttpAuthHandler> realm4_handler( 461 new MockAuthHandler( 462 HttpAuth::AUTH_SCHEME_BASIC, kRealm4, HttpAuth::AUTH_SERVER)); 463 464 HttpAuthCache first_cache; 465 HttpAuthCache::Entry* entry; 466 467 first_cache.Add(origin, realm1_handler->realm(), 468 realm1_handler->auth_scheme(), "basic realm=Realm1", 469 AuthCredentials(kAlice, k123), path); 470 first_cache.Add(origin, realm2_handler->realm(), 471 realm2_handler->auth_scheme(), "basic realm=Realm2", 472 AuthCredentials(kAlice2, k1234), path); 473 first_cache.Add(origin, realm3_digest_handler->realm(), 474 realm3_digest_handler->auth_scheme(), "digest realm=Realm3", 475 AuthCredentials(kRoot, kWileCoyote), path); 476 entry = first_cache.Add( 477 origin, realm3_digest_handler->realm(), 478 realm3_digest_handler->auth_scheme(), "digest realm=Realm3", 479 AuthCredentials(kRoot, kWileCoyote), another_path); 480 481 EXPECT_EQ(2, entry->IncrementNonceCount()); 482 483 HttpAuthCache second_cache; 484 // Will be overwritten by kRoot:kWileCoyote. 485 second_cache.Add(origin, realm3_digest_handler->realm(), 486 realm3_digest_handler->auth_scheme(), "digest realm=Realm3", 487 AuthCredentials(kAlice2, k1234), path); 488 // Should be left intact. 489 second_cache.Add(origin, realm4_handler->realm(), 490 realm4_handler->auth_scheme(), "basic realm=Realm4", 491 AuthCredentials(kAdmin, kRoot), path); 492 493 second_cache.UpdateAllFrom(first_cache); 494 495 // Copied from first_cache. 496 entry = second_cache.Lookup(origin, kRealm1, HttpAuth::AUTH_SCHEME_BASIC); 497 EXPECT_TRUE(NULL != entry); 498 EXPECT_EQ(kAlice, entry->credentials().username()); 499 EXPECT_EQ(k123, entry->credentials().password()); 500 501 // Copied from first_cache. 502 entry = second_cache.Lookup(origin, kRealm2, HttpAuth::AUTH_SCHEME_BASIC); 503 EXPECT_TRUE(NULL != entry); 504 EXPECT_EQ(kAlice2, entry->credentials().username()); 505 EXPECT_EQ(k1234, entry->credentials().password()); 506 507 // Overwritten from first_cache. 508 entry = second_cache.Lookup(origin, kRealm3, HttpAuth::AUTH_SCHEME_DIGEST); 509 EXPECT_TRUE(NULL != entry); 510 EXPECT_EQ(kRoot, entry->credentials().username()); 511 EXPECT_EQ(kWileCoyote, entry->credentials().password()); 512 // Nonce count should get copied. 513 EXPECT_EQ(3, entry->IncrementNonceCount()); 514 515 // All paths should get copied. 516 entry = second_cache.LookupByPath(origin, another_path); 517 EXPECT_TRUE(NULL != entry); 518 EXPECT_EQ(kRoot, entry->credentials().username()); 519 EXPECT_EQ(kWileCoyote, entry->credentials().password()); 520 521 // Left intact in second_cache. 522 entry = second_cache.Lookup(origin, kRealm4, HttpAuth::AUTH_SCHEME_BASIC); 523 EXPECT_TRUE(NULL != entry); 524 EXPECT_EQ(kAdmin, entry->credentials().username()); 525 EXPECT_EQ(kRoot, entry->credentials().password()); 526 } 527 528 // Test fixture class for eviction tests (contains helpers for bulk 529 // insertion and existence testing). 530 class HttpAuthCacheEvictionTest : public testing::Test { 531 protected: 532 HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { } 533 534 std::string GenerateRealm(int realm_i) { 535 return base::StringPrintf("Realm %d", realm_i); 536 } 537 538 std::string GeneratePath(int realm_i, int path_i) { 539 return base::StringPrintf("/%d/%d/x/y", realm_i, path_i); 540 } 541 542 void AddRealm(int realm_i) { 543 AddPathToRealm(realm_i, 0); 544 } 545 546 void AddPathToRealm(int realm_i, int path_i) { 547 cache_.Add(origin_, 548 GenerateRealm(realm_i), 549 HttpAuth::AUTH_SCHEME_BASIC, 550 std::string(), 551 AuthCredentials(kUsername, kPassword), 552 GeneratePath(realm_i, path_i)); 553 } 554 555 void CheckRealmExistence(int realm_i, bool exists) { 556 const HttpAuthCache::Entry* entry = 557 cache_.Lookup( 558 origin_, GenerateRealm(realm_i), HttpAuth::AUTH_SCHEME_BASIC); 559 if (exists) { 560 EXPECT_FALSE(entry == NULL); 561 EXPECT_EQ(GenerateRealm(realm_i), entry->realm()); 562 } else { 563 EXPECT_TRUE(entry == NULL); 564 } 565 } 566 567 void CheckPathExistence(int realm_i, int path_i, bool exists) { 568 const HttpAuthCache::Entry* entry = 569 cache_.LookupByPath(origin_, GeneratePath(realm_i, path_i)); 570 if (exists) { 571 EXPECT_FALSE(entry == NULL); 572 EXPECT_EQ(GenerateRealm(realm_i), entry->realm()); 573 } else { 574 EXPECT_TRUE(entry == NULL); 575 } 576 } 577 578 GURL origin_; 579 HttpAuthCache cache_; 580 581 static const int kMaxPaths = HttpAuthCache::kMaxNumPathsPerRealmEntry; 582 static const int kMaxRealms = HttpAuthCache::kMaxNumRealmEntries; 583 }; 584 585 // Add the maxinim number of realm entries to the cache. Each of these entries 586 // must still be retrievable. Next add three more entries -- since the cache is 587 // full this causes FIFO eviction of the first three entries. 588 TEST_F(HttpAuthCacheEvictionTest, RealmEntryEviction) { 589 for (int i = 0; i < kMaxRealms; ++i) 590 AddRealm(i); 591 592 for (int i = 0; i < kMaxRealms; ++i) 593 CheckRealmExistence(i, true); 594 595 for (int i = 0; i < 3; ++i) 596 AddRealm(i + kMaxRealms); 597 598 for (int i = 0; i < 3; ++i) 599 CheckRealmExistence(i, false); 600 601 for (int i = 0; i < kMaxRealms; ++i) 602 CheckRealmExistence(i + 3, true); 603 } 604 605 // Add the maximum number of paths to a single realm entry. Each of these 606 // paths should be retrievable. Next add 3 more paths -- since the cache is 607 // full this causes FIFO eviction of the first three paths. 608 TEST_F(HttpAuthCacheEvictionTest, RealmPathEviction) { 609 for (int i = 0; i < kMaxPaths; ++i) 610 AddPathToRealm(0, i); 611 612 for (int i = 1; i < kMaxRealms; ++i) 613 AddRealm(i); 614 615 for (int i = 0; i < 3; ++i) 616 AddPathToRealm(0, i + kMaxPaths); 617 618 for (int i = 0; i < 3; ++i) 619 CheckPathExistence(0, i, false); 620 621 for (int i = 0; i < kMaxPaths; ++i) 622 CheckPathExistence(0, i + 3, true); 623 624 for (int i = 0; i < kMaxRealms; ++i) 625 CheckRealmExistence(i, true); 626 } 627 628 } // namespace net 629