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 "chrome/browser/sync/test/integration/passwords_helper.h"
6 
7 #include <sstream>
8 #include <utility>
9 
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/compiler_specific.h"
13 #include "base/macros.h"
14 #include "base/run_loop.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/password_manager/account_password_store_factory.h"
20 #include "chrome/browser/password_manager/password_store_factory.h"
21 #include "chrome/browser/sync/profile_sync_service_factory.h"
22 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
23 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
24 #include "components/password_manager/core/browser/password_manager_test_utils.h"
25 #include "components/password_manager/core/browser/password_store.h"
26 #include "components/password_manager/core/browser/password_store_consumer.h"
27 #include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h"
28 #include "components/sync/nigori/cryptographer_impl.h"
29 #include "content/public/test/test_utils.h"
30 #include "net/base/escape.h"
31 #include "url/gurl.h"
32 
33 using password_manager::PasswordForm;
34 using password_manager::PasswordStore;
35 using sync_datatype_helper::test;
36 
37 namespace {
38 
39 const char kFakeSignonRealm[] = "http://fake-signon-realm.google.com/";
40 const char kIndexedFakeOrigin[] = "http://fake-signon-realm.google.com/%d";
41 
42 // We use a WaitableEvent to wait when logins are added, removed, or updated
43 // instead of running the UI message loop because of a restriction that
44 // prevents a DB thread from initiating a quit of the UI message loop.
PasswordStoreCallback(base::WaitableEvent * wait_event)45 void PasswordStoreCallback(base::WaitableEvent* wait_event) {
46   // Wake up passwords_helper::AddLogin.
47   wait_event->Signal();
48 }
49 
50 class PasswordStoreConsumerHelper
51     : public password_manager::PasswordStoreConsumer {
52  public:
PasswordStoreConsumerHelper()53   PasswordStoreConsumerHelper() {}
54 
OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>> results)55   void OnGetPasswordStoreResults(
56       std::vector<std::unique_ptr<PasswordForm>> results) override {
57     result_.swap(results);
58     run_loop_.Quit();
59   }
60 
WaitForResult()61   std::vector<std::unique_ptr<PasswordForm>> WaitForResult() {
62     DCHECK(!run_loop_.running());
63     content::RunThisRunLoop(&run_loop_);
64     return std::move(result_);
65   }
66 
67  private:
68   base::RunLoop run_loop_;
69   std::vector<std::unique_ptr<PasswordForm>> result_;
70 
71   DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
72 };
73 
74 // PasswordForm::date_synced is a local field. Therefore it may be different
75 // across clients.
ClearSyncDateField(std::vector<std::unique_ptr<PasswordForm>> * forms)76 void ClearSyncDateField(std::vector<std::unique_ptr<PasswordForm>>* forms) {
77   for (auto& form : *forms) {
78     form->date_synced = base::Time();
79   }
80 }
81 
SpecificsDataFromPasswordForm(const password_manager::PasswordForm & password_form)82 sync_pb::PasswordSpecificsData SpecificsDataFromPasswordForm(
83     const password_manager::PasswordForm& password_form) {
84   sync_pb::PasswordSpecificsData password_data;
85   password_data.set_scheme(static_cast<int>(password_form.scheme));
86   password_data.set_signon_realm(password_form.signon_realm);
87   password_data.set_origin(password_form.url.spec());
88   password_data.set_action(password_form.action.spec());
89   password_data.set_username_element(
90       base::UTF16ToUTF8(password_form.username_element));
91   password_data.set_password_element(
92       base::UTF16ToUTF8(password_form.password_element));
93   password_data.set_username_value(
94       base::UTF16ToUTF8(password_form.username_value));
95   password_data.set_password_value(
96       base::UTF16ToUTF8(password_form.password_value));
97   password_data.set_date_last_used(
98       password_form.date_last_used.ToDeltaSinceWindowsEpoch().InMicroseconds());
99   password_data.set_date_created(
100       password_form.date_created.ToDeltaSinceWindowsEpoch().InMicroseconds());
101   password_data.set_blacklisted(password_form.blocked_by_user);
102   password_data.set_type(static_cast<int>(password_form.type));
103   password_data.set_times_used(password_form.times_used);
104   password_data.set_display_name(base::UTF16ToUTF8(password_form.display_name));
105   password_data.set_avatar_url(password_form.icon_url.spec());
106   password_data.set_federation_url(
107       password_form.federation_origin.opaque()
108           ? std::string()
109           : password_form.federation_origin.Serialize());
110   return password_data;
111 }
112 
EncryptPasswordSpecifics(const sync_pb::PasswordSpecificsData & password_data,const std::string & passphrase,const syncer::KeyDerivationParams & key_derivation_params)113 sync_pb::EntitySpecifics EncryptPasswordSpecifics(
114     const sync_pb::PasswordSpecificsData& password_data,
115     const std::string& passphrase,
116     const syncer::KeyDerivationParams& key_derivation_params) {
117   std::unique_ptr<syncer::CryptographerImpl> cryptographer =
118       syncer::CryptographerImpl::FromSingleKeyForTesting(passphrase,
119                                                          key_derivation_params);
120   sync_pb::EntitySpecifics encrypted_specifics;
121   encrypted_specifics.mutable_password()
122       ->mutable_unencrypted_metadata()
123       ->set_url(password_data.signon_realm());
124   bool result = cryptographer->Encrypt(
125       password_data,
126       encrypted_specifics.mutable_password()->mutable_encrypted());
127   DCHECK(result);
128   return encrypted_specifics;
129 }
130 
GetClientTag(const sync_pb::PasswordSpecificsData & password_data)131 std::string GetClientTag(const sync_pb::PasswordSpecificsData& password_data) {
132   return net::EscapePath(GURL(password_data.origin()).spec()) + "|" +
133          net::EscapePath(password_data.username_element()) + "|" +
134          net::EscapePath(password_data.username_value()) + "|" +
135          net::EscapePath(password_data.password_element()) + "|" +
136          net::EscapePath(password_data.signon_realm());
137 }
138 
139 }  // namespace
140 
141 namespace passwords_helper {
142 
AddLogin(PasswordStore * store,const PasswordForm & form)143 void AddLogin(PasswordStore* store, const PasswordForm& form) {
144   ASSERT_TRUE(store);
145   base::WaitableEvent wait_event(
146       base::WaitableEvent::ResetPolicy::MANUAL,
147       base::WaitableEvent::InitialState::NOT_SIGNALED);
148   store->AddLogin(form);
149   store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
150   wait_event.Wait();
151 }
152 
UpdateLogin(PasswordStore * store,const PasswordForm & form)153 void UpdateLogin(PasswordStore* store, const PasswordForm& form) {
154   ASSERT_TRUE(store);
155   base::WaitableEvent wait_event(
156       base::WaitableEvent::ResetPolicy::MANUAL,
157       base::WaitableEvent::InitialState::NOT_SIGNALED);
158   store->UpdateLogin(form);
159   store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
160   wait_event.Wait();
161 }
162 
UpdateLoginWithPrimaryKey(PasswordStore * store,const PasswordForm & new_form,const PasswordForm & old_form)163 void UpdateLoginWithPrimaryKey(PasswordStore* store,
164                                const PasswordForm& new_form,
165                                const PasswordForm& old_form) {
166   ASSERT_TRUE(store);
167   base::WaitableEvent wait_event(
168       base::WaitableEvent::ResetPolicy::MANUAL,
169       base::WaitableEvent::InitialState::NOT_SIGNALED);
170   store->UpdateLoginWithPrimaryKey(new_form, old_form);
171   store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
172   wait_event.Wait();
173 }
174 
GetLogins(PasswordStore * store)175 std::vector<std::unique_ptr<PasswordForm>> GetLogins(PasswordStore* store) {
176   EXPECT_TRUE(store);
177   password_manager::PasswordStore::FormDigest matcher_form = {
178       PasswordForm::Scheme::kHtml, kFakeSignonRealm, GURL()};
179   PasswordStoreConsumerHelper consumer;
180   store->GetLogins(matcher_form, &consumer);
181   return consumer.WaitForResult();
182 }
183 
GetAllLogins(PasswordStore * store)184 std::vector<std::unique_ptr<PasswordForm>> GetAllLogins(PasswordStore* store) {
185   EXPECT_TRUE(store);
186   PasswordStoreConsumerHelper consumer;
187   store->GetAllLogins(&consumer);
188   return consumer.WaitForResult();
189 }
190 
RemoveLogin(PasswordStore * store,const PasswordForm & form)191 void RemoveLogin(PasswordStore* store, const PasswordForm& form) {
192   ASSERT_TRUE(store);
193   base::WaitableEvent wait_event(
194       base::WaitableEvent::ResetPolicy::MANUAL,
195       base::WaitableEvent::InitialState::NOT_SIGNALED);
196   store->RemoveLogin(form);
197   store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
198   wait_event.Wait();
199 }
200 
RemoveLogins(PasswordStore * store)201 void RemoveLogins(PasswordStore* store) {
202   std::vector<std::unique_ptr<PasswordForm>> forms = GetLogins(store);
203   for (const auto& form : forms) {
204     RemoveLogin(store, *form);
205   }
206 }
207 
GetPasswordStore(int index)208 PasswordStore* GetPasswordStore(int index) {
209   return PasswordStoreFactory::GetForProfile(test()->GetProfile(index),
210                                              ServiceAccessType::IMPLICIT_ACCESS)
211       .get();
212 }
213 
GetVerifierPasswordStore()214 PasswordStore* GetVerifierPasswordStore() {
215   return PasswordStoreFactory::GetForProfile(test()->verifier(),
216                                              ServiceAccessType::IMPLICIT_ACCESS)
217       .get();
218 }
219 
GetAccountPasswordStore(int index)220 PasswordStore* GetAccountPasswordStore(int index) {
221   return AccountPasswordStoreFactory::GetForProfile(
222              test()->GetProfile(index), ServiceAccessType::IMPLICIT_ACCESS)
223       .get();
224 }
225 
ProfileContainsSamePasswordFormsAsVerifier(int index)226 bool ProfileContainsSamePasswordFormsAsVerifier(int index) {
227   std::vector<std::unique_ptr<PasswordForm>> verifier_forms =
228       GetLogins(GetVerifierPasswordStore());
229   std::vector<std::unique_ptr<PasswordForm>> forms =
230       GetLogins(GetPasswordStore(index));
231   ClearSyncDateField(&forms);
232 
233   std::ostringstream mismatch_details_stream;
234   bool is_matching = password_manager::ContainsEqualPasswordFormsUnordered(
235       verifier_forms, forms, &mismatch_details_stream);
236   if (!is_matching) {
237     VLOG(1) << "Profile " << index
238             << " does not contain the same Password forms as Verifier Profile.";
239     VLOG(1) << mismatch_details_stream.str();
240   }
241   return is_matching;
242 }
243 
ProfilesContainSamePasswordForms(int index_a,int index_b)244 bool ProfilesContainSamePasswordForms(int index_a, int index_b) {
245   std::vector<std::unique_ptr<PasswordForm>> forms_a =
246       GetLogins(GetPasswordStore(index_a));
247   std::vector<std::unique_ptr<PasswordForm>> forms_b =
248       GetLogins(GetPasswordStore(index_b));
249   ClearSyncDateField(&forms_a);
250   ClearSyncDateField(&forms_b);
251 
252   std::ostringstream mismatch_details_stream;
253   bool is_matching = password_manager::ContainsEqualPasswordFormsUnordered(
254       forms_a, forms_b, &mismatch_details_stream);
255   if (!is_matching) {
256     VLOG(1) << "Password forms in Profile " << index_a
257             << " (listed as 'expected forms' below)"
258             << " do not match those in Profile " << index_b
259             << " (listed as 'actual forms' below)";
260     VLOG(1) << mismatch_details_stream.str();
261   }
262   return is_matching;
263 }
264 
AllProfilesContainSamePasswordFormsAsVerifier()265 bool AllProfilesContainSamePasswordFormsAsVerifier() {
266   for (int i = 0; i < test()->num_clients(); ++i) {
267     if (!ProfileContainsSamePasswordFormsAsVerifier(i)) {
268       DVLOG(1) << "Profile " << i
269                << " does not contain the same password"
270                   " forms as the verifier.";
271       return false;
272     }
273   }
274   return true;
275 }
276 
AllProfilesContainSamePasswordForms()277 bool AllProfilesContainSamePasswordForms() {
278   for (int i = 1; i < test()->num_clients(); ++i) {
279     if (!ProfilesContainSamePasswordForms(0, i)) {
280       DVLOG(1) << "Profile " << i
281                << " does not contain the same password"
282                   " forms as Profile 0.";
283       return false;
284     }
285   }
286   return true;
287 }
288 
GetPasswordCount(int index)289 int GetPasswordCount(int index) {
290   return GetLogins(GetPasswordStore(index)).size();
291 }
292 
GetVerifierPasswordCount()293 int GetVerifierPasswordCount() {
294   return GetLogins(GetVerifierPasswordStore()).size();
295 }
296 
CreateTestPasswordForm(int index)297 PasswordForm CreateTestPasswordForm(int index) {
298   PasswordForm form;
299   form.signon_realm = kFakeSignonRealm;
300   form.url = GURL(base::StringPrintf(kIndexedFakeOrigin, index));
301   form.username_value =
302       base::ASCIIToUTF16(base::StringPrintf("username%d", index));
303   form.password_value =
304       base::ASCIIToUTF16(base::StringPrintf("password%d", index));
305   form.date_created = base::Time::Now();
306   form.in_store = password_manager::PasswordForm::Store::kProfileStore;
307   return form;
308 }
309 
InjectEncryptedServerPassword(const password_manager::PasswordForm & form,const std::string & encryption_passphrase,const syncer::KeyDerivationParams & key_derivation_params,fake_server::FakeServer * fake_server)310 void InjectEncryptedServerPassword(
311     const password_manager::PasswordForm& form,
312     const std::string& encryption_passphrase,
313     const syncer::KeyDerivationParams& key_derivation_params,
314     fake_server::FakeServer* fake_server) {
315   InjectEncryptedServerPassword(SpecificsDataFromPasswordForm(form),
316                                 encryption_passphrase, key_derivation_params,
317                                 fake_server);
318 }
319 
InjectEncryptedServerPassword(const sync_pb::PasswordSpecificsData & password_data,const std::string & encryption_passphrase,const syncer::KeyDerivationParams & key_derivation_params,fake_server::FakeServer * fake_server)320 void InjectEncryptedServerPassword(
321     const sync_pb::PasswordSpecificsData& password_data,
322     const std::string& encryption_passphrase,
323     const syncer::KeyDerivationParams& key_derivation_params,
324     fake_server::FakeServer* fake_server) {
325   DCHECK(fake_server);
326   const sync_pb::EntitySpecifics encrypted_specifics = EncryptPasswordSpecifics(
327       password_data, encryption_passphrase, key_derivation_params);
328   fake_server->InjectEntity(
329       syncer::PersistentUniqueClientEntity::CreateFromSpecificsForTesting(
330           /*non_unique_name=*/"encrypted", GetClientTag(password_data),
331           encrypted_specifics,
332           /*creation_time=*/0, /*last_modified_time=*/0));
333 }
334 
InjectKeystoreEncryptedServerPassword(const password_manager::PasswordForm & form,fake_server::FakeServer * fake_server)335 void InjectKeystoreEncryptedServerPassword(
336     const password_manager::PasswordForm& form,
337     fake_server::FakeServer* fake_server) {
338   InjectKeystoreEncryptedServerPassword(SpecificsDataFromPasswordForm(form),
339                                         fake_server);
340 }
341 
InjectKeystoreEncryptedServerPassword(const sync_pb::PasswordSpecificsData & password_data,fake_server::FakeServer * fake_server)342 void InjectKeystoreEncryptedServerPassword(
343     const sync_pb::PasswordSpecificsData& password_data,
344     fake_server::FakeServer* fake_server) {
345   InjectEncryptedServerPassword(
346       password_data, base::Base64Encode(fake_server->GetKeystoreKeys().back()),
347       syncer::KeyDerivationParams::CreateForPbkdf2(), fake_server);
348 }
349 
350 }  // namespace passwords_helper
351 
PasswordSyncActiveChecker(syncer::ProfileSyncService * service)352 PasswordSyncActiveChecker::PasswordSyncActiveChecker(
353     syncer::ProfileSyncService* service)
354     : SingleClientStatusChangeChecker(service) {}
355 PasswordSyncActiveChecker::~PasswordSyncActiveChecker() = default;
356 
IsExitConditionSatisfied(std::ostream * os)357 bool PasswordSyncActiveChecker::IsExitConditionSatisfied(std::ostream* os) {
358   return service()->GetActiveDataTypes().Has(syncer::PASSWORDS);
359 }
360 
SamePasswordFormsChecker()361 SamePasswordFormsChecker::SamePasswordFormsChecker()
362     : MultiClientStatusChangeChecker(
363           sync_datatype_helper::test()->GetSyncServices()),
364       in_progress_(false),
365       needs_recheck_(false) {}
366 
367 // This method needs protection against re-entrancy.
368 //
369 // This function indirectly calls GetLogins(), which starts a RunLoop on the UI
370 // thread.  This can be a problem, since the next task to execute could very
371 // well contain a ProfileSyncService::OnStateChanged() event, which would
372 // trigger another call to this here function, and start another layer of
373 // nested RunLoops.  That makes the StatusChangeChecker's Quit() method
374 // ineffective.
375 //
376 // The work-around is to not allow re-entrancy.  But we can't just drop
377 // IsExitConditionSatisifed() calls if one is already in progress.  Instead, we
378 // set a flag to ask the current execution of IsExitConditionSatisfied() to be
379 // re-run.  This ensures that the return value is always based on the most
380 // up-to-date state.
IsExitConditionSatisfied(std::ostream * os)381 bool SamePasswordFormsChecker::IsExitConditionSatisfied(std::ostream* os) {
382   *os << "Waiting for matching passwords";
383 
384   if (in_progress_) {
385     LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
386     needs_recheck_ = true;
387     return false;
388   }
389 
390   // Keep retrying until we get a good reading.
391   bool result = false;
392   in_progress_ = true;
393   do {
394     needs_recheck_ = false;
395     result = passwords_helper::AllProfilesContainSamePasswordForms();
396   } while (needs_recheck_);
397   in_progress_ = false;
398   return result;
399 }
400 
SamePasswordFormsAsVerifierChecker(int i)401 SamePasswordFormsAsVerifierChecker::SamePasswordFormsAsVerifierChecker(int i)
402     : SingleClientStatusChangeChecker(
403           sync_datatype_helper::test()->GetSyncService(i)),
404       index_(i),
405       in_progress_(false),
406       needs_recheck_(false) {}
407 
408 // This method uses the same re-entrancy prevention trick as
409 // the SamePasswordFormsChecker.
IsExitConditionSatisfied(std::ostream * os)410 bool SamePasswordFormsAsVerifierChecker::IsExitConditionSatisfied(
411     std::ostream* os) {
412   *os << "Waiting for passwords to match verifier";
413 
414   if (in_progress_) {
415     LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
416     needs_recheck_ = true;
417     return false;
418   }
419 
420   // Keep retrying until we get a good reading.
421   bool result = false;
422   in_progress_ = true;
423   do {
424     needs_recheck_ = false;
425     result =
426         passwords_helper::ProfileContainsSamePasswordFormsAsVerifier(index_);
427   } while (needs_recheck_);
428   in_progress_ = false;
429   return result;
430 }
431 
PasswordFormsChecker(int index,const std::vector<password_manager::PasswordForm> & expected_forms)432 PasswordFormsChecker::PasswordFormsChecker(
433     int index,
434     const std::vector<password_manager::PasswordForm>& expected_forms)
435     : SingleClientStatusChangeChecker(
436           sync_datatype_helper::test()->GetSyncService(index)),
437       index_(index),
438       in_progress_(false),
439       needs_recheck_(false) {
440   for (auto& password_form : expected_forms) {
441     expected_forms_.push_back(
442         std::make_unique<password_manager::PasswordForm>(password_form));
443   }
444   ClearSyncDateField(&expected_forms_);
445 }
446 
447 PasswordFormsChecker::~PasswordFormsChecker() = default;
448 
449 // This method uses the same re-entrancy prevention trick as
450 // the SamePasswordFormsChecker.
IsExitConditionSatisfied(std::ostream * os)451 bool PasswordFormsChecker::IsExitConditionSatisfied(std::ostream* os) {
452   if (in_progress_) {
453     LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
454     *os << "Setting flag and returning early to prevent nesting.";
455     needs_recheck_ = true;
456     return false;
457   }
458 
459   // Keep retrying until we get a good reading.
460   bool result = false;
461   in_progress_ = true;
462   do {
463     needs_recheck_ = false;
464     result = IsExitConditionSatisfiedImpl(os);
465   } while (needs_recheck_);
466   in_progress_ = false;
467   return result;
468 }
469 
IsExitConditionSatisfiedImpl(std::ostream * os)470 bool PasswordFormsChecker::IsExitConditionSatisfiedImpl(std::ostream* os) {
471   std::vector<std::unique_ptr<PasswordForm>> forms =
472       passwords_helper::GetLogins(passwords_helper::GetPasswordStore(index_));
473   ClearSyncDateField(&forms);
474 
475   std::ostringstream mismatch_details_stream;
476   bool is_matching = password_manager::ContainsEqualPasswordFormsUnordered(
477       expected_forms_, forms, &mismatch_details_stream);
478   if (!is_matching) {
479     *os << "Profile " << index_
480         << " does not contain the same Password forms as expected. "
481         << mismatch_details_stream.str();
482   }
483   return is_matching;
484 }
485