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 "base/thread_task_runner_handle.h"
15 #include "components/password_manager/content/common/credential_manager_messages.h"
16 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
17 #include "components/password_manager/core/browser/mock_affiliated_match_helper.h"
18 #include "components/password_manager/core/browser/stub_password_manager_client.h"
19 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
20 #include "components/password_manager/core/browser/test_password_store.h"
21 #include "components/password_manager/core/common/credential_manager_types.h"
22 #include "components/password_manager/core/common/password_manager_pref_names.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/mock_render_process_host.h"
25 #include "content/public/test/test_renderer_host.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using content::BrowserContext
;
30 using content::WebContents
;
36 // Chosen by fair dice roll. Guaranteed to be random.
37 const int kRequestId
= 4;
39 const char kTestWebOrigin
[] = "https://example.com/";
40 const char kTestAndroidRealm1
[] = "android://hash@com.example.one.android/";
41 const char kTestAndroidRealm2
[] = "android://hash@com.example.two.android/";
43 class MockPasswordManagerClient
44 : public password_manager::StubPasswordManagerClient
{
46 MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage
, bool());
47 MOCK_CONST_METHOD0(IsOffTheRecord
, bool());
48 MOCK_CONST_METHOD0(DidLastPageLoadEncounterSSLErrors
, bool());
49 MOCK_METHOD1(NotifyUserAutoSigninPtr
,
50 bool(const std::vector
<autofill::PasswordForm
*>& local_forms
));
51 MOCK_METHOD2(PromptUserToSavePasswordPtr
,
52 void(password_manager::PasswordFormManager
*,
53 password_manager::CredentialSourceType type
));
54 MOCK_METHOD4(PromptUserToChooseCredentialsPtr
,
55 bool(const std::vector
<autofill::PasswordForm
*>& local_forms
,
56 const std::vector
<autofill::PasswordForm
*>& federated_forms
,
59 const password_manager::CredentialInfo
&)> callback
));
61 MockPasswordManagerClient(password_manager::PasswordStore
* store
)
63 prefs_
.registry()->RegisterBooleanPref(
64 password_manager::prefs::kPasswordManagerAutoSignin
, true);
66 ~MockPasswordManagerClient() override
{}
68 bool PromptUserToSaveOrUpdatePassword(
69 scoped_ptr
<password_manager::PasswordFormManager
> manager
,
70 password_manager::CredentialSourceType type
,
71 bool update_password
) override
{
72 manager_
.swap(manager
);
73 PromptUserToSavePasswordPtr(manager_
.get(), type
);
77 password_manager::PasswordStore
* GetPasswordStore() const override
{
81 PrefService
* GetPrefs() override
{ return &prefs_
; }
83 bool PromptUserToChooseCredentials(
84 ScopedVector
<autofill::PasswordForm
> local_forms
,
85 ScopedVector
<autofill::PasswordForm
> federated_forms
,
87 base::Callback
<void(const password_manager::CredentialInfo
&)> callback
) {
88 EXPECT_FALSE(local_forms
.empty() && federated_forms
.empty());
89 password_manager::CredentialInfo
info(
90 local_forms
.empty() ? *federated_forms
[0] : *local_forms
[0],
92 ? password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED
93 : password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD
);
94 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
95 base::Bind(callback
, info
));
96 PromptUserToChooseCredentialsPtr(local_forms
.get(), federated_forms
.get(),
101 void NotifyUserAutoSignin(
102 ScopedVector
<autofill::PasswordForm
> local_forms
) override
{
103 EXPECT_FALSE(local_forms
.empty());
104 NotifyUserAutoSigninPtr(local_forms
.get());
107 password_manager::PasswordFormManager
* pending_manager() const {
108 return manager_
.get();
111 void set_zero_click_enabled(bool zero_click_enabled
) {
112 prefs_
.SetBoolean(password_manager::prefs::kPasswordManagerAutoSignin
,
117 TestingPrefServiceSimple prefs_
;
118 password_manager::PasswordStore
* store_
;
119 scoped_ptr
<password_manager::PasswordFormManager
> manager_
;
121 DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient
);
124 class TestCredentialManagerDispatcher
125 : public password_manager::CredentialManagerDispatcher
{
127 TestCredentialManagerDispatcher(
128 content::WebContents
* web_contents
,
129 password_manager::PasswordManagerClient
* client
,
130 password_manager::PasswordManagerDriver
* driver
);
133 base::WeakPtr
<password_manager::PasswordManagerDriver
> GetDriver() override
;
135 base::WeakPtr
<password_manager::PasswordManagerDriver
> driver_
;
138 TestCredentialManagerDispatcher::TestCredentialManagerDispatcher(
139 content::WebContents
* web_contents
,
140 password_manager::PasswordManagerClient
* client
,
141 password_manager::PasswordManagerDriver
* driver
)
142 : CredentialManagerDispatcher(web_contents
, client
),
143 driver_(driver
->AsWeakPtr()) {
146 base::WeakPtr
<password_manager::PasswordManagerDriver
>
147 TestCredentialManagerDispatcher::GetDriver() {
151 void RunAllPendingTasks() {
152 base::RunLoop run_loop
;
153 base::MessageLoop::current()->PostTask(
154 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
160 namespace password_manager
{
162 class CredentialManagerDispatcherTest
163 : public content::RenderViewHostTestHarness
{
165 CredentialManagerDispatcherTest() {}
167 void SetUp() override
{
168 content::RenderViewHostTestHarness::SetUp();
169 store_
= new TestPasswordStore
;
170 client_
.reset(new MockPasswordManagerClient(store_
.get()));
171 dispatcher_
.reset(new TestCredentialManagerDispatcher(
172 web_contents(), client_
.get(), &stub_driver_
));
173 ON_CALL(*client_
, IsSavingAndFillingEnabledForCurrentPage())
174 .WillByDefault(testing::Return(true));
175 ON_CALL(*client_
, IsOffTheRecord()).WillByDefault(testing::Return(false));
176 ON_CALL(*client_
, DidLastPageLoadEncounterSSLErrors())
177 .WillByDefault(testing::Return(false));
179 NavigateAndCommit(GURL("https://example.com/test.html"));
181 form_
.username_value
= base::ASCIIToUTF16("Username");
182 form_
.display_name
= base::ASCIIToUTF16("Display Name");
183 form_
.password_value
= base::ASCIIToUTF16("Password");
184 form_
.origin
= web_contents()->GetLastCommittedURL().GetOrigin();
185 form_
.signon_realm
= form_
.origin
.spec();
186 form_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
187 form_
.skip_zero_click
= false;
188 form_
.ssl_valid
= true;
190 affiliated_form1_
.username_value
= base::ASCIIToUTF16("Affiliated 1");
191 affiliated_form1_
.display_name
= base::ASCIIToUTF16("Display Name");
192 affiliated_form1_
.password_value
= base::ASCIIToUTF16("Password");
193 affiliated_form1_
.origin
= GURL();
194 affiliated_form1_
.signon_realm
= kTestAndroidRealm1
;
195 affiliated_form1_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
196 affiliated_form1_
.skip_zero_click
= false;
197 affiliated_form1_
.ssl_valid
= true;
199 affiliated_form2_
.username_value
= base::ASCIIToUTF16("Affiliated 2");
200 affiliated_form2_
.display_name
= base::ASCIIToUTF16("Display Name");
201 affiliated_form2_
.password_value
= base::ASCIIToUTF16("Password");
202 affiliated_form2_
.origin
= GURL();
203 affiliated_form2_
.signon_realm
= kTestAndroidRealm2
;
204 affiliated_form2_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
205 affiliated_form2_
.skip_zero_click
= false;
206 affiliated_form2_
.ssl_valid
= true;
208 origin_path_form_
.username_value
= base::ASCIIToUTF16("Username 2");
209 origin_path_form_
.display_name
= base::ASCIIToUTF16("Display Name 2");
210 origin_path_form_
.password_value
= base::ASCIIToUTF16("Password 2");
211 origin_path_form_
.origin
= GURL("https://example.com/path");
212 origin_path_form_
.signon_realm
= origin_path_form_
.origin
.spec();
213 origin_path_form_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
214 origin_path_form_
.skip_zero_click
= false;
216 cross_origin_form_
.username_value
= base::ASCIIToUTF16("Username");
217 cross_origin_form_
.display_name
= base::ASCIIToUTF16("Display Name");
218 cross_origin_form_
.password_value
= base::ASCIIToUTF16("Password");
219 cross_origin_form_
.origin
= GURL("https://example.net/");
220 cross_origin_form_
.signon_realm
= cross_origin_form_
.origin
.spec();
221 cross_origin_form_
.scheme
= autofill::PasswordForm::SCHEME_HTML
;
222 cross_origin_form_
.skip_zero_click
= false;
225 EXPECT_TRUE(store_
->IsEmpty());
228 void TearDown() override
{
230 content::RenderViewHostTestHarness::TearDown();
233 void ExpectZeroClickSignInFailure() {
234 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
235 .Times(testing::Exactly(0));
236 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
))
237 .Times(testing::Exactly(0));
239 RunAllPendingTasks();
241 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
242 const IPC::Message
* message
=
243 process()->sink().GetFirstMessageMatching(kMsgID
);
244 ASSERT_TRUE(message
);
245 CredentialManagerMsg_SendCredential::Param send_param
;
246 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
248 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
,
249 base::get
<1>(send_param
).type
);
252 void ExpectZeroClickSignInSuccess() {
253 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
254 .Times(testing::Exactly(0));
255 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
))
256 .Times(testing::Exactly(1));
258 RunAllPendingTasks();
260 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
261 const IPC::Message
* message
=
262 process()->sink().GetFirstMessageMatching(kMsgID
);
263 ASSERT_TRUE(message
);
264 CredentialManagerMsg_SendCredential::Param send_param
;
265 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
267 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_PASSWORD
,
268 base::get
<1>(send_param
).type
);
271 CredentialManagerDispatcher
* dispatcher() { return dispatcher_
.get(); }
274 autofill::PasswordForm form_
;
275 autofill::PasswordForm affiliated_form1_
;
276 autofill::PasswordForm affiliated_form2_
;
277 autofill::PasswordForm origin_path_form_
;
278 autofill::PasswordForm cross_origin_form_
;
279 scoped_refptr
<TestPasswordStore
> store_
;
280 scoped_ptr
<MockPasswordManagerClient
> client_
;
281 StubPasswordManagerDriver stub_driver_
;
282 scoped_ptr
<CredentialManagerDispatcher
> dispatcher_
;
285 TEST_F(CredentialManagerDispatcherTest
, CredentialManagerOnStore
) {
287 form_
, password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD
);
290 PromptUserToSavePasswordPtr(
291 _
, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API
))
292 .Times(testing::Exactly(1));
294 dispatcher()->OnStore(kRequestId
, info
);
296 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeStore::ID
;
297 const IPC::Message
* message
=
298 process()->sink().GetFirstMessageMatching(kMsgID
);
299 EXPECT_TRUE(message
);
300 process()->sink().ClearMessages();
302 // Allow the PasswordFormManager to talk to the password store, determine
303 // that the form is new, and set it as pending.
304 RunAllPendingTasks();
306 EXPECT_TRUE(client_
->pending_manager()->HasCompletedMatching());
308 autofill::PasswordForm new_form
=
309 client_
->pending_manager()->pending_credentials();
310 EXPECT_EQ(form_
.username_value
, new_form
.username_value
);
311 EXPECT_EQ(form_
.display_name
, new_form
.display_name
);
312 EXPECT_EQ(form_
.password_value
, new_form
.password_value
);
313 EXPECT_EQ(form_
.origin
, new_form
.origin
);
314 EXPECT_EQ(form_
.signon_realm
, new_form
.signon_realm
);
315 EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML
, new_form
.scheme
);
318 TEST_F(CredentialManagerDispatcherTest
,
319 CredentialManagerSignInWithSavingDisabledForCurrentPage
) {
320 CredentialInfo
info(form_
, CredentialType::CREDENTIAL_TYPE_PASSWORD
);
321 EXPECT_CALL(*client_
, IsSavingAndFillingEnabledForCurrentPage())
322 .WillRepeatedly(testing::Return(false));
325 PromptUserToSavePasswordPtr(
326 _
, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API
))
327 .Times(testing::Exactly(0));
329 dispatcher()->OnStore(kRequestId
, info
);
331 const uint32 kMsgID
= CredentialManagerMsg_AcknowledgeStore::ID
;
332 const IPC::Message
* message
=
333 process()->sink().GetFirstMessageMatching(kMsgID
);
334 EXPECT_TRUE(message
);
335 process()->sink().ClearMessages();
337 RunAllPendingTasks();
339 EXPECT_FALSE(client_
->pending_manager());
342 TEST_F(CredentialManagerDispatcherTest
,
343 CredentialManagerOnRequireUserMediation
) {
344 store_
->AddLogin(form_
);
345 store_
->AddLogin(cross_origin_form_
);
346 RunAllPendingTasks();
348 TestPasswordStore::PasswordMap passwords
= store_
->stored_passwords();
349 EXPECT_EQ(2U, passwords
.size());
350 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
351 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
352 EXPECT_FALSE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
353 EXPECT_FALSE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
355 dispatcher()->OnRequireUserMediation(kRequestId
);
356 RunAllPendingTasks();
358 const uint32 kMsgID
=
359 CredentialManagerMsg_AcknowledgeRequireUserMediation::ID
;
360 const IPC::Message
* message
=
361 process()->sink().GetFirstMessageMatching(kMsgID
);
362 EXPECT_TRUE(message
);
363 process()->sink().ClearMessages();
365 passwords
= store_
->stored_passwords();
366 EXPECT_EQ(2U, passwords
.size());
367 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
368 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
369 EXPECT_TRUE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
370 EXPECT_FALSE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
373 TEST_F(CredentialManagerDispatcherTest
,
374 CredentialManagerOnRequestCredentialWithEmptyPasswordStore
) {
375 std::vector
<GURL
> federations
;
378 PromptUserToSavePasswordPtr(
379 _
, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API
))
380 .Times(testing::Exactly(0));
381 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
382 .Times(testing::Exactly(0));
383 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
385 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
387 RunAllPendingTasks();
389 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
390 const IPC::Message
* message
=
391 process()->sink().GetFirstMessageMatching(kMsgID
);
392 EXPECT_TRUE(message
);
393 CredentialManagerMsg_SendCredential::Param param
;
394 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
395 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, base::get
<1>(param
).type
);
396 process()->sink().ClearMessages();
399 TEST_F(CredentialManagerDispatcherTest
,
400 CredentialManagerOnRequestCredentialWithCrossOriginPasswordStore
) {
401 store_
->AddLogin(cross_origin_form_
);
403 std::vector
<GURL
> federations
;
406 PromptUserToSavePasswordPtr(
407 _
, password_manager::CredentialSourceType::CREDENTIAL_SOURCE_API
))
408 .Times(testing::Exactly(0));
409 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
410 .Times(testing::Exactly(0));
411 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
413 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
415 RunAllPendingTasks();
417 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
418 const IPC::Message
* message
=
419 process()->sink().GetFirstMessageMatching(kMsgID
);
420 EXPECT_TRUE(message
);
421 CredentialManagerMsg_SendCredential::Param param
;
422 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
423 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, base::get
<1>(param
).type
);
424 process()->sink().ClearMessages();
427 TEST_F(CredentialManagerDispatcherTest
,
428 CredentialManagerOnRequestCredentialWithFullPasswordStore
) {
429 client_
->set_zero_click_enabled(false);
430 store_
->AddLogin(form_
);
432 std::vector
<GURL
> federations
;
433 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
434 .Times(testing::Exactly(1));
435 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
437 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
439 RunAllPendingTasks();
441 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
442 const IPC::Message
* message
=
443 process()->sink().GetFirstMessageMatching(kMsgID
);
444 EXPECT_TRUE(message
);
448 CredentialManagerDispatcherTest
,
449 CredentialManagerOnRequestCredentialWithZeroClickOnlyEmptyPasswordStore
) {
450 std::vector
<GURL
> federations
;
451 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
452 .Times(testing::Exactly(0));
453 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
455 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
457 RunAllPendingTasks();
459 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
460 const IPC::Message
* message
=
461 process()->sink().GetFirstMessageMatching(kMsgID
);
462 EXPECT_TRUE(message
);
463 CredentialManagerMsg_SendCredential::Param send_param
;
464 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
465 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
,
466 base::get
<1>(send_param
).type
);
469 TEST_F(CredentialManagerDispatcherTest
,
470 CredentialManagerOnRequestCredentialWithZeroClickOnlyFullPasswordStore
) {
471 store_
->AddLogin(form_
);
473 std::vector
<GURL
> federations
;
474 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
476 ExpectZeroClickSignInSuccess();
479 TEST_F(CredentialManagerDispatcherTest
, RequestCredentialWithTLSErrors
) {
480 // If we encounter TLS errors, we won't return credentials.
481 EXPECT_CALL(*client_
, DidLastPageLoadEncounterSSLErrors())
482 .WillRepeatedly(testing::Return(true));
484 store_
->AddLogin(form_
);
486 std::vector
<GURL
> federations
;
487 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
489 ExpectZeroClickSignInFailure();
492 TEST_F(CredentialManagerDispatcherTest
,
493 CredentialManagerOnRequestCredentialWithZeroClickOnlyTwoPasswordStore
) {
494 store_
->AddLogin(form_
);
495 store_
->AddLogin(origin_path_form_
);
497 std::vector
<GURL
> federations
;
498 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
499 .Times(testing::Exactly(0));
500 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
502 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
504 RunAllPendingTasks();
506 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
507 const IPC::Message
* message
=
508 process()->sink().GetFirstMessageMatching(kMsgID
);
509 EXPECT_TRUE(message
);
510 CredentialManagerMsg_SendCredential::Param send_param
;
511 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
513 // With two items in the password store, we shouldn't get credentials back.
514 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
,
515 base::get
<1>(send_param
).type
);
518 TEST_F(CredentialManagerDispatcherTest
,
519 OnRequestCredentialWithZeroClickOnlyAndSkipZeroClickPasswordStore
) {
520 form_
.skip_zero_click
= true;
521 store_
->AddLogin(form_
);
522 store_
->AddLogin(origin_path_form_
);
524 std::vector
<GURL
> federations
;
525 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
526 .Times(testing::Exactly(0));
527 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
529 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
531 RunAllPendingTasks();
533 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
534 const IPC::Message
* message
=
535 process()->sink().GetFirstMessageMatching(kMsgID
);
536 EXPECT_TRUE(message
);
537 CredentialManagerMsg_SendCredential::Param send_param
;
538 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
540 // With two items in the password store, we shouldn't get credentials back,
541 // even though only one item has |skip_zero_click| set |false|.
542 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
,
543 base::get
<1>(send_param
).type
);
546 TEST_F(CredentialManagerDispatcherTest
,
547 OnRequestCredentialWithZeroClickOnlyCrossOriginPasswordStore
) {
548 store_
->AddLogin(cross_origin_form_
);
550 form_
.skip_zero_click
= true;
551 store_
->AddLogin(form_
);
553 std::vector
<GURL
> federations
;
554 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
555 .Times(testing::Exactly(0));
556 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
558 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
560 RunAllPendingTasks();
562 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
563 const IPC::Message
* message
=
564 process()->sink().GetFirstMessageMatching(kMsgID
);
565 EXPECT_TRUE(message
);
566 CredentialManagerMsg_SendCredential::Param send_param
;
567 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
569 // We only have cross-origin zero-click credentials; they should not be
571 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
,
572 base::get
<1>(send_param
).type
);
575 TEST_F(CredentialManagerDispatcherTest
,
576 CredentialManagerOnRequestCredentialWhileRequestPending
) {
577 client_
->set_zero_click_enabled(false);
578 store_
->AddLogin(form_
);
580 std::vector
<GURL
> federations
;
581 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
582 .Times(testing::Exactly(0));
583 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
585 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
586 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
588 // Check that the second request triggered a rejection.
589 uint32 kMsgID
= CredentialManagerMsg_RejectCredentialRequest::ID
;
590 const IPC::Message
* message
=
591 process()->sink().GetFirstMessageMatching(kMsgID
);
592 EXPECT_TRUE(message
);
594 CredentialManagerMsg_RejectCredentialRequest::Param reject_param
;
595 CredentialManagerMsg_RejectCredentialRequest::Read(message
, &reject_param
);
596 EXPECT_EQ(blink::WebCredentialManagerError::ErrorTypePendingRequest
,
597 base::get
<1>(reject_param
));
598 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
599 .Times(testing::Exactly(1));
600 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
602 process()->sink().ClearMessages();
604 // Execute the PasswordStore asynchronousness.
605 RunAllPendingTasks();
607 // Check that the first request resolves.
608 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
609 message
= process()->sink().GetFirstMessageMatching(kMsgID
);
610 EXPECT_TRUE(message
);
611 CredentialManagerMsg_SendCredential::Param send_param
;
612 CredentialManagerMsg_SendCredential::Read(message
, &send_param
);
613 EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY
,
614 base::get
<1>(send_param
).type
);
615 process()->sink().ClearMessages();
618 TEST_F(CredentialManagerDispatcherTest
, ResetSkipZeroClickAfterPrompt
) {
619 // Turn on the global zero-click flag, and add two credentials in separate
620 // origins, both set to skip zero-click.
621 client_
->set_zero_click_enabled(true);
622 form_
.skip_zero_click
= true;
623 store_
->AddLogin(form_
);
624 cross_origin_form_
.skip_zero_click
= true;
625 store_
->AddLogin(cross_origin_form_
);
627 // Execute the PasswordStore asynchronousness to ensure everything is
628 // written before proceeding.
629 RunAllPendingTasks();
632 TestPasswordStore::PasswordMap passwords
= store_
->stored_passwords();
633 EXPECT_EQ(2U, passwords
.size());
634 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
635 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
636 EXPECT_TRUE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
637 EXPECT_TRUE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
639 // Trigger a request which should return the credential found in |form_|, and
640 // wait for it to process.
641 std::vector
<GURL
> federations
;
642 // Check that the form in the database has been updated. `OnRequestCredential`
643 // generates a call to prompt the user to choose a credential.
644 // MockPasswordManagerClient mocks a user choice, and when users choose a
645 // credential (and have the global zero-click flag enabled), we make sure that
646 // they'll be logged in again next time.
647 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
648 .Times(testing::Exactly(1));
649 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
651 dispatcher()->OnRequestCredential(kRequestId
, false, federations
);
652 RunAllPendingTasks();
654 passwords
= store_
->stored_passwords();
655 EXPECT_EQ(2U, passwords
.size());
656 EXPECT_EQ(1U, passwords
[form_
.signon_realm
].size());
657 EXPECT_EQ(1U, passwords
[cross_origin_form_
.signon_realm
].size());
658 EXPECT_FALSE(passwords
[form_
.signon_realm
][0].skip_zero_click
);
659 EXPECT_TRUE(passwords
[cross_origin_form_
.signon_realm
][0].skip_zero_click
);
662 TEST_F(CredentialManagerDispatcherTest
, IncognitoZeroClickRequestCredential
) {
663 EXPECT_CALL(*client_
, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
664 store_
->AddLogin(form_
);
666 std::vector
<GURL
> federations
;
667 EXPECT_CALL(*client_
, PromptUserToChooseCredentialsPtr(_
, _
, _
, _
))
668 .Times(testing::Exactly(0));
669 EXPECT_CALL(*client_
, NotifyUserAutoSigninPtr(_
)).Times(testing::Exactly(0));
671 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
673 RunAllPendingTasks();
675 const uint32 kMsgID
= CredentialManagerMsg_SendCredential::ID
;
676 const IPC::Message
* message
=
677 process()->sink().GetFirstMessageMatching(kMsgID
);
678 ASSERT_TRUE(message
);
679 CredentialManagerMsg_SendCredential::Param param
;
680 CredentialManagerMsg_SendCredential::Read(message
, ¶m
);
681 EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY
, base::get
<1>(param
).type
);
684 TEST_F(CredentialManagerDispatcherTest
,
685 ZeroClickWithAffiliatedFormInPasswordStore
) {
686 // Insert the affiliated form into the store, and mock out the association
687 // with the current origin. As it's the only form matching the origin, it
688 // ought to be returned automagically.
689 store_
->AddLogin(affiliated_form1_
);
691 MockAffiliatedMatchHelper
* mock_helper
= new MockAffiliatedMatchHelper
;
692 store_
->SetAffiliatedMatchHelper(make_scoped_ptr(mock_helper
));
694 std::vector
<GURL
> federations
;
695 std::vector
<std::string
> affiliated_realms
;
696 affiliated_realms
.push_back(kTestAndroidRealm1
);
697 mock_helper
->ExpectCallToGetAffiliatedAndroidRealms(
698 dispatcher_
->GetSynthesizedFormForOrigin(), affiliated_realms
);
700 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
702 ExpectZeroClickSignInSuccess();
705 TEST_F(CredentialManagerDispatcherTest
,
706 ZeroClickWithTwoAffiliatedFormsInPasswordStore
) {
707 // Insert two affiliated forms into the store, and mock out the association
708 // with the current origin. Multiple forms === no zero-click sign in.
709 store_
->AddLogin(affiliated_form1_
);
710 store_
->AddLogin(affiliated_form2_
);
712 MockAffiliatedMatchHelper
* mock_helper
= new MockAffiliatedMatchHelper
;
713 store_
->SetAffiliatedMatchHelper(make_scoped_ptr(mock_helper
));
715 std::vector
<GURL
> federations
;
716 std::vector
<std::string
> affiliated_realms
;
717 affiliated_realms
.push_back(kTestAndroidRealm1
);
718 affiliated_realms
.push_back(kTestAndroidRealm2
);
719 mock_helper
->ExpectCallToGetAffiliatedAndroidRealms(
720 dispatcher_
->GetSynthesizedFormForOrigin(), affiliated_realms
);
722 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
724 ExpectZeroClickSignInFailure();
727 TEST_F(CredentialManagerDispatcherTest
,
728 ZeroClickWithUnaffiliatedFormsInPasswordStore
) {
729 // Insert the affiliated form into the store, but don't mock out the
730 // association with the current origin. No association === no zero-click sign
732 store_
->AddLogin(affiliated_form1_
);
734 MockAffiliatedMatchHelper
* mock_helper
= new MockAffiliatedMatchHelper
;
735 store_
->SetAffiliatedMatchHelper(make_scoped_ptr(mock_helper
));
737 std::vector
<GURL
> federations
;
738 std::vector
<std::string
> affiliated_realms
;
739 mock_helper
->ExpectCallToGetAffiliatedAndroidRealms(
740 dispatcher_
->GetSynthesizedFormForOrigin(), affiliated_realms
);
742 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
744 ExpectZeroClickSignInFailure();
747 TEST_F(CredentialManagerDispatcherTest
,
748 ZeroClickWithFormAndUnaffiliatedFormsInPasswordStore
) {
749 // Insert the affiliated form into the store, along with a real form for the
750 // origin, and don't mock out the association with the current origin. No
751 // association + existing form === zero-click sign in.
752 store_
->AddLogin(form_
);
753 store_
->AddLogin(affiliated_form1_
);
755 MockAffiliatedMatchHelper
* mock_helper
= new MockAffiliatedMatchHelper
;
756 store_
->SetAffiliatedMatchHelper(make_scoped_ptr(mock_helper
));
758 std::vector
<GURL
> federations
;
759 std::vector
<std::string
> affiliated_realms
;
760 mock_helper
->ExpectCallToGetAffiliatedAndroidRealms(
761 dispatcher_
->GetSynthesizedFormForOrigin(), affiliated_realms
);
763 dispatcher()->OnRequestCredential(kRequestId
, true, federations
);
765 ExpectZeroClickSignInSuccess();
768 TEST_F(CredentialManagerDispatcherTest
, GetSynthesizedFormForOrigin
) {
769 autofill::PasswordForm synthesized
=
770 dispatcher_
->GetSynthesizedFormForOrigin();
771 EXPECT_EQ(kTestWebOrigin
, synthesized
.origin
.spec());
772 EXPECT_EQ(kTestWebOrigin
, synthesized
.signon_realm
);
773 EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML
, synthesized
.scheme
);
774 EXPECT_TRUE(synthesized
.ssl_valid
);
777 } // namespace password_manager