Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_store_win_unittest.cc
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.
4
5 #include <windows.h>
6 #include <wincrypt.h>
7 #include <string>
8 #include <vector>
9
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"
31
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;
40 using testing::_;
41 using testing::DoAll;
42 using testing::WithArg;
43
44 namespace {
45
46 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
47  public:
48   MOCK_METHOD1(OnGetPasswordStoreResults,
49                void(const std::vector<autofill::PasswordForm*>&));
50 };
51
52 class MockWebDataServiceConsumer : public WebDataServiceConsumer {
53 public:
54   MOCK_METHOD2(OnWebDataServiceRequestDone,
55                void(WebDataService::Handle, const WDTypedResult*));
56 };
57
58 }  // anonymous namespace
59
60 typedef std::vector<PasswordForm*> VectorOfForms;
61
62 class PasswordStoreWinTest : public testing::Test {
63  protected:
64   PasswordStoreWinTest()
65       : ui_thread_(BrowserThread::UI, &message_loop_),
66         db_thread_(BrowserThread::DB) {
67   }
68
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"
82                            "\x6c\x00\x00\x00";
83     DATA_BLOB input = {0};
84     DATA_BLOB url_key = {0};
85     DATA_BLOB output = {0};
86
87     input.pbData = data;
88     input.cbData = sizeof(data);
89
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));
94
95     if (!CryptProtectData(&input, NULL, &url_key, NULL, NULL,
96                           CRYPTPROTECT_UI_FORBIDDEN, &output))
97       return false;
98
99     std::vector<unsigned char> encrypted_data;
100     encrypted_data.resize(output.cbData);
101     memcpy(&encrypted_data.front(), output.pbData, output.cbData);
102
103     LocalFree(output.pbData);
104
105     info->url_hash = ie7_password::GetUrlHash(url);
106     info->encrypted_data = encrypted_data;
107     info->date_created = created;
108
109     return true;
110   }
111
112   virtual void SetUp() {
113     ASSERT_TRUE(db_thread_.Start());
114     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
115
116     profile_.reset(new TestingProfile());
117
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());
130     wds_->Init();
131   }
132
133   virtual void TearDown() {
134     if (store_)
135       store_->Shutdown();
136     wds_->ShutdownOnUIThread();
137     wdbs_->ShutdownDatabase();
138     wds_ = NULL;
139     wdbs_ = NULL;
140     base::WaitableEvent done(false, false);
141     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
142         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
143     done.Wait();
144     base::MessageLoop::current()->PostTask(FROM_HERE,
145                                            base::MessageLoop::QuitClosure());
146     base::MessageLoop::current()->Run();
147     db_thread_.Stop();
148   }
149
150   PasswordStoreWin* CreatePasswordStore() {
151     return new PasswordStoreWin(
152         base::MessageLoopProxy::current(),
153         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
154         login_db_.release(),
155         wds_.get());
156   }
157
158   base::MessageLoopForUI message_loop_;
159   content::TestBrowserThread ui_thread_;
160   // PasswordStore, WDS schedule work on this thread.
161   content::TestBrowserThread db_thread_;
162
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_;
169 };
170
171 ACTION(STLDeleteElements0) {
172   STLDeleteContainerPointers(arg0.begin(), arg0.end());
173 }
174
175 ACTION(QuitUIMessageLoop) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177   base::MessageLoop::current()->Quit();
178 }
179
180 MATCHER(EmptyWDResult, "") {
181   return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
182       arg)->GetValue().empty();
183 }
184
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),
190                                     &password_info));
191   // Verify the URL hash
192   ASSERT_EQ(L"39471418FF5453FEEB3731E382DEB5D53E14FAF9B5",
193             password_info.url_hash);
194
195   // This IE7 password will be retrieved by the GetLogins call.
196   wds_->AddIE7Login(password_info);
197
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)));
203   done.Wait();
204
205   store_ = CreatePasswordStore();
206   EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
207
208   MockPasswordStoreConsumer consumer;
209
210   // Make sure we quit the MessageLoop even if the test fails.
211   ON_CALL(consumer, OnGetPasswordStoreResults(_))
212       .WillByDefault(QuitUIMessageLoop());
213
214   PasswordFormData form_data = {
215     PasswordForm::SCHEME_HTML,
216     "http://example.com/",
217     "http://example.com/origin",
218     "http://example.com/action",
219     L"submit_element",
220     L"username_element",
221     L"password_element",
222     L"",
223     L"",
224     true, false, 1,
225   };
226   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
227
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",
234     "",
235     L"",
236     L"",
237     L"",
238     L"abcdefgh",
239     L"abcdefghijkl",
240     true, false, 1,
241   };
242   std::vector<PasswordForm*> forms;
243   forms.push_back(CreatePasswordFormFromData(expected_form_data));
244
245   // The IE7 password should be returned.
246   EXPECT_CALL(consumer,
247               OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
248       .WillOnce(QuitUIMessageLoop());
249
250   store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
251   base::MessageLoop::current()->Run();
252
253   STLDeleteElements(&forms);
254 }
255
256 // Crashy.  http://crbug.com/86558
257 TEST_F(PasswordStoreWinTest, DISABLED_OutstandingWDSQueries) {
258   store_ = CreatePasswordStore();
259   EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
260
261   PasswordFormData form_data = {
262     PasswordForm::SCHEME_HTML,
263     "http://example.com/",
264     "http://example.com/origin",
265     "http://example.com/action",
266     L"submit_element",
267     L"username_element",
268     L"password_element",
269     L"",
270     L"",
271     true, false, 1,
272   };
273   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
274
275   MockPasswordStoreConsumer consumer;
276   store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
277
278   // Release the PSW and the WDS before the query can return.
279   store_->Shutdown();
280   store_ = NULL;
281   wds_ = NULL;
282
283   base::MessageLoop::current()->RunUntilIdle();
284 }
285
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),
291                                     &password_info));
292   wds_->AddIE7Login(password_info);
293
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)));
299   done.Wait();
300
301   store_ = CreatePasswordStore();
302   EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
303
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());
308
309   PasswordFormData form_data = {
310     PasswordForm::SCHEME_HTML,
311     "http://example.com/",
312     "http://example.com/origin",
313     "http://example.com/action",
314     L"submit_element",
315     L"username_element",
316     L"password_element",
317     L"",
318     L"",
319     true, false, 1,
320   };
321   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
322
323   PasswordFormData expected_form_data = {
324     PasswordForm::SCHEME_HTML,
325     "http://example.com/",
326     "http://example.com/origin",
327     "http://example.com/action",
328     L"submit_element",
329     L"username_element",
330     L"password_element",
331     L"abcdefgh",
332     L"abcdefghijkl",
333     true, false, 1,
334   };
335   std::vector<PasswordForm*> forms;
336   forms.push_back(CreatePasswordFormFromData(expected_form_data));
337
338   // The IE7 password should be returned.
339   EXPECT_CALL(password_consumer,
340               OnGetPasswordStoreResults(ContainsAllPasswordForms(forms)))
341       .WillOnce(QuitUIMessageLoop());
342
343   store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &password_consumer);
344
345   MockWebDataServiceConsumer wds_consumer;
346
347   EXPECT_CALL(wds_consumer,
348               OnWebDataServiceRequestDone(_, _))
349       .WillOnce(QuitUIMessageLoop());
350
351   wds_->GetIE7Login(password_info, &wds_consumer);
352
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
355   // thread.
356   base::MessageLoop::current()->Run();
357   base::MessageLoop::current()->Run();
358
359   STLDeleteElements(&forms);
360 }
361
362 TEST_F(PasswordStoreWinTest, EmptyLogins) {
363   store_ = CreatePasswordStore();
364   store_->Init(syncer::SyncableService::StartSyncFlare());
365
366   PasswordFormData form_data = {
367     PasswordForm::SCHEME_HTML,
368     "http://example.com/",
369     "http://example.com/origin",
370     "http://example.com/action",
371     L"submit_element",
372     L"username_element",
373     L"password_element",
374     L"",
375     L"",
376     true, false, 1,
377   };
378   scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(form_data));
379
380   MockPasswordStoreConsumer consumer;
381
382   // Make sure we quit the MessageLoop even if the test fails.
383   ON_CALL(consumer, OnGetPasswordStoreResults(_))
384       .WillByDefault(QuitUIMessageLoop());
385
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()));
391
392   store_->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &consumer);
393   base::MessageLoop::current()->Run();
394 }
395
396 TEST_F(PasswordStoreWinTest, EmptyBlacklistLogins) {
397   store_ = CreatePasswordStore();
398   store_->Init(syncer::SyncableService::StartSyncFlare());
399
400   MockPasswordStoreConsumer consumer;
401
402   // Make sure we quit the MessageLoop even if the test fails.
403   ON_CALL(consumer, OnGetPasswordStoreResults(_))
404       .WillByDefault(QuitUIMessageLoop());
405
406   VectorOfForms expect_none;
407   // expect that we get no results;
408   EXPECT_CALL(
409       consumer,
410       OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
411       .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
412
413   store_->GetBlacklistLogins(&consumer);
414   base::MessageLoop::current()->Run();
415 }
416
417 TEST_F(PasswordStoreWinTest, EmptyAutofillableLogins) {
418   store_ = CreatePasswordStore();
419   store_->Init(syncer::SyncableService::StartSyncFlare());
420
421   MockPasswordStoreConsumer consumer;
422
423   // Make sure we quit the MessageLoop even if the test fails.
424   ON_CALL(consumer, OnGetPasswordStoreResults(_))
425       .WillByDefault(QuitUIMessageLoop());
426
427   VectorOfForms expect_none;
428   // expect that we get no results;
429   EXPECT_CALL(
430       consumer,
431       OnGetPasswordStoreResults(ContainsAllPasswordForms(expect_none)))
432       .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
433
434   store_->GetAutofillableLogins(&consumer);
435   base::MessageLoop::current()->Run();
436 }