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: 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 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 73 ACTION_P2(InvokeConsumer, handle, forms) { 74 arg0->OnPasswordStoreRequestDone(handle, forms); 75 } 76 77 ACTION_P(SaveToScopedPtr, scoped) { 78 scoped->reset(arg0); 79 } 80 81 class 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 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 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 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 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 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 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 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