Home | History | Annotate | Download | only in browser
      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 (at) 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 (at) 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 (at) 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 (at) 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 (at) 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 (at) 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 (at) 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 (at) 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
    967