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