• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "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:
LoginsTableTest()21   LoginsTableTest() {}
~LoginsTableTest()22   virtual ~LoginsTableTest() {}
23 
24  protected:
SetUp()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 
TearDown()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 
TEST_F(LoginsTableTest,Logins)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@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 
AddTimestampedLogin(WebDatabase * db,std::string url,const std::string & unique_string,const Time & time)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 
ClearResults(std::vector<PasswordForm * > * results)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 
TEST_F(LoginsTableTest,ClearPrivateData_SavedPasswords)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 
TEST_F(LoginsTableTest,BlacklistedLogins)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