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
21using webkit_glue::PasswordForm;
22using testing::_;
23using testing::DoAll;
24using ::testing::Exactly;
25using ::testing::WithArg;
26using ::testing::Return;
27
28class 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
37class TestingProfileWithPasswordStore : public TestingProfile {
38 public:
39  explicit TestingProfileWithPasswordStore(PasswordStore* store)
40      : store_(store) {}
41  virtual ~TestingProfileWithPasswordStore() {
42    store_->Shutdown();
43  }
44  virtual PasswordStore* GetPasswordStore(ServiceAccessType access) {
45    return store_;
46  }
47 private:
48  scoped_refptr<PasswordStore> store_;
49};
50
51class 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
73ACTION_P2(InvokeConsumer, handle, forms) {
74  arg0->OnPasswordStoreRequestDone(handle, forms);
75}
76
77ACTION_P(SaveToScopedPtr, scoped) {
78  scoped->reset(arg0);
79}
80
81class PasswordManagerTest : public RenderViewHostTestHarness {
82 public:
83  PasswordManagerTest()
84      : ui_thread_(BrowserThread::UI, MessageLoopForUI::current()) {}
85 protected:
86
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
99  virtual void TearDown() {
100    manager_.reset();
101    store_ = NULL;
102  }
103
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
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
128MATCHER_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
137TEST_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
166TEST_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
197TEST_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
214TEST_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
235TEST_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
267TEST_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