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

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

Powered by Google App Engine
This is Rietveld 408576698