Commit d0acf2a7 authored by Eric Lawrence's avatar Eric Lawrence Committed by Commit Bot

Move SensitiveInputVisibility from password manager to browser

Previously, SensitiveInputVisibility events were reported to the
password manager. Chrome will soon introduce new states that trigger
the "Not Secure" warning in Chrome's omnibox (including edits of any
input type), meaning that the events are more naturally handled in
\chrome\browser\ssl instead. This CL extracts the handler from the
password manager to a new class. Future CLs will extend the mojo
interface with new events.

Bug: 720094
Change-Id: If7d2678dce2bda050fe488b69da0f754c7bb668b
Reviewed-on: https://chromium-review.googlesource.com/574759
Commit-Queue: Eric Lawrence <elawrence@chromium.org>
Reviewed-by: default avatarEmily Stark <estark@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarVaclav Brozek <vabr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488308}
parent 0e0ca1fb
......@@ -1301,6 +1301,10 @@ split_static_library("browser") {
"ssl/chrome_ssl_host_state_delegate_factory.h",
"ssl/common_name_mismatch_handler.cc",
"ssl/common_name_mismatch_handler.h",
"ssl/insecure_sensitive_input_driver.cc",
"ssl/insecure_sensitive_input_driver.h",
"ssl/insecure_sensitive_input_driver_factory.cc",
"ssl/insecure_sensitive_input_driver_factory.h",
"ssl/security_state_tab_helper.cc",
"ssl/security_state_tab_helper.h",
"ssl/ssl_blocking_page.cc",
......@@ -1309,6 +1313,8 @@ split_static_library("browser") {
"ssl/ssl_client_certificate_selector.h",
"ssl/ssl_error_handler.cc",
"ssl/ssl_error_handler.h",
"ssl/visible_password_observer.cc",
"ssl/visible_password_observer.h",
"status_icons/status_icon.cc",
"status_icons/status_icon.h",
"status_icons/status_icon_menu_model.cc",
......
......@@ -134,6 +134,7 @@ include_rules = [
"+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
"+third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
"+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
"+third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h",
"+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h",
"+third_party/WebKit/public/platform/site_engagement.mojom.h",
"+third_party/WebKit/public/public_features.h",
......
......@@ -84,6 +84,7 @@
#include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h"
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/browser/speech/tts_message_filter.h"
#include "chrome/browser/ssl/insecure_sensitive_input_driver_factory.h"
#include "chrome/browser/ssl/ssl_blocking_page.h"
#include "chrome/browser/ssl/ssl_cert_reporter.h"
#include "chrome/browser/ssl/ssl_client_certificate_selector.h"
......@@ -3297,8 +3298,7 @@ void ChromeContentBrowserClient::InitFrameInterfaces() {
BindPasswordManagerDriver));
frame_interfaces_parameterized_->AddInterface(
base::Bind(&password_manager::ContentPasswordManagerDriverFactory::
BindSensitiveInputVisibilityService));
base::Bind(&InsecureSensitiveInputDriverFactory::BindDriver));
#if defined(OS_ANDROID)
frame_interfaces_parameterized_->AddInterface(base::Bind(
......
// Copyright 2017 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 "chrome/browser/ssl/insecure_sensitive_input_driver.h"
#include <utility>
#include "chrome/browser/ssl/insecure_sensitive_input_driver_factory.h"
#include "chrome/browser/ssl/visible_password_observer.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
InsecureSensitiveInputDriver::InsecureSensitiveInputDriver(
content::RenderFrameHost* render_frame_host)
: render_frame_host_(render_frame_host) {
// Does nothing if a VisiblePasswordObserver has already been created
// for this WebContents.
VisiblePasswordObserver::CreateForWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
}
InsecureSensitiveInputDriver::~InsecureSensitiveInputDriver() {}
void InsecureSensitiveInputDriver::BindSensitiveInputVisibilityServiceRequest(
blink::mojom::SensitiveInputVisibilityServiceRequest request) {
sensitive_input_visibility_bindings_.AddBinding(this, std::move(request));
}
void InsecureSensitiveInputDriver::PasswordFieldVisibleInInsecureContext() {
VisiblePasswordObserver* observer = VisiblePasswordObserver::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
observer->RenderFrameHasVisiblePasswordField(render_frame_host_);
}
void InsecureSensitiveInputDriver::
AllPasswordFieldsInInsecureContextInvisible() {
VisiblePasswordObserver* observer = VisiblePasswordObserver::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
observer->RenderFrameHasNoVisiblePasswordFields(render_frame_host_);
}
// Copyright 2017 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.
#ifndef CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_H_
#define CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_H_
#include "mojo/public/cpp/bindings/binding_set.h"
#include "third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h"
namespace content {
class RenderFrameHost;
}
// The InsecureSensitiveInputDriver watches for SensitiveInputVisibility
// events from renderers, and surfaces notifications through
// VisiblePasswordObservers.
//
// There is one InsecureSensitiveInputDriver per RenderFrameHost.
// The lifetime is managed by the InsecureSensitiveInputDriverFactory.
class InsecureSensitiveInputDriver
: public blink::mojom::SensitiveInputVisibilityService {
public:
explicit InsecureSensitiveInputDriver(
content::RenderFrameHost* render_frame_host);
~InsecureSensitiveInputDriver() override;
void BindSensitiveInputVisibilityServiceRequest(
blink::mojom::SensitiveInputVisibilityServiceRequest request);
// blink::mojom::SensitiveInputVisibility:
void PasswordFieldVisibleInInsecureContext() override;
void AllPasswordFieldsInInsecureContextInvisible() override;
private:
content::RenderFrameHost* render_frame_host_;
mojo::BindingSet<blink::mojom::SensitiveInputVisibilityService>
sensitive_input_visibility_bindings_;
DISALLOW_COPY_AND_ASSIGN(InsecureSensitiveInputDriver);
};
#endif // CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_H_
// Copyright 2017 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 "chrome/browser/ssl/insecure_sensitive_input_driver_factory.h"
#include <utility>
#include <vector>
#include "base/stl_util.h"
#include "chrome/browser/ssl/insecure_sensitive_input_driver.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(InsecureSensitiveInputDriverFactory);
InsecureSensitiveInputDriverFactory::~InsecureSensitiveInputDriverFactory() {}
// static
void InsecureSensitiveInputDriverFactory::BindDriver(
blink::mojom::SensitiveInputVisibilityServiceRequest request,
content::RenderFrameHost* render_frame_host) {
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents)
return;
InsecureSensitiveInputDriverFactory* factory = FromWebContents(web_contents);
// If a factory does not yet exist for |web_contents|, create one.
if (!factory) {
content::WebContentsUserData<InsecureSensitiveInputDriverFactory>::
CreateForWebContents(web_contents);
factory = FromWebContents(web_contents);
DCHECK(factory);
}
InsecureSensitiveInputDriver* driver =
factory->GetDriverForFrame(render_frame_host);
if (driver)
driver->BindSensitiveInputVisibilityServiceRequest(std::move(request));
}
InsecureSensitiveInputDriver*
InsecureSensitiveInputDriverFactory::GetDriverForFrame(
content::RenderFrameHost* render_frame_host) {
auto mapping = frame_driver_map_.find(render_frame_host);
return mapping == frame_driver_map_.end() ? nullptr : mapping->second.get();
}
void InsecureSensitiveInputDriverFactory::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
auto insertion_result =
frame_driver_map_.insert(std::make_pair(render_frame_host, nullptr));
// If the map didn't already contain |render_frame_host|, construct a
// new InsecureSensitiveInputDriver.
if (insertion_result.second) {
insertion_result.first->second =
base::MakeUnique<InsecureSensitiveInputDriver>(render_frame_host);
}
}
void InsecureSensitiveInputDriverFactory::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
frame_driver_map_.erase(render_frame_host);
}
InsecureSensitiveInputDriverFactory::InsecureSensitiveInputDriverFactory(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
// Create a |InsecureSensitiveInputDriver| for each frame in |web_contents|.
const std::vector<content::RenderFrameHost*> frames =
web_contents->GetAllFrames();
for (content::RenderFrameHost* frame : frames) {
if (frame->IsRenderFrameLive())
RenderFrameCreated(frame);
}
}
// Copyright 2017 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.
#ifndef CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_FACTORY_H_
#define CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_FACTORY_H_
#include <map>
#include <memory>
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h"
namespace content {
class WebContents;
}
class InsecureSensitiveInputDriver;
// Creates and owns InsecureSensitiveInputDrivers. There is one
// factory per WebContents, and one driver per render frame.
class InsecureSensitiveInputDriverFactory
: public content::WebContentsObserver,
public content::WebContentsUserData<InsecureSensitiveInputDriverFactory> {
public:
~InsecureSensitiveInputDriverFactory() override;
// Creates a factory for the |web_contents|, enumerates its current frames
// and creates an |InsecureSensitiveInputDriver| for each.
static void BindDriver(
blink::mojom::SensitiveInputVisibilityServiceRequest request,
content::RenderFrameHost* render_frame_host);
// Returns the |InsecureSensitiveInputDriver| previously created for the
// specified |render_frame_host| by |CreateForWebContents| or
// |RenderFrameCreated|. Returns nullptr if the driver is missing.
InsecureSensitiveInputDriver* GetDriverForFrame(
content::RenderFrameHost* render_frame_host);
// content::WebContentsObserver:
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
private:
explicit InsecureSensitiveInputDriverFactory(
content::WebContents* web_contents);
friend class content::WebContentsUserData<
InsecureSensitiveInputDriverFactory>;
std::map<content::RenderFrameHost*,
std::unique_ptr<InsecureSensitiveInputDriver>>
frame_driver_map_;
DISALLOW_COPY_AND_ASSIGN(InsecureSensitiveInputDriverFactory);
};
#endif // CHROME_BROWSER_SSL_INSECURE_SENSITIVE_INPUT_DRIVER_FACTORY_H_
// Copyright 2017 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 "chrome/browser/ssl/insecure_sensitive_input_driver.h"
#include <memory>
#include <string>
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/web_contents_tester.h"
namespace {
class InsecureSensitiveInputDriverTest
: public ChromeRenderViewHostTestHarness {
protected:
InsecureSensitiveInputDriverTest() {}
~InsecureSensitiveInputDriverTest() override {}
private:
DISALLOW_COPY_AND_ASSIGN(InsecureSensitiveInputDriverTest);
};
// Tests that password visibility notifications are forwarded to the
// WebContents.
TEST_F(InsecureSensitiveInputDriverTest, PasswordVisibility) {
std::unique_ptr<InsecureSensitiveInputDriver> driver(
new InsecureSensitiveInputDriver(main_rfh()));
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->PasswordFieldVisibleInInsecureContext();
// Check that the password visibility notification was passed on to
// the WebContents (and from there to the SSLStatus).
entry = web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// If the password field becomes hidden, then the flag should be unset
// on the SSLStatus.
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that password visibility notifications from subframes are
// recorded correctly.
TEST_F(InsecureSensitiveInputDriverTest, PasswordVisibilityWithSubframe) {
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
// Create a subframe with a password field and check that
// notifications for it are handled properly.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver =
base::MakeUnique<InsecureSensitiveInputDriver>(subframe);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that password visibility notifications are recorded correctly
// when there is a password field in both the main frame and a subframe.
TEST_F(InsecureSensitiveInputDriverTest,
PasswordVisibilityWithMainFrameAndSubframe) {
std::unique_ptr<InsecureSensitiveInputDriver> driver(
new InsecureSensitiveInputDriver(main_rfh()));
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// Create a subframe with a password field and check that
// notifications for it are handled properly.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver =
base::MakeUnique<InsecureSensitiveInputDriver>(subframe);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
entry = web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that when a frame is deleted, its password visibility flag gets
// unset.
TEST_F(InsecureSensitiveInputDriverTest,
PasswordVisibilityWithSubframeDeleted) {
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
// Create a subframe with a password field.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver =
base::MakeUnique<InsecureSensitiveInputDriver>(subframe);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_tester->Detach();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// Check that the subframe's flag isn't hanging around preventing the
// warning from being removed.
std::unique_ptr<InsecureSensitiveInputDriver> driver(
new InsecureSensitiveInputDriver(main_rfh()));
driver->PasswordFieldVisibleInInsecureContext();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that a cross-process navigation does not remove the password
// field flag when the RenderFrameHost for the original process goes
// away. Regression test for https://crbug.com/664674
TEST_F(InsecureSensitiveInputDriverTest,
RenderFrameHostDeletionOnCrossProcessNavigation) {
NavigateAndCommit(GURL("http://example.test"));
content::RenderFrameHostTester* old_rfh_tester =
content::RenderFrameHostTester::For(web_contents()->GetMainFrame());
content::WebContentsTester* tester =
content::WebContentsTester::For(web_contents());
controller().LoadURL(GURL("http://example2.test"), content::Referrer(),
ui::PAGE_TRANSITION_TYPED, std::string());
content::RenderFrameHost* pending_rfh = tester->GetPendingMainFrame();
ASSERT_TRUE(pending_rfh);
int entry_id = controller().GetPendingEntry()->GetUniqueID();
tester->TestDidNavigate(pending_rfh, entry_id, true,
GURL("http://example2.test"),
ui::PAGE_TRANSITION_TYPED);
auto driver = base::MakeUnique<InsecureSensitiveInputDriver>(main_rfh());
driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// After the old RenderFrameHost is deleted, the password flag should still be
// set.
old_rfh_tester->SimulateSwapOutACK();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
} // namespace
......@@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/password_manager/content/browser/visible_password_observer.h"
#include "chrome/browser/ssl/visible_password_observer.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/origin_util.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(password_manager::VisiblePasswordObserver);
namespace password_manager {
DEFINE_WEB_CONTENTS_USER_DATA_KEY(VisiblePasswordObserver);
VisiblePasswordObserver::~VisiblePasswordObserver() {}
......@@ -27,12 +25,8 @@ void VisiblePasswordObserver::RenderFrameHasNoVisiblePasswordFields(
void VisiblePasswordObserver::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
// If a renderer process crashes, it won't send notifications that
// the password fields have been hidden, so watch for crashing
// processes and remove them from
// |frames_with_visible_password_fields_|.
frames_with_visible_password_fields_.erase(render_frame_host);
MaybeNotifyAllFieldsInvisible();
// After a renderer crashes, it has no visible password fields.
RenderFrameHasNoVisiblePasswordFields(render_frame_host);
}
VisiblePasswordObserver::VisiblePasswordObserver(
......@@ -40,16 +34,11 @@ VisiblePasswordObserver::VisiblePasswordObserver(
: content::WebContentsObserver(web_contents), web_contents_(web_contents) {}
void VisiblePasswordObserver::MaybeNotifyPasswordInputShownOnHttp() {
if (!content::IsOriginSecure(web_contents_->GetVisibleURL())) {
web_contents_->OnPasswordInputShownOnHttp();
}
web_contents_->OnPasswordInputShownOnHttp();
}
void VisiblePasswordObserver::MaybeNotifyAllFieldsInvisible() {
if (frames_with_visible_password_fields_.empty() &&
!content::IsOriginSecure(web_contents_->GetVisibleURL())) {
if (frames_with_visible_password_fields_.empty()) {
web_contents_->OnAllPasswordInputsHiddenOnHttp();
}
}
} // namespace password_manager
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_VISIBLE_PASSWORD_OBSERVER_H_
#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_VISIBLE_PASSWORD_OBSERVER_H_
#ifndef CHROME_BROWSER_SSL_VISIBLE_PASSWORD_OBSERVER_H_
#define CHROME_BROWSER_SSL_VISIBLE_PASSWORD_OBSERVER_H_
#include <set>
......@@ -16,8 +16,6 @@ namespace content {
class RenderFrameHost;
} // namespace content
namespace password_manager {
// This class tracks password visibility notifications for the
// RenderFrameHosts in a WebContents. There is one
// VisiblePasswordObserver per WebContents. When a RenderFrameHost has a
......@@ -69,6 +67,4 @@ class VisiblePasswordObserver
DISALLOW_COPY_AND_ASSIGN(VisiblePasswordObserver);
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_VISIBLE_PASSWORD_OBSERVER_H_
#endif // CHROME_BROWSER_SSL_VISIBLE_PASSWORD_OBSERVER_H_
......@@ -3318,6 +3318,7 @@ test("unit_tests") {
"../browser/signin/test_signin_client_builder.cc",
"../browser/signin/test_signin_client_builder.h",
"../browser/ssl/chrome_expect_ct_reporter_unittest.cc",
"../browser/ssl/insecure_sensitive_input_driver_unittest.cc",
"../browser/ssl/security_state_tab_helper_unittest.cc",
"../browser/ssl/ssl_error_handler_unittest.cc",
"../browser/status_icons/status_icon_menu_model_unittest.cc",
......@@ -3563,9 +3564,7 @@ test("unit_tests") {
"../browser/offline_pages/test_request_coordinator_builder.h",
]
if (is_android) {
sources += [
"../browser/offline_pages/android/prerendering_offliner_unittest.cc",
]
sources += [ "../browser/offline_pages/android/prerendering_offliner_unittest.cc" ]
}
deps += [
"//components/offline_pages/content/background_loader:test_support",
......
......@@ -14,8 +14,6 @@ static_library("browser") {
"credential_manager_impl.h",
"password_manager_internals_service_factory.cc",
"password_manager_internals_service_factory.h",
"visible_password_observer.cc",
"visible_password_observer.h",
]
public_deps = [
......
......@@ -6,5 +6,4 @@ include_rules = [
"+content/public/browser",
"+net",
"+services/service_manager/public/cpp",
"+third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h",
]
......@@ -4,12 +4,13 @@
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include <utility>
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/content/browser/bad_message.h"
#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
#include "components/password_manager/content/browser/visible_password_observer.h"
#include "components/password_manager/core/browser/log_manager.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
......@@ -42,10 +43,6 @@ ContentPasswordManagerDriver::ContentPasswordManagerDriver(
is_main_frame_(render_frame_host->GetParent() == nullptr),
password_manager_binding_(this),
weak_factory_(this) {
// Does nothing if a VisiblePasswordObserver has already been created
// for this WebContents.
VisiblePasswordObserver::CreateForWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
// For some frames |this| may be instantiated before log manager creation, so
// here we can not send logging state to renderer process for them. For such
......@@ -79,11 +76,6 @@ void ContentPasswordManagerDriver::BindRequest(
password_manager_binding_.Bind(std::move(request));
}
void ContentPasswordManagerDriver::BindSensitiveInputVisibilityServiceRequest(
blink::mojom::SensitiveInputVisibilityServiceRequest request) {
sensitive_input_visibility_bindings_.AddBinding(this, std::move(request));
}
void ContentPasswordManagerDriver::FillPasswordForm(
const autofill::PasswordFormFillData& form_data) {
const int key = next_free_key_++;
......@@ -226,19 +218,6 @@ void ContentPasswordManagerDriver::OnFocusedPasswordFormFound(
GetPasswordManager()->OnPasswordFormForceSaveRequested(this, password_form);
}
void ContentPasswordManagerDriver::PasswordFieldVisibleInInsecureContext() {
VisiblePasswordObserver* observer = VisiblePasswordObserver::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
observer->RenderFrameHasVisiblePasswordField(render_frame_host_);
}
void ContentPasswordManagerDriver::
AllPasswordFieldsInInsecureContextInvisible() {
VisiblePasswordObserver* observer = VisiblePasswordObserver::FromWebContents(
content::WebContents::FromRenderFrameHost(render_frame_host_));
observer->RenderFrameHasNoVisiblePasswordFields(render_frame_host_);
}
void ContentPasswordManagerDriver::DidNavigateFrame(
content::NavigationHandle* navigation_handle) {
// Clear page specific data after main frame navigation.
......
......@@ -6,6 +6,7 @@
#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_H_
#include <map>
#include <string>
#include <vector>
#include "base/compiler_specific.h"
......@@ -20,7 +21,6 @@
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h"
namespace autofill {
struct PasswordForm;
......@@ -38,8 +38,7 @@ enum class BadMessageReason;
// The lifetime is managed by the ContentPasswordManagerDriverFactory.
class ContentPasswordManagerDriver
: public PasswordManagerDriver,
public autofill::mojom::PasswordManagerDriver,
public blink::mojom::SensitiveInputVisibilityService {
public autofill::mojom::PasswordManagerDriver {
public:
ContentPasswordManagerDriver(content::RenderFrameHost* render_frame_host,
PasswordManagerClient* client,
......@@ -51,8 +50,6 @@ class ContentPasswordManagerDriver
content::RenderFrameHost* render_frame_host);
void BindRequest(autofill::mojom::PasswordManagerDriverRequest request);
void BindSensitiveInputVisibilityServiceRequest(
blink::mojom::SensitiveInputVisibilityServiceRequest request);
// PasswordManagerDriver implementation.
void FillPasswordForm(
......@@ -118,10 +115,6 @@ class ContentPasswordManagerDriver
const std::vector<autofill::PasswordForm>& forms);
void OnFocusedPasswordFormFound(const autofill::PasswordForm& password_form);
// blink::mojom::SensitiveInputVisibility:
void PasswordFieldVisibleInInsecureContext() override;
void AllPasswordFieldsInInsecureContextInvisible() override;
private:
bool CheckChildProcessSecurityPolicy(const GURL& url,
BadMessageReason reason);
......@@ -158,8 +151,6 @@ class ContentPasswordManagerDriver
mojo::Binding<autofill::mojom::PasswordManagerDriver>
password_manager_binding_;
mojo::BindingSet<blink::mojom::SensitiveInputVisibilityService>
sensitive_input_visibility_bindings_;
base::WeakPtrFactory<ContentPasswordManagerDriver> weak_factory_;
......
......@@ -97,30 +97,6 @@ void ContentPasswordManagerDriverFactory::BindPasswordManagerDriver(
driver->BindRequest(std::move(request));
}
// static
void ContentPasswordManagerDriverFactory::BindSensitiveInputVisibilityService(
blink::mojom::SensitiveInputVisibilityServiceRequest request,
content::RenderFrameHost* render_frame_host) {
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents)
return;
ContentPasswordManagerDriverFactory* factory =
ContentPasswordManagerDriverFactory::FromWebContents(web_contents);
// We try to bind to the driver, but if driver is not ready for now or totally
// not available for this render frame host, the request will be just dropped.
// This would cause the message pipe to be closed, which will raise a
// connection error on the peer side.
if (!factory)
return;
ContentPasswordManagerDriver* driver =
factory->GetDriverForFrame(render_frame_host);
if (driver)
driver->BindSensitiveInputVisibilityServiceRequest(std::move(request));
}
ContentPasswordManagerDriver*
ContentPasswordManagerDriverFactory::GetDriverForFrame(
content::RenderFrameHost* render_frame_host) {
......
......@@ -17,7 +17,7 @@
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/WebKit/public/platform/modules/sensitive_input_visibility/sensitive_input_visibility_service.mojom.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
namespace content {
class WebContents;
......@@ -45,10 +45,6 @@ class ContentPasswordManagerDriverFactory
autofill::mojom::PasswordManagerDriverRequest request,
content::RenderFrameHost* render_frame_host);
static void BindSensitiveInputVisibilityService(
blink::mojom::SensitiveInputVisibilityServiceRequest request,
content::RenderFrameHost* render_frame_host);
ContentPasswordManagerDriver* GetDriverForFrame(
content::RenderFrameHost* render_frame_host);
......
......@@ -4,6 +4,9 @@
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
......@@ -219,200 +222,6 @@ TEST_P(ContentPasswordManagerDriverTest, SendLoggingStateAfterLogManagerReady) {
EXPECT_EQ(should_allow_logging, logging_activated);
}
// Tests that password visibility notifications are forwarded to the
// WebContents.
TEST_P(ContentPasswordManagerDriverTest, PasswordVisibility) {
std::unique_ptr<ContentPasswordManagerDriver> driver(
new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
&autofill_client_));
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->PasswordFieldVisibleInInsecureContext();
// Check that the password visibility notification was passed on to
// the WebContents (and from there to the SSLStatus).
entry = web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// If the password field becomes hidden, then the flag should be unset
// on the SSLStatus.
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that password visibility notifications from subframes are
// recorded correctly.
TEST_P(ContentPasswordManagerDriverTest, PasswordVisibilityWithSubframe) {
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
// Create a subframe with a password field and check that
// notifications for it are handled properly.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver = base::MakeUnique<ContentPasswordManagerDriver>(
subframe, &password_manager_client_, &autofill_client_);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that password visibility notifications are recorded correctly
// when there is a password field in both the main frame and a subframe.
TEST_P(ContentPasswordManagerDriverTest,
PasswordVisibilityWithMainFrameAndSubframe) {
std::unique_ptr<ContentPasswordManagerDriver> driver(
new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
&autofill_client_));
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// Create a subframe with a password field and check that
// notifications for it are handled properly.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver = base::MakeUnique<ContentPasswordManagerDriver>(
subframe, &password_manager_client_, &autofill_client_);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
entry = web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that when a frame is deleted, its password visibility flag gets
// unset.
TEST_P(ContentPasswordManagerDriverTest,
PasswordVisibilityWithSubframeDeleted) {
// Do a mock navigation so that there is a navigation entry on which
// password visibility gets recorded.
GURL url("http://example.test");
NavigateAndCommit(url);
// Create a subframe with a password field.
content::RenderFrameHost* subframe =
content::RenderFrameHostTester::For(main_rfh())->AppendChild("child");
auto subframe_driver = base::MakeUnique<ContentPasswordManagerDriver>(
subframe, &password_manager_client_, &autofill_client_);
content::RenderFrameHostTester* subframe_tester =
content::RenderFrameHostTester::For(subframe);
subframe_tester->SimulateNavigationStart(GURL("http://example2.test"));
subframe_tester->SimulateNavigationCommit(GURL("http://example2.test"));
subframe_driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_EQ(url, entry->GetURL());
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
subframe_tester->Detach();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// Check that the subframe's flag isn't hanging around preventing the
// warning from being removed.
std::unique_ptr<ContentPasswordManagerDriver> driver(
new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
&autofill_client_));
driver->PasswordFieldVisibleInInsecureContext();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
driver->AllPasswordFieldsInInsecureContextInvisible();
EXPECT_FALSE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
// Tests that a cross-process navigation does not remove the password
// field flag when the RenderFrameHost for the original process goes
// away. Regression test for https://crbug.com/664674
TEST_F(ContentPasswordManagerDriverTest,
RenderFrameHostDeletionOnCrossProcessNavigation) {
NavigateAndCommit(GURL("http://example.test"));
content::RenderFrameHostTester* old_rfh_tester =
content::RenderFrameHostTester::For(web_contents()->GetMainFrame());
content::WebContentsTester* tester =
content::WebContentsTester::For(web_contents());
controller().LoadURL(GURL("http://example2.test"), content::Referrer(),
ui::PAGE_TRANSITION_TYPED, std::string());
content::RenderFrameHost* pending_rfh = tester->GetPendingMainFrame();
ASSERT_TRUE(pending_rfh);
int entry_id = controller().GetPendingEntry()->GetUniqueID();
tester->TestDidNavigate(pending_rfh, entry_id, true,
GURL("http://example2.test"),
ui::PAGE_TRANSITION_TYPED);
auto driver = base::MakeUnique<ContentPasswordManagerDriver>(
main_rfh(), &password_manager_client_, &autofill_client_);
driver->PasswordFieldVisibleInInsecureContext();
content::NavigationEntry* entry =
web_contents()->GetController().GetVisibleEntry();
ASSERT_TRUE(entry);
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
// After the old RenderFrameHost is deleted, the password flag should still be
// set.
old_rfh_tester->SimulateSwapOutACK();
EXPECT_TRUE(!!(entry->GetSSL().content_status &
content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
}
TEST_F(ContentPasswordManagerDriverTest, ClearPasswordsOnAutofill) {
std::unique_ptr<ContentPasswordManagerDriver> driver(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment