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