• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/compiler_specific.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/password_manager/password_store_factory.h"
13 #include "chrome/browser/sync/profile_sync_service.h"
14 #include "chrome/browser/sync/profile_sync_service_factory.h"
15 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
16 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
17 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
18 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "components/password_manager/core/browser/password_form_data.h"
21 #include "components/password_manager/core/browser/password_store.h"
22 #include "components/password_manager/core/browser/password_store_consumer.h"
23 
24 using autofill::PasswordForm;
25 using password_manager::PasswordStore;
26 using sync_datatype_helper::test;
27 
28 const std::string kFakeSignonRealm = "http://fake-signon-realm.google.com/";
29 const char* kIndexedFakeOrigin = "http://fake-signon-realm.google.com/%d";
30 
31 namespace {
32 
33 // We use a WaitableEvent to wait when logins are added, removed, or updated
34 // instead of running the UI message loop because of a restriction that
35 // prevents a DB thread from initiating a quit of the UI message loop.
PasswordStoreCallback(base::WaitableEvent * wait_event)36 void PasswordStoreCallback(base::WaitableEvent* wait_event) {
37   // Wake up passwords_helper::AddLogin.
38   wait_event->Signal();
39 }
40 
41 class PasswordStoreConsumerHelper
42     : public password_manager::PasswordStoreConsumer {
43  public:
PasswordStoreConsumerHelper(std::vector<PasswordForm> * result)44   explicit PasswordStoreConsumerHelper(std::vector<PasswordForm>* result)
45       : password_manager::PasswordStoreConsumer(), result_(result) {}
46 
OnGetPasswordStoreResults(const std::vector<PasswordForm * > & result)47   virtual void OnGetPasswordStoreResults(
48       const std::vector<PasswordForm*>& result) OVERRIDE {
49     result_->clear();
50     for (std::vector<PasswordForm*>::const_iterator it = result.begin();
51          it != result.end();
52          ++it) {
53       result_->push_back(**it);
54       delete *it;
55     }
56 
57     // Quit the message loop to wake up passwords_helper::GetLogins.
58     base::MessageLoopForUI::current()->Quit();
59   }
60 
61  private:
62   std::vector<PasswordForm>* result_;
63 
64   DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
65 };
66 
67 // PasswordForm::date_synced is a local field. Therefore it may be different
68 // across clients.
ClearSyncDateField(std::vector<PasswordForm> * forms)69 void ClearSyncDateField(std::vector<PasswordForm>* forms) {
70   for (std::vector<PasswordForm>::iterator it = forms->begin();
71        it != forms->end();
72        ++it) {
73     it->date_synced = base::Time();
74   }
75 }
76 
77 }  // namespace
78 
79 namespace passwords_helper {
80 
AddLogin(PasswordStore * store,const PasswordForm & form)81 void AddLogin(PasswordStore* store, const PasswordForm& form) {
82   ASSERT_TRUE(store);
83   base::WaitableEvent wait_event(true, false);
84   store->AddLogin(form);
85   store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
86   wait_event.Wait();
87 }
88 
UpdateLogin(PasswordStore * store,const PasswordForm & form)89 void UpdateLogin(PasswordStore* store, const PasswordForm& form) {
90   ASSERT_TRUE(store);
91   base::WaitableEvent wait_event(true, false);
92   store->UpdateLogin(form);
93   store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
94   wait_event.Wait();
95 }
96 
GetLogins(PasswordStore * store,std::vector<PasswordForm> & matches)97 void GetLogins(PasswordStore* store, std::vector<PasswordForm>& matches) {
98   ASSERT_TRUE(store);
99   PasswordForm matcher_form;
100   matcher_form.signon_realm = kFakeSignonRealm;
101   PasswordStoreConsumerHelper consumer(&matches);
102   store->GetLogins(matcher_form, PasswordStore::DISALLOW_PROMPT, &consumer);
103   content::RunMessageLoop();
104 }
105 
RemoveLogin(PasswordStore * store,const PasswordForm & form)106 void RemoveLogin(PasswordStore* store, const PasswordForm& form) {
107   ASSERT_TRUE(store);
108   base::WaitableEvent wait_event(true, false);
109   store->RemoveLogin(form);
110   store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
111   wait_event.Wait();
112 }
113 
RemoveLogins(PasswordStore * store)114 void RemoveLogins(PasswordStore* store) {
115   std::vector<PasswordForm> forms;
116   GetLogins(store, forms);
117   for (std::vector<PasswordForm>::iterator it = forms.begin();
118        it != forms.end(); ++it) {
119     RemoveLogin(store, *it);
120   }
121 }
122 
SetEncryptionPassphrase(int index,const std::string & passphrase,ProfileSyncService::PassphraseType type)123 void SetEncryptionPassphrase(int index,
124                              const std::string& passphrase,
125                              ProfileSyncService::PassphraseType type) {
126   ProfileSyncServiceFactory::GetForProfile(
127       test()->GetProfile(index))->SetEncryptionPassphrase(passphrase, type);
128 }
129 
SetDecryptionPassphrase(int index,const std::string & passphrase)130 bool SetDecryptionPassphrase(int index, const std::string& passphrase) {
131   return ProfileSyncServiceFactory::GetForProfile(
132       test()->GetProfile(index))->SetDecryptionPassphrase(passphrase);
133 }
134 
GetPasswordStore(int index)135 PasswordStore* GetPasswordStore(int index) {
136   return PasswordStoreFactory::GetForProfile(test()->GetProfile(index),
137                                              Profile::IMPLICIT_ACCESS).get();
138 }
139 
GetVerifierPasswordStore()140 PasswordStore* GetVerifierPasswordStore() {
141   return PasswordStoreFactory::GetForProfile(test()->verifier(),
142                                              Profile::IMPLICIT_ACCESS).get();
143 }
144 
ProfileContainsSamePasswordFormsAsVerifier(int index)145 bool ProfileContainsSamePasswordFormsAsVerifier(int index) {
146   std::vector<PasswordForm> verifier_forms;
147   std::vector<PasswordForm> forms;
148   GetLogins(GetVerifierPasswordStore(), verifier_forms);
149   GetLogins(GetPasswordStore(index), forms);
150   ClearSyncDateField(&forms);
151   bool result =
152       password_manager::ContainsSamePasswordForms(verifier_forms, forms);
153   if (!result) {
154     LOG(ERROR) << "Password forms in Verifier Profile:";
155     for (std::vector<PasswordForm>::iterator it = verifier_forms.begin();
156          it != verifier_forms.end(); ++it) {
157       LOG(ERROR) << *it << std::endl;
158     }
159     LOG(ERROR) << "Password forms in Profile" << index << ":";
160     for (std::vector<PasswordForm>::iterator it = forms.begin();
161          it != forms.end(); ++it) {
162       LOG(ERROR) << *it << std::endl;
163     }
164   }
165   return result;
166 }
167 
ProfilesContainSamePasswordForms(int index_a,int index_b)168 bool ProfilesContainSamePasswordForms(int index_a, int index_b) {
169   std::vector<PasswordForm> forms_a;
170   std::vector<PasswordForm> forms_b;
171   GetLogins(GetPasswordStore(index_a), forms_a);
172   GetLogins(GetPasswordStore(index_b), forms_b);
173   ClearSyncDateField(&forms_a);
174   ClearSyncDateField(&forms_b);
175   bool result = password_manager::ContainsSamePasswordForms(forms_a, forms_b);
176   if (!result) {
177     LOG(ERROR) << "Password forms in Profile" << index_a << ":";
178     for (std::vector<PasswordForm>::iterator it = forms_a.begin();
179          it != forms_a.end(); ++it) {
180       LOG(ERROR) << *it << std::endl;
181     }
182     LOG(ERROR) << "Password forms in Profile" << index_b << ":";
183     for (std::vector<PasswordForm>::iterator it = forms_b.begin();
184          it != forms_b.end(); ++it) {
185       LOG(ERROR) << *it << std::endl;
186     }
187   }
188   return result;
189 }
190 
AllProfilesContainSamePasswordFormsAsVerifier()191 bool AllProfilesContainSamePasswordFormsAsVerifier() {
192   for (int i = 0; i < test()->num_clients(); ++i) {
193     if (!ProfileContainsSamePasswordFormsAsVerifier(i)) {
194       DVLOG(1) << "Profile " << i << " does not contain the same password"
195                                      " forms as the verifier.";
196       return false;
197     }
198   }
199   return true;
200 }
201 
AllProfilesContainSamePasswordForms()202 bool AllProfilesContainSamePasswordForms() {
203   for (int i = 1; i < test()->num_clients(); ++i) {
204     if (!ProfilesContainSamePasswordForms(0, i)) {
205       DVLOG(1) << "Profile " << i << " does not contain the same password"
206                                      " forms as Profile 0.";
207       return false;
208     }
209   }
210   return true;
211 }
212 
213 namespace {
214 
215 // Helper class used in the implementation of
216 // AwaitAllProfilesContainSamePasswordForms.
217 class SamePasswordFormsChecker : public MultiClientStatusChangeChecker {
218  public:
219   SamePasswordFormsChecker();
220   virtual ~SamePasswordFormsChecker();
221 
222   virtual bool IsExitConditionSatisfied() OVERRIDE;
223   virtual std::string GetDebugMessage() const OVERRIDE;
224 
225  private:
226   bool in_progress_;
227   bool needs_recheck_;
228 };
229 
SamePasswordFormsChecker()230 SamePasswordFormsChecker::SamePasswordFormsChecker()
231     : MultiClientStatusChangeChecker(
232         sync_datatype_helper::test()->GetSyncServices()),
233       in_progress_(false),
234       needs_recheck_(false) {}
235 
~SamePasswordFormsChecker()236 SamePasswordFormsChecker::~SamePasswordFormsChecker() {}
237 
238 // This method needs protection against re-entrancy.
239 //
240 // This function indirectly calls GetLogins(), which starts a RunLoop on the UI
241 // thread.  This can be a problem, since the next task to execute could very
242 // well contain a ProfileSyncService::OnStateChanged() event, which would
243 // trigger another call to this here function, and start another layer of
244 // nested RunLoops.  That makes the StatusChangeChecker's Quit() method
245 // ineffective.
246 //
247 // The work-around is to not allow re-entrancy.  But we can't just drop
248 // IsExitConditionSatisifed() calls if one is already in progress.  Instead, we
249 // set a flag to ask the current execution of IsExitConditionSatisfied() to be
250 // re-run.  This ensures that the return value is always based on the most
251 // up-to-date state.
IsExitConditionSatisfied()252 bool SamePasswordFormsChecker::IsExitConditionSatisfied() {
253   if (in_progress_) {
254     LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
255     needs_recheck_ = true;
256     return false;
257   }
258 
259   // Keep retrying until we get a good reading.
260   bool result = false;
261   in_progress_ = true;
262   do {
263     needs_recheck_ = false;
264     result = AllProfilesContainSamePasswordForms();
265   } while (needs_recheck_);
266   in_progress_ = false;
267   return result;
268 }
269 
GetDebugMessage() const270 std::string SamePasswordFormsChecker::GetDebugMessage() const {
271   return "Waiting for matching passwords";
272 }
273 
274 }  //  namespace
275 
AwaitAllProfilesContainSamePasswordForms()276 bool AwaitAllProfilesContainSamePasswordForms() {
277   SamePasswordFormsChecker checker;
278   checker.Wait();
279   return !checker.TimedOut();
280 }
281 
282 namespace {
283 
284 // Helper class used in the implementation of
285 // AwaitProfileContainSamePasswordFormsAsVerifier.
286 class SamePasswordFormsAsVerifierChecker
287     : public SingleClientStatusChangeChecker {
288  public:
289   explicit SamePasswordFormsAsVerifierChecker(int index);
290   virtual ~SamePasswordFormsAsVerifierChecker();
291 
292   virtual bool IsExitConditionSatisfied() OVERRIDE;
293   virtual std::string GetDebugMessage() const OVERRIDE;
294 
295  private:
296   int index_;
297 
298   bool in_progress_;
299   bool needs_recheck_;
300 };
301 
SamePasswordFormsAsVerifierChecker(int i)302 SamePasswordFormsAsVerifierChecker::SamePasswordFormsAsVerifierChecker(int i)
303     : SingleClientStatusChangeChecker(
304           sync_datatype_helper::test()->GetSyncService(i)),
305       index_(i),
306       in_progress_(false),
307       needs_recheck_(false) {
308 }
309 
~SamePasswordFormsAsVerifierChecker()310 SamePasswordFormsAsVerifierChecker::~SamePasswordFormsAsVerifierChecker() {
311 }
312 
313 // This method uses the same re-entrancy prevention trick as
314 // the SamePasswordFormsChecker.
IsExitConditionSatisfied()315 bool SamePasswordFormsAsVerifierChecker::IsExitConditionSatisfied() {
316   if (in_progress_) {
317     LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
318     needs_recheck_ = true;
319     return false;
320   }
321 
322   // Keep retrying until we get a good reading.
323   bool result = false;
324   in_progress_ = true;
325   do {
326     needs_recheck_ = false;
327     result = ProfileContainsSamePasswordFormsAsVerifier(index_);
328   } while (needs_recheck_);
329   in_progress_ = false;
330   return result;
331 }
332 
GetDebugMessage() const333 std::string SamePasswordFormsAsVerifierChecker::GetDebugMessage() const {
334   return "Waiting for passwords to match verifier";
335 }
336 
337 }  //  namespace
338 
AwaitProfileContainsSamePasswordFormsAsVerifier(int index)339 bool AwaitProfileContainsSamePasswordFormsAsVerifier(int index) {
340   SamePasswordFormsAsVerifierChecker checker(index);
341   checker.Wait();
342   return !checker.TimedOut();
343 }
344 
GetPasswordCount(int index)345 int GetPasswordCount(int index) {
346   std::vector<PasswordForm> forms;
347   GetLogins(GetPasswordStore(index), forms);
348   return forms.size();
349 }
350 
GetVerifierPasswordCount()351 int GetVerifierPasswordCount() {
352   std::vector<PasswordForm> verifier_forms;
353   GetLogins(GetVerifierPasswordStore(), verifier_forms);
354   return verifier_forms.size();
355 }
356 
CreateTestPasswordForm(int index)357 PasswordForm CreateTestPasswordForm(int index) {
358   PasswordForm form;
359   form.signon_realm = kFakeSignonRealm;
360   form.origin = GURL(base::StringPrintf(kIndexedFakeOrigin, index));
361   form.username_value =
362       base::ASCIIToUTF16(base::StringPrintf("username%d", index));
363   form.password_value =
364       base::ASCIIToUTF16(base::StringPrintf("password%d", index));
365   form.date_created = base::Time::Now();
366   return form;
367 }
368 
369 }  // namespace passwords_helper
370