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