Home | History | Annotate | Download | only in webdata
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/file_util.h"
      6 #include "base/path_service.h"
      7 #include "base/string_number_conversions.h"
      8 #include "base/time.h"
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/webdata/web_database.h"
     11 #include "chrome/common/chrome_paths.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 #include "webkit/glue/password_form.h"
     14 
     15 using base::Time;
     16 using base::TimeDelta;
     17 using webkit_glue::PasswordForm;
     18 
     19 class LoginsTableTest : public testing::Test {
     20  public:
     21   LoginsTableTest() {}
     22   virtual ~LoginsTableTest() {}
     23 
     24  protected:
     25   virtual void SetUp() {
     26     PathService::Get(chrome::DIR_TEST_DATA, &file_);
     27     const std::string test_db = "TestWebDatabase" +
     28         base::Int64ToString(Time::Now().ToTimeT()) +
     29         ".db";
     30     file_ = file_.AppendASCII(test_db);
     31     file_util::Delete(file_, false);
     32   }
     33 
     34   virtual void TearDown() {
     35     file_util::Delete(file_, false);
     36   }
     37 
     38   FilePath file_;
     39 
     40  private:
     41   DISALLOW_COPY_AND_ASSIGN(LoginsTableTest);
     42 };
     43 
     44 TEST_F(LoginsTableTest, Logins) {
     45   WebDatabase db;
     46 
     47   ASSERT_EQ(sql::INIT_OK, db.Init(file_));
     48 
     49   std::vector<PasswordForm*> result;
     50 
     51   // Verify the database is empty.
     52   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
     53   EXPECT_EQ(0U, result.size());
     54 
     55   // Example password form.
     56   PasswordForm form;
     57   form.origin = GURL("http://www.google.com/accounts/LoginAuth");
     58   form.action = GURL("http://www.google.com/accounts/Login");
     59   form.username_element = ASCIIToUTF16("Email");
     60   form.username_value = ASCIIToUTF16("test (at) gmail.com");
     61   form.password_element = ASCIIToUTF16("Passwd");
     62   form.password_value = ASCIIToUTF16("test");
     63   form.submit_element = ASCIIToUTF16("signIn");
     64   form.signon_realm = "http://www.google.com/";
     65   form.ssl_valid = false;
     66   form.preferred = false;
     67   form.scheme = PasswordForm::SCHEME_HTML;
     68 
     69   // Add it and make sure it is there.
     70   EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form));
     71   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
     72   EXPECT_EQ(1U, result.size());
     73   delete result[0];
     74   result.clear();
     75 
     76   // Match against an exact copy.
     77   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
     78   EXPECT_EQ(1U, result.size());
     79   delete result[0];
     80   result.clear();
     81 
     82   // The example site changes...
     83   PasswordForm form2(form);
     84   form2.origin = GURL("http://www.google.com/new/accounts/LoginAuth");
     85   form2.submit_element = ASCIIToUTF16("reallySignIn");
     86 
     87   // Match against an inexact copy
     88   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form2, &result));
     89   EXPECT_EQ(1U, result.size());
     90   delete result[0];
     91   result.clear();
     92 
     93   // Uh oh, the site changed origin & action URL's all at once!
     94   PasswordForm form3(form2);
     95   form3.action = GURL("http://www.google.com/new/accounts/Login");
     96 
     97   // signon_realm is the same, should match.
     98   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form3, &result));
     99   EXPECT_EQ(1U, result.size());
    100   delete result[0];
    101   result.clear();
    102 
    103   // Imagine the site moves to a secure server for login.
    104   PasswordForm form4(form3);
    105   form4.signon_realm = "https://www.google.com/";
    106   form4.ssl_valid = true;
    107 
    108   // We have only an http record, so no match for this.
    109   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form4, &result));
    110   EXPECT_EQ(0U, result.size());
    111 
    112   // Let's imagine the user logs into the secure site.
    113   EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form4));
    114   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    115   EXPECT_EQ(2U, result.size());
    116   delete result[0];
    117   delete result[1];
    118   result.clear();
    119 
    120   // Now the match works
    121   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form4, &result));
    122   EXPECT_EQ(1U, result.size());
    123   delete result[0];
    124   result.clear();
    125 
    126   // The user chose to forget the original but not the new.
    127   EXPECT_TRUE(db.GetLoginsTable()->RemoveLogin(form));
    128   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    129   EXPECT_EQ(1U, result.size());
    130   delete result[0];
    131   result.clear();
    132 
    133   // The old form wont match the new site (http vs https).
    134   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
    135   EXPECT_EQ(0U, result.size());
    136 
    137   // The user's request for the HTTPS site is intercepted
    138   // by an attacker who presents an invalid SSL cert.
    139   PasswordForm form5(form4);
    140   form5.ssl_valid = 0;
    141 
    142   // It will match in this case.
    143   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form5, &result));
    144   EXPECT_EQ(1U, result.size());
    145   delete result[0];
    146   result.clear();
    147 
    148   // User changes his password.
    149   PasswordForm form6(form5);
    150   form6.password_value = ASCIIToUTF16("test6");
    151   form6.preferred = true;
    152 
    153   // We update, and check to make sure it matches the
    154   // old form, and there is only one record.
    155   EXPECT_TRUE(db.GetLoginsTable()->UpdateLogin(form6));
    156   // matches
    157   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form5, &result));
    158   EXPECT_EQ(1U, result.size());
    159   delete result[0];
    160   result.clear();
    161   // Only one record.
    162   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    163   EXPECT_EQ(1U, result.size());
    164   // password element was updated.
    165   EXPECT_EQ(form6.password_value, result[0]->password_value);
    166   // Preferred login.
    167   EXPECT_TRUE(form6.preferred);
    168   delete result[0];
    169   result.clear();
    170 
    171   // Make sure everything can disappear.
    172   EXPECT_TRUE(db.GetLoginsTable()->RemoveLogin(form4));
    173   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    174   EXPECT_EQ(0U, result.size());
    175 }
    176 
    177 static bool AddTimestampedLogin(WebDatabase* db, std::string url,
    178                                 const std::string& unique_string,
    179                                 const Time& time) {
    180   // Example password form.
    181   PasswordForm form;
    182   form.origin = GURL(url + std::string("/LoginAuth"));
    183   form.username_element = ASCIIToUTF16(unique_string);
    184   form.username_value = ASCIIToUTF16(unique_string);
    185   form.password_element = ASCIIToUTF16(unique_string);
    186   form.submit_element = ASCIIToUTF16("signIn");
    187   form.signon_realm = url;
    188   form.date_created = time;
    189   return db->GetLoginsTable()->AddLogin(form);
    190 }
    191 
    192 static void ClearResults(std::vector<PasswordForm*>* results) {
    193   for (size_t i = 0; i < results->size(); ++i) {
    194     delete (*results)[i];
    195   }
    196   results->clear();
    197 }
    198 
    199 TEST_F(LoginsTableTest, ClearPrivateData_SavedPasswords) {
    200   WebDatabase db;
    201 
    202   ASSERT_EQ(sql::INIT_OK, db.Init(file_));
    203 
    204   std::vector<PasswordForm*> result;
    205 
    206   // Verify the database is empty.
    207   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    208   EXPECT_EQ(0U, result.size());
    209 
    210   Time now = Time::Now();
    211   TimeDelta one_day = TimeDelta::FromDays(1);
    212 
    213   // Create one with a 0 time.
    214   EXPECT_TRUE(AddTimestampedLogin(&db, "1", "foo1", Time()));
    215   // Create one for now and +/- 1 day.
    216   EXPECT_TRUE(AddTimestampedLogin(&db, "2", "foo2", now - one_day));
    217   EXPECT_TRUE(AddTimestampedLogin(&db, "3", "foo3", now));
    218   EXPECT_TRUE(AddTimestampedLogin(&db, "4", "foo4", now + one_day));
    219 
    220   // Verify inserts worked.
    221   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    222   EXPECT_EQ(4U, result.size());
    223   ClearResults(&result);
    224 
    225   // Delete everything from today's date and on.
    226   db.GetLoginsTable()->RemoveLoginsCreatedBetween(now, Time());
    227 
    228   // Should have deleted half of what we inserted.
    229   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    230   EXPECT_EQ(2U, result.size());
    231   ClearResults(&result);
    232 
    233   // Delete with 0 date (should delete all).
    234   db.GetLoginsTable()->RemoveLoginsCreatedBetween(Time(), Time());
    235 
    236   // Verify nothing is left.
    237   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    238   EXPECT_EQ(0U, result.size());
    239 }
    240 
    241 TEST_F(LoginsTableTest, BlacklistedLogins) {
    242   WebDatabase db;
    243 
    244   ASSERT_EQ(sql::INIT_OK, db.Init(file_));
    245   std::vector<PasswordForm*> result;
    246 
    247   // Verify the database is empty.
    248   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    249   ASSERT_EQ(0U, result.size());
    250 
    251   // Save a form as blacklisted.
    252   PasswordForm form;
    253   form.origin = GURL("http://www.google.com/accounts/LoginAuth");
    254   form.action = GURL("http://www.google.com/accounts/Login");
    255   form.username_element = ASCIIToUTF16("Email");
    256   form.password_element = ASCIIToUTF16("Passwd");
    257   form.submit_element = ASCIIToUTF16("signIn");
    258   form.signon_realm = "http://www.google.com/";
    259   form.ssl_valid = false;
    260   form.preferred = true;
    261   form.blacklisted_by_user = true;
    262   form.scheme = PasswordForm::SCHEME_HTML;
    263   EXPECT_TRUE(db.GetLoginsTable()->AddLogin(form));
    264 
    265   // Get all non-blacklisted logins (should be none).
    266   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, false));
    267   ASSERT_EQ(0U, result.size());
    268 
    269   // GetLogins should give the blacklisted result.
    270   EXPECT_TRUE(db.GetLoginsTable()->GetLogins(form, &result));
    271   EXPECT_EQ(1U, result.size());
    272   ClearResults(&result);
    273 
    274   // So should GetAll including blacklisted.
    275   EXPECT_TRUE(db.GetLoginsTable()->GetAllLogins(&result, true));
    276   EXPECT_EQ(1U, result.size());
    277   ClearResults(&result);
    278 }
    279