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