• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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