blob: 157aaee2e67d06d3e7a08d3f75a5d6fba41eb830 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/autofill/content/common/autofill_messages.h"
#include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
#include "components/password_manager/core/browser/log_receiver.h"
#include "components/password_manager/core/browser/password_manager_internals_service.h"
#include "components/password_manager/core/common/password_manager_switches.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/mock_render_process_host.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserContext;
using content::WebContents;
namespace {
const char kTestText[] = "abcd1234";
class MockLogReceiver : public password_manager::LogReceiver {
public:
MOCK_METHOD1(LogSavePasswordProgress, void(const std::string&));
};
class TestChromePasswordManagerClient : public ChromePasswordManagerClient {
public:
explicit TestChromePasswordManagerClient(content::WebContents* web_contents)
: ChromePasswordManagerClient(web_contents, NULL),
is_sync_account_credential_(false) {}
virtual ~TestChromePasswordManagerClient() {}
virtual bool IsSyncAccountCredential(
const std::string& username,
const std::string& origin) const OVERRIDE {
return is_sync_account_credential_;
}
void set_is_sync_account_credential(bool is_sync_account_credential) {
is_sync_account_credential_ = is_sync_account_credential;
}
private:
bool is_sync_account_credential_;
DISALLOW_COPY_AND_ASSIGN(TestChromePasswordManagerClient);
};
} // namespace
class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness {
public:
ChromePasswordManagerClientTest();
virtual void SetUp() OVERRIDE;
protected:
ChromePasswordManagerClient* GetClient();
// If the test IPC sink contains an AutofillMsg_SetLoggingState message, then
// copies its argument into |activation_flag| and returns true. Otherwise
// returns false.
bool WasLoggingActivationMessageSent(bool* activation_flag);
password_manager::PasswordManagerInternalsService* service_;
testing::StrictMock<MockLogReceiver> receiver_;
};
ChromePasswordManagerClientTest::ChromePasswordManagerClientTest()
: service_(NULL) {
}
void ChromePasswordManagerClientTest::SetUp() {
ChromeRenderViewHostTestHarness::SetUp();
ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
web_contents(), NULL);
service_ = password_manager::PasswordManagerInternalsServiceFactory::
GetForBrowserContext(profile());
ASSERT_TRUE(service_);
}
ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() {
return ChromePasswordManagerClient::FromWebContents(web_contents());
}
bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent(
bool* activation_flag) {
const uint32 kMsgID = AutofillMsg_SetLoggingState::ID;
const IPC::Message* message =
process()->sink().GetFirstMessageMatching(kMsgID);
if (!message)
return false;
Tuple1<bool> param;
AutofillMsg_SetLoggingState::Read(message, &param);
*activation_flag = param.a;
process()->sink().ClearMessages();
return true;
}
TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNoReceiver) {
ChromePasswordManagerClient* client = GetClient();
EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0);
// Before attaching the receiver, no text should be passed.
client->LogSavePasswordProgress(kTestText);
EXPECT_FALSE(client->IsLoggingActive());
}
TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressAttachReceiver) {
ChromePasswordManagerClient* client = GetClient();
EXPECT_FALSE(client->IsLoggingActive());
// After attaching the logger, text should be passed.
service_->RegisterReceiver(&receiver_);
EXPECT_TRUE(client->IsLoggingActive());
EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1);
client->LogSavePasswordProgress(kTestText);
service_->UnregisterReceiver(&receiver_);
EXPECT_FALSE(client->IsLoggingActive());
}
TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressDetachReceiver) {
ChromePasswordManagerClient* client = GetClient();
service_->RegisterReceiver(&receiver_);
EXPECT_TRUE(client->IsLoggingActive());
service_->UnregisterReceiver(&receiver_);
EXPECT_FALSE(client->IsLoggingActive());
// After detaching the logger, no text should be passed.
EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0);
client->LogSavePasswordProgress(kTestText);
}
TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNotifyRenderer) {
ChromePasswordManagerClient* client = GetClient();
bool logging_active = false;
// Initially, the logging should be off, so no IPC messages.
EXPECT_FALSE(WasLoggingActivationMessageSent(&logging_active));
service_->RegisterReceiver(&receiver_);
EXPECT_TRUE(client->IsLoggingActive());
EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
EXPECT_TRUE(logging_active);
service_->UnregisterReceiver(&receiver_);
EXPECT_FALSE(client->IsLoggingActive());
EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
EXPECT_FALSE(logging_active);
}
TEST_F(ChromePasswordManagerClientTest, AnswerToPingsAboutLoggingState_Active) {
service_->RegisterReceiver(&receiver_);
process()->sink().ClearMessages();
// Ping the client for logging activity update.
AutofillHostMsg_PasswordAutofillAgentConstructed msg(0);
static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg);
bool logging_active = false;
EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
EXPECT_TRUE(logging_active);
service_->UnregisterReceiver(&receiver_);
}
TEST_F(ChromePasswordManagerClientTest,
AnswerToPingsAboutLoggingState_Inactive) {
process()->sink().ClearMessages();
// Ping the client for logging activity update.
AutofillHostMsg_PasswordAutofillAgentConstructed msg(0);
static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg);
bool logging_active = true;
EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
EXPECT_FALSE(logging_active);
}
TEST_F(ChromePasswordManagerClientTest,
IsAutomaticPasswordSavingEnabledDefaultBehaviourTest) {
EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled());
}
TEST_F(ChromePasswordManagerClientTest,
IsAutomaticPasswordSavingEnabledWhenFlagIsSetTest) {
CommandLine::ForCurrentProcess()->AppendSwitch(
password_manager::switches::kEnableAutomaticPasswordSaving);
if (chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN)
EXPECT_TRUE(GetClient()->IsAutomaticPasswordSavingEnabled());
else
EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled());
}
TEST_F(ChromePasswordManagerClientTest, LogToAReceiver) {
ChromePasswordManagerClient* client = GetClient();
service_->RegisterReceiver(&receiver_);
EXPECT_TRUE(client->IsLoggingActive());
EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1);
client->LogSavePasswordProgress(kTestText);
service_->UnregisterReceiver(&receiver_);
EXPECT_FALSE(client->IsLoggingActive());
}
TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult_Reauth) {
// Make client disallow only reauth requests.
CommandLine* command_line = CommandLine::ForCurrentProcess();
command_line->AppendSwitch(
password_manager::switches::kDisallowAutofillSyncCredentialForReauth);
scoped_ptr<TestChromePasswordManagerClient> client(
new TestChromePasswordManagerClient(web_contents()));
autofill::PasswordForm form;
client->set_is_sync_account_credential(false);
NavigateAndCommit(
GURL("https://accounts.google.com/login?rart=123&continue=blah"));
EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
client->set_is_sync_account_credential(true);
NavigateAndCommit(
GURL("https://accounts.google.com/login?rart=123&continue=blah"));
EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
// This counts as a reauth url, though a valid URL should have a value for
// "rart"
NavigateAndCommit(GURL("https://accounts.google.com/addlogin?rart"));
EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
NavigateAndCommit(GURL("https://accounts.google.com/login?param=123"));
EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
NavigateAndCommit(GURL("https://site.com/login?rart=678"));
EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
}
TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult) {
// Normally the client should allow any credentials through, even if they
// are the sync credential.
scoped_ptr<TestChromePasswordManagerClient> client(
new TestChromePasswordManagerClient(web_contents()));
autofill::PasswordForm form;
client->set_is_sync_account_credential(true);
NavigateAndCommit(GURL("https://accounts.google.com/Login"));
EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
// Adding disallow switch should cause sync credential to be filtered.
CommandLine* command_line = CommandLine::ForCurrentProcess();
command_line->AppendSwitch(
password_manager::switches::kDisallowAutofillSyncCredential);
client.reset(new TestChromePasswordManagerClient(web_contents()));
client->set_is_sync_account_credential(true);
NavigateAndCommit(GURL("https://accounts.google.com/Login"));
EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
}
TEST_F(ChromePasswordManagerClientTest,
IsPasswordManagerEnabledForCurrentPage) {
ChromePasswordManagerClient* client = GetClient();
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://passwords.google.com/settings&rart=123"));
EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
// Password site is inaccesible via HTTP, but because of HSTS the following
// link should still continue to https://passwords.google.com.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"http://passwords.google.com/settings&rart=123"));
EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
// Specifying default port still passes.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://passwords.google.com:443/settings&rart=123"));
EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
// Encoded URL is considered the same.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://passwords.%67oogle.com/settings&rart=123"));
EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
// Fully qualified domain name is considered a different hostname by GURL.
// Ideally this would not be the case, but this quirk can be avoided by
// verification on the server. This test is simply documentation of this
// behavior.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://passwords.google.com./settings&rart=123"));
EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
// Not a transactional reauth page.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://passwords.google.com/settings"));
EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
// Should be enabled for other transactional reauth pages.
NavigateAndCommit(
GURL("https://accounts.google.com/ServiceLogin?continue="
"https://mail.google.com&rart=234"));
EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
// Reauth pages are only on accounts.google.com
NavigateAndCommit(
GURL("https://other.site.com/ServiceLogin?continue="
"https://passwords.google.com&rart=234"));
EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
}