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

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/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_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<webkit::forms::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 typedef std::vector<PasswordForm*> VectorOfForms;
87
88 class PasswordStoreTest : public testing::Test {
89 protected:
90 PasswordStoreTest()
91 : ui_thread_(BrowserThread::UI, &message_loop_),
92 db_thread_(BrowserThread::DB) {
93 }
94
95 virtual void SetUp() {
96 ASSERT_TRUE(db_thread_.Start());
97 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
98
99 profile_.reset(new TestingProfile());
100
101 login_db_.reset(new LoginDatabase());
102 ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
103 FILE_PATH_LITERAL("login_test"))));
104 }
105
106 virtual void TearDown() {
107 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
108 MessageLoop::current()->Run();
109 db_thread_.Stop();
110 }
111
112 MessageLoopForUI message_loop_;
113 content::TestBrowserThread ui_thread_;
114 // PasswordStore schedules work on this thread.
115 content::TestBrowserThread db_thread_;
116
117 scoped_ptr<LoginDatabase> login_db_;
118 scoped_ptr<TestingProfile> profile_;
119 ScopedTempDir temp_dir_;
120 };
121
122 ACTION(STLDeleteElements0) {
123 STLDeleteContainerPointers(arg0.begin(), arg0.end());
124 }
125
126 ACTION(QuitUIMessageLoop) {
127 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128 MessageLoop::current()->Quit();
129 }
130
131 TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
132 scoped_refptr<PasswordStoreDefault> store(
133 new PasswordStoreDefault(login_db_.release(), profile_.get()));
134 store->Init();
135
136 const time_t cutoff = 1325376000; // 00:00 Jan 1 2012 UTC
137 static const PasswordFormData form_data[] = {
138 // A form on https://www.google.com/ older than the cutoff. Will be ignored.
139 { PasswordForm::SCHEME_HTML,
140 "https://www.google.com",
141 "https://www.google.com/origin",
142 "https://www.google.com/action",
143 L"submit_element",
144 L"username_element",
145 L"password_element",
146 L"username_value_1",
147 L"password_value_1",
148 true, true, cutoff - 1 },
149 // A form on https://www.google.com/ newer than the cutoff.
150 { PasswordForm::SCHEME_HTML,
151 "https://www.google.com",
Tom Sepez 2012/04/28 01:04:08 Might want to include a trailing slash on one of t
Mike Mammarella 2012/04/30 16:09:45 Done.
152 "https://www.google.com/origin",
153 "https://www.google.com/action",
154 L"submit_element",
155 L"username_element",
156 L"password_element",
157 L"username_value_2",
158 L"password_value_2",
159 true, true, cutoff + 1 },
160 // A form on https://accounts.google.com/ older than the cutoff.
161 { PasswordForm::SCHEME_HTML,
162 "https://accounts.google.com",
163 "https://accounts.google.com/origin",
164 "https://accounts.google.com/action",
165 L"submit_element",
166 L"username_element",
167 L"password_element",
168 L"username_value",
169 L"password_value",
170 true, true, cutoff - 1 },
171 // A form on http://bar.example.com/ older than the cutoff.
172 { PasswordForm::SCHEME_HTML,
173 "http://bar.example.com",
174 "http://bar.example.com/origin",
175 "http://bar.example.com/action",
176 L"submit_element",
177 L"username_element",
178 L"password_element",
179 L"username_value",
180 L"password_value",
181 true, false, cutoff - 1 },
182 };
183
184 // Build the forms vector and add the forms to the store.
185 VectorOfForms all_forms;
186 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
187 PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
188 all_forms.push_back(form);
189 store->AddLogin(*form);
190 }
191
192 // The PasswordStore schedules tasks to run on the DB thread so we schedule
193 // yet another task to notify us that it's safe to carry on with the test.
194 WaitableEvent done(false, false);
195 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
196 base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
197 done.Wait();
198
199 // We expect to get back only the "recent" www.google.com login.
200 // Theoretically these should never actually exist since there are no longer
201 // any login forms on www.google.com to save, but we technically allow them.
202 // We should not get back the older saved password though.
203 PasswordForm www_google;
204 www_google.scheme = PasswordForm::SCHEME_HTML;
205 www_google.signon_realm = "https://www.google.com";
206 VectorOfForms www_google_expected;
207 www_google_expected.push_back(all_forms[1]);
208
209 // We should still get the accounts.google.com login even though it's older
210 // than our cutoff - this is the new location of all Google login forms.
211 PasswordForm accounts_google;
212 accounts_google.scheme = PasswordForm::SCHEME_HTML;
213 accounts_google.signon_realm = "https://accounts.google.com";
214 VectorOfForms accounts_google_expected;
215 accounts_google_expected.push_back(all_forms[2]);
216
217 // Same thing for a generic saved login.
218 PasswordForm bar_example;
219 bar_example.scheme = PasswordForm::SCHEME_HTML;
220 bar_example.signon_realm = "http://bar.example.com";
221 VectorOfForms bar_example_expected;
222 bar_example_expected.push_back(all_forms[3]);
223
224 MockPasswordStoreConsumer consumer;
225
226 // Make sure we quit the MessageLoop even if the test fails.
227 ON_CALL(consumer, OnPasswordStoreRequestDone(_, _))
228 .WillByDefault(QuitUIMessageLoop());
229
230 // Expect the appropriate replies, as above, in reverse order that we will
231 // issue the queries. Each retires on saturation to avoid matcher spew, except
232 // the last which quits the message loop.
233 EXPECT_CALL(consumer,
234 OnPasswordStoreRequestDone(_,
235 ContainsAllPasswordForms(bar_example_expected)))
236 .WillOnce(DoAll(WithArg<1>(STLDeleteElements0()), QuitUIMessageLoop()));
237 EXPECT_CALL(consumer,
238 OnPasswordStoreRequestDone(_,
239 ContainsAllPasswordForms(accounts_google_expected)))
240 .WillOnce(WithArg<1>(STLDeleteElements0())).RetiresOnSaturation();
241 EXPECT_CALL(consumer,
242 OnPasswordStoreRequestDone(_,
243 ContainsAllPasswordForms(www_google_expected)))
244 .WillOnce(WithArg<1>(STLDeleteElements0())).RetiresOnSaturation();
245
246 store->GetLogins(www_google, &consumer);
247 store->GetLogins(accounts_google, &consumer);
248 store->GetLogins(bar_example, &consumer);
249
250 MessageLoop::current()->Run();
251
252 STLDeleteElements(&all_forms);
253 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698