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