Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win_unittest.cc
blobc1c7ecba434f823528ac96d62b6d51cf25de79ac
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>
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/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "chrome/browser/password_manager/password_store_win.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "components/os_crypt/ie7_password_win.h"
23 #include "components/password_manager/core/browser/password_manager_test_utils.h"
24 #include "components/password_manager/core/browser/password_store_consumer.h"
25 #include "components/password_manager/core/browser/webdata/logins_table.h"
26 #include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
27 #include "components/password_manager/core/common/password_manager_pref_names.h"
28 #include "components/webdata/common/web_database_service.h"
29 #include "content/public/test/test_browser_thread.h"
30 #include "crypto/wincrypt_shim.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 using autofill::PasswordForm;
35 using base::WaitableEvent;
36 using content::BrowserThread;
37 using password_manager::LoginDatabase;
38 using password_manager::PasswordFormData;
39 using password_manager::PasswordStore;
40 using password_manager::PasswordStoreConsumer;
41 using password_manager::UnorderedPasswordFormElementsAre;
42 using testing::_;
43 using testing::DoAll;
44 using testing::IsEmpty;
45 using testing::WithArg;
47 namespace {
49 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
50 public:
51 MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
52 void(const std::vector<PasswordForm*>&));
54 // GMock cannot mock methods with move-only args.
55 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
56 OnGetPasswordStoreResultsConstRef(results.get());
60 class MockWebDataServiceConsumer : public WebDataServiceConsumer {
61 public:
62 MOCK_METHOD2(OnWebDataServiceRequestDone,
63 void(PasswordWebDataService::Handle, const WDTypedResult*));
66 } // anonymous namespace
68 class PasswordStoreWinTest : public testing::Test {
69 protected:
70 PasswordStoreWinTest()
71 : ui_thread_(BrowserThread::UI, &message_loop_),
72 db_thread_(BrowserThread::DB) {
75 bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created,
76 IE7PasswordInfo* info) {
77 // Copied from chrome/browser/importer/importer_unittest.cc
78 // The username is "abcdefgh" and the password "abcdefghijkl".
79 unsigned char data[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
80 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
81 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
82 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
83 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
84 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
85 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
86 "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
87 "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
88 "\x6c\x00\x00\x00";
89 DATA_BLOB input = {0};
90 DATA_BLOB url_key = {0};
91 DATA_BLOB output = {0};
93 input.pbData = data;
94 input.cbData = sizeof(data);
96 url_key.pbData = reinterpret_cast<unsigned char*>(
97 const_cast<wchar_t*>(url.data()));
98 url_key.cbData = static_cast<DWORD>((url.size() + 1) *
99 sizeof(std::wstring::value_type));
101 if (!CryptProtectData(&input, nullptr, &url_key, nullptr, nullptr,
102 CRYPTPROTECT_UI_FORBIDDEN, &output))
103 return false;
105 std::vector<unsigned char> encrypted_data;
106 encrypted_data.resize(output.cbData);
107 memcpy(&encrypted_data.front(), output.pbData, output.cbData);
109 LocalFree(output.pbData);
111 info->url_hash = ie7_password::GetUrlHash(url);
112 info->encrypted_data = encrypted_data;
113 info->date_created = created;
115 return true;
118 void SetUp() override {
119 ASSERT_TRUE(db_thread_.Start());
120 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
122 profile_.reset(new TestingProfile());
124 base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
125 wdbs_ = new WebDatabaseService(path,
126 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
127 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
128 // Need to add at least one table so the database gets created.
129 wdbs_->AddTable(scoped_ptr<WebDatabaseTable>(new LoginsTable()));
130 wdbs_->LoadDatabase();
131 wds_ = new PasswordWebDataService(
132 wdbs_,
133 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
134 WebDataServiceBase::ProfileErrorCallback());
135 wds_->Init();
138 void TearDown() override {
139 if (store_.get())
140 store_->Shutdown();
141 wds_->ShutdownOnUIThread();
142 wdbs_->ShutdownDatabase();
143 wds_ = nullptr;
144 wdbs_ = nullptr;
145 base::WaitableEvent done(false, false);
146 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
147 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
148 done.Wait();
149 base::MessageLoop::current()->PostTask(FROM_HERE,
150 base::MessageLoop::QuitClosure());
151 base::MessageLoop::current()->Run();
152 db_thread_.Stop();
155 base::FilePath test_login_db_file_path() const {
156 return temp_dir_.path().Append(FILE_PATH_LITERAL("login_test"));
159 PasswordStoreWin* CreatePasswordStore() {
160 return new PasswordStoreWin(
161 base::ThreadTaskRunnerHandle::Get(),
162 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
163 make_scoped_ptr(new LoginDatabase(test_login_db_file_path())),
164 wds_.get());
167 base::MessageLoopForUI message_loop_;
168 content::TestBrowserThread ui_thread_;
169 // PasswordStore, WDS schedule work on this thread.
170 content::TestBrowserThread db_thread_;
172 base::ScopedTempDir temp_dir_;
173 scoped_ptr<TestingProfile> profile_;
174 scoped_refptr<PasswordWebDataService> wds_;
175 scoped_refptr<WebDatabaseService> wdbs_;
176 scoped_refptr<PasswordStore> store_;
179 ACTION(STLDeleteElements0) {
180 STLDeleteContainerPointers(arg0.begin(), arg0.end());
183 ACTION(QuitUIMessageLoop) {
184 DCHECK_CURRENTLY_ON(BrowserThread::UI);
185 base::MessageLoop::current()->Quit();
188 MATCHER(EmptyWDResult, "") {
189 return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
190 arg)->GetValue().empty();
193 // Hangs flakily, http://crbug.com/71385.
194 TEST_F(PasswordStoreWinTest, DISABLED_ConvertIE7Login) {
195 IE7PasswordInfo password_info;
196 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
197 base::Time::FromDoubleT(1),
198 &password_info));
199 // Verify the URL hash
200 ASSERT_EQ(L"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
201 password_info.url_hash);
203 // This IE7 password will be retrieved by the GetLogins call.
204 wds_->AddIE7Login(password_info);
206 // The WDS schedules tasks to run on the DB thread so we schedule yet another
207 // task to notify us that it's safe to carry on with the test.
208 WaitableEvent done(false, false);
209 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
210 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
211 done.Wait();
213 store_ = CreatePasswordStore();
214 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
216 MockPasswordStoreConsumer consumer;
218 // Make sure we quit the MessageLoop even if the test fails.
219 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
220 .WillByDefault(QuitUIMessageLoop());
222 PasswordFormData form_data = {
223 PasswordForm::SCHEME_HTML,
224 "http://example.com/",
225 "http://example.com/origin",
226 "http://example.com/action",
227 L"submit_element",
228 L"username_element",
229 L"password_element",
230 L"",
231 L"",
232 true, false, 1,
234 scoped_ptr<PasswordForm> form =
235 CreatePasswordFormFromDataForTesting(form_data);
237 // The returned form will not have 'action' or '*_element' fields set. This
238 // is because credentials imported from IE don't have this information.
239 PasswordFormData expected_form_data = {
240 PasswordForm::SCHEME_HTML,
241 "http://example.com/",
242 "http://example.com/origin",
244 L"",
245 L"",
246 L"",
247 L"abcdefgh",
248 L"abcdefghijkl",
249 true, false, 1,
251 ScopedVector<autofill::PasswordForm> expected_forms;
252 expected_forms.push_back(
253 CreatePasswordFormFromDataForTesting(expected_form_data));
255 // The IE7 password should be returned.
256 EXPECT_CALL(consumer,
257 OnGetPasswordStoreResultsConstRef(
258 UnorderedPasswordFormElementsAre(expected_forms.get())));
260 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
261 base::MessageLoop::current()->Run();
264 // Crashy. http://crbug.com/86558
265 TEST_F(PasswordStoreWinTest, DISABLED_OutstandingWDSQueries) {
266 store_ = CreatePasswordStore();
267 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
269 PasswordFormData form_data = {
270 PasswordForm::SCHEME_HTML,
271 "http://example.com/",
272 "http://example.com/origin",
273 "http://example.com/action",
274 L"submit_element",
275 L"username_element",
276 L"password_element",
277 L"",
278 L"",
279 true, false, 1,
281 scoped_ptr<PasswordForm> form =
282 CreatePasswordFormFromDataForTesting(form_data);
284 MockPasswordStoreConsumer consumer;
285 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
287 // Release the PSW and the WDS before the query can return.
288 store_->Shutdown();
289 store_ = nullptr;
290 wds_ = nullptr;
292 base::MessageLoop::current()->RunUntilIdle();
295 // Hangs flakily, see http://crbug.com/43836.
296 TEST_F(PasswordStoreWinTest, DISABLED_MultipleWDSQueriesOnDifferentThreads) {
297 IE7PasswordInfo password_info;
298 ASSERT_TRUE(CreateIE7PasswordInfo(L"http://example.com/origin",
299 base::Time::FromDoubleT(1),
300 &password_info));
301 wds_->AddIE7Login(password_info);
303 // The WDS schedules tasks to run on the DB thread so we schedule yet another
304 // task to notify us that it's safe to carry on with the test.
305 WaitableEvent done(false, false);
306 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
307 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
308 done.Wait();
310 store_ = CreatePasswordStore();
311 EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
313 MockPasswordStoreConsumer password_consumer;
314 // Make sure we quit the MessageLoop even if the test fails.
315 ON_CALL(password_consumer, OnGetPasswordStoreResultsConstRef(_))
316 .WillByDefault(QuitUIMessageLoop());
318 PasswordFormData 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"",
327 L"",
328 true, false, 1,
330 scoped_ptr<PasswordForm> form =
331 CreatePasswordFormFromDataForTesting(form_data);
333 PasswordFormData expected_form_data = {
334 PasswordForm::SCHEME_HTML,
335 "http://example.com/",
336 "http://example.com/origin",
337 "http://example.com/action",
338 L"submit_element",
339 L"username_element",
340 L"password_element",
341 L"abcdefgh",
342 L"abcdefghijkl",
343 true, false, 1,
345 ScopedVector<autofill::PasswordForm> expected_forms;
346 expected_forms.push_back(
347 CreatePasswordFormFromDataForTesting(expected_form_data));
349 // The IE7 password should be returned.
350 EXPECT_CALL(password_consumer,
351 OnGetPasswordStoreResultsConstRef(
352 UnorderedPasswordFormElementsAre(expected_forms.get())));
354 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &password_consumer);
356 MockWebDataServiceConsumer wds_consumer;
358 EXPECT_CALL(wds_consumer, OnWebDataServiceRequestDone(_, _))
359 .WillOnce(QuitUIMessageLoop());
361 wds_->GetIE7Login(password_info, &wds_consumer);
363 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin
364 // schedules on the DB thread and once for the one we just scheduled on the UI
365 // thread.
366 base::MessageLoop::current()->Run();
367 base::MessageLoop::current()->Run();
370 TEST_F(PasswordStoreWinTest, EmptyLogins) {
371 store_ = CreatePasswordStore();
372 store_->Init(syncer::SyncableService::StartSyncFlare());
374 PasswordFormData form_data = {
375 PasswordForm::SCHEME_HTML,
376 "http://example.com/",
377 "http://example.com/origin",
378 "http://example.com/action",
379 L"submit_element",
380 L"username_element",
381 L"password_element",
382 L"",
383 L"",
384 true, false, 1,
386 scoped_ptr<PasswordForm> form =
387 CreatePasswordFormFromDataForTesting(form_data);
389 MockPasswordStoreConsumer consumer;
391 // Make sure we quit the MessageLoop even if the test fails.
392 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
393 .WillByDefault(QuitUIMessageLoop());
395 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
397 store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
398 base::MessageLoop::current()->Run();
401 TEST_F(PasswordStoreWinTest, EmptyBlacklistLogins) {
402 store_ = CreatePasswordStore();
403 store_->Init(syncer::SyncableService::StartSyncFlare());
405 MockPasswordStoreConsumer consumer;
407 // Make sure we quit the MessageLoop even if the test fails.
408 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
409 .WillByDefault(QuitUIMessageLoop());
411 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
413 store_->GetBlacklistLogins(&consumer);
414 base::MessageLoop::current()->Run();
417 TEST_F(PasswordStoreWinTest, EmptyAutofillableLogins) {
418 store_ = CreatePasswordStore();
419 store_->Init(syncer::SyncableService::StartSyncFlare());
421 MockPasswordStoreConsumer consumer;
423 // Make sure we quit the MessageLoop even if the test fails.
424 ON_CALL(consumer, OnGetPasswordStoreResultsConstRef(_))
425 .WillByDefault(QuitUIMessageLoop());
427 EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef(IsEmpty()));
429 store_->GetAutofillableLogins(&consumer);
430 base::MessageLoop::current()->Run();