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.
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/test/base/testing_profile.h"
23 #include "components/os_crypt/ie7_password_win.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/password_manager/core/common/password_manager_pref_names.h"
27 #include "components/webdata/common/web_database_service.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 password_manager::LoginDatabase
;
36 using password_manager::ContainsAllPasswordForms
;
37 using password_manager::PasswordFormData
;
38 using password_manager::PasswordStore
;
39 using password_manager::PasswordStoreConsumer
;
42 using testing::WithArg
;
46 class MockPasswordStoreConsumer
: public PasswordStoreConsumer
{
48 MOCK_METHOD1(OnGetPasswordStoreResults
,
49 void(const std::vector
<autofill::PasswordForm
*>&));
52 class MockWebDataServiceConsumer
: public WebDataServiceConsumer
{
54 MOCK_METHOD2(OnWebDataServiceRequestDone
,
55 void(WebDataService::Handle
, const WDTypedResult
*));
58 } // anonymous namespace
60 typedef std::vector
<PasswordForm
*> VectorOfForms
;
62 class PasswordStoreWinTest
: public testing::Test
{
64 PasswordStoreWinTest()
65 : ui_thread_(BrowserThread::UI
, &message_loop_
),
66 db_thread_(BrowserThread::DB
) {
69 bool CreateIE7PasswordInfo(const std::wstring
& url
, const base::Time
& created
,
70 IE7PasswordInfo
* info
) {
71 // Copied from chrome/browser/importer/importer_unittest.cc
72 // The username is "abcdefgh" and the password "abcdefghijkl".
73 unsigned char data
[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
74 "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
75 "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
76 "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
77 "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
78 "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
79 "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
80 "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
81 "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
83 DATA_BLOB input
= {0};
84 DATA_BLOB url_key
= {0};
85 DATA_BLOB output
= {0};
88 input
.cbData
= sizeof(data
);
90 url_key
.pbData
= reinterpret_cast<unsigned char*>(
91 const_cast<wchar_t*>(url
.data()));
92 url_key
.cbData
= static_cast<DWORD
>((url
.size() + 1) *
93 sizeof(std::wstring::value_type
));
95 if (!CryptProtectData(&input
, NULL
, &url_key
, NULL
, NULL
,
96 CRYPTPROTECT_UI_FORBIDDEN
, &output
))
99 std::vector
<unsigned char> encrypted_data
;
100 encrypted_data
.resize(output
.cbData
);
101 memcpy(&encrypted_data
.front(), output
.pbData
, output
.cbData
);
103 LocalFree(output
.pbData
);
105 info
->url_hash
= ie7_password::GetUrlHash(url
);
106 info
->encrypted_data
= encrypted_data
;
107 info
->date_created
= created
;
112 virtual void SetUp() {
113 ASSERT_TRUE(db_thread_
.Start());
114 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
116 profile_
.reset(new TestingProfile());
118 login_db_
.reset(new LoginDatabase());
119 ASSERT_TRUE(login_db_
->Init(temp_dir_
.path().Append(
120 FILE_PATH_LITERAL("login_test"))));
121 base::FilePath path
= temp_dir_
.path().AppendASCII("web_data_test");
122 wdbs_
= new WebDatabaseService(path
,
123 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI
),
124 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB
));
125 // Need to add at least one table so the database gets created.
126 wdbs_
->AddTable(scoped_ptr
<WebDatabaseTable
>(new LoginsTable()));
127 wdbs_
->LoadDatabase();
128 wds_
= new WebDataService(wdbs_
,
129 WebDataServiceBase::ProfileErrorCallback());
133 virtual void TearDown() {
136 wds_
->ShutdownOnUIThread();
137 wdbs_
->ShutdownDatabase();
140 base::WaitableEvent
done(false, false);
141 BrowserThread::PostTask(BrowserThread::DB
, FROM_HERE
,
142 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
144 base::MessageLoop::current()->PostTask(FROM_HERE
,
145 base::MessageLoop::QuitClosure());
146 base::MessageLoop::current()->Run();
150 PasswordStoreWin
* CreatePasswordStore() {
151 return new PasswordStoreWin(
152 base::MessageLoopProxy::current(),
153 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB
),
158 base::MessageLoopForUI message_loop_
;
159 content::TestBrowserThread ui_thread_
;
160 // PasswordStore, WDS schedule work on this thread.
161 content::TestBrowserThread db_thread_
;
163 base::ScopedTempDir temp_dir_
;
164 scoped_ptr
<TestingProfile
> profile_
;
165 scoped_ptr
<LoginDatabase
> login_db_
;
166 scoped_refptr
<WebDataService
> wds_
;
167 scoped_refptr
<WebDatabaseService
> wdbs_
;
168 scoped_refptr
<PasswordStore
> store_
;
171 ACTION(STLDeleteElements0
) {
172 STLDeleteContainerPointers(arg0
.begin(), arg0
.end());
175 ACTION(QuitUIMessageLoop
) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
177 base::MessageLoop::current()->Quit();
180 MATCHER(EmptyWDResult
, "") {
181 return static_cast<const WDResult
<std::vector
<PasswordForm
*> >*>(
182 arg
)->GetValue().empty();
185 // Hangs flakily, http://crbug.com/71385.
186 TEST_F(PasswordStoreWinTest
, DISABLED_ConvertIE7Login
) {
187 IE7PasswordInfo password_info
;
188 ASSERT_TRUE(CreateIE7PasswordInfo(L
"http://example.com/origin",
189 base::Time::FromDoubleT(1),
191 // Verify the URL hash
192 ASSERT_EQ(L
"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
193 password_info
.url_hash
);
195 // This IE7 password will be retrieved by the GetLogins call.
196 wds_
->AddIE7Login(password_info
);
198 // The WDS schedules tasks to run on the DB thread so we schedule yet another
199 // task to notify us that it's safe to carry on with the test.
200 WaitableEvent
done(false, false);
201 BrowserThread::PostTask(BrowserThread::DB
, FROM_HERE
,
202 base::Bind(&WaitableEvent::Signal
, base::Unretained(&done
)));
205 store_
= CreatePasswordStore();
206 EXPECT_TRUE(store_
->Init(syncer::SyncableService::StartSyncFlare()));
208 MockPasswordStoreConsumer consumer
;
210 // Make sure we quit the MessageLoop even if the test fails.
211 ON_CALL(consumer
, OnGetPasswordStoreResults(_
))
212 .WillByDefault(QuitUIMessageLoop());
214 PasswordFormData form_data
= {
215 PasswordForm::SCHEME_HTML
,
216 "http://example.com/",
217 "http://example.com/origin",
218 "http://example.com/action",
226 scoped_ptr
<PasswordForm
> form(CreatePasswordFormFromData(form_data
));
228 // The returned form will not have 'action' or '*_element' fields set. This
229 // is because credentials imported from IE don't have this information.
230 PasswordFormData expected_form_data
= {
231 PasswordForm::SCHEME_HTML
,
232 "http://example.com/",
233 "http://example.com/origin",
242 std::vector
<PasswordForm
*> forms
;
243 forms
.push_back(CreatePasswordFormFromData(expected_form_data
));
245 // The IE7 password should be returned.
246 EXPECT_CALL(consumer
,
247 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms
)))
248 .WillOnce(QuitUIMessageLoop());
250 store_
->GetLogins(*form
, PasswordStore::DISALLOW_PROMPT
, &consumer
);
251 base::MessageLoop::current()->Run();
253 STLDeleteElements(&forms
);
256 // Crashy. http://crbug.com/86558
257 TEST_F(PasswordStoreWinTest
, DISABLED_OutstandingWDSQueries
) {
258 store_
= CreatePasswordStore();
259 EXPECT_TRUE(store_
->Init(syncer::SyncableService::StartSyncFlare()));
261 PasswordFormData form_data
= {
262 PasswordForm::SCHEME_HTML
,
263 "http://example.com/",
264 "http://example.com/origin",
265 "http://example.com/action",
273 scoped_ptr
<PasswordForm
> form(CreatePasswordFormFromData(form_data
));
275 MockPasswordStoreConsumer consumer
;
276 store_
->GetLogins(*form
, PasswordStore::DISALLOW_PROMPT
, &consumer
);
278 // Release the PSW and the WDS before the query can return.
283 base::MessageLoop::current()->RunUntilIdle();
286 // Hangs flakily, see http://crbug.com/43836.
287 TEST_F(PasswordStoreWinTest
, DISABLED_MultipleWDSQueriesOnDifferentThreads
) {
288 IE7PasswordInfo password_info
;
289 ASSERT_TRUE(CreateIE7PasswordInfo(L
"http://example.com/origin",
290 base::Time::FromDoubleT(1),
292 wds_
->AddIE7Login(password_info
);
294 // The WDS schedules tasks to run on the DB thread so we schedule yet another
295 // task to notify us that it's safe to carry on with the test.
296 WaitableEvent
done(false, false);
297 BrowserThread::PostTask(BrowserThread::DB
, FROM_HERE
,
298 base::Bind(&WaitableEvent::Signal
, base::Unretained(&done
)));
301 store_
= CreatePasswordStore();
302 EXPECT_TRUE(store_
->Init(syncer::SyncableService::StartSyncFlare()));
304 MockPasswordStoreConsumer password_consumer
;
305 // Make sure we quit the MessageLoop even if the test fails.
306 ON_CALL(password_consumer
, OnGetPasswordStoreResults(_
))
307 .WillByDefault(QuitUIMessageLoop());
309 PasswordFormData form_data
= {
310 PasswordForm::SCHEME_HTML
,
311 "http://example.com/",
312 "http://example.com/origin",
313 "http://example.com/action",
321 scoped_ptr
<PasswordForm
> form(CreatePasswordFormFromData(form_data
));
323 PasswordFormData expected_form_data
= {
324 PasswordForm::SCHEME_HTML
,
325 "http://example.com/",
326 "http://example.com/origin",
327 "http://example.com/action",
335 std::vector
<PasswordForm
*> forms
;
336 forms
.push_back(CreatePasswordFormFromData(expected_form_data
));
338 // The IE7 password should be returned.
339 EXPECT_CALL(password_consumer
,
340 OnGetPasswordStoreResults(ContainsAllPasswordForms(forms
)))
341 .WillOnce(QuitUIMessageLoop());
343 store_
->GetLogins(*form
, PasswordStore::DISALLOW_PROMPT
, &password_consumer
);
345 MockWebDataServiceConsumer wds_consumer
;
347 EXPECT_CALL(wds_consumer
,
348 OnWebDataServiceRequestDone(_
, _
))
349 .WillOnce(QuitUIMessageLoop());
351 wds_
->GetIE7Login(password_info
, &wds_consumer
);
353 // Run the MessageLoop twice: once for the GetIE7Login that PasswordStoreWin
354 // schedules on the DB thread and once for the one we just scheduled on the UI
356 base::MessageLoop::current()->Run();
357 base::MessageLoop::current()->Run();
359 STLDeleteElements(&forms
);
362 TEST_F(PasswordStoreWinTest
, EmptyLogins
) {
363 store_
= CreatePasswordStore();
364 store_
->Init(syncer::SyncableService::StartSyncFlare());
366 PasswordFormData form_data
= {
367 PasswordForm::SCHEME_HTML
,
368 "http://example.com/",
369 "http://example.com/origin",
370 "http://example.com/action",
378 scoped_ptr
<PasswordForm
> form(CreatePasswordFormFromData(form_data
));
380 MockPasswordStoreConsumer consumer
;
382 // Make sure we quit the MessageLoop even if the test fails.
383 ON_CALL(consumer
, OnGetPasswordStoreResults(_
))
384 .WillByDefault(QuitUIMessageLoop());
386 VectorOfForms expect_none
;
387 // expect that we get no results;
388 EXPECT_CALL(consumer
,
389 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none
)))
390 .WillOnce(DoAll(WithArg
<0>(STLDeleteElements0()), QuitUIMessageLoop()));
392 store_
->GetLogins(*form
, PasswordStore::DISALLOW_PROMPT
, &consumer
);
393 base::MessageLoop::current()->Run();
396 TEST_F(PasswordStoreWinTest
, EmptyBlacklistLogins
) {
397 store_
= CreatePasswordStore();
398 store_
->Init(syncer::SyncableService::StartSyncFlare());
400 MockPasswordStoreConsumer consumer
;
402 // Make sure we quit the MessageLoop even if the test fails.
403 ON_CALL(consumer
, OnGetPasswordStoreResults(_
))
404 .WillByDefault(QuitUIMessageLoop());
406 VectorOfForms expect_none
;
407 // expect that we get no results;
410 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none
)))
411 .WillOnce(DoAll(WithArg
<0>(STLDeleteElements0()), QuitUIMessageLoop()));
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
, OnGetPasswordStoreResults(_
))
425 .WillByDefault(QuitUIMessageLoop());
427 VectorOfForms expect_none
;
428 // expect that we get no results;
431 OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none
)))
432 .WillOnce(DoAll(WithArg
<0>(STLDeleteElements0()), QuitUIMessageLoop()));
434 store_
->GetAutofillableLogins(&consumer
);
435 base::MessageLoop::current()->Run();