1 // Copyright (c) 2011 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 <vector>
6
7 #include "base/message_loop.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/password_manager/password_manager.h"
11 #include "chrome/browser/password_manager/password_manager_delegate.h"
12 #include "chrome/browser/password_manager/password_store.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/test/testing_profile.h"
15 #include "content/browser/browser_thread.h"
16 #include "content/browser/renderer_host/test_render_view_host.h"
17 #include "content/browser/tab_contents/test_tab_contents.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20
21 using webkit_glue::PasswordForm;
22 using testing::_;
23 using testing::DoAll;
24 using ::testing::Exactly;
25 using ::testing::WithArg;
26 using ::testing::Return;
27
28 class MockPasswordManagerDelegate : public PasswordManagerDelegate {
29 public:
30 MOCK_METHOD1(FillPasswordForm, void(
31 const webkit_glue::PasswordFormFillData&));
32 MOCK_METHOD1(AddSavePasswordInfoBar, void(PasswordFormManager*));
33 MOCK_METHOD0(GetProfileForPasswordManager, Profile*());
34 MOCK_METHOD0(DidLastPageLoadEncounterSSLErrors, bool());
35 };
36
37 class TestingProfileWithPasswordStore : public TestingProfile {
38 public:
TestingProfileWithPasswordStore(PasswordStore * store)39 explicit TestingProfileWithPasswordStore(PasswordStore* store)
40 : store_(store) {}
~TestingProfileWithPasswordStore()41 virtual ~TestingProfileWithPasswordStore() {
42 store_->Shutdown();
43 }
GetPasswordStore(ServiceAccessType access)44 virtual PasswordStore* GetPasswordStore(ServiceAccessType access) {
45 return store_;
46 }
47 private:
48 scoped_refptr<PasswordStore> store_;
49 };
50
51 class MockPasswordStore : public PasswordStore {
52 public:
53 MOCK_METHOD1(RemoveLogin, void(const PasswordForm&));
54 MOCK_METHOD2(GetLogins, int(const PasswordForm&, PasswordStoreConsumer*));
55 MOCK_METHOD1(AddLogin, void(const PasswordForm&));
56 MOCK_METHOD1(UpdateLogin, void(const PasswordForm&));
57 MOCK_METHOD0(ReportMetrics, void());
58 MOCK_METHOD0(ReportMetricsImpl, void());
59 MOCK_METHOD1(AddLoginImpl, void(const PasswordForm&));
60 MOCK_METHOD1(UpdateLoginImpl, void(const PasswordForm&));
61 MOCK_METHOD1(RemoveLoginImpl, void(const PasswordForm&));
62 MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl, void(const base::Time&,
63 const base::Time&));
64 MOCK_METHOD2(GetLoginsImpl, void(GetLoginsRequest*, const PasswordForm&));
65 MOCK_METHOD1(GetAutofillableLoginsImpl, void(GetLoginsRequest*));
66 MOCK_METHOD1(GetBlacklistLoginsImpl, void(GetLoginsRequest*));
67 MOCK_METHOD1(FillAutofillableLogins,
68 bool(std::vector<webkit_glue::PasswordForm*>*));
69 MOCK_METHOD1(FillBlacklistLogins,
70 bool(std::vector<webkit_glue::PasswordForm*>*));
71 };
72
ACTION_P2(InvokeConsumer,handle,forms)73 ACTION_P2(InvokeConsumer, handle, forms) {
74 arg0->OnPasswordStoreRequestDone(handle, forms);
75 }
76
ACTION_P(SaveToScopedPtr,scoped)77 ACTION_P(SaveToScopedPtr, scoped) {
78 scoped->reset(arg0);
79 }
80
81 class PasswordManagerTest : public RenderViewHostTestHarness {
82 public:
PasswordManagerTest()83 PasswordManagerTest()
84 : ui_thread_(BrowserThread::UI, MessageLoopForUI::current()) {}
85 protected:
86
SetUp()87 virtual void SetUp() {
88 RenderViewHostTestHarness::SetUp();
89
90 store_ = new MockPasswordStore();
91 profile_.reset(new TestingProfileWithPasswordStore(store_));
92 EXPECT_CALL(delegate_, GetProfileForPasswordManager())
93 .WillRepeatedly(Return(profile_.get()));
94 manager_.reset(new PasswordManager(contents(), &delegate_));
95 EXPECT_CALL(delegate_, DidLastPageLoadEncounterSSLErrors())
96 .WillRepeatedly(Return(false));
97 }
98
TearDown()99 virtual void TearDown() {
100 manager_.reset();
101 store_ = NULL;
102 }
103
MakeSimpleForm()104 PasswordForm MakeSimpleForm() {
105 PasswordForm form;
106 form.origin = GURL("http://www.google.com/a/LoginAuth");
107 form.action = GURL("http://www.google.com/a/Login");
108 form.username_element = ASCIIToUTF16("Email");
109 form.password_element = ASCIIToUTF16("Passwd");
110 form.username_value = ASCIIToUTF16("google");
111 form.password_value = ASCIIToUTF16("password");
112 form.submit_element = ASCIIToUTF16("signIn");
113 form.signon_realm = "http://www.google.com";
114 return form;
115 }
116
manager()117 PasswordManager* manager() { return manager_.get(); }
118
119 // We create a UI thread to satisfy PasswordStore.
120 BrowserThread ui_thread_;
121
122 scoped_ptr<Profile> profile_;
123 scoped_refptr<MockPasswordStore> store_;
124 MockPasswordManagerDelegate delegate_; // Owned by manager_.
125 scoped_ptr<PasswordManager> manager_;
126 };
127
128 MATCHER_P(FormMatches, form, "") {
129 return form.signon_realm == arg.signon_realm &&
130 form.origin == arg.origin &&
131 form.action == arg.action &&
132 form.username_element == arg.username_element &&
133 form.password_element == arg.password_element &&
134 form.submit_element == arg.submit_element;
135 }
136
TEST_F(PasswordManagerTest,FormSubmitEmptyStore)137 TEST_F(PasswordManagerTest, FormSubmitEmptyStore) {
138 // Test that observing a newly submitted form shows the save password bar.
139 std::vector<PasswordForm*> result; // Empty password store.
140 EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
141 EXPECT_CALL(*store_, GetLogins(_,_))
142 .WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
143 std::vector<PasswordForm> observed;
144 PasswordForm form(MakeSimpleForm());
145 observed.push_back(form);
146 manager()->OnPasswordFormsFound(observed); // The initial load.
147 manager()->OnPasswordFormsVisible(observed); // The initial layout.
148
149 // And the form submit contract is to call ProvisionallySavePassword.
150 manager()->ProvisionallySavePassword(form);
151
152 scoped_ptr<PasswordFormManager> form_to_save;
153 EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
154 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
155
156 // Now the password manager waits for the navigation to complete.
157 manager()->DidStopLoading();
158
159 ASSERT_FALSE(NULL == form_to_save.get());
160 EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
161
162 // Simulate saving the form, as if the info bar was accepted.
163 form_to_save->Save();
164 }
165
TEST_F(PasswordManagerTest,FormSubmitNoGoodMatch)166 TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
167 // Same as above, except with an existing form for the same signon realm,
168 // but different origin. Detailed cases like this are covered by
169 // PasswordFormManagerTest.
170 std::vector<PasswordForm*> result;
171 PasswordForm* existing_different = new PasswordForm(MakeSimpleForm());
172 existing_different->username_value = ASCIIToUTF16("google2");
173 result.push_back(existing_different);
174 EXPECT_CALL(delegate_, FillPasswordForm(_));
175 EXPECT_CALL(*store_, GetLogins(_,_))
176 .WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
177
178 std::vector<PasswordForm> observed;
179 PasswordForm form(MakeSimpleForm());
180 observed.push_back(form);
181 manager()->OnPasswordFormsFound(observed); // The initial load.
182 manager()->OnPasswordFormsVisible(observed); // The initial layout.
183 manager()->ProvisionallySavePassword(form);
184
185 // We still expect an add, since we didn't have a good match.
186 scoped_ptr<PasswordFormManager> form_to_save;
187 EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
188 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
189
190 manager()->DidStopLoading();
191
192 EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
193 // Simulate saving the form.
194 form_to_save->Save();
195 }
196
TEST_F(PasswordManagerTest,FormSeenThenLeftPage)197 TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
198 std::vector<PasswordForm*> result; // Empty password store.
199 EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
200 EXPECT_CALL(*store_, GetLogins(_,_))
201 .WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
202 std::vector<PasswordForm> observed;
203 PasswordForm form(MakeSimpleForm());
204 observed.push_back(form);
205 manager()->OnPasswordFormsFound(observed); // The initial load.
206 manager()->OnPasswordFormsVisible(observed); // The initial layout.
207
208 manager()->DidNavigate();
209
210 // No expected calls.
211 manager()->DidStopLoading();
212 }
213
TEST_F(PasswordManagerTest,FormSubmitFailedLogin)214 TEST_F(PasswordManagerTest, FormSubmitFailedLogin) {
215 std::vector<PasswordForm*> result; // Empty password store.
216 EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
217 EXPECT_CALL(*store_, GetLogins(_,_))
218 .WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
219 std::vector<PasswordForm> observed;
220 PasswordForm form(MakeSimpleForm());
221 observed.push_back(form);
222 manager()->OnPasswordFormsFound(observed); // The initial load.
223 manager()->OnPasswordFormsVisible(observed); // The initial layout.
224
225 manager()->ProvisionallySavePassword(form);
226
227 // The form reappears, and is visible in the layout:
228 manager()->OnPasswordFormsFound(observed);
229 manager()->OnPasswordFormsVisible(observed);
230
231 // No expected calls to the PasswordStore...
232 manager()->DidStopLoading();
233 }
234
TEST_F(PasswordManagerTest,FormSubmitInvisibleLogin)235 TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) {
236 // Tests fix of issue 28911: if the login form reappears on the subsequent
237 // page, but is invisible, it shouldn't count as a failed login.
238 std::vector<PasswordForm*> result; // Empty password store.
239 EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
240 EXPECT_CALL(*store_, GetLogins(_,_))
241 .WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
242 std::vector<PasswordForm> observed;
243 PasswordForm form(MakeSimpleForm());
244 observed.push_back(form);
245 manager()->OnPasswordFormsFound(observed); // The initial load.
246 manager()->OnPasswordFormsVisible(observed); // The initial layout.
247
248 manager()->ProvisionallySavePassword(form);
249
250 // The form reappears, but is not visible in the layout:
251 manager()->OnPasswordFormsFound(observed);
252 // No call to PasswordFormsVisible.
253
254 // Expect info bar to appear:
255 scoped_ptr<PasswordFormManager> form_to_save;
256 EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
257 .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
258
259 manager()->DidStopLoading();
260
261 ASSERT_FALSE(NULL == form_to_save.get());
262 EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
263 // Simulate saving the form.
264 form_to_save->Save();
265 }
266
TEST_F(PasswordManagerTest,InitiallyInvisibleForm)267 TEST_F(PasswordManagerTest, InitiallyInvisibleForm) {
268 // Make sure an invisible login form still gets autofilled.
269 std::vector<PasswordForm*> result;
270 PasswordForm* existing = new PasswordForm(MakeSimpleForm());
271 result.push_back(existing);
272 EXPECT_CALL(delegate_, FillPasswordForm(_));
273 EXPECT_CALL(*store_, GetLogins(_,_))
274 .WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
275 std::vector<PasswordForm> observed;
276 PasswordForm form(MakeSimpleForm());
277 observed.push_back(form);
278 manager()->OnPasswordFormsFound(observed); // The initial load.
279 // PasswordFormsVisible is not called.
280
281 manager()->DidStopLoading();
282 }
283