Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / password_manager / core / browser / login_database_unittest.cc
1 // Copyright 2014 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 "components/password_manager/core/browser/login_database.h"
6
7 #include "base/basictypes.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "components/autofill/core/common/password_form.h"
16 #include "components/password_manager/core/browser/psl_matching_helper.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using autofill::PasswordForm;
21 using base::ASCIIToUTF16;
22 using ::testing::Eq;
23
24 namespace password_manager {
25 namespace {
26 PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) {
27   return PasswordStoreChangeList(1,
28                                  PasswordStoreChange(PasswordStoreChange::ADD,
29                                                      form));
30 }
31
32 PasswordStoreChangeList UpdateChangeForForm(const PasswordForm& form) {
33   return PasswordStoreChangeList(1, PasswordStoreChange(
34       PasswordStoreChange::UPDATE, form));
35 }
36
37 }  // namespace
38
39 // Serialization routines for vectors implemented in login_database.cc.
40 Pickle SerializeVector(const std::vector<base::string16>& vec);
41 std::vector<base::string16> DeserializeVector(const Pickle& pickle);
42
43 class LoginDatabaseTest : public testing::Test {
44  protected:
45   virtual void SetUp() {
46     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
47     file_ = temp_dir_.path().AppendASCII("TestMetadataStoreMacDatabase");
48
49     ASSERT_TRUE(db_.Init(file_));
50   }
51
52   void FormsAreEqual(const PasswordForm& expected, const PasswordForm& actual) {
53     PasswordForm expected_copy(expected);
54 #if defined(OS_MACOSX) && !defined(OS_IOS)
55     // On the Mac we should never be storing passwords in the database.
56     expected_copy.password_value = ASCIIToUTF16("");
57 #endif
58     EXPECT_EQ(expected_copy, actual);
59   }
60
61   void TestNonHTMLFormPSLMatching(const PasswordForm::Scheme& scheme) {
62     ScopedVector<PasswordForm> result;
63
64     base::Time now = base::Time::Now();
65
66     // Simple non-html auth form.
67     PasswordForm non_html_auth;
68     non_html_auth.origin = GURL("http://example.com");
69     non_html_auth.username_value = ASCIIToUTF16("test@gmail.com");
70     non_html_auth.password_value = ASCIIToUTF16("test");
71     non_html_auth.signon_realm = "http://example.com/Realm";
72     non_html_auth.scheme = scheme;
73     non_html_auth.date_created = now;
74
75     // Simple password form.
76     PasswordForm html_form(non_html_auth);
77     html_form.action = GURL("http://example.com/login");
78     html_form.username_element = ASCIIToUTF16("username");
79     html_form.username_value = ASCIIToUTF16("test2@gmail.com");
80     html_form.password_element = ASCIIToUTF16("password");
81     html_form.submit_element = ASCIIToUTF16("");
82     html_form.signon_realm = "http://example.com/";
83     html_form.scheme = PasswordForm::SCHEME_HTML;
84     html_form.date_created = now;
85
86     // Add them and make sure they are there.
87     EXPECT_EQ(AddChangeForForm(non_html_auth), db_.AddLogin(non_html_auth));
88     EXPECT_EQ(AddChangeForForm(html_form), db_.AddLogin(html_form));
89     EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
90     EXPECT_EQ(2U, result.size());
91     result.clear();
92
93     PasswordForm second_non_html_auth(non_html_auth);
94     second_non_html_auth.origin = GURL("http://second.example.com");
95     second_non_html_auth.signon_realm = "http://second.example.com/Realm";
96
97     // This shouldn't match anything.
98     EXPECT_TRUE(db_.GetLogins(second_non_html_auth, &result.get()));
99     EXPECT_EQ(0U, result.size());
100
101     // non-html auth still matches again itself.
102     EXPECT_TRUE(db_.GetLogins(non_html_auth, &result.get()));
103     ASSERT_EQ(1U, result.size());
104     EXPECT_EQ(result[0]->signon_realm, "http://example.com/Realm");
105
106     // Clear state.
107     db_.RemoveLoginsCreatedBetween(now, base::Time());
108   }
109
110   base::ScopedTempDir temp_dir_;
111   base::FilePath file_;
112   LoginDatabase db_;
113 };
114
115 TEST_F(LoginDatabaseTest, Logins) {
116   std::vector<PasswordForm*> result;
117
118   // Verify the database is empty.
119   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
120   EXPECT_EQ(0U, result.size());
121
122   // Example password form.
123   PasswordForm form;
124   form.origin = GURL("http://accounts.google.com/LoginAuth");
125   form.action = GURL("http://accounts.google.com/Login");
126   form.username_element = ASCIIToUTF16("Email");
127   form.username_value = ASCIIToUTF16("test@gmail.com");
128   form.password_element = ASCIIToUTF16("Passwd");
129   form.password_value = ASCIIToUTF16("test");
130   form.submit_element = ASCIIToUTF16("signIn");
131   form.signon_realm = "http://www.google.com/";
132   form.ssl_valid = false;
133   form.preferred = false;
134   form.scheme = PasswordForm::SCHEME_HTML;
135   form.times_used = 1;
136   form.form_data.name = ASCIIToUTF16("form_name");
137   form.date_synced = base::Time::Now();
138   form.display_name = ASCIIToUTF16("Mr. Smith");
139   form.avatar_url = GURL("https://accounts.google.com/Avatar");
140   form.federation_url = GURL("https://accounts.google.com/federation");
141   form.is_zero_click = true;
142
143   // Add it and make sure it is there and that all the fields were retrieved
144   // correctly.
145   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
146   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
147   ASSERT_EQ(1U, result.size());
148   FormsAreEqual(form, *result[0]);
149   delete result[0];
150   result.clear();
151
152   // Match against an exact copy.
153   EXPECT_TRUE(db_.GetLogins(form, &result));
154   ASSERT_EQ(1U, result.size());
155   FormsAreEqual(form, *result[0]);
156   delete result[0];
157   result.clear();
158
159   // The example site changes...
160   PasswordForm form2(form);
161   form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
162   form2.submit_element = ASCIIToUTF16("reallySignIn");
163
164   // Match against an inexact copy
165   EXPECT_TRUE(db_.GetLogins(form2, &result));
166   EXPECT_EQ(1U, result.size());
167   delete result[0];
168   result.clear();
169
170   // Uh oh, the site changed origin & action URLs all at once!
171   PasswordForm form3(form2);
172   form3.action = GURL("http://www.google.com/new/accounts/Login");
173
174   // signon_realm is the same, should match.
175   EXPECT_TRUE(db_.GetLogins(form3, &result));
176   EXPECT_EQ(1U, result.size());
177   delete result[0];
178   result.clear();
179
180   // Imagine the site moves to a secure server for login.
181   PasswordForm form4(form3);
182   form4.signon_realm = "https://www.google.com/";
183   form4.ssl_valid = true;
184
185   // We have only an http record, so no match for this.
186   EXPECT_TRUE(db_.GetLogins(form4, &result));
187   EXPECT_EQ(0U, result.size());
188
189   // Let's imagine the user logs into the secure site.
190   EXPECT_EQ(AddChangeForForm(form4), db_.AddLogin(form4));
191   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
192   EXPECT_EQ(2U, result.size());
193   delete result[0];
194   delete result[1];
195   result.clear();
196
197   // Now the match works
198   EXPECT_TRUE(db_.GetLogins(form4, &result));
199   EXPECT_EQ(1U, result.size());
200   delete result[0];
201   result.clear();
202
203   // The user chose to forget the original but not the new.
204   EXPECT_TRUE(db_.RemoveLogin(form));
205   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
206   EXPECT_EQ(1U, result.size());
207   delete result[0];
208   result.clear();
209
210   // The old form wont match the new site (http vs https).
211   EXPECT_TRUE(db_.GetLogins(form, &result));
212   EXPECT_EQ(0U, result.size());
213
214   // The user's request for the HTTPS site is intercepted
215   // by an attacker who presents an invalid SSL cert.
216   PasswordForm form5(form4);
217   form5.ssl_valid = 0;
218
219   // It will match in this case.
220   EXPECT_TRUE(db_.GetLogins(form5, &result));
221   EXPECT_EQ(1U, result.size());
222   delete result[0];
223   result.clear();
224
225   // User changes his password.
226   PasswordForm form6(form5);
227   form6.password_value = ASCIIToUTF16("test6");
228   form6.preferred = true;
229
230   // We update, and check to make sure it matches the
231   // old form, and there is only one record.
232   EXPECT_EQ(UpdateChangeForForm(form6), db_.UpdateLogin(form6));
233   // matches
234   EXPECT_TRUE(db_.GetLogins(form5, &result));
235   EXPECT_EQ(1U, result.size());
236   delete result[0];
237   result.clear();
238   // Only one record.
239   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
240   EXPECT_EQ(1U, result.size());
241   // Password element was updated.
242 #if defined(OS_MACOSX) && !defined(OS_IOS)
243   // On the Mac we should never be storing passwords in the database.
244   EXPECT_EQ(base::string16(), result[0]->password_value);
245 #else
246   EXPECT_EQ(form6.password_value, result[0]->password_value);
247 #endif
248   // Preferred login.
249   EXPECT_TRUE(form6.preferred);
250   delete result[0];
251   result.clear();
252
253   // Make sure everything can disappear.
254   EXPECT_TRUE(db_.RemoveLogin(form4));
255   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
256   EXPECT_EQ(0U, result.size());
257 }
258
259 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) {
260   std::vector<PasswordForm*> result;
261
262   // Verify the database is empty.
263   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
264   EXPECT_EQ(0U, result.size());
265
266   // Example password form.
267   PasswordForm form;
268   form.origin = GURL("https://foo.com/");
269   form.action = GURL("https://foo.com/login");
270   form.username_element = ASCIIToUTF16("username");
271   form.username_value = ASCIIToUTF16("test@gmail.com");
272   form.password_element = ASCIIToUTF16("password");
273   form.password_value = ASCIIToUTF16("test");
274   form.submit_element = ASCIIToUTF16("");
275   form.signon_realm = "https://foo.com/";
276   form.ssl_valid = true;
277   form.preferred = false;
278   form.scheme = PasswordForm::SCHEME_HTML;
279
280   // Add it and make sure it is there.
281   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
282   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
283   EXPECT_EQ(1U, result.size());
284   delete result[0];
285   result.clear();
286
287   // Match against an exact copy.
288   EXPECT_TRUE(db_.GetLogins(form, &result));
289   EXPECT_EQ(1U, result.size());
290   delete result[0];
291   result.clear();
292
293   // We go to the mobile site.
294   PasswordForm form2(form);
295   form2.origin = GURL("https://mobile.foo.com/");
296   form2.action = GURL("https://mobile.foo.com/login");
297   form2.signon_realm = "https://mobile.foo.com/";
298
299   // Match against the mobile site.
300   EXPECT_TRUE(db_.GetLogins(form2, &result));
301   EXPECT_EQ(1U, result.size());
302   EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
303   EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
304   delete result[0];
305   result.clear();
306 }
307
308 TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) {
309   TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC);
310   TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST);
311   TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_OTHER);
312 }
313
314 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
315   std::vector<PasswordForm*> result;
316
317   // Verify the database is empty.
318   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
319   EXPECT_EQ(0U, result.size());
320
321   // Example password form.
322   PasswordForm form;
323   form.origin = GURL("https://accounts.google.com/");
324   form.action = GURL("https://accounts.google.com/login");
325   form.username_element = ASCIIToUTF16("username");
326   form.username_value = ASCIIToUTF16("test@gmail.com");
327   form.password_element = ASCIIToUTF16("password");
328   form.password_value = ASCIIToUTF16("test");
329   form.submit_element = ASCIIToUTF16("");
330   form.signon_realm = "https://accounts.google.com/";
331   form.ssl_valid = true;
332   form.preferred = false;
333   form.scheme = PasswordForm::SCHEME_HTML;
334
335   // Add it and make sure it is there.
336   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
337   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
338   EXPECT_EQ(1U, result.size());
339   delete result[0];
340   result.clear();
341
342   // Match against an exact copy.
343   EXPECT_TRUE(db_.GetLogins(form, &result));
344   EXPECT_EQ(1U, result.size());
345   delete result[0];
346   result.clear();
347
348   // We go to a different site on the same domain where feature is not needed.
349   PasswordForm form2(form);
350   form2.origin = GURL("https://some.other.google.com/");
351   form2.action = GURL("https://some.other.google.com/login");
352   form2.signon_realm = "https://some.other.google.com/";
353
354   // Match against the other site. Should not match since feature should not be
355   // enabled for this domain.
356   EXPECT_TRUE(db_.GetLogins(form2, &result));
357   EXPECT_EQ(0U, result.size());
358 }
359
360 // This test fails if the implementation of GetLogins uses GetCachedStatement
361 // instead of GetUniqueStatement, since REGEXP is in use. See
362 // http://crbug.com/248608.
363 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingDifferentSites) {
364   std::vector<PasswordForm*> result;
365
366   // Verify the database is empty.
367   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
368   EXPECT_EQ(0U, result.size());
369
370   // Example password form.
371   PasswordForm form;
372   form.origin = GURL("https://foo.com/");
373   form.action = GURL("https://foo.com/login");
374   form.username_element = ASCIIToUTF16("username");
375   form.username_value = ASCIIToUTF16("test@gmail.com");
376   form.password_element = ASCIIToUTF16("password");
377   form.password_value = ASCIIToUTF16("test");
378   form.submit_element = ASCIIToUTF16("");
379   form.signon_realm = "https://foo.com/";
380   form.ssl_valid = true;
381   form.preferred = false;
382   form.scheme = PasswordForm::SCHEME_HTML;
383
384   // Add it and make sure it is there.
385   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
386   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
387   EXPECT_EQ(1U, result.size());
388   delete result[0];
389   result.clear();
390
391   // Match against an exact copy.
392   EXPECT_TRUE(db_.GetLogins(form, &result));
393   EXPECT_EQ(1U, result.size());
394   delete result[0];
395   result.clear();
396
397   // We go to the mobile site.
398   PasswordForm form2(form);
399   form2.origin = GURL("https://mobile.foo.com/");
400   form2.action = GURL("https://mobile.foo.com/login");
401   form2.signon_realm = "https://mobile.foo.com/";
402
403   // Match against the mobile site.
404   EXPECT_TRUE(db_.GetLogins(form2, &result));
405   EXPECT_EQ(1U, result.size());
406   EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm);
407   EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm);
408   delete result[0];
409   result.clear();
410
411   // Add baz.com desktop site.
412   form.origin = GURL("https://baz.com/login/");
413   form.action = GURL("https://baz.com/login/");
414   form.username_element = ASCIIToUTF16("email");
415   form.username_value = ASCIIToUTF16("test@gmail.com");
416   form.password_element = ASCIIToUTF16("password");
417   form.password_value = ASCIIToUTF16("test");
418   form.submit_element = ASCIIToUTF16("");
419   form.signon_realm = "https://baz.com/";
420   form.ssl_valid = true;
421   form.preferred = false;
422   form.scheme = PasswordForm::SCHEME_HTML;
423
424   // Add it and make sure it is there.
425   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
426   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
427   EXPECT_EQ(2U, result.size());
428   delete result[0];
429   delete result[1];
430   result.clear();
431
432   // We go to the mobile site of baz.com.
433   PasswordForm form3(form);
434   form3.origin = GURL("https://m.baz.com/login/");
435   form3.action = GURL("https://m.baz.com/login/");
436   form3.signon_realm = "https://m.baz.com/";
437
438   // Match against the mobile site of baz.com.
439   EXPECT_TRUE(db_.GetLogins(form3, &result));
440   EXPECT_EQ(1U, result.size());
441   EXPECT_EQ("https://m.baz.com/", result[0]->signon_realm);
442   EXPECT_EQ("https://baz.com/", result[0]->original_signon_realm);
443   delete result[0];
444   result.clear();
445 }
446
447 PasswordForm GetFormWithNewSignonRealm(PasswordForm form,
448                                        std::string signon_realm) {
449   PasswordForm form2(form);
450   form2.origin = GURL(signon_realm);
451   form2.action = GURL(signon_realm);
452   form2.signon_realm = signon_realm;
453   return form2;
454 }
455
456 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
457   std::vector<PasswordForm*> result;
458
459   // Verify the database is empty.
460   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
461   EXPECT_EQ(0U, result.size());
462
463   // Example password form.
464   PasswordForm form;
465   form.origin = GURL("http://foo.com/");
466   form.action = GURL("http://foo.com/login");
467   form.username_element = ASCIIToUTF16("username");
468   form.username_value = ASCIIToUTF16("test@gmail.com");
469   form.password_element = ASCIIToUTF16("password");
470   form.password_value = ASCIIToUTF16("test");
471   form.submit_element = ASCIIToUTF16("");
472   form.signon_realm = "http://foo.com/";
473   form.ssl_valid = false;
474   form.preferred = false;
475   form.scheme = PasswordForm::SCHEME_HTML;
476
477   // Add it and make sure it is there.
478   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
479   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
480   EXPECT_EQ(1U, result.size());
481   delete result[0];
482   result.clear();
483
484   // Example password form that has - in the domain name.
485   PasswordForm form_dash =
486       GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
487
488   // Add it and make sure it is there.
489   EXPECT_EQ(AddChangeForForm(form_dash), db_.AddLogin(form_dash));
490   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
491   EXPECT_EQ(2U, result.size());
492   delete result[0];
493   delete result[1];
494   result.clear();
495
496   // Match against an exact copy.
497   EXPECT_TRUE(db_.GetLogins(form, &result));
498   EXPECT_EQ(1U, result.size());
499   delete result[0];
500   result.clear();
501
502   // www.foo.com should match.
503   PasswordForm form2 = GetFormWithNewSignonRealm(form, "http://www.foo.com/");
504   EXPECT_TRUE(db_.GetLogins(form2, &result));
505   EXPECT_EQ(1U, result.size());
506   delete result[0];
507   result.clear();
508
509   // a.b.foo.com should match.
510   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo.com/");
511   EXPECT_TRUE(db_.GetLogins(form2, &result));
512   EXPECT_EQ(1U, result.size());
513   delete result[0];
514   result.clear();
515
516   // a-b.foo.com should match.
517   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo.com/");
518   EXPECT_TRUE(db_.GetLogins(form2, &result));
519   EXPECT_EQ(1U, result.size());
520   delete result[0];
521   result.clear();
522
523   // foo-bar.com should match.
524   form2 = GetFormWithNewSignonRealm(form, "http://foo-bar.com/");
525   EXPECT_TRUE(db_.GetLogins(form2, &result));
526   EXPECT_EQ(1U, result.size());
527   delete result[0];
528   result.clear();
529
530   // www.foo-bar.com should match.
531   form2 = GetFormWithNewSignonRealm(form, "http://www.foo-bar.com/");
532   EXPECT_TRUE(db_.GetLogins(form2, &result));
533   EXPECT_EQ(1U, result.size());
534   delete result[0];
535   result.clear();
536
537   // a.b.foo-bar.com should match.
538   form2 = GetFormWithNewSignonRealm(form, "http://a.b.foo-bar.com/");
539   EXPECT_TRUE(db_.GetLogins(form2, &result));
540   EXPECT_EQ(1U, result.size());
541   delete result[0];
542   result.clear();
543
544   // a-b.foo-bar.com should match.
545   form2 = GetFormWithNewSignonRealm(form, "http://a-b.foo-bar.com/");
546   EXPECT_TRUE(db_.GetLogins(form2, &result));
547   EXPECT_EQ(1U, result.size());
548   delete result[0];
549   result.clear();
550
551   // foo.com with port 1337 should not match.
552   form2 = GetFormWithNewSignonRealm(form, "http://foo.com:1337/");
553   EXPECT_TRUE(db_.GetLogins(form2, &result));
554   EXPECT_EQ(0U, result.size());
555
556   // http://foo.com should not match since the scheme is wrong.
557   form2 = GetFormWithNewSignonRealm(form, "https://foo.com/");
558   EXPECT_TRUE(db_.GetLogins(form2, &result));
559   EXPECT_EQ(0U, result.size());
560
561   // notfoo.com should not match.
562   form2 = GetFormWithNewSignonRealm(form, "http://notfoo.com/");
563   EXPECT_TRUE(db_.GetLogins(form2, &result));
564   EXPECT_EQ(0U, result.size());
565
566   // baz.com should not match.
567   form2 = GetFormWithNewSignonRealm(form, "http://baz.com/");
568   EXPECT_TRUE(db_.GetLogins(form2, &result));
569   EXPECT_EQ(0U, result.size());
570
571   // foo-baz.com should not match.
572   form2 = GetFormWithNewSignonRealm(form, "http://foo-baz.com/");
573   EXPECT_TRUE(db_.GetLogins(form2, &result));
574   EXPECT_EQ(0U, result.size());
575 }
576
577 static bool AddTimestampedLogin(LoginDatabase* db,
578                                 std::string url,
579                                 const std::string& unique_string,
580                                 const base::Time& time,
581                                 bool date_is_creation) {
582   // Example password form.
583   PasswordForm form;
584   form.origin = GURL(url + std::string("/LoginAuth"));
585   form.username_element = ASCIIToUTF16(unique_string);
586   form.username_value = ASCIIToUTF16(unique_string);
587   form.password_element = ASCIIToUTF16(unique_string);
588   form.submit_element = ASCIIToUTF16("signIn");
589   form.signon_realm = url;
590   form.display_name = ASCIIToUTF16(unique_string);
591   form.avatar_url = GURL("https://accounts.google.com/Avatar");
592   form.federation_url = GURL("https://accounts.google.com/federation");
593   form.is_zero_click = true;
594
595   if (date_is_creation)
596     form.date_created = time;
597   else
598     form.date_synced = time;
599   return db->AddLogin(form) == AddChangeForForm(form);
600 }
601
602 static void ClearResults(std::vector<PasswordForm*>* results) {
603   for (size_t i = 0; i < results->size(); ++i) {
604     delete (*results)[i];
605   }
606   results->clear();
607 }
608
609 TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
610   std::vector<PasswordForm*> result;
611
612   // Verify the database is empty.
613   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
614   EXPECT_EQ(0U, result.size());
615
616   base::Time now = base::Time::Now();
617   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
618
619   // Create one with a 0 time.
620   EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), true));
621   // Create one for now and +/- 1 day.
622   EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, true));
623   EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, true));
624   EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, true));
625
626   // Verify inserts worked.
627   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
628   EXPECT_EQ(4U, result.size());
629   ClearResults(&result);
630
631   // Get everything from today's date and on.
632   EXPECT_TRUE(db_.GetLoginsCreatedBetween(now, base::Time(), &result));
633   EXPECT_EQ(2U, result.size());
634   ClearResults(&result);
635
636   // Delete everything from today's date and on.
637   db_.RemoveLoginsCreatedBetween(now, base::Time());
638
639   // Should have deleted half of what we inserted.
640   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
641   EXPECT_EQ(2U, result.size());
642   ClearResults(&result);
643
644   // Delete with 0 date (should delete all).
645   db_.RemoveLoginsCreatedBetween(base::Time(), base::Time());
646
647   // Verify nothing is left.
648   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
649   EXPECT_EQ(0U, result.size());
650 }
651
652 TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) {
653   ScopedVector<autofill::PasswordForm> result;
654
655   base::Time now = base::Time::Now();
656   base::TimeDelta one_day = base::TimeDelta::FromDays(1);
657
658   // Create one with a 0 time.
659   EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), false));
660   // Create one for now and +/- 1 day.
661   EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, false));
662   EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, false));
663   EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, false));
664
665   // Verify inserts worked.
666   EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
667   EXPECT_EQ(4U, result.size());
668   result.clear();
669
670   // Get everything from today's date and on.
671   EXPECT_TRUE(db_.GetLoginsSyncedBetween(now, base::Time(), &result.get()));
672   ASSERT_EQ(2U, result.size());
673   EXPECT_EQ("3", result[0]->signon_realm);
674   EXPECT_EQ("4", result[1]->signon_realm);
675   result.clear();
676
677   // Delete everything from today's date and on.
678   db_.RemoveLoginsSyncedBetween(now, base::Time());
679
680   // Should have deleted half of what we inserted.
681   EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
682   ASSERT_EQ(2U, result.size());
683   EXPECT_EQ("1", result[0]->signon_realm);
684   EXPECT_EQ("2", result[1]->signon_realm);
685   result.clear();
686
687   // Delete with 0 date (should delete all).
688   db_.RemoveLoginsSyncedBetween(base::Time(), now);
689
690   // Verify nothing is left.
691   EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
692   EXPECT_EQ(0U, result.size());
693 }
694
695 TEST_F(LoginDatabaseTest, BlacklistedLogins) {
696   std::vector<PasswordForm*> result;
697
698   // Verify the database is empty.
699   EXPECT_TRUE(db_.GetBlacklistLogins(&result));
700   ASSERT_EQ(0U, result.size());
701
702   // Save a form as blacklisted.
703   PasswordForm form;
704   form.origin = GURL("http://accounts.google.com/LoginAuth");
705   form.action = GURL("http://accounts.google.com/Login");
706   form.username_element = ASCIIToUTF16("Email");
707   form.password_element = ASCIIToUTF16("Passwd");
708   form.submit_element = ASCIIToUTF16("signIn");
709   form.signon_realm = "http://www.google.com/";
710   form.ssl_valid = false;
711   form.preferred = true;
712   form.blacklisted_by_user = true;
713   form.scheme = PasswordForm::SCHEME_HTML;
714   form.date_synced = base::Time::Now();
715   form.display_name = ASCIIToUTF16("Mr. Smith");
716   form.avatar_url = GURL("https://accounts.google.com/Avatar");
717   form.federation_url = GURL("https://accounts.google.com/federation");
718   form.is_zero_click = true;
719   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
720
721   // Get all non-blacklisted logins (should be none).
722   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
723   ASSERT_EQ(0U, result.size());
724
725   // GetLogins should give the blacklisted result.
726   EXPECT_TRUE(db_.GetLogins(form, &result));
727   ASSERT_EQ(1U, result.size());
728   FormsAreEqual(form, *result[0]);
729   ClearResults(&result);
730
731   // So should GetAllBlacklistedLogins.
732   EXPECT_TRUE(db_.GetBlacklistLogins(&result));
733   ASSERT_EQ(1U, result.size());
734   FormsAreEqual(form, *result[0]);
735   ClearResults(&result);
736 }
737
738 TEST_F(LoginDatabaseTest, VectorSerialization) {
739   // Empty vector.
740   std::vector<base::string16> vec;
741   Pickle temp = SerializeVector(vec);
742   std::vector<base::string16> output = DeserializeVector(temp);
743   EXPECT_THAT(output, Eq(vec));
744
745   // Normal data.
746   vec.push_back(ASCIIToUTF16("first"));
747   vec.push_back(ASCIIToUTF16("second"));
748   vec.push_back(ASCIIToUTF16("third"));
749
750   temp = SerializeVector(vec);
751   output = DeserializeVector(temp);
752   EXPECT_THAT(output, Eq(vec));
753 }
754
755 TEST_F(LoginDatabaseTest, UpdateIncompleteCredentials) {
756   std::vector<autofill::PasswordForm*> result;
757   // Verify the database is empty.
758   EXPECT_TRUE(db_.GetAutofillableLogins(&result));
759   ASSERT_EQ(0U, result.size());
760
761   // Save an incomplete form. Note that it only has a few fields set, ex. it's
762   // missing 'action', 'username_element' and 'password_element'. Such forms
763   // are sometimes inserted during import from other browsers (which may not
764   // store this info).
765   PasswordForm incomplete_form;
766   incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth");
767   incomplete_form.signon_realm = "http://accounts.google.com/";
768   incomplete_form.username_value = ASCIIToUTF16("my_username");
769   incomplete_form.password_value = ASCIIToUTF16("my_password");
770   incomplete_form.ssl_valid = false;
771   incomplete_form.preferred = true;
772   incomplete_form.blacklisted_by_user = false;
773   incomplete_form.scheme = PasswordForm::SCHEME_HTML;
774   EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form));
775
776   // A form on some website. It should trigger a match with the stored one.
777   PasswordForm encountered_form;
778   encountered_form.origin = GURL("http://accounts.google.com/LoginAuth");
779   encountered_form.signon_realm = "http://accounts.google.com/";
780   encountered_form.action = GURL("http://accounts.google.com/Login");
781   encountered_form.username_element = ASCIIToUTF16("Email");
782   encountered_form.password_element = ASCIIToUTF16("Passwd");
783   encountered_form.submit_element = ASCIIToUTF16("signIn");
784
785   // Get matches for encountered_form.
786   EXPECT_TRUE(db_.GetLogins(encountered_form, &result));
787   ASSERT_EQ(1U, result.size());
788   EXPECT_EQ(incomplete_form.origin, result[0]->origin);
789   EXPECT_EQ(incomplete_form.signon_realm, result[0]->signon_realm);
790   EXPECT_EQ(incomplete_form.username_value, result[0]->username_value);
791 #if defined(OS_MACOSX) && !defined(OS_IOS)
792   // On Mac, passwords are not stored in login database, instead they're in
793   // the keychain.
794   EXPECT_TRUE(result[0]->password_value.empty());
795 #else
796   EXPECT_EQ(incomplete_form.password_value, result[0]->password_value);
797 #endif  // OS_MACOSX && !OS_IOS
798   EXPECT_TRUE(result[0]->preferred);
799   EXPECT_FALSE(result[0]->ssl_valid);
800
801   // We should return empty 'action', 'username_element', 'password_element'
802   // and 'submit_element' as we can't be sure if the credentials were entered
803   // in this particular form on the page.
804   EXPECT_EQ(GURL(), result[0]->action);
805   EXPECT_TRUE(result[0]->username_element.empty());
806   EXPECT_TRUE(result[0]->password_element.empty());
807   EXPECT_TRUE(result[0]->submit_element.empty());
808   ClearResults(&result);
809
810   // Let's say this login form worked. Now update the stored credentials with
811   // 'action', 'username_element', 'password_element' and 'submit_element' from
812   // the encountered form.
813   PasswordForm completed_form(incomplete_form);
814   completed_form.action = encountered_form.action;
815   completed_form.username_element = encountered_form.username_element;
816   completed_form.password_element = encountered_form.password_element;
817   completed_form.submit_element = encountered_form.submit_element;
818   EXPECT_EQ(AddChangeForForm(completed_form), db_.AddLogin(completed_form));
819   EXPECT_TRUE(db_.RemoveLogin(incomplete_form));
820
821   // Get matches for encountered_form again.
822   EXPECT_TRUE(db_.GetLogins(encountered_form, &result));
823   ASSERT_EQ(1U, result.size());
824
825   // This time we should have all the info available.
826   PasswordForm expected_form(completed_form);
827 #if defined(OS_MACOSX) && !defined(OS_IOS)
828   expected_form.password_value.clear();
829 #endif  // OS_MACOSX && !OS_IOS
830   EXPECT_EQ(expected_form, *result[0]);
831   ClearResults(&result);
832 }
833
834 TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
835   // Save an incomplete form. Note that it only has a few fields set, ex. it's
836   // missing 'action', 'username_element' and 'password_element'. Such forms
837   // are sometimes inserted during import from other browsers (which may not
838   // store this info).
839   PasswordForm incomplete_form;
840   incomplete_form.origin = GURL("http://accounts.google.com/LoginAuth");
841   incomplete_form.signon_realm = "http://accounts.google.com/";
842   incomplete_form.username_value = ASCIIToUTF16("my_username");
843   incomplete_form.password_value = ASCIIToUTF16("my_password");
844   incomplete_form.ssl_valid = false;
845   incomplete_form.preferred = true;
846   incomplete_form.blacklisted_by_user = false;
847   incomplete_form.scheme = PasswordForm::SCHEME_HTML;
848   EXPECT_EQ(AddChangeForForm(incomplete_form), db_.AddLogin(incomplete_form));
849
850   // Save a complete version of the previous form. Both forms could exist if
851   // the user created the complete version before importing the incomplete
852   // version from a different browser.
853   PasswordForm complete_form = incomplete_form;
854   complete_form.action = GURL("http://accounts.google.com/Login");
855   complete_form.username_element = ASCIIToUTF16("username_element");
856   complete_form.password_element = ASCIIToUTF16("password_element");
857   complete_form.submit_element = ASCIIToUTF16("submit");
858
859   // An update fails because the primary key for |complete_form| is different.
860   EXPECT_EQ(PasswordStoreChangeList(), db_.UpdateLogin(complete_form));
861   EXPECT_EQ(AddChangeForForm(complete_form), db_.AddLogin(complete_form));
862
863   // Make sure both passwords exist.
864   ScopedVector<autofill::PasswordForm> result;
865   EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
866   ASSERT_EQ(2U, result.size());
867   result.clear();
868
869   // Simulate the user changing their password.
870   complete_form.password_value = ASCIIToUTF16("new_password");
871   complete_form.date_synced = base::Time::Now();
872   EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form));
873
874   // Both still exist now.
875   EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
876   ASSERT_EQ(2U, result.size());
877
878 #if defined(OS_MACOSX) && !defined(OS_IOS)
879   // On Mac, passwords are not stored in login database, instead they're in
880   // the keychain.
881   complete_form.password_value.clear();
882   incomplete_form.password_value.clear();
883 #endif  // OS_MACOSX && !OS_IOS
884   if (result[0]->username_element.empty())
885     std::swap(result[0], result[1]);
886   EXPECT_EQ(complete_form, *result[0]);
887   EXPECT_EQ(incomplete_form, *result[1]);
888 }
889
890 TEST_F(LoginDatabaseTest, DoubleAdd) {
891   PasswordForm form;
892   form.origin = GURL("http://accounts.google.com/LoginAuth");
893   form.signon_realm = "http://accounts.google.com/";
894   form.username_value = ASCIIToUTF16("my_username");
895   form.password_value = ASCIIToUTF16("my_password");
896   form.ssl_valid = false;
897   form.preferred = true;
898   form.blacklisted_by_user = false;
899   form.scheme = PasswordForm::SCHEME_HTML;
900   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
901
902   // Add almost the same form again.
903   form.times_used++;
904   PasswordStoreChangeList list;
905   list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
906   list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
907   EXPECT_EQ(list, db_.AddLogin(form));
908 }
909
910 TEST_F(LoginDatabaseTest, UpdateLogin) {
911   PasswordForm form;
912   form.origin = GURL("http://accounts.google.com/LoginAuth");
913   form.signon_realm = "http://accounts.google.com/";
914   form.username_value = ASCIIToUTF16("my_username");
915   form.password_value = ASCIIToUTF16("my_password");
916   form.ssl_valid = false;
917   form.preferred = true;
918   form.blacklisted_by_user = false;
919   form.scheme = PasswordForm::SCHEME_HTML;
920   EXPECT_EQ(AddChangeForForm(form), db_.AddLogin(form));
921
922   form.action = GURL("http://accounts.google.com/login");
923   form.password_value = ASCIIToUTF16("my_new_password");
924   form.ssl_valid = true;
925   form.preferred = false;
926   form.other_possible_usernames.push_back(ASCIIToUTF16("my_new_username"));
927   form.times_used = 20;
928   form.submit_element = ASCIIToUTF16("submit_element");
929   form.date_synced = base::Time::Now();
930   form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1);
931   // Remove this line after crbug/374132 is fixed.
932   form.date_created = base::Time::FromTimeT(form.date_created.ToTimeT());
933   form.blacklisted_by_user = true;
934   form.scheme = PasswordForm::SCHEME_BASIC;
935   form.type = PasswordForm::TYPE_GENERATED;
936   form.display_name = ASCIIToUTF16("Mr. Smith");
937   form.avatar_url = GURL("https://accounts.google.com/Avatar");
938   form.federation_url = GURL("https://accounts.google.com/federation");
939   form.is_zero_click = true;
940   EXPECT_EQ(UpdateChangeForForm(form), db_.UpdateLogin(form));
941
942   ScopedVector<autofill::PasswordForm> result;
943   EXPECT_TRUE(db_.GetLogins(form, &result.get()));
944   ASSERT_EQ(1U, result.size());
945 #if defined(OS_MACOSX) && !defined(OS_IOS)
946   // On Mac, passwords are not stored in login database, instead they're in
947   // the keychain.
948   form.password_value.clear();
949 #endif  // OS_MACOSX && !OS_IOS
950   EXPECT_EQ(form, *result[0]);
951 }
952
953 #if defined(OS_POSIX)
954 // Only the current user has permission to read the database.
955 //
956 // Only POSIX because GetPosixFilePermissions() only exists on POSIX.
957 // This tests that sql::Connection::set_restrict_to_user() was called,
958 // and that function is a noop on non-POSIX platforms in any case.
959 TEST_F(LoginDatabaseTest, FilePermissions) {
960   int mode = base::FILE_PERMISSION_MASK;
961   EXPECT_TRUE(base::GetPosixFilePermissions(file_, &mode));
962   EXPECT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode);
963 }
964 #endif  // defined(OS_POSIX)
965
966 }  // namespace password_manager