Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: chrome/browser/password_manager/password_store_unittest.cc

Issue 10209036: Per bug 121738, ignore old saved logins for http*://www.google.com. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: update Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/scoped_temp_dir.h"
8 #include "base/stl_util.h"
9 #include "base/string_util.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/time.h"
12 #include "chrome/browser/password_manager/password_form_data.h"
13 #include "chrome/browser/password_manager/password_store_consumer.h"
14 #include "chrome/browser/password_manager/password_store_default.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_registrar.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/test/notification_observer_mock.h"
21 #include "content/test/test_browser_thread.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 using base::WaitableEvent;
26 using content::BrowserThread;
27 using testing::_;
28 using testing::DoAll;
29 using testing::WithArg;
30 using webkit::forms::PasswordForm;
31
32 namespace {
33
34 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
35 public:
36 MOCK_METHOD2(OnPasswordStoreRequestDone,
37 void(CancelableRequestProvider::Handle,
38 const std::vector<webkit::forms::PasswordForm*>&));
Ilya Sherman 2012/05/02 22:10:17 nit: Might as well omit the "webkit::forms::" here
Mike Mammarella 2012/05/07 00:14:36 Done.
39 };
40
41 // This class will add and remove a mock notification observer from
42 // the DB thread.
43 class DBThreadObserverHelper
44 : public base::RefCountedThreadSafe<DBThreadObserverHelper,
45 BrowserThread::DeleteOnDBThread> {
46 public:
47 DBThreadObserverHelper() : done_event_(true, false) {}
48
49 void Init(PasswordStore* password_store) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51 BrowserThread::PostTask(
52 BrowserThread::DB,
53 FROM_HERE,
54 base::Bind(&DBThreadObserverHelper::AddObserverTask,
55 this,
56 make_scoped_refptr(password_store)));
57 done_event_.Wait();
58 }
59
60 virtual ~DBThreadObserverHelper() {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
62 registrar_.RemoveAll();
63 }
64
65 content::NotificationObserverMock& observer() {
66 return observer_;
67 }
68
69 protected:
70 friend class base::RefCountedThreadSafe<DBThreadObserverHelper>;
71
72 void AddObserverTask(PasswordStore* password_store) {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
74 registrar_.Add(&observer_,
75 chrome::NOTIFICATION_LOGINS_CHANGED,
76 content::Source<PasswordStore>(password_store));
77 done_event_.Signal();
78 }
79
80 WaitableEvent done_event_;
81 content::NotificationRegistrar registrar_;
82 content::NotificationObserverMock observer_;
83 };
84
85 } // anonymous namespace
86
87 typedef std::vector<PasswordForm*> VectorOfForms;
Ilya Sherman 2012/05/02 22:10:17 nit: Please either shorten this to "Forms" or "For
Ilya Sherman 2012/05/02 22:10:17 nit: Please move this to the top of the file, toge
Mike Mammarella 2012/05/07 00:14:36 Done.
Mike Mammarella 2012/05/07 00:14:36 Removed.
88
89 class PasswordStoreTest : public testing::Test {
90 protected:
91 PasswordStoreTest()
92 : ui_thread_(BrowserThread::UI, &message_loop_),
93 db_thread_(BrowserThread::DB) {
94 }
95
96 virtual void SetUp() {
97 ASSERT_TRUE(db_thread_.Start());
98 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Ilya Sherman 2012/05/02 22:10:17 nit: Can you re-use the TestingProfile's tempdir,
Mike Mammarella 2012/05/07 00:14:36 Looks like we can reuse it. Done.
99
100 profile_.reset(new TestingProfile());
101
102 login_db_.reset(new LoginDatabase());
103 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
104 FILE_PATH_LITERAL("login_test"))));
105 }
106
107 virtual void TearDown() {
108 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
109 MessageLoop::current()->Run();
110 db_thread_.Stop();
111 }
112
113 MessageLoopForUI message_loop_;
114 content::TestBrowserThread ui_thread_;
115 // PasswordStore schedules work on this thread.
116 content::TestBrowserThread db_thread_;
117
118 scoped_ptr<LoginDatabase> login_db_;
119 scoped_ptr<TestingProfile> profile_;
120 ScopedTempDir temp_dir_;
121 };
122
123 ACTION(STLDeleteElements0) {
124 STLDeleteContainerPointers(arg0.begin(), arg0.end());
125 }
126
127 ACTION(QuitUIMessageLoop) {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
129 MessageLoop::current()->Quit();
130 }
131
132 TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
133 scoped_refptr<PasswordStoreDefault> store(
134 new PasswordStoreDefault(login_db_.release(), profile_.get()));
135 store->Init();
136
137 const time_t cutoff = 1325376000; // 00:00 Jan 1 2012 UTC
138 // The passwords are all empty because PasswordStoreDefault doesn't store the
139 // actual passwords on OS X (they're stored in the Keychain instead). We could
140 // special-case it, but it's easier to just have empty passwords.
141 static const PasswordFormData form_data[] = {
142 // A form on https://www.google.com/ older than the cutoff. Will be ignored.
143 { PasswordForm::SCHEME_HTML,
144 "https://www.google.com",
145 "https://www.google.com/origin",
146 "https://www.google.com/action",
147 L"submit_element",
148 L"username_element",
149 L"password_element",
150 L"username_value_1",
151 L"",
152 true, true, cutoff - 1 },
153 // A form on https://www.google.com/ older than the cutoff. Will be ignored.
154 { PasswordForm::SCHEME_HTML,
155 "https://www.google.com/",
156 "https://www.google.com/origin",
157 "https://www.google.com/action",
158 L"submit_element",
159 L"username_element",
160 L"password_element",
161 L"username_value_2",
162 L"",
163 true, true, cutoff - 1 },
164 // A form on https://www.google.com/ newer than the cutoff.
165 { PasswordForm::SCHEME_HTML,
166 "https://www.google.com",
167 "https://www.google.com/origin",
168 "https://www.google.com/action",
169 L"submit_element",
170 L"username_element",
171 L"password_element",
172 L"username_value_3",
173 L"",
174 true, true, cutoff + 1 },
175 // A form on https://accounts.google.com/ older than the cutoff.
176 { PasswordForm::SCHEME_HTML,
177 "https://accounts.google.com",
178 "https://accounts.google.com/origin",
179 "https://accounts.google.com/action",
180 L"submit_element",
181 L"username_element",
182 L"password_element",
183 L"username_value",
184 L"",
185 true, true, cutoff - 1 },
186 // A form on http://bar.example.com/ older than the cutoff.
187 { PasswordForm::SCHEME_HTML,
188 "http://bar.example.com",
189 "http://bar.example.com/origin",
190 "http://bar.example.com/action",
191 L"submit_element",
192 L"username_element",
193 L"password_element",
194 L"username_value",
195 L"",
196 true, false, cutoff - 1 },
197 };
198
199 // Build the forms vector and add the forms to the store.
200 VectorOfForms all_forms;
201 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
202 PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
203 all_forms.push_back(form);
204 store->AddLogin(*form);
205 }
206
207 // The PasswordStore schedules tasks to run on the DB thread so we schedule
208 // yet another task to notify us that it's safe to carry on with the test.
209 WaitableEvent done(false, false);
210 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
211 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
212 done.Wait();
Ilya Sherman 2012/05/02 22:10:17 Is there any named notification / callback that yo
Mike Mammarella 2012/05/07 00:14:36 Ah, so, thinking about this more I don't think the
213
214 // We expect to get back only the "recent" www.google.com login.
215 // Theoretically these should never actually exist since there are no longer
216 // any login forms on www.google.com to save, but we technically allow them.
217 // We should not get back the older saved password though.
218 PasswordForm www_google;
219 www_google.scheme = PasswordForm::SCHEME_HTML;
220 www_google.signon_realm = "https://www.google.com";
221 VectorOfForms www_google_expected;
222 www_google_expected.push_back(all_forms[2]);
223
224 // We should still get the accounts.google.com login even though it's older
225 // than our cutoff - this is the new location of all Google login forms.
226 PasswordForm accounts_google;
227 accounts_google.scheme = PasswordForm::SCHEME_HTML;
228 accounts_google.signon_realm = "https://accounts.google.com";
229 VectorOfForms accounts_google_expected;
230 accounts_google_expected.push_back(all_forms[3]);
231
232 // Same thing for a generic saved login.
233 PasswordForm bar_example;
234 bar_example.scheme = PasswordForm::SCHEME_HTML;
235 bar_example.signon_realm = "http://bar.example.com";
236 VectorOfForms bar_example_expected;
237 bar_example_expected.push_back(all_forms[4]);
238
239 MockPasswordStoreConsumer consumer;
240
241 // Make sure we quit the MessageLoop even if the test fails.
242 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
243 .WillByDefault(QuitUIMessageLoop());
244
245 // Expect the appropriate replies, as above, in reverse order that we will
Ilya Sherman 2012/05/02 22:10:17 nit: "that" -> "than"
Mike Mammarella 2012/05/07 00:14:36 Done.
246 // issue the queries. Each retires on saturation to avoid matcher spew, except
247 // the last which quits the message loop.
Ilya Sherman 2012/05/02 22:10:17 For my own edification, why is it important that t
Mike Mammarella 2012/05/03 03:23:41 Good question! When you register expectations with
Ilya Sherman 2012/05/04 07:22:35 Aha, I was not aware that expectations are process
248 EXPECT_CALL(consumer,
249 OnPasswordStoreRequestDone(_,
250 ContainsAllPasswordForms(bar_example_expected)))
251 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
252 EXPECT_CALL(consumer,
253 OnPasswordStoreRequestDone(_,
254 ContainsAllPasswordForms(accounts_google_expected)))
255 .WillOnce(WithArg<1>(STLDeleteElements0())).RetiresOnSaturation();
256 EXPECT_CALL(consumer,
257 OnPasswordStoreRequestDone(_,
258 ContainsAllPasswordForms(www_google_expected)))
259 .WillOnce(WithArg<1>(STLDeleteElements0())).RetiresOnSaturation();
260
261 store->GetLogins(www_google, &consumer);
262 store->GetLogins(accounts_google, &consumer);
263 store->GetLogins(bar_example, &consumer);
264
265 MessageLoop::current()->Run();
266
267 STLDeleteElements(&all_forms);
268 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698