1 // Copyright 2014 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 "components/password_manager/content/browser/credential_manager_dispatcher.h"
8 #include "base/command_line.h"
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/testing_pref_service.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/password_manager/content/browser/credential_manager_password_form_manager.h"
15 #include "components/password_manager/content/common/credential_manager_messages.h"
16 #include "components/password_manager/content/common/credential_manager_types.h"
17 #include "components/password_manager/core/browser/stub_password_manager_client.h"
18 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
19 #include "components/password_manager/core/browser/test_password_store.h"
20 #include "components/password_manager/core/common/password_manager_pref_names.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/test/mock_render_process_host.h"
23 #include "content/public/test/test_renderer_host.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using content::BrowserContext
;
28 using content::WebContents
;
32 // Chosen by fair dice roll. Guaranteed to be random.
33 const int kRequestId
= 4;
35 class TestPasswordManagerClient
36 : public password_manager::StubPasswordManagerClient
{
38 TestPasswordManagerClient(password_manager::PasswordStore
* store
)
39 : did_prompt_user_to_save_(false),
40 did_prompt_user_to_choose_(false),
41 is_off_the_record_(false),
43 prefs_
.registry()->RegisterBooleanPref(
44 password_manager::prefs::kPasswordManagerAutoSignin
, true);
46 ~TestPasswordManagerClient() override
{}
48 password_manager::PasswordStore
* GetPasswordStore() override
{
52 PrefService
* GetPrefs() override
{ return &prefs_
; }
54 bool PromptUserToSavePassword(
55 scoped_ptr
<password_manager::PasswordFormManager
> manager
) override
{
56 did_prompt_user_to_save_
= true;
57 manager_
.reset(manager
.release());
61 bool PromptUserToChooseCredentials(
62 ScopedVector
<autofill::PasswordForm
> local_forms
,
63 ScopedVector
<autofill::PasswordForm
> federated_forms
,
64 base::Callback
<void(const password_manager::CredentialInfo
&)> callback
)
66 EXPECT_FALSE(local_forms
.empty() && federated_forms
.empty());
67 did_prompt_user_to_choose_
= true;
68 password_manager::CredentialInfo
info(
69 local_forms
.empty() ? *federated_forms
[0] : *local_forms
[0],
71 ? password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED
72 : password_manager::CredentialType::CREDENTIAL_TYPE_LOCAL
);
73 base::MessageLoop::current()->PostTask(FROM_HERE
,
74 base::Bind(callback
, info
));
78 bool IsOffTheRecord() override
{ return is_off_the_record_
; }
80 bool did_prompt_user_to_save() const { return did_prompt_user_to_save_
; }
81 bool did_prompt_user_to_choose() const { return did_prompt_user_to_choose_
; }
83 password_manager::PasswordFormManager
* pending_manager() const {
84 return manager_
.get();
87 void set_off_the_record(bool off_the_record
) {
88 is_off_the_record_
= off_the_record
;
91 void set_zero_click_enabled(bool zero_click_enabled
) {
92 prefs_
.SetBoolean(password_manager::prefs::kPasswordManagerAutoSignin
,
97 TestingPrefServiceSimple prefs_
;
98 bool did_prompt_user_to_save_
;
99 bool did_prompt_user_to_choose_
;
100 bool is_off_the_record_
;
101 password_manager::PasswordStore
* store_
;
102 scoped_ptr
<password_manager::PasswordFormManager
> manager_
;
105 class TestCredentialManagerDispatcher
106 : public password_manager::CredentialManagerDispatcher
{
108 TestCredentialManagerDispatcher(
109 content::WebContents
* web_contents
,
110 password_manager::PasswordManagerClient
* client
,
111 password_manager::PasswordManagerDriver
* driver
);
114 base::WeakPtr
<password_manager::PasswordManagerDriver
> GetDriver() override
;
116 base::WeakPtr
<password_manager::PasswordManagerDriver
> driver_
;
119 TestCredentialManagerDispatcher::TestCredentialManagerDispatcher(
120 content::WebContents
* web_contents
,
121 password_manager::PasswordManagerClient
* client
,
122 password_manager::PasswordManagerDriver
* driver
)
123 : CredentialManagerDispatcher(web_contents
, client
),
124 driver_(driver
->AsWeakPtr()) {
127 base::WeakPtr
<password_manager::PasswordManagerDriver
>
128 TestCredentialManagerDispatcher::GetDriver() {
132 void RunAllPendingTasks() {
133 base::RunLoop run_loop
;
134 base::MessageLoop::current()->PostTask(
135 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
141 namespace password_manager
{
143 class CredentialManagerDispatcherTest
144 : public content::RenderViewHostTestHarness
{
146 CredentialManagerDispatcherTest() {}
148 void SetUp() override
{
149 content::RenderViewHostTestHarness::SetUp();
150 store_
= new TestPasswordStore
;
151 client_
.reset(new TestPasswordManagerClient(store_
.get()));
152 dispatcher_
.reset(new TestCredentialManagerDispatcher(
153 web_contents(), client_
.get(), &stub_driver_
));
155 NavigateAndCommit(GURL("https://example.com/test.html"));
157 form_
.username_value
= base::ASCIIToUTF16("Username");
158 form_
.display_name
= base::ASCIIToUTF16("Display Name");
159 form_
.password_value
= base::ASCIIToUTF16("Password");
160 form_
.origin
= web_contents()->GetLastCommittedURL().GetOrigin();
161 form_
.signon_realm
= form_
.origin
.spec();
162 form_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
163 form_
.skip_zero_click
= false;
165 form2_
.username_value
= base::ASCIIToUTF16("Username 2");
166 form2_
.display_name
= base::ASCIIToUTF16("Display Name 2");
167 form2_
.password_value
= base::ASCIIToUTF16("Password 2");
168 form2_
.origin
= web_contents()->GetLastCommittedURL().GetOrigin();
169 form2_
.signon_realm
= form2_
.origin
.spec();
170 form2_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
171 form2_
.skip_zero_click
= false;
173 cross_origin_form_
.username_value
= base::ASCIIToUTF16("Username");
174 cross_origin_form_
.display_name
= base::ASCIIToUTF16("Display Name");
175 cross_origin_form_
.password_value
= base::ASCIIToUTF16("Password");
176 cross_origin_form_
.origin
= GURL("https://example.net/");
177 cross_origin_form_
.signon_realm
= cross_origin_form_
.origin
.spec();
178 cross_origin_form_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
179 cross_origin_form_
.skip_zero_click
= false;
182 EXPECT_TRUE(store_
->IsEmpty());
185 void TearDown() override
{
187 content::RenderViewHostTestHarness::TearDown();
190 CredentialManagerDispatcher
* dispatcher() { return dispatcher_
.get(); }
193 autofill::PasswordForm form_
;
194 autofill::PasswordForm form2_
;
195 autofill::PasswordForm cross_origin_form_
;
196 scoped_refptr
<TestPasswordStore
> store_
;
197 scoped_ptr
<TestPasswordManagerClient
> client_
;
198 StubPasswordManagerDriver stub_driver_
;
199 scoped_ptr
<CredentialManagerDispatcher
> dispatcher_
;
202 TEST_F(CredentialManagerDispatcherTest
, CredentialManagerOnNotifyFailedSignIn
) {
204 info
.type
= CredentialType::CREDENTIAL_TYPE_LOCAL
;
205 dispatcher()->OnNotifyFailedSignIn(kRequestId
, info
);
207 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeFailedSignIn::ID
;
208 const IPC::Message
* message
=
209 process()->sink().GetFirstMessageMatching(kMsgID
);
210 EXPECT_TRUE(message
);
211 process()->sink().ClearMessages();
214 TEST_F(CredentialManagerDispatcherTest
, CredentialManagerOnNotifySignedIn
) {
215 CredentialInfo
info(form_
,
216 password_manager::CredentialType::CREDENTIAL_TYPE_LOCAL
);
217 dispatcher()->OnNotifySignedIn(kRequestId
, info
);
219 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeSignedIn::ID
;
220 const IPC::Message
* message
=
221 process()->sink().GetFirstMessageMatching(kMsgID
);
222 EXPECT_TRUE(message
);
223 process()->sink().ClearMessages();
225 // Allow the PasswordFormManager to talk to the password store, determine
226 // that the form is new, and set it as pending.
227 RunAllPendingTasks();
229 EXPECT_TRUE(client_
->did_prompt_user_to_save());
230 EXPECT_TRUE(client_
->pending_manager()->HasCompletedMatching());
232 autofill::PasswordForm new_form
=
233 client_
->pending_manager()->pending_credentials();
234 EXPECT_EQ(form_
.username_value
, new_form
.username_value
);
235 EXPECT_EQ(form_
.display_name
, new_form
.display_name
);
236 EXPECT_EQ(form_
.password_value
, new_form
.password_value
);
237 EXPECT_EQ(form_
.origin
, new_form
.origin
);
238 EXPECT_EQ(form_
.signon_realm
, new_form
.signon_realm
);
239 EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML
, new_form
.scheme
);
242 TEST_F(CredentialManagerDispatcherTest
, CredentialManagerIncognitoSignedIn
) {
243 CredentialInfo
info(form_
, CredentialType::CREDENTIAL_TYPE_LOCAL
);
244 client_
->set_off_the_record(true);
245 dispatcher()->OnNotifySignedIn(kRequestId
, info
);
247 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeSignedIn::ID
;
248 const IPC::Message
* message
=
249 process()->sink().GetFirstMessageMatching(kMsgID
);
250 EXPECT_TRUE(message
);
251 process()->sink().ClearMessages();
253 RunAllPendingTasks();
255 EXPECT_FALSE(client_
->did_prompt_user_to_save());
256 EXPECT_FALSE(client_
->pending_manager());
259 TEST_F(CredentialManagerDispatcherTest
, CredentialManagerOnNotifySignedOut
) {
260 store_
->AddLogin(form_
);
261 store_
->AddLogin(cross_origin_form_
);
262 RunAllPendingTasks();
264 TestPasswordStore::PasswordMap passwords
= store_
->stored_passwords();
265 EXPECT_EQ(2U, passwords
.size());
266 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
267 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
268 EXPECT_FALSE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
269 EXPECT_FALSE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
271 dispatcher()->OnNotifySignedOut(kRequestId
);
272 RunAllPendingTasks();
274 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeSignedOut::ID
;
275 const IPC::Message
* message
=
276 process()->sink().GetFirstMessageMatching(kMsgID
);
277 EXPECT_TRUE(message
);
278 process()->sink().ClearMessages();
280 passwords
= store_
->stored_passwords();
281 EXPECT_EQ(2U, passwords
.size());
282 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
283 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
284 EXPECT_TRUE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
285 EXPECT_FALSE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
288 TEST_F(CredentialManagerDispatcherTest
,
289 CredentialManagerOnRequestCredentialWithEmptyPasswordStore
) {
290 std::vector
<GURL
> federations
;
291 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
293 RunAllPendingTasks();
295 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
296 const IPC::Message
* message
=
297 process()->sink().GetFirstMessageMatching(kMsgID
);
298 EXPECT_TRUE(message
);
299 CredentialManagerMsg_SendCredential::Param param
;
300 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
301 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(param
).type
);
302 process()->sink().ClearMessages();
303 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
306 TEST_F(CredentialManagerDispatcherTest
,
307 CredentialManagerOnRequestCredentialWithCrossOriginPasswordStore
) {
308 store_
->AddLogin(cross_origin_form_
);
310 std::vector
<GURL
> federations
;
311 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
313 RunAllPendingTasks();
315 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
316 const IPC::Message
* message
=
317 process()->sink().GetFirstMessageMatching(kMsgID
);
318 EXPECT_TRUE(message
);
319 CredentialManagerMsg_SendCredential::Param param
;
320 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
321 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(param
).type
);
322 process()->sink().ClearMessages();
323 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
326 TEST_F(CredentialManagerDispatcherTest
,
327 CredentialManagerOnRequestCredentialWithFullPasswordStore
) {
328 client_
->set_zero_click_enabled(false);
329 store_
->AddLogin(form_
);
331 std::vector
<GURL
> federations
;
332 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
334 RunAllPendingTasks();
336 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
337 const IPC::Message
* message
=
338 process()->sink().GetFirstMessageMatching(kMsgID
);
339 EXPECT_TRUE(message
);
340 EXPECT_TRUE(client_
->did_prompt_user_to_choose());
344 CredentialManagerDispatcherTest
,
345 CredentialManagerOnRequestCredentialWithZeroClickOnlyEmptyPasswordStore
) {
346 std::vector
<GURL
> federations
;
347 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
349 RunAllPendingTasks();
351 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
352 const IPC::Message
* message
=
353 process()->sink().GetFirstMessageMatching(kMsgID
);
354 EXPECT_TRUE(message
);
355 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
356 CredentialManagerMsg_SendCredential::Param send_param
;
357 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
358 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(send_param
).type
);
361 TEST_F(CredentialManagerDispatcherTest
,
362 CredentialManagerOnRequestCredentialWithZeroClickOnlyFullPasswordStore
) {
363 store_
->AddLogin(form_
);
365 std::vector
<GURL
> federations
;
366 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
368 RunAllPendingTasks();
370 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
371 const IPC::Message
* message
=
372 process()->sink().GetFirstMessageMatching(kMsgID
);
373 EXPECT_TRUE(message
);
374 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
375 CredentialManagerMsg_SendCredential::Param send_param
;
376 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
377 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_LOCAL
, get
<1>(send_param
).type
);
380 TEST_F(CredentialManagerDispatcherTest
,
381 CredentialManagerOnRequestCredentialWithZeroClickOnlyTwoPasswordStore
) {
382 store_
->AddLogin(form_
);
383 store_
->AddLogin(form2_
);
385 std::vector
<GURL
> federations
;
386 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
388 RunAllPendingTasks();
390 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
391 const IPC::Message
* message
=
392 process()->sink().GetFirstMessageMatching(kMsgID
);
393 EXPECT_TRUE(message
);
394 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
395 CredentialManagerMsg_SendCredential::Param send_param
;
396 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
398 // With two items in the password store, we shouldn't get credentials back.
399 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(send_param
).type
);
402 TEST_F(CredentialManagerDispatcherTest
,
403 OnRequestCredentialWithZeroClickOnlyOnePasswordStore
) {
404 form_
.skip_zero_click
= true;
405 store_
->AddLogin(form_
);
406 store_
->AddLogin(form2_
);
408 std::vector
<GURL
> federations
;
409 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
411 RunAllPendingTasks();
413 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
414 const IPC::Message
* message
=
415 process()->sink().GetFirstMessageMatching(kMsgID
);
416 EXPECT_TRUE(message
);
417 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
418 CredentialManagerMsg_SendCredential::Param send_param
;
419 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
421 // We should get |form2_| back, as |form_| is marked as skipping zero-click.
422 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_LOCAL
, get
<1>(send_param
).type
);
423 EXPECT_EQ(form2_
.username_value
, get
<1>(send_param
).id
);
424 EXPECT_EQ(form2_
.display_name
, get
<1>(send_param
).name
);
425 EXPECT_EQ(form2_
.password_value
, get
<1>(send_param
).password
);
428 TEST_F(CredentialManagerDispatcherTest
,
429 OnRequestCredentialWithZeroClickOnlyCrossOriginPasswordStore
) {
430 store_
->AddLogin(cross_origin_form_
);
432 form_
.skip_zero_click
= true;
433 store_
->AddLogin(form_
);
435 std::vector
<GURL
> federations
;
436 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
438 RunAllPendingTasks();
440 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
441 const IPC::Message
* message
=
442 process()->sink().GetFirstMessageMatching(kMsgID
);
443 EXPECT_TRUE(message
);
444 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
445 CredentialManagerMsg_SendCredential::Param send_param
;
446 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
448 // We only have cross-origin zero-click credentials; they should not be
450 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(send_param
).type
);
453 TEST_F(CredentialManagerDispatcherTest
,
454 CredentialManagerOnRequestCredentialWhileRequestPending
) {
455 client_
->set_zero_click_enabled(false);
456 store_
->AddLogin(form_
);
458 std::vector
<GURL
> federations
;
459 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
460 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
462 // Check that the second request triggered a rejection.
463 uint32 kMsgID
= CredentialManagerMsg_RejectCredentialRequest::ID
;
464 const IPC::Message
* message
=
465 process()->sink().GetFirstMessageMatching(kMsgID
);
466 EXPECT_TRUE(message
);
467 CredentialManagerMsg_RejectCredentialRequest::Param reject_param
;
468 CredentialManagerMsg_RejectCredentialRequest::Read(message
, &reject_param
);
469 EXPECT_EQ(blink::WebCredentialManagerError::ErrorTypePendingRequest
,
470 get
<1>(reject_param
));
471 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
473 process()->sink().ClearMessages();
475 // Execute the PasswordStore asynchronousness.
476 RunAllPendingTasks();
478 // Check that the first request resolves.
479 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
480 message
= process()->sink().GetFirstMessageMatching(kMsgID
);
481 EXPECT_TRUE(message
);
482 CredentialManagerMsg_SendCredential::Param send_param
;
483 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
484 EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(send_param
).type
);
485 process()->sink().ClearMessages();
486 EXPECT_TRUE(client_
->did_prompt_user_to_choose());
489 TEST_F(CredentialManagerDispatcherTest
, IncognitoRequestCredential
) {
490 client_
->set_off_the_record(true);
491 store_
->AddLogin(form_
);
493 std::vector
<GURL
> federations
;
494 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
496 RunAllPendingTasks();
498 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
499 const IPC::Message
* message
=
500 process()->sink().GetFirstMessageMatching(kMsgID
);
501 ASSERT_TRUE(message
);
502 CredentialManagerMsg_SendCredential::Param param
;
503 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
504 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, get
<1>(param
).type
);
505 EXPECT_FALSE(client_
->did_prompt_user_to_choose());
508 } // namespace password_manager