NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win_unittest.cc
blobcd9a821b86271a0deb2ea7ca8bd025c98212881c
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_store_win.h"
20 #include "chrome/browser/webdata/logins_table.h"
21 #include "chrome/browser/webdata/web_data_service.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "components/password_manager/core/browser/password_form_data.h"
25 #include "components/password_manager/core/browser/password_store_consumer.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_METHOD1(OnGetPasswordStoreResults,
44 void(const std::vector<autofill::PasswordForm*>&));
47 class MockWebDataServiceConsumer : public WebDataServiceConsumer {
48 public:
49 MOCK_METHOD2(OnWebDataServiceRequestDone,
50 void(WebDataService::Handle, const WDTypedResult*));
53 } // anonymous namespace
55 typedef std::vector<PasswordForm*> VectorOfForms;
57 class PasswordStoreWinTest : public testing::Test {
58 protected:
59 PasswordStoreWinTest()
60 : ui_thread_(BrowserThread::UI, &message_loop_),
61 db_thread_(BrowserThread::DB) {
64 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created,
65 IE7PasswordInfo* info) {
66 // Copied from chrome/browser/importer/importer_unittest.cc
67 // The username is "abcdefgh" and the password "abcdefghijkl".
68 unsigned char data[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
69 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
70 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
71 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
72 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
73 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
74 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
75 "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
76 "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
77 "\x6c\x00\x00\x00";
78 DATA_BLOB input = {0};
79 DATA_BLOB url_key = {0};
80 DATA_BLOB output = {0};
82 input.pbData = data;
83 input.cbData = sizeof(data);
85 url_key.pbData = reinterpret_cast<unsigned char*>(
86 const_cast<wchar_t*>(url.data()));
87 url_key.cbData = static_cast<DWORD>((url.size() + 1) *
88 sizeof(std::wstring::value_type));
90 if (!CryptProtectData(&input, NULL, &url_key, NULL, NULL,
91 CRYPTPROTECT_UI_FORBIDDEN, &output))
92 return false;
94 std::vector<unsigned char> encrypted_data;
95 encrypted_data.resize(output.cbData);
96 memcpy(&encrypted_data.front(), output.pbData, output.cbData);
98 LocalFree(output.pbData);
100 info->url_hash = ie7_password::GetUrlHash(url);
101 info->encrypted_data = encrypted_data;
102 info->date_created = created;
104 return true;
107 virtual void SetUp() {
108 ASSERT_TRUE(db_thread_.Start());
109 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
111 profile_.reset(new TestingProfile());
113 login_db_.reset(new LoginDatabase());
114 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
115 FILE_PATH_LITERAL("login_test"))));
116 base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
117 wdbs_ = new WebDatabaseService(path,
118 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
119 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
120 // Need to add at least one table so the database gets created.
121 wdbs_->AddTable(scoped_ptr<WebDatabaseTable>(new LoginsTable()));
122 wdbs_->LoadDatabase();
123 wds_ = new WebDataService(wdbs_,
124 WebDataServiceBase::ProfileErrorCallback());
125 wds_->Init();
128 virtual void TearDown() {
129 if (store_)
130 store_->Shutdown();
131 wds_->ShutdownOnUIThread();
132 wdbs_->ShutdownDatabase();
133 wds_ = NULL;
134 wdbs_ = NULL;
135 base::WaitableEvent done(false, false);
136 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
137 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
138 done.Wait();
139 base::MessageLoop::current()->PostTask(FROM_HERE,
140 base::MessageLoop::QuitClosure());
141 base::MessageLoop::current()->Run();
142 db_thread_.Stop();
145 PasswordStoreWin* CreatePasswordStore() {
146 return new PasswordStoreWin(
147 base::MessageLoopProxy::current(),
148 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
149 login_db_.release(),
150 wds_.get());
153 base::MessageLoopForUI message_loop_;
154 content::TestBrowserThread ui_thread_;
155 // PasswordStore, WDS schedule work on this thread.
156 content::TestBrowserThread db_thread_;
158 base::ScopedTempDir temp_dir_;
159 scoped_ptr<TestingProfile> profile_;
160 scoped_ptr<LoginDatabase> login_db_;
161 scoped_refptr<WebDataService> wds_;
162 scoped_refptr<WebDatabaseService> wdbs_;
163 scoped_refptr<PasswordStore> store_;
166 ACTION(STLDeleteElements0) {
167 STLDeleteContainerPointers(arg0.begin(), arg0.end());
170 ACTION(QuitUIMessageLoop) {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 base::MessageLoop::current()->Quit();
175 MATCHER(EmptyWDResult, "") {
176 return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
177 arg)->GetValue().empty();
180 // Hangs flakily, http://crbug.com/71385.
181 TEST_F(PasswordStoreWinTest, DISABLED_ConvertIE7Login) {
182 IE7PasswordInfo password_info;
183 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
184 base::Time::FromDoubleT(1),
185 &password_info));
186 // Verify the URL hash
187 ASSERT_EQ(L"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
188 password_info.url_hash);
190 // This IE7 password will be retrieved by the GetLogins call.
191 wds_->AddIE7Login(password_info);
193 // The WDS schedules tasks to run on the DB thread so we schedule yet another
194 // task to notify us that it's safe to carry on with the test.
195 WaitableEvent done(false, false);
196 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
197 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
198 done.Wait();
200 store_ = CreatePasswordStore();
201 EXPECT_TRUE(store_->Init());
203 MockPasswordStoreConsumer consumer;
205 // Make sure we quit the MessageLoop even if the test fails.
206 ON_CALL(consumer, OnGetPasswordStoreResults(_))
207 .WillByDefault(QuitUIMessageLoop());
209 PasswordFormData form_data = {
210 PasswordForm::SCHEME_HTML,
211 "http://example.com/",
212 "http://example.com/origin",
213 "http://example.com/action",
214 L"submit_element",
215 L"username_element",
216 L"password_element",
217 L"",
218 L"",
219 true, false, 1,
221 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
223 // The returned form will not have 'action' or '*_element' fields set. This
224 // is because credentials imported from IE don't have this information.
225 PasswordFormData expected_form_data = {
226 PasswordForm::SCHEME_HTML,
227 "http://example.com/",
228 "http://example.com/origin",
230 L"",
231 L"",
232 L"",
233 L"abcdefgh",
234 L"abcdefghijkl",
235 true, false, 1,
237 std::vector<PasswordForm*> forms;
238 forms.push_back(CreatePasswordFormFromData(expected_form_data));
240 // The IE7 password should be returned.
241 EXPECT_CALL(consumer,
242 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
243 .WillOnce(QuitUIMessageLoop());
245 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
246 base::MessageLoop::current()->Run();
248 STLDeleteElements(&forms);
251 // Crashy. http://crbug.com/86558
252 TEST_F(PasswordStoreWinTest, DISABLED_OutstandingWDSQueries) {
253 store_ = CreatePasswordStore();
254 EXPECT_TRUE(store_->Init());
256 PasswordFormData form_data = {
257 PasswordForm::SCHEME_HTML,
258 "http://example.com/",
259 "http://example.com/origin",
260 "http://example.com/action",
261 L"submit_element",
262 L"username_element",
263 L"password_element",
264 L"",
265 L"",
266 true, false, 1,
268 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
270 MockPasswordStoreConsumer consumer;
271 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
273 // Release the PSW and the WDS before the query can return.
274 store_->Shutdown();
275 store_ = NULL;
276 wds_ = NULL;
278 base::MessageLoop::current()->RunUntilIdle();
281 // Hangs flakily, see http://crbug.com/43836.
282 TEST_F(PasswordStoreWinTest, DISABLED_MultipleWDSQueriesOnDifferentThreads) {
283 IE7PasswordInfo password_info;
284 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
285 base::Time::FromDoubleT(1),
286 &password_info));
287 wds_->AddIE7Login(password_info);
289 // The WDS schedules tasks to run on the DB thread so we schedule yet another
290 // task to notify us that it's safe to carry on with the test.
291 WaitableEvent done(false, false);
292 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
293 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
294 done.Wait();
296 store_ = CreatePasswordStore();
297 EXPECT_TRUE(store_->Init());
299 MockPasswordStoreConsumer password_consumer;
300 // Make sure we quit the MessageLoop even if the test fails.
301 ON_CALL(password_consumer, OnGetPasswordStoreResults(_))
302 .WillByDefault(QuitUIMessageLoop());
304 PasswordFormData form_data = {
305 PasswordForm::SCHEME_HTML,
306 "http://example.com/",
307 "http://example.com/origin",
308 "http://example.com/action",
309 L"submit_element",
310 L"username_element",
311 L"password_element",
312 L"",
313 L"",
314 true, false, 1,
316 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
318 PasswordFormData expected_form_data = {
319 PasswordForm::SCHEME_HTML,
320 "http://example.com/",
321 "http://example.com/origin",
322 "http://example.com/action",
323 L"submit_element",
324 L"username_element",
325 L"password_element",
326 L"abcdefgh",
327 L"abcdefghijkl",
328 true, false, 1,
330 std::vector<PasswordForm*> forms;
331 forms.push_back(CreatePasswordFormFromData(expected_form_data));
333 // The IE7 password should be returned.
334 EXPECT_CALL(password_consumer,
335 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
336 .WillOnce(QuitUIMessageLoop());
338 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &password_consumer);
340 MockWebDataServiceConsumer wds_consumer;
342 EXPECT_CALL(wds_consumer,
343 OnWebDataServiceRequestDone(_, _))
344 .WillOnce(QuitUIMessageLoop());
346 wds_->GetIE7Login(password_info, &wds_consumer);
348 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin
349 // schedules on the DB thread and once for the one we just scheduled on the UI
350 // thread.
351 base::MessageLoop::current()->Run();
352 base::MessageLoop::current()->Run();
354 STLDeleteElements(&forms);
357 TEST_F(PasswordStoreWinTest, EmptyLogins) {
358 store_ = CreatePasswordStore();
359 store_->Init();
361 PasswordFormData form_data = {
362 PasswordForm::SCHEME_HTML,
363 "http://example.com/",
364 "http://example.com/origin",
365 "http://example.com/action",
366 L"submit_element",
367 L"username_element",
368 L"password_element",
369 L"",
370 L"",
371 true, false, 1,
373 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
375 MockPasswordStoreConsumer consumer;
377 // Make sure we quit the MessageLoop even if the test fails.
378 ON_CALL(consumer, OnGetPasswordStoreResults(_))
379 .WillByDefault(QuitUIMessageLoop());
381 VectorOfForms expect_none;
382 // expect that we get no results;
383 EXPECT_CALL(consumer,
384 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
385 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
387 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
388 base::MessageLoop::current()->Run();
391 TEST_F(PasswordStoreWinTest, EmptyBlacklistLogins) {
392 store_ = CreatePasswordStore();
393 store_->Init();
395 MockPasswordStoreConsumer consumer;
397 // Make sure we quit the MessageLoop even if the test fails.
398 ON_CALL(consumer, OnGetPasswordStoreResults(_))
399 .WillByDefault(QuitUIMessageLoop());
401 VectorOfForms expect_none;
402 // expect that we get no results;
403 EXPECT_CALL(
404 consumer,
405 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
406 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
408 store_->GetBlacklistLogins(&consumer);
409 base::MessageLoop::current()->Run();
412 TEST_F(PasswordStoreWinTest, EmptyAutofillableLogins) {
413 store_ = CreatePasswordStore();
414 store_->Init();
416 MockPasswordStoreConsumer consumer;
418 // Make sure we quit the MessageLoop even if the test fails.
419 ON_CALL(consumer, OnGetPasswordStoreResults(_))
420 .WillByDefault(QuitUIMessageLoop());
422 VectorOfForms expect_none;
423 // expect that we get no results;
424 EXPECT_CALL(
425 consumer,
426 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
427 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
429 store_->GetAutofillableLogins(&consumer);
430 base::MessageLoop::current()->Run();