1 // Copyright 2020 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 "components/password_manager/core/browser/ui/insecure_credentials_manager.h"
6
7 #include "base/memory/scoped_refptr.h"
8 #include "base/strings/string_piece_forward.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/metrics/histogram_tester.h"
11 #include "base/test/mock_callback.h"
12 #include "base/test/task_environment.h"
13 #include "base/timer/elapsed_timer.h"
14 #include "build/build_config.h"
15 #include "components/password_manager/core/browser/compromised_credentials_table.h"
16 #include "components/password_manager/core/browser/password_form.h"
17 #include "components/password_manager/core/browser/test_password_store.h"
18 #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace password_manager {
23
24 namespace {
25
26 constexpr char kExampleCom[] = "https://example.com";
27 constexpr char kExampleOrg[] = "https://example.org";
28
29 constexpr char kUsername1[] = "alice";
30 constexpr char kUsername2[] = "bob";
31
32 constexpr char kPassword1[] = "f00b4r";
33 constexpr char kPassword2[] = "s3cr3t";
34 constexpr char kPassword3[] = "484her";
35
36 constexpr char kWeakPassword1[] = "123456";
37 constexpr char kWeakPassword2[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda";
38 constexpr char kStrongPassword1[] = "fnlsr4@cm^mdls@fkspnsg3d";
39 constexpr char kStrongPassword2[] = "pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns";
40
41 using ::testing::ElementsAre;
42 using ::testing::ElementsAreArray;
43 using ::testing::IsEmpty;
44
45 // Delay in milliseconds.
46 const int kDelay = 2;
47
48 struct MockInsecureCredentialsManagerObserver
49 : InsecureCredentialsManager::Observer {
50 MOCK_METHOD(void,
51 OnCompromisedCredentialsChanged,
52 (InsecureCredentialsManager::CredentialsView),
53 (override));
54 MOCK_METHOD(void, OnWeakCredentialsChanged, (), (override));
55 };
56
57 using StrictMockInsecureCredentialsManagerObserver =
58 ::testing::StrictMock<MockInsecureCredentialsManagerObserver>;
59
MakeCompromised(base::StringPiece signon_realm,base::StringPiece username,CompromiseType type=CompromiseType::kLeaked)60 CompromisedCredentials MakeCompromised(
61 base::StringPiece signon_realm,
62 base::StringPiece username,
63 CompromiseType type = CompromiseType::kLeaked) {
64 return {.signon_realm = std::string(signon_realm),
65 .username = base::ASCIIToUTF16(username),
66 .compromise_type = type};
67 }
68
MakeSavedPassword(base::StringPiece signon_realm,base::StringPiece username,base::StringPiece password,base::StringPiece username_element="")69 PasswordForm MakeSavedPassword(base::StringPiece signon_realm,
70 base::StringPiece username,
71 base::StringPiece password,
72 base::StringPiece username_element = "") {
73 PasswordForm form;
74 form.signon_realm = std::string(signon_realm);
75 form.url = GURL(signon_realm);
76 form.username_value = base::ASCIIToUTF16(username);
77 form.password_value = base::ASCIIToUTF16(password);
78 form.username_element = base::ASCIIToUTF16(username_element);
79 return form;
80 }
81
MakeLeakCredential(base::StringPiece username,base::StringPiece password)82 LeakCheckCredential MakeLeakCredential(base::StringPiece username,
83 base::StringPiece password) {
84 return LeakCheckCredential(base::ASCIIToUTF16(username),
85 base::ASCIIToUTF16(password));
86 }
87
MakeCompromisedCredential(const PasswordForm & form,const CompromisedCredentials & credential)88 CredentialWithPassword MakeCompromisedCredential(
89 const PasswordForm& form,
90 const CompromisedCredentials& credential) {
91 CredentialWithPassword credential_with_password((CredentialView(form)));
92 credential_with_password.create_time = credential.create_time;
93 credential_with_password.insecure_type =
94 credential.compromise_type == CompromiseType::kLeaked
95 ? InsecureCredentialTypeFlags::kCredentialLeaked
96 : InsecureCredentialTypeFlags::kCredentialPhished;
97 return credential_with_password;
98 }
99
MakeWeakCredential(const PasswordForm & form)100 CredentialWithPassword MakeWeakCredential(const PasswordForm& form) {
101 CredentialWithPassword weak_credential{CredentialView(form)};
102 weak_credential.insecure_type = InsecureCredentialTypeFlags::kWeakCredential;
103 return weak_credential;
104 }
105
MakeWeakAndCompromisedCredential(const PasswordForm & form,const CompromisedCredentials & credential)106 CredentialWithPassword MakeWeakAndCompromisedCredential(
107 const PasswordForm& form,
108 const CompromisedCredentials& credential) {
109 CredentialWithPassword credential_with_password =
110 MakeCompromisedCredential(form, credential);
111 credential_with_password.insecure_type |=
112 InsecureCredentialTypeFlags::kWeakCredential;
113 return credential_with_password;
114 }
115
116 class InsecureCredentialsManagerTest : public ::testing::Test {
117 protected:
InsecureCredentialsManagerTest()118 InsecureCredentialsManagerTest() { store_->Init(/*prefs=*/nullptr); }
119
~InsecureCredentialsManagerTest()120 ~InsecureCredentialsManagerTest() override {
121 store_->ShutdownOnUIThread();
122 task_env_.RunUntilIdle();
123 }
124
store()125 TestPasswordStore& store() { return *store_; }
provider()126 InsecureCredentialsManager& provider() { return provider_; }
127
RunUntilIdle()128 void RunUntilIdle() { task_env_.RunUntilIdle(); }
129
130 // Returns saved password if it matches with |signon_realm| and |username|.
131 // Otherwise, returns an empty string, because the saved password should never
132 // be empty, unless it's a federated credential or "Never save" entry.
GetSavedPasswordForUsername(const std::string & signon_realm,const std::string & username)133 std::string GetSavedPasswordForUsername(const std::string& signon_realm,
134 const std::string& username) {
135 SavedPasswordsPresenter::SavedPasswordsView saved_passwords =
136 presenter_.GetSavedPasswords();
137 for (const auto& form : saved_passwords) {
138 if (form.signon_realm == signon_realm &&
139 form.username_value == base::UTF8ToUTF16(username)) {
140 return base::UTF16ToUTF8(form.password_value);
141 }
142 }
143 return std::string();
144 }
145
histogram_tester()146 base::HistogramTester& histogram_tester() { return histogram_tester_; }
147
AdvanceClock(base::TimeDelta time)148 void AdvanceClock(base::TimeDelta time) { task_env_.AdvanceClock(time); }
149
150 private:
151 base::test::TaskEnvironment task_env_{
152 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
153 base::HistogramTester histogram_tester_;
154 scoped_refptr<TestPasswordStore> store_ =
155 base::MakeRefCounted<TestPasswordStore>();
156 SavedPasswordsPresenter presenter_{store_};
157 InsecureCredentialsManager provider_{&presenter_, store_};
158 };
159
160 } // namespace
161
operator ==(const CredentialWithPassword & lhs,const CredentialWithPassword & rhs)162 bool operator==(const CredentialWithPassword& lhs,
163 const CredentialWithPassword& rhs) {
164 return lhs.signon_realm == rhs.signon_realm && lhs.username == rhs.username &&
165 lhs.create_time == rhs.create_time &&
166 lhs.insecure_type == rhs.insecure_type && lhs.password == rhs.password;
167 }
168
operator <<(std::ostream & out,const CredentialWithPassword & credential)169 std::ostream& operator<<(std::ostream& out,
170 const CredentialWithPassword& credential) {
171 return out << "{ signon_realm: " << credential.signon_realm
172 << ", username: " << credential.username
173 << ", create_time: " << credential.create_time
174 << ", compromise_type: "
175 << static_cast<int>(credential.insecure_type)
176 << ", password: " << credential.password << " }";
177 }
178
179 // Tests whether adding and removing an observer works as expected.
TEST_F(InsecureCredentialsManagerTest,NotifyObserversAboutCompromisedCredentialChanges)180 TEST_F(InsecureCredentialsManagerTest,
181 NotifyObserversAboutCompromisedCredentialChanges) {
182 std::vector<CompromisedCredentials> credentials = {
183 MakeCompromised(kExampleCom, kUsername1)};
184
185 StrictMockInsecureCredentialsManagerObserver observer;
186 provider().AddObserver(&observer);
187
188 // Adding a compromised credential should notify observers.
189 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
190 store().AddCompromisedCredentials(credentials[0]);
191 RunUntilIdle();
192 EXPECT_THAT(store().compromised_credentials(), ElementsAreArray(credentials));
193
194 // Adding the exact same credential should not result in a notification, as
195 // the database is not actually modified.
196 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0);
197 store().AddCompromisedCredentials(credentials[0]);
198 RunUntilIdle();
199
200 // Remove should notify, and observers should be passed an empty list.
201 EXPECT_CALL(observer, OnCompromisedCredentialsChanged(IsEmpty()));
202 store().RemoveCompromisedCredentials(
203 credentials[0].signon_realm, credentials[0].username,
204 RemoveCompromisedCredentialsReason::kRemove);
205 RunUntilIdle();
206 EXPECT_THAT(store().compromised_credentials(), IsEmpty());
207
208 // Similarly to repeated add, a repeated remove should not notify either.
209 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0);
210 store().RemoveCompromisedCredentials(
211 credentials[0].signon_realm, credentials[0].username,
212 RemoveCompromisedCredentialsReason::kRemove);
213 RunUntilIdle();
214
215 // After an observer is removed it should no longer receive notifications.
216 provider().RemoveObserver(&observer);
217 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0);
218 store().AddCompromisedCredentials(credentials[0]);
219 RunUntilIdle();
220 EXPECT_THAT(store().compromised_credentials(), ElementsAreArray(credentials));
221 }
222
223 // Tests removing a compromised credentials by compromise type triggers an
224 // observer works as expected.
TEST_F(InsecureCredentialsManagerTest,NotifyObserversAboutRemovingCompromisedCredentialsByCompromisedType)225 TEST_F(InsecureCredentialsManagerTest,
226 NotifyObserversAboutRemovingCompromisedCredentialsByCompromisedType) {
227 CompromisedCredentials phished_credentials =
228 MakeCompromised(kExampleCom, kUsername1, CompromiseType::kPhished);
229 CompromisedCredentials leaked_credentials =
230 MakeCompromised(kExampleCom, kUsername1, CompromiseType::kLeaked);
231
232 StrictMockInsecureCredentialsManagerObserver observer;
233 provider().AddObserver(&observer);
234 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
235 store().AddCompromisedCredentials(phished_credentials);
236 RunUntilIdle();
237 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
238 store().AddCompromisedCredentials(leaked_credentials);
239 RunUntilIdle();
240
241 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(1);
242 store().RemoveCompromisedCredentialsByCompromiseType(
243 phished_credentials.signon_realm, phished_credentials.username,
244 CompromiseType::kPhished, RemoveCompromisedCredentialsReason::kRemove);
245 RunUntilIdle();
246 EXPECT_THAT(store().compromised_credentials(),
247 ElementsAre(leaked_credentials));
248
249 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(1);
250 store().RemoveCompromisedCredentialsByCompromiseType(
251 leaked_credentials.signon_realm, leaked_credentials.username,
252 CompromiseType::kLeaked, RemoveCompromisedCredentialsReason::kRemove);
253 RunUntilIdle();
254 EXPECT_THAT(store().compromised_credentials(), IsEmpty());
255 provider().RemoveObserver(&observer);
256 }
257
258 // Tests whether adding and removing an observer works as expected.
TEST_F(InsecureCredentialsManagerTest,NotifyObserversAboutSavedPasswordsChanges)259 TEST_F(InsecureCredentialsManagerTest,
260 NotifyObserversAboutSavedPasswordsChanges) {
261 StrictMockInsecureCredentialsManagerObserver observer;
262 provider().AddObserver(&observer);
263
264 PasswordForm saved_password =
265 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
266
267 // Adding a saved password should notify observers.
268 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
269 EXPECT_CALL(observer, OnWeakCredentialsChanged);
270 store().AddLogin(saved_password);
271 RunUntilIdle();
272
273 // Updating a saved password should notify observers.
274 saved_password.password_value = base::ASCIIToUTF16(kPassword2);
275 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
276 EXPECT_CALL(observer, OnWeakCredentialsChanged);
277 store().UpdateLogin(saved_password);
278 RunUntilIdle();
279
280 // Removing a saved password should notify observers.
281 EXPECT_CALL(observer, OnCompromisedCredentialsChanged);
282 EXPECT_CALL(observer, OnWeakCredentialsChanged);
283 store().RemoveLogin(saved_password);
284 RunUntilIdle();
285
286 // After an observer is removed it should no longer receive notifications.
287 provider().RemoveObserver(&observer);
288 EXPECT_CALL(observer, OnCompromisedCredentialsChanged).Times(0);
289 EXPECT_CALL(observer, OnWeakCredentialsChanged).Times(0);
290 store().AddLogin(saved_password);
291 RunUntilIdle();
292 }
293
294 // Tests that the provider is able to join a single password with a compromised
295 // credential.
TEST_F(InsecureCredentialsManagerTest,JoinSingleCredentials)296 TEST_F(InsecureCredentialsManagerTest, JoinSingleCredentials) {
297 PasswordForm password =
298 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
299 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
300
301 store().AddLogin(password);
302 store().AddCompromisedCredentials(credential);
303 RunUntilIdle();
304
305 CredentialWithPassword expected =
306 MakeCompromisedCredential(password, credential);
307 expected.password = password.password_value;
308 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
309 }
310
311 // Tests that the provider is able to join a password with a credential that was
312 // compromised in multiple ways.
TEST_F(InsecureCredentialsManagerTest,JoinPhishedAndLeaked)313 TEST_F(InsecureCredentialsManagerTest, JoinPhishedAndLeaked) {
314 PasswordForm password =
315 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
316 CompromisedCredentials leaked =
317 MakeCompromised(kExampleCom, kUsername1, CompromiseType::kLeaked);
318 CompromisedCredentials phished =
319 MakeCompromised(kExampleCom, kUsername1, CompromiseType::kPhished);
320
321 store().AddLogin(password);
322 store().AddCompromisedCredentials(leaked);
323 store().AddCompromisedCredentials(phished);
324 RunUntilIdle();
325
326 CredentialWithPassword expected = MakeCompromisedCredential(password, leaked);
327 expected.password = password.password_value;
328 expected.insecure_type = (InsecureCredentialTypeFlags::kCredentialLeaked |
329 InsecureCredentialTypeFlags::kCredentialPhished);
330
331 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
332 }
333
334 // Tests that the provider reacts whenever the saved passwords or the
335 // compromised credentials change.
TEST_F(InsecureCredentialsManagerTest,ReactToChangesInBothTables)336 TEST_F(InsecureCredentialsManagerTest, ReactToChangesInBothTables) {
337 std::vector<PasswordForm> passwords = {
338 MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
339 MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
340
341 std::vector<CompromisedCredentials> credentials = {
342 MakeCompromised(kExampleCom, kUsername1),
343 MakeCompromised(kExampleCom, kUsername2)};
344
345 std::vector<CredentialWithPassword> expected = {
346 MakeCompromisedCredential(passwords[0], credentials[0]),
347 MakeCompromisedCredential(passwords[1], credentials[1])};
348
349 store().AddLogin(passwords[0]);
350 RunUntilIdle();
351 EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
352
353 store().AddCompromisedCredentials(credentials[0]);
354 RunUntilIdle();
355 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected[0]));
356
357 store().AddLogin(passwords[1]);
358 RunUntilIdle();
359 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected[0]));
360
361 store().AddCompromisedCredentials(credentials[1]);
362 RunUntilIdle();
363 EXPECT_THAT(provider().GetCompromisedCredentials(),
364 ElementsAreArray(expected));
365
366 store().RemoveLogin(passwords[0]);
367 RunUntilIdle();
368 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected[1]));
369
370 store().RemoveLogin(passwords[1]);
371 RunUntilIdle();
372 EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
373 }
374
375 // Tests that the provider is able to join multiple passwords with compromised
376 // credentials.
TEST_F(InsecureCredentialsManagerTest,JoinMultipleCredentials)377 TEST_F(InsecureCredentialsManagerTest, JoinMultipleCredentials) {
378 std::vector<PasswordForm> passwords = {
379 MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
380 MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
381
382 std::vector<CompromisedCredentials> credentials = {
383 MakeCompromised(kExampleCom, kUsername1),
384 MakeCompromised(kExampleCom, kUsername2)};
385
386 store().AddLogin(passwords[0]);
387 store().AddLogin(passwords[1]);
388 store().AddCompromisedCredentials(credentials[0]);
389 store().AddCompromisedCredentials(credentials[1]);
390 RunUntilIdle();
391
392 CredentialWithPassword expected1 =
393 MakeCompromisedCredential(passwords[0], credentials[0]);
394 CredentialWithPassword expected2 =
395 MakeCompromisedCredential(passwords[1], credentials[1]);
396
397 EXPECT_THAT(provider().GetCompromisedCredentials(),
398 ElementsAre(expected1, expected2));
399 }
400
401 // Tests that joining a compromised credential with saved passwords with a
402 // different username results in an empty list.
TEST_F(InsecureCredentialsManagerTest,JoinWitDifferentUsername)403 TEST_F(InsecureCredentialsManagerTest, JoinWitDifferentUsername) {
404 std::vector<PasswordForm> passwords = {
405 MakeSavedPassword(kExampleCom, kUsername2, kPassword1),
406 MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
407
408 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
409
410 store().AddLogin(passwords[0]);
411 store().AddLogin(passwords[1]);
412 store().AddCompromisedCredentials(credential);
413 RunUntilIdle();
414
415 EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
416 }
417
418 // Tests that joining a compromised credential with saved passwords with a
419 // matching username but different signon_realm results in an empty list.
TEST_F(InsecureCredentialsManagerTest,JoinWitDifferentSignonRealm)420 TEST_F(InsecureCredentialsManagerTest, JoinWitDifferentSignonRealm) {
421 std::vector<PasswordForm> passwords = {
422 MakeSavedPassword(kExampleOrg, kUsername1, kPassword1),
423 MakeSavedPassword(kExampleOrg, kUsername1, kPassword2)};
424
425 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
426
427 store().AddLogin(passwords[0]);
428 store().AddLogin(passwords[1]);
429 store().AddCompromisedCredentials(credential);
430 RunUntilIdle();
431
432 EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
433 }
434
435 // Tests that joining a compromised credential with multiple saved passwords for
436 // the same signon_realm and username combination results in multiple entries
437 // when the passwords are distinct.
TEST_F(InsecureCredentialsManagerTest,JoinWithMultipleDistinctPasswords)438 TEST_F(InsecureCredentialsManagerTest, JoinWithMultipleDistinctPasswords) {
439 std::vector<PasswordForm> passwords = {
440 MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
441 MakeSavedPassword(kExampleCom, kUsername1, kPassword2, "element_2")};
442
443 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
444
445 store().AddLogin(passwords[0]);
446 store().AddLogin(passwords[1]);
447 store().AddCompromisedCredentials(credential);
448 RunUntilIdle();
449
450 CredentialWithPassword expected1 =
451 MakeCompromisedCredential(passwords[0], credential);
452 CredentialWithPassword expected2 =
453 MakeCompromisedCredential(passwords[1], credential);
454
455 EXPECT_THAT(provider().GetCompromisedCredentials(),
456 ElementsAre(expected1, expected2));
457 }
458
459 // Tests that joining a compromised credential with multiple saved passwords for
460 // the same signon_realm and username combination results in a single entry
461 // when the passwords are the same.
TEST_F(InsecureCredentialsManagerTest,JoinWithMultipleRepeatedPasswords)462 TEST_F(InsecureCredentialsManagerTest, JoinWithMultipleRepeatedPasswords) {
463 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
464 std::vector<PasswordForm> passwords = {
465 MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
466 MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_2")};
467
468 store().AddLogin(passwords[0]);
469 store().AddLogin(passwords[1]);
470 store().AddCompromisedCredentials(credential);
471 RunUntilIdle();
472
473 CredentialWithPassword expected =
474 MakeCompromisedCredential(passwords[0], credential);
475
476 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
477 }
478
479 // Tests that verifies mapping compromised credentials to passwords works
480 // correctly.
TEST_F(InsecureCredentialsManagerTest,MapCompromisedPasswordsToPasswords)481 TEST_F(InsecureCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
482 std::vector<PasswordForm> passwords = {
483 MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
484 MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_2"),
485 MakeSavedPassword(kExampleOrg, kUsername2, kPassword2)};
486
487 std::vector<CompromisedCredentials> credentials = {
488 MakeCompromised(kExampleCom, kUsername1),
489 MakeCompromised(kExampleOrg, kUsername2)};
490
491 std::vector<CredentialWithPassword> credentials_with_password = {
492 MakeCompromisedCredential(passwords[0], credentials[0]),
493 MakeCompromisedCredential(passwords[1], credentials[0]),
494 MakeCompromisedCredential(passwords[2], credentials[1])};
495
496 store().AddLogin(passwords[0]);
497 store().AddLogin(passwords[1]);
498 store().AddLogin(passwords[2]);
499 store().AddCompromisedCredentials(credentials[0]);
500 store().AddCompromisedCredentials(credentials[1]);
501
502 RunUntilIdle();
503 EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[0]),
504 ElementsAreArray(store().stored_passwords().at(kExampleCom)));
505
506 EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[1]),
507 ElementsAreArray(store().stored_passwords().at(kExampleCom)));
508
509 EXPECT_THAT(provider().GetSavedPasswordsFor(credentials_with_password[2]),
510 ElementsAreArray(store().stored_passwords().at(kExampleOrg)));
511 }
512
TEST_F(InsecureCredentialsManagerTest,StartWeakCheckNotifiesOnCompletion)513 TEST_F(InsecureCredentialsManagerTest, StartWeakCheckNotifiesOnCompletion) {
514 base::MockOnceClosure closure;
515 provider().StartWeakCheck(closure.Get());
516 EXPECT_CALL(closure, Run);
517 RunUntilIdle();
518 }
519
TEST_F(InsecureCredentialsManagerTest,StartWeakCheckOnEmptyPasswordsList)520 TEST_F(InsecureCredentialsManagerTest, StartWeakCheckOnEmptyPasswordsList) {
521 EXPECT_THAT(
522 histogram_tester().GetTotalCountsForPrefix("PasswordManager.WeakCheck"),
523 IsEmpty());
524
525 RunUntilIdle();
526 provider().StartWeakCheck();
527 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
528 RunUntilIdle();
529
530 EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty());
531
532 histogram_tester().ExpectUniqueSample(
533 "PasswordManager.WeakCheck.CheckedPasswords", 0, 1);
534 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
535 kDelay, 1);
536 histogram_tester().ExpectUniqueSample(
537 "PasswordManager.WeakCheck.WeakPasswords", 0, 1);
538 }
539
TEST_F(InsecureCredentialsManagerTest,WeakCredentialsNotFound)540 TEST_F(InsecureCredentialsManagerTest, WeakCredentialsNotFound) {
541 std::vector<PasswordForm> passwords = {
542 MakeSavedPassword(kExampleCom, kUsername1, kStrongPassword1),
543 MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword2)};
544
545 store().AddLogin(passwords[0]);
546 store().AddLogin(passwords[1]);
547 EXPECT_THAT(
548 histogram_tester().GetTotalCountsForPrefix("PasswordManager.WeakCheck"),
549 IsEmpty());
550
551 RunUntilIdle();
552 provider().StartWeakCheck();
553 AdvanceClock(base::TimeDelta::FromMilliseconds(2 * kDelay));
554 RunUntilIdle();
555
556 EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty());
557
558 histogram_tester().ExpectUniqueSample(
559 "PasswordManager.WeakCheck.CheckedPasswords", 2, 1);
560 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
561 2 * kDelay, 1);
562 histogram_tester().ExpectUniqueSample(
563 "PasswordManager.WeakCheck.WeakPasswords", 0, 1);
564 histogram_tester().ExpectUniqueSample(
565 "PasswordManager.WeakCheck.PasswordScore", 4, 2);
566 }
567
TEST_F(InsecureCredentialsManagerTest,DetectedWeakCredential)568 TEST_F(InsecureCredentialsManagerTest, DetectedWeakCredential) {
569 std::vector<PasswordForm> passwords = {
570 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1),
571 MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword1)};
572
573 store().AddLogin(passwords[0]);
574 store().AddLogin(passwords[1]);
575 EXPECT_THAT(
576 histogram_tester().GetTotalCountsForPrefix("PasswordManager.WeakCheck"),
577 IsEmpty());
578
579 RunUntilIdle();
580 provider().StartWeakCheck();
581 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
582 RunUntilIdle();
583
584 std::vector<CredentialWithPassword> weak_credentials =
585 provider().GetWeakCredentials();
586
587 ASSERT_EQ(weak_credentials.size(), 1u);
588 EXPECT_EQ(base::UTF16ToUTF8(weak_credentials[0].password), kWeakPassword1);
589 EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
590
591 histogram_tester().ExpectUniqueSample(
592 "PasswordManager.WeakCheck.CheckedPasswords", 2, 1);
593 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
594 kDelay, 1);
595 histogram_tester().ExpectUniqueSample(
596 "PasswordManager.WeakCheck.WeakPasswords", 1, 1);
597 histogram_tester().ExpectTotalCount("PasswordManager.WeakCheck.PasswordScore",
598 2);
599 }
600
601 // Tests that credentials with the same signon_realm and username, but different
602 // passwords will be both returned by GetWeakCredentials().
TEST_F(InsecureCredentialsManagerTest,FindBothWeakCredentialsWithDifferentPasswords)603 TEST_F(InsecureCredentialsManagerTest,
604 FindBothWeakCredentialsWithDifferentPasswords) {
605 std::vector<PasswordForm> passwords = {
606 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_1"),
607 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword2, "element_2")};
608
609 store().AddLogin(passwords[0]);
610 store().AddLogin(passwords[1]);
611
612 RunUntilIdle();
613 provider().StartWeakCheck();
614 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
615 RunUntilIdle();
616
617 std::vector<CredentialWithPassword> weak_credentials =
618 provider().GetWeakCredentials();
619
620 ASSERT_EQ(weak_credentials.size(), 2u);
621 EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
622 EXPECT_TRUE(IsWeak(weak_credentials[1].insecure_type));
623
624 histogram_tester().ExpectUniqueSample(
625 "PasswordManager.WeakCheck.CheckedPasswords", 2, 1);
626 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
627 kDelay, 1);
628 histogram_tester().ExpectUniqueSample(
629 "PasswordManager.WeakCheck.WeakPasswords", 2, 1);
630 histogram_tester().ExpectTotalCount("PasswordManager.WeakCheck.PasswordScore",
631 2);
632 }
633
634 // Tests that credentials with the same signon_realm, username and passwords
635 // will be joind and GetWeakCredentials() will return one credential.
TEST_F(InsecureCredentialsManagerTest,JoinWeakCredentialsWithTheSamePasswords)636 TEST_F(InsecureCredentialsManagerTest,
637 JoinWeakCredentialsWithTheSamePasswords) {
638 std::vector<PasswordForm> passwords = {
639 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_1"),
640 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_2")};
641
642 store().AddLogin(passwords[0]);
643 store().AddLogin(passwords[1]);
644
645 RunUntilIdle();
646 provider().StartWeakCheck();
647 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
648 RunUntilIdle();
649
650 std::vector<CredentialWithPassword> weak_credentials =
651 provider().GetWeakCredentials();
652
653 ASSERT_EQ(weak_credentials.size(), 1u);
654 EXPECT_EQ(base::UTF16ToUTF8(weak_credentials[0].password), kWeakPassword1);
655 EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
656
657 histogram_tester().ExpectUniqueSample(
658 "PasswordManager.WeakCheck.CheckedPasswords", 1, 1);
659 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
660 kDelay, 1);
661 histogram_tester().ExpectUniqueSample(
662 "PasswordManager.WeakCheck.WeakPasswords", 1, 1);
663 histogram_tester().ExpectUniqueSample(
664 "PasswordManager.WeakCheck.PasswordScore", 0, 1);
665 }
666
TEST_F(InsecureCredentialsManagerTest,BothWeakAndCompromisedCredentialsExist)667 TEST_F(InsecureCredentialsManagerTest, BothWeakAndCompromisedCredentialsExist) {
668 std::vector<PasswordForm> passwords = {
669 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1),
670 MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword1)};
671 std::vector<CompromisedCredentials> compromised_credentials = {
672 MakeCompromised(kExampleCom, kUsername1),
673 MakeCompromised(kExampleCom, kUsername2)};
674
675 store().AddLogin(passwords[0]);
676 store().AddLogin(passwords[1]);
677 store().AddCompromisedCredentials(compromised_credentials[0]);
678 store().AddCompromisedCredentials(compromised_credentials[1]);
679
680 RunUntilIdle();
681 provider().StartWeakCheck();
682 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
683 RunUntilIdle();
684
685 std::vector<CredentialWithPassword> returned_weak_credentials =
686 provider().GetWeakCredentials();
687 std::vector<CredentialWithPassword> returned_compromised_credentials =
688 provider().GetCompromisedCredentials();
689
690 ASSERT_EQ(returned_weak_credentials.size(), 1u);
691 EXPECT_EQ(base::UTF16ToUTF8(returned_weak_credentials[0].password),
692 kWeakPassword1);
693 EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type));
694
695 ASSERT_EQ(returned_compromised_credentials.size(), 2u);
696 EXPECT_TRUE(IsCompromised(returned_compromised_credentials[0].insecure_type));
697 EXPECT_TRUE(IsCompromised(returned_compromised_credentials[1].insecure_type));
698
699 histogram_tester().ExpectUniqueSample(
700 "PasswordManager.WeakCheck.CheckedPasswords", 2, 1);
701 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
702 kDelay, 1);
703 histogram_tester().ExpectUniqueSample(
704 "PasswordManager.WeakCheck.WeakPasswords", 1, 1);
705 histogram_tester().ExpectTotalCount("PasswordManager.WeakCheck.PasswordScore",
706 2);
707 }
708
709 // Checks that for a credential that is both weak and compromised,
710 // getWeakCredentials and GetCompromisedCredentials will return this credential
711 // in one instance.
TEST_F(InsecureCredentialsManagerTest,SingleCredentialIsWeakAndCompromised)712 TEST_F(InsecureCredentialsManagerTest, SingleCredentialIsWeakAndCompromised) {
713 std::vector<PasswordForm> passwords = {
714 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1)};
715 std::vector<CompromisedCredentials> compromised_credentials = {
716 MakeCompromised(kExampleCom, kUsername1)};
717
718 store().AddLogin(passwords[0]);
719 store().AddCompromisedCredentials(compromised_credentials[0]);
720
721 RunUntilIdle();
722 provider().StartWeakCheck();
723 AdvanceClock(base::TimeDelta::FromMilliseconds(kDelay));
724 RunUntilIdle();
725
726 std::vector<CredentialWithPassword> returned_weak_credentials =
727 provider().GetWeakCredentials();
728 std::vector<CredentialWithPassword> returned_compromised_credentials =
729 provider().GetCompromisedCredentials();
730
731 // Since the credential is weak and compromised, the |insecure_type| should be
732 // weak and compromised for elements from |returned_weak_credentials| and
733 // |returned_compromised_credentials|.
734 ASSERT_EQ(returned_weak_credentials.size(), 1u);
735 EXPECT_EQ(base::UTF16ToUTF8(returned_weak_credentials[0].password),
736 kWeakPassword1);
737 EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type));
738 EXPECT_TRUE(IsCompromised(returned_weak_credentials[0].insecure_type));
739
740 ASSERT_EQ(returned_compromised_credentials.size(), 1u);
741 EXPECT_EQ(base::UTF16ToUTF8(returned_compromised_credentials[0].password),
742 kWeakPassword1);
743 EXPECT_TRUE(IsWeak(returned_compromised_credentials[0].insecure_type));
744 EXPECT_TRUE(IsCompromised(returned_compromised_credentials[0].insecure_type));
745
746 histogram_tester().ExpectUniqueSample(
747 "PasswordManager.WeakCheck.CheckedPasswords", 1, 1);
748 histogram_tester().ExpectUniqueSample("PasswordManager.WeakCheck.Time",
749 kDelay, 1);
750 histogram_tester().ExpectUniqueSample(
751 "PasswordManager.WeakCheck.WeakPasswords", 1, 1);
752 histogram_tester().ExpectUniqueSample(
753 "PasswordManager.WeakCheck.PasswordScore", 0, 1);
754 }
755
756 // Test verifies that saving LeakCheckCredential via provider adds expected
757 // compromised credential.
TEST_F(InsecureCredentialsManagerTest,SaveCompromisedPassword)758 TEST_F(InsecureCredentialsManagerTest, SaveCompromisedPassword) {
759 PasswordForm password_form =
760 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
761 LeakCheckCredential credential = MakeLeakCredential(kUsername1, kPassword1);
762 CompromisedCredentials compromised_credential =
763 MakeCompromised(kExampleCom, kUsername1);
764
765 store().AddLogin(password_form);
766 RunUntilIdle();
767
768 CredentialWithPassword expected =
769 MakeCompromisedCredential(password_form, compromised_credential);
770 expected.create_time = base::Time::Now();
771
772 provider().SaveCompromisedCredential(credential);
773 RunUntilIdle();
774
775 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
776 }
777
778 // Test verifies that editing Compromised Credential via provider change the
779 // original password form.
TEST_F(InsecureCredentialsManagerTest,UpdateCompromisedPassword)780 TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
781 PasswordForm password_form =
782 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
783 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
784
785 store().AddLogin(password_form);
786 store().AddCompromisedCredentials(credential);
787
788 RunUntilIdle();
789 CredentialWithPassword expected =
790 #if !defined(OS_ANDROID) && !defined(OS_IOS)
791 MakeWeakAndCompromisedCredential(password_form, credential);
792 #else
793 MakeCompromisedCredential(password_form, credential);
794 #endif
795
796 EXPECT_TRUE(provider().UpdateCredential(expected, kPassword2));
797 RunUntilIdle();
798 expected.password = base::UTF8ToUTF16(kPassword2);
799
800 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
801 }
802
803 // Test verifies that editing weak credential via provider has affect on weak
804 // credentials and updates password in the store.
TEST_F(InsecureCredentialsManagerTest,UpdateWeakPassword)805 TEST_F(InsecureCredentialsManagerTest, UpdateWeakPassword) {
806 PasswordForm password_form =
807 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
808
809 store().AddLogin(password_form);
810 RunUntilIdle();
811 provider().StartWeakCheck();
812 RunUntilIdle();
813
814 EXPECT_EQ(provider().GetWeakCredentials().size(), 1u);
815 EXPECT_TRUE(provider().UpdateCredential(CredentialView(password_form),
816 kStrongPassword1));
817 RunUntilIdle();
818
819 EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty());
820 EXPECT_EQ(GetSavedPasswordForUsername(kExampleCom, kUsername1),
821 kStrongPassword1);
822 }
823
824 #if !defined(OS_ANDROID) && !defined(OS_IOS)
825 // Test verifies that editing a weak credential to another weak credential
826 // continues to be treated weak.
TEST_F(InsecureCredentialsManagerTest,UpdatedWeakPasswordRemainsWeak)827 TEST_F(InsecureCredentialsManagerTest, UpdatedWeakPasswordRemainsWeak) {
828 PasswordForm password_form =
829 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
830
831 store().AddLogin(password_form);
832 RunUntilIdle();
833
834 provider().StartWeakCheck();
835 RunUntilIdle();
836
837 CredentialWithPassword expected = MakeWeakCredential(password_form);
838 EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
839
840 EXPECT_TRUE(provider().UpdateCredential(expected, kWeakPassword2));
841 RunUntilIdle();
842
843 expected.password = base::ASCIIToUTF16(kWeakPassword2);
844 EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
845 }
846 #endif
847
848 // Test verifies that editing credential that is weak and compromised via
849 // provider change the saved password.
TEST_F(InsecureCredentialsManagerTest,UpdateInsecurePassword)850 TEST_F(InsecureCredentialsManagerTest, UpdateInsecurePassword) {
851 PasswordForm password_form =
852 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
853 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
854
855 store().AddLogin(password_form);
856 store().AddCompromisedCredentials(credential);
857 RunUntilIdle();
858 provider().StartWeakCheck();
859 RunUntilIdle();
860
861 CredentialWithPassword expected =
862 MakeWeakAndCompromisedCredential(password_form, credential);
863 EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
864 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
865
866 EXPECT_TRUE(provider().UpdateCredential(expected, kStrongPassword1));
867 RunUntilIdle();
868
869 EXPECT_EQ(GetSavedPasswordForUsername(kExampleCom, kUsername1),
870 kStrongPassword1);
871 }
872
TEST_F(InsecureCredentialsManagerTest,RemoveCompromisedCredential)873 TEST_F(InsecureCredentialsManagerTest, RemoveCompromisedCredential) {
874 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
875 PasswordForm password =
876 MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
877
878 store().AddLogin(password);
879 store().AddCompromisedCredentials(credential);
880 RunUntilIdle();
881
882 CredentialWithPassword expected =
883 MakeCompromisedCredential(password, credential);
884 expected.password = password.password_value;
885
886 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
887
888 EXPECT_TRUE(provider().RemoveCredential(expected));
889 RunUntilIdle();
890 EXPECT_THAT(provider().GetCompromisedCredentials(), IsEmpty());
891 }
892
TEST_F(InsecureCredentialsManagerTest,RemoveWeakCredential)893 TEST_F(InsecureCredentialsManagerTest, RemoveWeakCredential) {
894 PasswordForm password =
895 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
896
897 store().AddLogin(password);
898 RunUntilIdle();
899 provider().StartWeakCheck();
900 RunUntilIdle();
901
902 EXPECT_EQ(provider().GetWeakCredentials().size(), 1u);
903 EXPECT_TRUE(provider().RemoveCredential(CredentialView(password)));
904 RunUntilIdle();
905 EXPECT_THAT(GetSavedPasswordForUsername(kExampleCom, kUsername1), IsEmpty());
906 }
907
TEST_F(InsecureCredentialsManagerTest,RemoveInsecureCredential)908 TEST_F(InsecureCredentialsManagerTest, RemoveInsecureCredential) {
909 PasswordForm password_form =
910 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
911 CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
912
913 store().AddLogin(password_form);
914 store().AddCompromisedCredentials(credential);
915 RunUntilIdle();
916 provider().StartWeakCheck();
917 RunUntilIdle();
918
919 CredentialWithPassword expected =
920 MakeWeakAndCompromisedCredential(password_form, credential);
921 EXPECT_THAT(provider().GetWeakCredentials(), ElementsAre(expected));
922 EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
923
924 EXPECT_TRUE(provider().RemoveCredential(expected));
925 RunUntilIdle();
926 EXPECT_THAT(GetSavedPasswordForUsername(kExampleCom, kUsername1), IsEmpty());
927 }
928
929 // Verifues that GetWeakCredentials() returns sorted weak credentials by using
930 // CreateSortKey.
TEST_F(InsecureCredentialsManagerTest,GetWeakCredentialsReturnsSortedData)931 TEST_F(InsecureCredentialsManagerTest, GetWeakCredentialsReturnsSortedData) {
932 const std::vector<PasswordForm> password_forms = {
933 MakeSavedPassword("http://example-a.com", "user_a1", "pwd"),
934 MakeSavedPassword("http://example-a.com", "user_a2", "pwd"),
935 MakeSavedPassword("http://example-b.com", "user_a", "pwd"),
936 MakeSavedPassword("http://example-c.com", "user_a", "pwd")};
937 store().AddLogin(password_forms[0]);
938 store().AddLogin(password_forms[1]);
939 store().AddLogin(password_forms[2]);
940 store().AddLogin(password_forms[3]);
941 RunUntilIdle();
942
943 provider().StartWeakCheck();
944 RunUntilIdle();
945
946 EXPECT_THAT(provider().GetWeakCredentials(),
947 ElementsAre(MakeWeakCredential(password_forms[0]),
948 MakeWeakCredential(password_forms[1]),
949 MakeWeakCredential(password_forms[2]),
950 MakeWeakCredential(password_forms[3])));
951 }
952
953 namespace {
954 class InsecureCredentialsManagerWithTwoStoresTest : public ::testing::Test {
955 protected:
InsecureCredentialsManagerWithTwoStoresTest()956 InsecureCredentialsManagerWithTwoStoresTest() {
957 profile_store_->Init(/*prefs=*/nullptr);
958 account_store_->Init(/*prefs=*/nullptr);
959 }
960
~InsecureCredentialsManagerWithTwoStoresTest()961 ~InsecureCredentialsManagerWithTwoStoresTest() override {
962 account_store_->ShutdownOnUIThread();
963 profile_store_->ShutdownOnUIThread();
964 task_env_.RunUntilIdle();
965 }
966
profile_store()967 TestPasswordStore& profile_store() { return *profile_store_; }
account_store()968 TestPasswordStore& account_store() { return *account_store_; }
provider()969 InsecureCredentialsManager& provider() { return provider_; }
970
RunUntilIdle()971 void RunUntilIdle() { task_env_.RunUntilIdle(); }
972
973 private:
974 base::test::TaskEnvironment task_env_;
975 scoped_refptr<TestPasswordStore> profile_store_ =
976 base::MakeRefCounted<TestPasswordStore>(IsAccountStore(false));
977 scoped_refptr<TestPasswordStore> account_store_ =
978 base::MakeRefCounted<TestPasswordStore>(IsAccountStore(true));
979 SavedPasswordsPresenter presenter_{profile_store_, account_store_};
980 InsecureCredentialsManager provider_{&presenter_, profile_store_,
981 account_store_};
982 };
983 } // namespace
984
985 // Tests that verifies mapping compromised credentials to passwords works
986 // correctly.
TEST_F(InsecureCredentialsManagerWithTwoStoresTest,MapCompromisedPasswordsToPasswords)987 TEST_F(InsecureCredentialsManagerWithTwoStoresTest,
988 MapCompromisedPasswordsToPasswords) {
989 // Add credentials for both `kExampleCom` and `kExampleOrg` in both stores
990 // with the same username and difference passwords. For `kUsername1`, the
991 // `kPassword1` are `kPassword2` are compromised while
992 // `kPassword3` is safe.
993 std::vector<PasswordForm> profile_store_passwords = {
994 MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
995 MakeSavedPassword(kExampleOrg, kUsername1, kPassword3)};
996 for (const PasswordForm& profile_password : profile_store_passwords)
997 profile_store().AddLogin(profile_password);
998
999 std::vector<PasswordForm> account_store_passwords = {
1000 MakeSavedPassword(kExampleCom, kUsername1, kPassword3),
1001 MakeSavedPassword(kExampleOrg, kUsername1, kPassword2)};
1002 for (const PasswordForm& account_password : account_store_passwords)
1003 account_store().AddLogin(account_password);
1004
1005 // Mark `kPassword1` to be compromised in the profile store, and `kPassword2`
1006 // to be compromised in the account store.
1007 profile_store().AddCompromisedCredentials(
1008 MakeCompromised(kExampleCom, kUsername1));
1009 account_store().AddCompromisedCredentials(
1010 MakeCompromised(kExampleOrg, kUsername1));
1011
1012 RunUntilIdle();
1013
1014 // Each password should be joined only with compromised credential from
1015 // their store.
1016 EXPECT_THAT(
1017 provider().GetSavedPasswordsFor(
1018 CredentialView(kExampleCom, GURL(), base::ASCIIToUTF16(kUsername1),
1019 base::ASCIIToUTF16(kPassword1))),
1020 ElementsAreArray(profile_store().stored_passwords().at(kExampleCom)));
1021
1022 EXPECT_THAT(provider().GetSavedPasswordsFor(CredentialView(
1023 kExampleOrg, GURL(), base::ASCIIToUTF16(kUsername1),
1024 base::ASCIIToUTF16(kPassword3))),
1025 IsEmpty());
1026
1027 EXPECT_THAT(provider().GetSavedPasswordsFor(CredentialView(
1028 kExampleCom, GURL(), base::ASCIIToUTF16(kUsername1),
1029 base::ASCIIToUTF16(kPassword3))),
1030 IsEmpty());
1031
1032 EXPECT_THAT(
1033 provider().GetSavedPasswordsFor(
1034 CredentialView(kExampleOrg, GURL(), base::ASCIIToUTF16(kUsername1),
1035 base::ASCIIToUTF16(kPassword2))),
1036 ElementsAreArray(account_store().stored_passwords().at(kExampleOrg)));
1037 }
1038
1039 // Test verifies that saving LeakCheckCredential via provider adds expected
1040 // compromised credential to the correct store.
TEST_F(InsecureCredentialsManagerWithTwoStoresTest,SaveCompromisedPassword)1041 TEST_F(InsecureCredentialsManagerWithTwoStoresTest, SaveCompromisedPassword) {
1042 ASSERT_TRUE(profile_store().compromised_credentials().empty());
1043 ASSERT_TRUE(account_store().compromised_credentials().empty());
1044 // Add `kUsername1`,`kPassword1` to both stores.
1045 // And add `kUsername1`,`kPassword2` to the account store only.
1046 profile_store().AddLogin(
1047 MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
1048
1049 account_store().AddLogin(
1050 MakeSavedPassword(kExampleOrg, kUsername1, kPassword1));
1051 account_store().AddLogin(
1052 MakeSavedPassword(kExampleCom, kUsername1, kPassword2));
1053
1054 RunUntilIdle();
1055
1056 // Mark `kUsername1`, `kPassword1` as compromised, a new entry should be
1057 // added to both stores.
1058 provider().SaveCompromisedCredential(
1059 MakeLeakCredential(kUsername1, kPassword1));
1060 RunUntilIdle();
1061
1062 EXPECT_EQ(1U, profile_store().compromised_credentials().size());
1063 EXPECT_EQ(1U, account_store().compromised_credentials().size());
1064
1065 // Now, mark `kUsername1`, `kPassword2` as compromised, a new entry should be
1066 // added only to the account store.
1067 provider().SaveCompromisedCredential(
1068 MakeLeakCredential(kUsername1, kPassword2));
1069 RunUntilIdle();
1070
1071 EXPECT_EQ(1U, profile_store().compromised_credentials().size());
1072 EXPECT_EQ(2U, account_store().compromised_credentials().size());
1073 }
1074
TEST_F(InsecureCredentialsManagerWithTwoStoresTest,RemoveCompromisedCredential)1075 TEST_F(InsecureCredentialsManagerWithTwoStoresTest,
1076 RemoveCompromisedCredential) {
1077 // Add `kUsername1`,`kPassword1` to both stores.
1078 profile_store().AddLogin(
1079 MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
1080 account_store().AddLogin(
1081 MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
1082
1083 // Mark `kUsername1` and `kPassword1` to be compromised in both stores.
1084 profile_store().AddCompromisedCredentials(
1085 MakeCompromised(kExampleCom, kUsername1));
1086 account_store().AddCompromisedCredentials(
1087 MakeCompromised(kExampleCom, kUsername1));
1088 RunUntilIdle();
1089
1090 // Now remove the compromised credentials
1091 EXPECT_TRUE(provider().RemoveCredential(
1092 CredentialView(kExampleCom, GURL(), base::ASCIIToUTF16(kUsername1),
1093 base::ASCIIToUTF16(kPassword1))));
1094 RunUntilIdle();
1095
1096 // It should have been removed from both stores.
1097 EXPECT_TRUE(profile_store().stored_passwords().at(kExampleCom).empty());
1098 EXPECT_TRUE(account_store().stored_passwords().at(kExampleCom).empty());
1099 }
1100
TEST_F(InsecureCredentialsManagerWithTwoStoresTest,RemoveWeakCredential)1101 TEST_F(InsecureCredentialsManagerWithTwoStoresTest, RemoveWeakCredential) {
1102 // Add `kUsername1`,`kPassword1` to both stores.
1103 profile_store().AddLogin(
1104 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
1105 account_store().AddLogin(
1106 MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
1107 RunUntilIdle();
1108 provider().StartWeakCheck();
1109 RunUntilIdle();
1110
1111 // Now remove the weak credential
1112 EXPECT_TRUE(provider().RemoveCredential(
1113 CredentialView(kExampleCom, GURL(), base::ASCIIToUTF16(kUsername1),
1114 base::ASCIIToUTF16(kWeakPassword1))));
1115 RunUntilIdle();
1116
1117 // It should have been removed from both stores.
1118 EXPECT_THAT(profile_store().stored_passwords().at(kExampleCom), IsEmpty());
1119 EXPECT_THAT(account_store().stored_passwords().at(kExampleCom), IsEmpty());
1120 }
1121
1122 } // namespace password_manager
1123