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:
MockAuthHandler(HttpAuth::Scheme scheme,const std::string & realm,HttpAuth::Target target)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
HandleAnotherChallenge(HttpAuthChallengeTokenizer * challenge)35 virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
36 HttpAuthChallengeTokenizer* challenge) OVERRIDE {
37 return HttpAuth::AUTHORIZATION_RESULT_REJECT;
38 }
39
40 protected:
Init(HttpAuthChallengeTokenizer * challenge)41 virtual bool Init(HttpAuthChallengeTokenizer* challenge) OVERRIDE {
42 return false; // Unused.
43 }
44
GenerateAuthTokenImpl(const AuthCredentials *,const HttpRequestInfo *,const CompletionCallback & callback,std::string * auth_token)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:
~MockAuthHandler()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
CreateASCIICredentials(const char * username,const char * password)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).
TEST(HttpAuthCacheTest,Basic)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
TEST(HttpAuthCacheTest,AddPath)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.
TEST(HttpAuthCacheTest,AddToExistingEntry)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
TEST(HttpAuthCacheTest,Remove)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
TEST(HttpAuthCacheTest,UpdateStaleChallenge)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
TEST(HttpAuthCacheTest,UpdateAllFrom)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:
HttpAuthCacheEvictionTest()532 HttpAuthCacheEvictionTest() : origin_("http://www.google.com") { }
533
GenerateRealm(int realm_i)534 std::string GenerateRealm(int realm_i) {
535 return base::StringPrintf("Realm %d", realm_i);
536 }
537
GeneratePath(int realm_i,int path_i)538 std::string GeneratePath(int realm_i, int path_i) {
539 return base::StringPrintf("/%d/%d/x/y", realm_i, path_i);
540 }
541
AddRealm(int realm_i)542 void AddRealm(int realm_i) {
543 AddPathToRealm(realm_i, 0);
544 }
545
AddPathToRealm(int realm_i,int path_i)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
CheckRealmExistence(int realm_i,bool exists)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
CheckPathExistence(int realm_i,int path_i,bool exists)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.
TEST_F(HttpAuthCacheEvictionTest,RealmEntryEviction)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.
TEST_F(HttpAuthCacheEvictionTest,RealmPathEviction)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