Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win_unittest.cc
blobc8ec9e5d3e2cfe4d2dd451ed92c7f181d23c89c2
1 // Copyright (c) 2012 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.
5 #include <windows.h>
6 #include <wincrypt.h>
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/stl_util.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/password_manager/password_form_data.h"
20 #include "chrome/browser/password_manager/password_store_consumer.h"
21 #include "chrome/browser/password_manager/password_store_win.h"
22 #include "chrome/browser/webdata/logins_table.h"
23 #include "chrome/browser/webdata/web_data_service.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "components/webdata/common/web_database_service.h"
27 #include "components/webdata/encryptor/ie7_password_win.h"
28 #include "content/public/test/test_browser_thread.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
32 using autofill::PasswordForm;
33 using base::WaitableEvent;
34 using content::BrowserThread;
35 using testing::_;
36 using testing::DoAll;
37 using testing::WithArg;
39 namespace {
41 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
42 public:
43 MOCK_METHOD2(OnPasswordStoreRequestDone,
44 void(CancelableRequestProvider::Handle,
45 const std::vector<autofill::PasswordForm*>&));
46 MOCK_METHOD1(OnGetPasswordStoreResults,
47 void(const std::vector<autofill::PasswordForm*>&));
50 class MockWebDataServiceConsumer : public WebDataServiceConsumer {
51 public:
52 MOCK_METHOD2(OnWebDataServiceRequestDone,
53 void(WebDataService::Handle, const WDTypedResult*));
56 } // anonymous namespace
58 typedef std::vector<PasswordForm*> VectorOfForms;
60 class PasswordStoreWinTest : public testing::Test {
61 protected:
62 PasswordStoreWinTest()
63 : ui_thread_(BrowserThread::UI, &message_loop_),
64 db_thread_(BrowserThread::DB) {
67 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created,
68 IE7PasswordInfo* info) {
69 // Copied from chrome/browser/importer/importer_unittest.cc
70 // The username is "abcdefgh" and the password "abcdefghijkl".
71 unsigned char data[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
72 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
73 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
74 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
75 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
76 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
77 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
78 "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
79 "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
80 "\x6c\x00\x00\x00";
81 DATA_BLOB input = {0};
82 DATA_BLOB url_key = {0};
83 DATA_BLOB output = {0};
85 input.pbData = data;
86 input.cbData = sizeof(data);
88 url_key.pbData = reinterpret_cast<unsigned char*>(
89 const_cast<wchar_t*>(url.data()));
90 url_key.cbData = static_cast<DWORD>((url.size() + 1) *
91 sizeof(std::wstring::value_type));
93 if (!CryptProtectData(&input, NULL, &url_key, NULL, NULL,
94 CRYPTPROTECT_UI_FORBIDDEN, &output))
95 return false;
97 std::vector<unsigned char> encrypted_data;
98 encrypted_data.resize(output.cbData);
99 memcpy(&encrypted_data.front(), output.pbData, output.cbData);
101 LocalFree(output.pbData);
103 info->url_hash = ie7_password::GetUrlHash(url);
104 info->encrypted_data = encrypted_data;
105 info->date_created = created;
107 return true;
110 virtual void SetUp() {
111 ASSERT_TRUE(db_thread_.Start());
112 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
114 profile_.reset(new TestingProfile());
116 login_db_.reset(new LoginDatabase());
117 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
118 FILE_PATH_LITERAL("login_test"))));
119 base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
120 wdbs_ = new WebDatabaseService(path,
121 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
122 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
123 // Need to add at least one table so the database gets created.
124 wdbs_->AddTable(scoped_ptr<WebDatabaseTable>(new LoginsTable()));
125 wdbs_->LoadDatabase();
126 wds_ = new WebDataService(wdbs_,
127 WebDataServiceBase::ProfileErrorCallback());
128 wds_->Init();
131 virtual void TearDown() {
132 if (store_.get())
133 store_->ShutdownOnUIThread();
134 wds_->ShutdownOnUIThread();
135 wdbs_->ShutdownDatabase();
136 wds_ = NULL;
137 wdbs_ = NULL;
138 base::WaitableEvent done(false, false);
139 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
140 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
141 done.Wait();
142 base::MessageLoop::current()->PostTask(FROM_HERE,
143 base::MessageLoop::QuitClosure());
144 base::MessageLoop::current()->Run();
145 db_thread_.Stop();
148 base::MessageLoopForUI message_loop_;
149 content::TestBrowserThread ui_thread_;
150 // PasswordStore, WDS schedule work on this thread.
151 content::TestBrowserThread db_thread_;
153 base::ScopedTempDir temp_dir_;
154 scoped_ptr<TestingProfile> profile_;
155 scoped_ptr<LoginDatabase> login_db_;
156 scoped_refptr<WebDataService> wds_;
157 scoped_refptr<WebDatabaseService> wdbs_;
158 scoped_refptr<PasswordStore> store_;
161 ACTION(STLDeleteElements0) {
162 STLDeleteContainerPointers(arg0.begin(), arg0.end());
165 ACTION(QuitUIMessageLoop) {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167 base::MessageLoop::current()->Quit();
170 MATCHER(EmptyWDResult, "") {
171 return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
172 arg)->GetValue().empty();
175 // Hangs flakily, http://crbug.com/71385.
176 TEST_F(PasswordStoreWinTest, DISABLED_ConvertIE7Login) {
177 IE7PasswordInfo password_info;
178 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
179 base::Time::FromDoubleT(1),
180 &password_info));
181 // Verify the URL hash
182 ASSERT_EQ(L"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
183 password_info.url_hash);
185 // This IE7 password will be retrieved by the GetLogins call.
186 wds_->AddIE7Login(password_info);
188 // The WDS schedules tasks to run on the DB thread so we schedule yet another
189 // task to notify us that it's safe to carry on with the test.
190 WaitableEvent done(false, false);
191 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
192 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
193 done.Wait();
195 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
196 wds_.get());
197 EXPECT_TRUE(store_->Init());
199 MockPasswordStoreConsumer consumer;
201 // Make sure we quit the MessageLoop even if the test fails.
202 ON_CALL(consumer, OnGetPasswordStoreResults(_))
203 .WillByDefault(QuitUIMessageLoop());
205 PasswordFormData form_data = {
206 PasswordForm::SCHEME_HTML,
207 "http://example.com/",
208 "http://example.com/origin",
209 "http://example.com/action",
210 L"submit_element",
211 L"username_element",
212 L"password_element",
213 L"",
214 L"",
215 true, false, 1,
217 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
219 PasswordFormData expected_form_data = {
220 PasswordForm::SCHEME_HTML,
221 "http://example.com/",
222 "http://example.com/origin",
223 "http://example.com/action",
224 L"submit_element",
225 L"username_element",
226 L"password_element",
227 L"abcdefgh",
228 L"abcdefghijkl",
229 true, false, 1,
231 std::vector<PasswordForm*> forms;
232 forms.push_back(CreatePasswordFormFromData(expected_form_data));
234 // The IE7 password should be returned.
235 EXPECT_CALL(consumer,
236 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
237 .WillOnce(QuitUIMessageLoop());
239 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
240 base::MessageLoop::current()->Run();
242 STLDeleteElements(&forms);
245 // Crashy. http://crbug.com/86558
246 TEST_F(PasswordStoreWinTest, DISABLED_OutstandingWDSQueries) {
247 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
248 wds_.get());
249 EXPECT_TRUE(store_->Init());
251 PasswordFormData form_data = {
252 PasswordForm::SCHEME_HTML,
253 "http://example.com/",
254 "http://example.com/origin",
255 "http://example.com/action",
256 L"submit_element",
257 L"username_element",
258 L"password_element",
259 L"",
260 L"",
261 true, false, 1,
263 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
265 MockPasswordStoreConsumer consumer;
266 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
268 // Release the PSW and the WDS before the query can return.
269 store_->ShutdownOnUIThread();
270 store_ = NULL;
271 wds_ = NULL;
273 base::MessageLoop::current()->RunUntilIdle();
276 // Hangs flakily, see http://crbug.com/43836.
277 TEST_F(PasswordStoreWinTest, DISABLED_MultipleWDSQueriesOnDifferentThreads) {
278 IE7PasswordInfo password_info;
279 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
280 base::Time::FromDoubleT(1),
281 &password_info));
282 wds_->AddIE7Login(password_info);
284 // The WDS schedules tasks to run on the DB thread so we schedule yet another
285 // task to notify us that it's safe to carry on with the test.
286 WaitableEvent done(false, false);
287 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
288 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
289 done.Wait();
291 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
292 wds_.get());
293 EXPECT_TRUE(store_->Init());
295 MockPasswordStoreConsumer password_consumer;
296 // Make sure we quit the MessageLoop even if the test fails.
297 ON_CALL(password_consumer, OnGetPasswordStoreResults(_))
298 .WillByDefault(QuitUIMessageLoop());
300 PasswordFormData form_data = {
301 PasswordForm::SCHEME_HTML,
302 "http://example.com/",
303 "http://example.com/origin",
304 "http://example.com/action",
305 L"submit_element",
306 L"username_element",
307 L"password_element",
308 L"",
309 L"",
310 true, false, 1,
312 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
314 PasswordFormData expected_form_data = {
315 PasswordForm::SCHEME_HTML,
316 "http://example.com/",
317 "http://example.com/origin",
318 "http://example.com/action",
319 L"submit_element",
320 L"username_element",
321 L"password_element",
322 L"abcdefgh",
323 L"abcdefghijkl",
324 true, false, 1,
326 std::vector<PasswordForm*> forms;
327 forms.push_back(CreatePasswordFormFromData(expected_form_data));
329 // The IE7 password should be returned.
330 EXPECT_CALL(password_consumer,
331 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
332 .WillOnce(QuitUIMessageLoop());
334 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &password_consumer);
336 MockWebDataServiceConsumer wds_consumer;
338 EXPECT_CALL(wds_consumer,
339 OnWebDataServiceRequestDone(_, _))
340 .WillOnce(QuitUIMessageLoop());
342 wds_->GetIE7Login(password_info, &wds_consumer);
344 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin
345 // schedules on the DB thread and once for the one we just scheduled on the UI
346 // thread.
347 base::MessageLoop::current()->Run();
348 base::MessageLoop::current()->Run();
350 STLDeleteElements(&forms);
353 TEST_F(PasswordStoreWinTest, EmptyLogins) {
354 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
355 wds_.get());
356 store_->Init();
358 PasswordFormData form_data = {
359 PasswordForm::SCHEME_HTML,
360 "http://example.com/",
361 "http://example.com/origin",
362 "http://example.com/action",
363 L"submit_element",
364 L"username_element",
365 L"password_element",
366 L"",
367 L"",
368 true, false, 1,
370 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
372 MockPasswordStoreConsumer consumer;
374 // Make sure we quit the MessageLoop even if the test fails.
375 ON_CALL(consumer, OnGetPasswordStoreResults(_))
376 .WillByDefault(QuitUIMessageLoop());
378 VectorOfForms expect_none;
379 // expect that we get no results;
380 EXPECT_CALL(consumer,
381 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
382 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
384 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
385 base::MessageLoop::current()->Run();
388 TEST_F(PasswordStoreWinTest, EmptyBlacklistLogins) {
389 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
390 wds_.get());
391 store_->Init();
393 MockPasswordStoreConsumer consumer;
395 // Make sure we quit the MessageLoop even if the test fails.
396 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
397 .WillByDefault(QuitUIMessageLoop());
399 VectorOfForms expect_none;
400 // expect that we get no results;
401 EXPECT_CALL(
402 consumer,
403 OnPasswordStoreRequestDone(_, ContainsAllPasswordForms(expect_none)))
404 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
406 store_->GetBlacklistLogins(&consumer);
407 base::MessageLoop::current()->Run();
410 TEST_F(PasswordStoreWinTest, EmptyAutofillableLogins) {
411 store_ = new PasswordStoreWin(login_db_.release(), profile_.get(),
412 wds_.get());
413 store_->Init();
415 MockPasswordStoreConsumer consumer;
417 // Make sure we quit the MessageLoop even if the test fails.
418 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
419 .WillByDefault(QuitUIMessageLoop());
421 VectorOfForms expect_none;
422 // expect that we get no results;
423 EXPECT_CALL(
424 consumer,
425 OnPasswordStoreRequestDone(_, ContainsAllPasswordForms(expect_none)))
426 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
428 store_->GetAutofillableLogins(&consumer);
429 base::MessageLoop::current()->Run();