1 // Copyright 2014 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 "chrome/browser/password_manager/chrome_password_manager_client.h" 6 7 #include "base/command_line.h" 8 #include "base/strings/string16.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/common/chrome_version_info.h" 11 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 12 #include "chrome/test/base/testing_profile.h" 13 #include "components/autofill/content/common/autofill_messages.h" 14 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h" 15 #include "components/password_manager/content/common/credential_manager_messages.h" 16 #include "components/password_manager/content/common/credential_manager_types.h" 17 #include "components/password_manager/core/browser/log_receiver.h" 18 #include "components/password_manager/core/browser/password_manager_internals_service.h" 19 #include "components/password_manager/core/common/password_manager_switches.h" 20 #include "content/public/browser/browser_context.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/test/mock_render_process_host.h" 23 #include "testing/gmock/include/gmock/gmock.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 26 using content::BrowserContext; 27 using content::WebContents; 28 29 namespace { 30 31 const char kTestText[] = "abcd1234"; 32 const int kRequestId = 4; 33 34 class MockLogReceiver : public password_manager::LogReceiver { 35 public: 36 MOCK_METHOD1(LogSavePasswordProgress, void(const std::string&)); 37 }; 38 39 class TestChromePasswordManagerClient : public ChromePasswordManagerClient { 40 public: 41 explicit TestChromePasswordManagerClient(content::WebContents* web_contents) 42 : ChromePasswordManagerClient(web_contents, NULL), 43 is_sync_account_credential_(false) {} 44 virtual ~TestChromePasswordManagerClient() {} 45 46 virtual bool IsSyncAccountCredential( 47 const std::string& username, 48 const std::string& origin) const OVERRIDE { 49 return is_sync_account_credential_; 50 } 51 52 void set_is_sync_account_credential(bool is_sync_account_credential) { 53 is_sync_account_credential_ = is_sync_account_credential; 54 } 55 56 private: 57 bool is_sync_account_credential_; 58 59 DISALLOW_COPY_AND_ASSIGN(TestChromePasswordManagerClient); 60 }; 61 62 } // namespace 63 64 class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness { 65 public: 66 ChromePasswordManagerClientTest(); 67 68 virtual void SetUp() OVERRIDE; 69 70 protected: 71 ChromePasswordManagerClient* GetClient(); 72 73 // If the test IPC sink contains an AutofillMsg_SetLoggingState message, then 74 // copies its argument into |activation_flag| and returns true. Otherwise 75 // returns false. 76 bool WasLoggingActivationMessageSent(bool* activation_flag); 77 78 password_manager::PasswordManagerInternalsService* service_; 79 80 testing::StrictMock<MockLogReceiver> receiver_; 81 }; 82 83 ChromePasswordManagerClientTest::ChromePasswordManagerClientTest() 84 : service_(NULL) { 85 } 86 87 void ChromePasswordManagerClientTest::SetUp() { 88 ChromeRenderViewHostTestHarness::SetUp(); 89 ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient( 90 web_contents(), NULL); 91 service_ = password_manager::PasswordManagerInternalsServiceFactory:: 92 GetForBrowserContext(profile()); 93 ASSERT_TRUE(service_); 94 } 95 96 ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() { 97 return ChromePasswordManagerClient::FromWebContents(web_contents()); 98 } 99 100 bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent( 101 bool* activation_flag) { 102 const uint32 kMsgID = AutofillMsg_SetLoggingState::ID; 103 const IPC::Message* message = 104 process()->sink().GetFirstMessageMatching(kMsgID); 105 if (!message) 106 return false; 107 Tuple1<bool> param; 108 AutofillMsg_SetLoggingState::Read(message, ¶m); 109 *activation_flag = param.a; 110 process()->sink().ClearMessages(); 111 return true; 112 } 113 114 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNoReceiver) { 115 ChromePasswordManagerClient* client = GetClient(); 116 117 EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0); 118 // Before attaching the receiver, no text should be passed. 119 client->LogSavePasswordProgress(kTestText); 120 EXPECT_FALSE(client->IsLoggingActive()); 121 } 122 123 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressAttachReceiver) { 124 ChromePasswordManagerClient* client = GetClient(); 125 EXPECT_FALSE(client->IsLoggingActive()); 126 127 // After attaching the logger, text should be passed. 128 service_->RegisterReceiver(&receiver_); 129 EXPECT_TRUE(client->IsLoggingActive()); 130 EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1); 131 client->LogSavePasswordProgress(kTestText); 132 service_->UnregisterReceiver(&receiver_); 133 EXPECT_FALSE(client->IsLoggingActive()); 134 } 135 136 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressDetachReceiver) { 137 ChromePasswordManagerClient* client = GetClient(); 138 139 service_->RegisterReceiver(&receiver_); 140 EXPECT_TRUE(client->IsLoggingActive()); 141 service_->UnregisterReceiver(&receiver_); 142 EXPECT_FALSE(client->IsLoggingActive()); 143 144 // After detaching the logger, no text should be passed. 145 EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0); 146 client->LogSavePasswordProgress(kTestText); 147 } 148 149 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNotifyRenderer) { 150 ChromePasswordManagerClient* client = GetClient(); 151 bool logging_active = false; 152 153 // Initially, the logging should be off, so no IPC messages. 154 EXPECT_FALSE(WasLoggingActivationMessageSent(&logging_active)); 155 156 service_->RegisterReceiver(&receiver_); 157 EXPECT_TRUE(client->IsLoggingActive()); 158 EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); 159 EXPECT_TRUE(logging_active); 160 161 service_->UnregisterReceiver(&receiver_); 162 EXPECT_FALSE(client->IsLoggingActive()); 163 EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); 164 EXPECT_FALSE(logging_active); 165 } 166 167 TEST_F(ChromePasswordManagerClientTest, AnswerToPingsAboutLoggingState_Active) { 168 service_->RegisterReceiver(&receiver_); 169 170 process()->sink().ClearMessages(); 171 172 // Ping the client for logging activity update. 173 AutofillHostMsg_PasswordAutofillAgentConstructed msg(0); 174 static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg); 175 176 bool logging_active = false; 177 EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); 178 EXPECT_TRUE(logging_active); 179 180 service_->UnregisterReceiver(&receiver_); 181 } 182 183 TEST_F(ChromePasswordManagerClientTest, 184 AnswerToPingsAboutLoggingState_Inactive) { 185 process()->sink().ClearMessages(); 186 187 // Ping the client for logging activity update. 188 AutofillHostMsg_PasswordAutofillAgentConstructed msg(0); 189 static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg); 190 191 bool logging_active = true; 192 EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); 193 EXPECT_FALSE(logging_active); 194 } 195 196 TEST_F(ChromePasswordManagerClientTest, 197 IsAutomaticPasswordSavingEnabledDefaultBehaviourTest) { 198 EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled()); 199 } 200 201 TEST_F(ChromePasswordManagerClientTest, 202 IsAutomaticPasswordSavingEnabledWhenFlagIsSetTest) { 203 CommandLine::ForCurrentProcess()->AppendSwitch( 204 password_manager::switches::kEnableAutomaticPasswordSaving); 205 if (chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN) 206 EXPECT_TRUE(GetClient()->IsAutomaticPasswordSavingEnabled()); 207 else 208 EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled()); 209 } 210 211 TEST_F(ChromePasswordManagerClientTest, LogToAReceiver) { 212 ChromePasswordManagerClient* client = GetClient(); 213 service_->RegisterReceiver(&receiver_); 214 EXPECT_TRUE(client->IsLoggingActive()); 215 216 EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1); 217 client->LogSavePasswordProgress(kTestText); 218 219 service_->UnregisterReceiver(&receiver_); 220 EXPECT_FALSE(client->IsLoggingActive()); 221 } 222 223 TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult_Reauth) { 224 // Make client disallow only reauth requests. 225 CommandLine* command_line = CommandLine::ForCurrentProcess(); 226 command_line->AppendSwitch( 227 password_manager::switches::kDisallowAutofillSyncCredentialForReauth); 228 scoped_ptr<TestChromePasswordManagerClient> client( 229 new TestChromePasswordManagerClient(web_contents())); 230 autofill::PasswordForm form; 231 232 client->set_is_sync_account_credential(false); 233 NavigateAndCommit( 234 GURL("https://accounts.google.com/login?rart=123&continue=blah")); 235 EXPECT_FALSE(client->ShouldFilterAutofillResult(form)); 236 237 client->set_is_sync_account_credential(true); 238 NavigateAndCommit( 239 GURL("https://accounts.google.com/login?rart=123&continue=blah")); 240 EXPECT_TRUE(client->ShouldFilterAutofillResult(form)); 241 242 // This counts as a reauth url, though a valid URL should have a value for 243 // "rart" 244 NavigateAndCommit(GURL("https://accounts.google.com/addlogin?rart")); 245 EXPECT_TRUE(client->ShouldFilterAutofillResult(form)); 246 247 NavigateAndCommit(GURL("https://accounts.google.com/login?param=123")); 248 EXPECT_FALSE(client->ShouldFilterAutofillResult(form)); 249 250 NavigateAndCommit(GURL("https://site.com/login?rart=678")); 251 EXPECT_FALSE(client->ShouldFilterAutofillResult(form)); 252 } 253 254 TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult) { 255 // Normally the client should allow any credentials through, even if they 256 // are the sync credential. 257 scoped_ptr<TestChromePasswordManagerClient> client( 258 new TestChromePasswordManagerClient(web_contents())); 259 autofill::PasswordForm form; 260 client->set_is_sync_account_credential(true); 261 NavigateAndCommit(GURL("https://accounts.google.com/Login")); 262 EXPECT_FALSE(client->ShouldFilterAutofillResult(form)); 263 264 // Adding disallow switch should cause sync credential to be filtered. 265 CommandLine* command_line = CommandLine::ForCurrentProcess(); 266 command_line->AppendSwitch( 267 password_manager::switches::kDisallowAutofillSyncCredential); 268 client.reset(new TestChromePasswordManagerClient(web_contents())); 269 client->set_is_sync_account_credential(true); 270 NavigateAndCommit(GURL("https://accounts.google.com/Login")); 271 EXPECT_TRUE(client->ShouldFilterAutofillResult(form)); 272 } 273 274 TEST_F(ChromePasswordManagerClientTest, 275 IsPasswordManagerEnabledForCurrentPage) { 276 ChromePasswordManagerClient* client = GetClient(); 277 NavigateAndCommit( 278 GURL("https://accounts.google.com/ServiceLogin?continue=" 279 "https://passwords.google.com/settings&rart=123")); 280 EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage()); 281 282 // Password site is inaccesible via HTTP, but because of HSTS the following 283 // link should still continue to https://passwords.google.com. 284 NavigateAndCommit( 285 GURL("https://accounts.google.com/ServiceLogin?continue=" 286 "http://passwords.google.com/settings&rart=123")); 287 EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage()); 288 289 // Specifying default port still passes. 290 NavigateAndCommit( 291 GURL("https://accounts.google.com/ServiceLogin?continue=" 292 "https://passwords.google.com:443/settings&rart=123")); 293 EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage()); 294 295 // Encoded URL is considered the same. 296 NavigateAndCommit( 297 GURL("https://accounts.google.com/ServiceLogin?continue=" 298 "https://passwords.%67oogle.com/settings&rart=123")); 299 EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage()); 300 301 // Make sure testing sites are disabled as well. 302 NavigateAndCommit( 303 GURL("https://accounts.google.com/Login?continue=" 304 "https://passwords-ac-testing.corp.google.com/settings&rart=456")); 305 EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage()); 306 307 // Fully qualified domain name is considered a different hostname by GURL. 308 // Ideally this would not be the case, but this quirk can be avoided by 309 // verification on the server. This test is simply documentation of this 310 // behavior. 311 NavigateAndCommit( 312 GURL("https://accounts.google.com/ServiceLogin?continue=" 313 "https://passwords.google.com./settings&rart=123")); 314 EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage()); 315 316 // Not a transactional reauth page. 317 NavigateAndCommit( 318 GURL("https://accounts.google.com/ServiceLogin?continue=" 319 "https://passwords.google.com/settings")); 320 EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage()); 321 322 // Should be enabled for other transactional reauth pages. 323 NavigateAndCommit( 324 GURL("https://accounts.google.com/ServiceLogin?continue=" 325 "https://mail.google.com&rart=234")); 326 EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage()); 327 328 // Reauth pages are only on accounts.google.com 329 NavigateAndCommit( 330 GURL("https://other.site.com/ServiceLogin?continue=" 331 "https://passwords.google.com&rart=234")); 332 EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage()); 333 } 334 335 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifyFailedSignIn) { 336 scoped_ptr<TestChromePasswordManagerClient> client( 337 new TestChromePasswordManagerClient(web_contents())); 338 339 password_manager::CredentialInfo info(base::ASCIIToUTF16("id"), 340 base::ASCIIToUTF16("name"), 341 GURL("https://example.com/image.png")); 342 client->OnNotifyFailedSignIn(kRequestId, info); 343 344 const uint32 kMsgID = CredentialManagerMsg_AcknowledgeFailedSignIn::ID; 345 const IPC::Message* message = 346 process()->sink().GetFirstMessageMatching(kMsgID); 347 EXPECT_TRUE(message); 348 process()->sink().ClearMessages(); 349 } 350 351 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifySignedIn) { 352 scoped_ptr<TestChromePasswordManagerClient> client( 353 new TestChromePasswordManagerClient(web_contents())); 354 355 password_manager::CredentialInfo info(base::ASCIIToUTF16("id"), 356 base::ASCIIToUTF16("name"), 357 GURL("https://example.com/image.png")); 358 client->OnNotifySignedIn(kRequestId, info); 359 360 const uint32 kMsgID = CredentialManagerMsg_AcknowledgeSignedIn::ID; 361 const IPC::Message* message = 362 process()->sink().GetFirstMessageMatching(kMsgID); 363 EXPECT_TRUE(message); 364 process()->sink().ClearMessages(); 365 } 366 367 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifySignedOut) { 368 scoped_ptr<TestChromePasswordManagerClient> client( 369 new TestChromePasswordManagerClient(web_contents())); 370 371 client->OnNotifySignedOut(kRequestId); 372 373 const uint32 kMsgID = CredentialManagerMsg_AcknowledgeSignedOut::ID; 374 const IPC::Message* message = 375 process()->sink().GetFirstMessageMatching(kMsgID); 376 EXPECT_TRUE(message); 377 process()->sink().ClearMessages(); 378 } 379 380 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnRequestCredential) { 381 scoped_ptr<TestChromePasswordManagerClient> client( 382 new TestChromePasswordManagerClient(web_contents())); 383 384 std::vector<GURL> federations; 385 client->OnRequestCredential(kRequestId, false, federations); 386 387 const uint32 kMsgID = CredentialManagerMsg_SendCredential::ID; 388 const IPC::Message* message = 389 process()->sink().GetFirstMessageMatching(kMsgID); 390 EXPECT_TRUE(message); 391 process()->sink().ClearMessages(); 392 } 393