1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include <limits>
8 #include <tuple>
9
10 #include "base/guid.h"
11 #include "base/hash/hash.h"
12 #include "base/macros.h"
13 #include "base/rand_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/metrics/histogram_tester.h"
16 #include "build/build_config.h"
17 #include "chrome/browser/sync/test/integration/passwords_helper.h"
18 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
19 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
20 #include "chrome/browser/sync/test/integration/sync_test.h"
21 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
22 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
23 #include "content/public/test/browser_test.h"
24
25 using passwords_helper::AddLogin;
26 using passwords_helper::AllProfilesContainSamePasswordForms;
27 using passwords_helper::AllProfilesContainSamePasswordFormsAsVerifier;
28 using passwords_helper::CreateTestPasswordForm;
29 using passwords_helper::GetLogins;
30 using passwords_helper::GetPasswordCount;
31 using passwords_helper::GetPasswordStore;
32 using passwords_helper::GetVerifierPasswordCount;
33 using passwords_helper::GetVerifierPasswordStore;
34 using passwords_helper::RemoveLogin;
35 using passwords_helper::RemoveLogins;
36 using passwords_helper::UpdateLogin;
37 using passwords_helper::UpdateLoginWithPrimaryKey;
38
39 using password_manager::PasswordForm;
40
41 static const char* kValidPassphrase = "passphrase!";
42
43 class TwoClientPasswordsSyncTest : public SyncTest {
44 public:
TwoClientPasswordsSyncTest()45 TwoClientPasswordsSyncTest() : SyncTest(TWO_CLIENT) {}
46 ~TwoClientPasswordsSyncTest() override = default;
47 };
48
49 class TwoClientPasswordsSyncTestWithVerifier
50 : public TwoClientPasswordsSyncTest {
51 public:
52 TwoClientPasswordsSyncTestWithVerifier() = default;
53 ~TwoClientPasswordsSyncTestWithVerifier() override = default;
54
UseVerifier()55 bool UseVerifier() override {
56 // TODO(crbug.com/1137740): rewrite tests to not use verifier.
57 return true;
58 }
59 };
60
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ENABLED (Add))61 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, E2E_ENABLED(Add)) {
62 ResetSyncForPrimaryAccount();
63 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
64 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
65
66 PasswordForm form = CreateTestPasswordForm(0);
67 AddLogin(GetPasswordStore(0), form);
68 ASSERT_EQ(1, GetPasswordCount(0));
69
70 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
71 ASSERT_EQ(1, GetPasswordCount(1));
72 }
73
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ENABLED (Race))74 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, E2E_ENABLED(Race)) {
75 ResetSyncForPrimaryAccount();
76 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
77 ASSERT_TRUE(AllProfilesContainSamePasswordForms());
78
79 PasswordForm form0 = CreateTestPasswordForm(0);
80 AddLogin(GetPasswordStore(0), form0);
81
82 PasswordForm form1 = form0;
83 form1.password_value = base::ASCIIToUTF16("new_password");
84 AddLogin(GetPasswordStore(1), form1);
85
86 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
87 }
88
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,MergeWithTheMostRecent)89 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, MergeWithTheMostRecent) {
90 // Setup the test to have Form 0 and Form 1 added on both clients. Form 0 is
91 // more recent on Client 0, and Form 1 is more recent on Client 1. They should
92 // be merged such that recent passwords are chosen.
93
94 base::Time now = base::Time::Now();
95 base::Time yesterday = now - base::TimeDelta::FromDays(1);
96
97 PasswordForm form0_recent = CreateTestPasswordForm(0);
98 form0_recent.date_created = now;
99 PasswordForm form0_old = CreateTestPasswordForm(0);
100 form0_old.date_created = yesterday;
101
102 PasswordForm form1_recent = CreateTestPasswordForm(1);
103 form1_recent.date_created = now;
104 PasswordForm form1_old = CreateTestPasswordForm(1);
105 form1_old.date_created = yesterday;
106
107 ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
108
109 // Add the passwords to Client 0.
110 AddLogin(GetPasswordStore(0), form0_recent);
111 AddLogin(GetPasswordStore(0), form1_old);
112 // Enable sync on Client 0 and wait until they are committed.
113 ASSERT_TRUE(GetClient(0)->SetupSync()) << "GetClient(0)->SetupSync() failed.";
114 ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
115
116 // Add the passwords to Client 1.
117 AddLogin(GetPasswordStore(1), form0_old);
118 AddLogin(GetPasswordStore(1), form1_recent);
119
120 // Enable sync on Client 1 and wait until all passwords are merged.
121 ASSERT_TRUE(GetClient(1)->SetupSync()) << "GetClient(1)->SetupSync() failed.";
122 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
123
124 // There should be only 2 passwords.
125 EXPECT_EQ(2, GetPasswordCount(0));
126 // All passwords should be the recent ones.
127 for (const std::unique_ptr<PasswordForm>& form :
128 GetLogins(GetPasswordStore(0))) {
129 EXPECT_EQ(now, form->date_created);
130 }
131 }
132
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ENABLED (SetPassphraseAndAddPassword))133 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,
134 E2E_ENABLED(SetPassphraseAndAddPassword)) {
135 ResetSyncForPrimaryAccount();
136 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
137
138 GetSyncService(0)->GetUserSettings()->SetEncryptionPassphrase(
139 kValidPassphrase);
140 ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait());
141
142 ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(1)).Wait());
143 ASSERT_TRUE(GetSyncService(1)->GetUserSettings()->SetDecryptionPassphrase(
144 kValidPassphrase));
145 ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(1)).Wait());
146
147 PasswordForm form = CreateTestPasswordForm(0);
148 AddLogin(GetPasswordStore(0), form);
149 ASSERT_EQ(1, GetPasswordCount(0));
150
151 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
152 }
153
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier,Update)154 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier, Update) {
155 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
156 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
157
158 PasswordForm form = CreateTestPasswordForm(0);
159 AddLogin(GetVerifierPasswordStore(), form);
160 AddLogin(GetPasswordStore(0), form);
161
162 // Wait for client 0 to commit and client 1 to receive the update.
163 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
164
165 form.password_value = base::ASCIIToUTF16("new_password");
166 UpdateLogin(GetVerifierPasswordStore(), form);
167 UpdateLogin(GetPasswordStore(1), form);
168 ASSERT_EQ(1, GetVerifierPasswordCount());
169
170 // Wait for client 1 to commit and client 0 to receive the update.
171 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
172 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
173 }
174
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,AddTwice)175 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, AddTwice) {
176 // Password store supports adding the same form twice, so this is testing this
177 // behaviour.
178 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
179 ASSERT_TRUE(AllProfilesContainSamePasswordForms());
180
181 PasswordForm form = CreateTestPasswordForm(0);
182 AddLogin(GetPasswordStore(0), form);
183 ASSERT_EQ(1, GetPasswordCount(0));
184
185 // Wait for client 0 to commit and client 1 to receive the update.
186 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
187 ASSERT_EQ(1, GetPasswordCount(1));
188
189 // Update the password and add it again to client 0.
190 form.password_value = base::ASCIIToUTF16("new_password");
191 AddLogin(GetPasswordStore(0), form);
192 ASSERT_EQ(1, GetPasswordCount(0));
193
194 // Wait for client 1 to receive the update.
195 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
196 ASSERT_EQ(1, GetPasswordCount(1));
197 }
198
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier,Delete)199 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier, Delete) {
200 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
201 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
202
203 PasswordForm form0 = CreateTestPasswordForm(0);
204 AddLogin(GetVerifierPasswordStore(), form0);
205 AddLogin(GetPasswordStore(0), form0);
206 PasswordForm form1 = CreateTestPasswordForm(1);
207 AddLogin(GetVerifierPasswordStore(), form1);
208 AddLogin(GetPasswordStore(0), form1);
209
210 // Wait for client 0 to commit and client 1 to receive the update.
211 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
212
213 RemoveLogin(GetPasswordStore(1), form0);
214 RemoveLogin(GetVerifierPasswordStore(), form0);
215 ASSERT_EQ(1, GetVerifierPasswordCount());
216
217 // Wait for deletion from client 1 to propagate.
218 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
219 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
220 }
221
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,SetPassphraseAndThenSetupSync)222 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,
223 SetPassphraseAndThenSetupSync) {
224 ASSERT_TRUE(SetupClients());
225
226 ASSERT_TRUE(GetClient(0)->SetupSync());
227 GetSyncService(0)->GetUserSettings()->SetEncryptionPassphrase(
228 kValidPassphrase);
229 ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait());
230 // Wait for the client to commit the updates.
231 ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
232
233 // When client 1 hits a passphrase required state, we can infer that
234 // client 0's passphrase has been committed. to the server.
235 ASSERT_TRUE(GetClient(1)->SetupSyncNoWaitForCompletion(
236 GetRegisteredSelectableTypes(1)));
237 ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(1)).Wait());
238
239 // Get client 1 out of the passphrase required state.
240 ASSERT_TRUE(GetSyncService(1)->GetUserSettings()->SetDecryptionPassphrase(
241 kValidPassphrase));
242 ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(1)).Wait());
243
244 // We must mark the setup complete now, since we just entered the passphrase
245 // and the previous SetupSync() call failed.
246 GetClient(1)->FinishSyncSetup();
247
248 // Move around some passwords to make sure it's all working.
249 PasswordForm form0 = CreateTestPasswordForm(0);
250 AddLogin(GetPasswordStore(0), form0);
251
252 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
253 }
254
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ONLY (DeleteTwo))255 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, E2E_ONLY(DeleteTwo)) {
256 ResetSyncForPrimaryAccount();
257 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
258 ASSERT_TRUE(AllProfilesContainSamePasswordForms());
259
260 PasswordForm form0 =
261 CreateTestPasswordForm(base::FastHash(base::GenerateGUID()));
262 PasswordForm form1 =
263 CreateTestPasswordForm(base::FastHash(base::GenerateGUID()));
264 AddLogin(GetPasswordStore(0), form0);
265 AddLogin(GetPasswordStore(0), form1);
266
267 const int init_password_count = GetPasswordCount(0);
268
269 // Wait for client 0 to commit and client 1 to receive the update.
270 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
271 ASSERT_EQ(init_password_count, GetPasswordCount(1));
272
273 RemoveLogin(GetPasswordStore(1), form0);
274
275 // Wait for deletion from client 1 to propagate.
276 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
277 ASSERT_EQ(init_password_count - 1, GetPasswordCount(0));
278
279 RemoveLogin(GetPasswordStore(1), form1);
280
281 // Wait for deletion from client 1 to propagate.
282 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
283 ASSERT_EQ(init_password_count - 2, GetPasswordCount(0));
284 }
285
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier,DeleteAll)286 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier, DeleteAll) {
287 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
288 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
289
290 PasswordForm form0 = CreateTestPasswordForm(0);
291 AddLogin(GetVerifierPasswordStore(), form0);
292 AddLogin(GetPasswordStore(0), form0);
293 PasswordForm form1 = CreateTestPasswordForm(1);
294 AddLogin(GetVerifierPasswordStore(), form1);
295 AddLogin(GetPasswordStore(0), form1);
296 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
297 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
298
299 RemoveLogins(GetPasswordStore(1));
300 RemoveLogins(GetVerifierPasswordStore());
301 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(0).Wait());
302 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
303 ASSERT_EQ(0, GetVerifierPasswordCount());
304 }
305
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ENABLED (Merge))306 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, E2E_ENABLED(Merge)) {
307 ResetSyncForPrimaryAccount();
308 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
309 ASSERT_TRUE(AllProfilesContainSamePasswordForms());
310
311 PasswordForm form0 = CreateTestPasswordForm(0);
312 AddLogin(GetPasswordStore(0), form0);
313 PasswordForm form1 = CreateTestPasswordForm(1);
314 AddLogin(GetPasswordStore(1), form1);
315 PasswordForm form2 = CreateTestPasswordForm(2);
316 AddLogin(GetPasswordStore(1), form2);
317
318 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
319 ASSERT_EQ(3, GetPasswordCount(0));
320 }
321
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest,E2E_ONLY (TwoClientAddPass))322 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTest, E2E_ONLY(TwoClientAddPass)) {
323 ResetSyncForPrimaryAccount();
324 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
325 // All profiles should sync same passwords.
326 ASSERT_TRUE(SamePasswordFormsChecker().Wait())
327 << "Initial password forms did not match for all profiles";
328 const int init_password_count = GetPasswordCount(0);
329
330 // Add one new password per profile. A unique form is created for each to
331 // prevent them from overwriting each other.
332 for (int i = 0; i < num_clients(); ++i) {
333 AddLogin(GetPasswordStore(i), CreateTestPasswordForm(base::RandInt(
334 0, std::numeric_limits<int32_t>::max())));
335 }
336
337 // Blocks and waits for password forms in all profiles to match.
338 ASSERT_TRUE(SamePasswordFormsChecker().Wait());
339
340 // Check that total number of passwords is as expected.
341 for (int i = 0; i < num_clients(); ++i) {
342 ASSERT_EQ(GetPasswordCount(i), init_password_count + num_clients()) <<
343 "Total password count is wrong.";
344 }
345 }
346
IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier,AddImmediatelyAfterDelete)347 IN_PROC_BROWSER_TEST_F(TwoClientPasswordsSyncTestWithVerifier,
348 AddImmediatelyAfterDelete) {
349 ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
350 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
351 base::HistogramTester histogram_tester;
352
353 PasswordForm form0 = CreateTestPasswordForm(0);
354 AddLogin(GetVerifierPasswordStore(), form0);
355 AddLogin(GetPasswordStore(0), form0);
356
357 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
358 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
359
360 PasswordForm form1 = CreateTestPasswordForm(1);
361 UpdateLoginWithPrimaryKey(GetVerifierPasswordStore(), form1, form0);
362 UpdateLoginWithPrimaryKey(GetPasswordStore(0), form1, form0);
363
364 ASSERT_TRUE(SamePasswordFormsAsVerifierChecker(1).Wait());
365 ASSERT_TRUE(AllProfilesContainSamePasswordFormsAsVerifier());
366 // There should be only one deletion. This is to test the bug
367 // (crbug.com/1046309) where the USS client was local deletions when receiving
368 // remote deletions.
369 EXPECT_EQ(
370 1, histogram_tester.GetBucketCount("Sync.ModelTypeEntityChange3.PASSWORD",
371 /*LOCAL_DELETION=*/0));
372 }
373