Commit c4c44586 authored by Sergey Poromov's avatar Sergey Poromov Committed by Commit Bot

Reland "DLP: Do not start screen capture for restricted content."

This is a reland of aa433c9b

Original change's description:
> DLP: Do not start screen capture for restricted content.
>
> During creation of a screen capture (desktop, window or tab) it needs to
> be checked whether the captured area contains any DLP
> (Data Leak Prevention) restricted content.
> The corresponding MediaAccessHandlers should do this check on Chrome OS.
>
> Bug: 1134566
> Change-Id: Id77739a9b6df9f3ed946e563d508c43df83b5580
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2446329
> Reviewed-by: Guido Urdaneta <guidou@chromium.org>
> Reviewed-by: Yuri Wiitala <miu@chromium.org>
> Commit-Queue: Sergey Poromov <poromov@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#820713}

Cq-Include-Trybots: luci.chromium.try:mac10.15-blink-rel,mac_chromium_10.15_rel_ng
Bug: 1134566
Change-Id: Ie1bdd637d9364cc7e75248627c7393438353e230
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2497450Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Commit-Queue: Sergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820927}
parent 37fb0cde
...@@ -76,6 +76,40 @@ bool DlpContentManager::IsPrintingRestricted( ...@@ -76,6 +76,40 @@ bool DlpContentManager::IsPrintingRestricted(
.HasRestriction(DlpContentRestriction::kPrint); .HasRestriction(DlpContentRestriction::kPrint);
} }
bool DlpContentManager::IsScreenCaptureRestricted(
const content::DesktopMediaID& media_id) const {
if (media_id.type == content::DesktopMediaID::Type::TYPE_SCREEN) {
return GetOnScreenPresentRestrictions().HasRestriction(
DlpContentRestriction::kScreenShare);
}
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(
media_id.web_contents_id.render_process_id,
media_id.web_contents_id.main_render_frame_id));
if (media_id.type == content::DesktopMediaID::Type::TYPE_WEB_CONTENTS) {
return GetConfidentialRestrictions(web_contents)
.HasRestriction(DlpContentRestriction::kScreenShare);
}
DCHECK_EQ(media_id.type, content::DesktopMediaID::Type::TYPE_WINDOW);
aura::Window* window = content::DesktopMediaID::GetNativeWindowById(media_id);
if (!window) {
return false;
}
for (auto& entry : confidential_web_contents_) {
aura::Window* web_contents_window = entry.first->GetNativeView();
if (entry.second.HasRestriction(DlpContentRestriction::kScreenShare) &&
window->Contains(web_contents_window)) {
return true;
}
}
return false;
}
void DlpContentManager::OnVideoCaptureStarted(const ScreenshotArea& area, void DlpContentManager::OnVideoCaptureStarted(const ScreenshotArea& area,
base::OnceClosure stop_callback) { base::OnceClosure stop_callback) {
if (IsVideoCaptureRestricted(area)) { if (IsVideoCaptureRestricted(area)) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h" #include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_window_observer.h" #include "chrome/browser/chromeos/policy/dlp/dlp_window_observer.h"
#include "chrome/browser/ui/ash/screenshot_area.h" #include "chrome/browser/ui/ash/screenshot_area.h"
#include "content/public/browser/desktop_media_id.h"
class GURL; class GURL;
struct ScreenshotArea; struct ScreenshotArea;
...@@ -60,6 +61,10 @@ class DlpContentManager : public DlpWindowObserver::Delegate { ...@@ -60,6 +61,10 @@ class DlpContentManager : public DlpWindowObserver::Delegate {
// Returns whether printing should be restricted. // Returns whether printing should be restricted.
bool IsPrintingRestricted(content::WebContents* web_contents) const; bool IsPrintingRestricted(content::WebContents* web_contents) const;
// Returns whether screen capture of the defined content should be restricted.
virtual bool IsScreenCaptureRestricted(
const content::DesktopMediaID& media_id) const;
// Called when video capturing for |area| is started. // Called when video capturing for |area| is started.
// |stop_callback| will be called when restricted content will appear there. // |stop_callback| will be called when restricted content will appear there.
void OnVideoCaptureStarted(const ScreenshotArea& area, void OnVideoCaptureStarted(const ScreenshotArea& area,
......
...@@ -21,6 +21,8 @@ enum DlpContentRestriction { ...@@ -21,6 +21,8 @@ enum DlpContentRestriction {
kPrint = 1 << 2, kPrint = 1 << 2,
// Do not allow video capturing of the content. // Do not allow video capturing of the content.
kVideoCapture = 1 << 3, kVideoCapture = 1 << 3,
// Do not allow screen share.
kScreenShare = 1 << 4,
}; };
// Represents set of restrictions applied to on-screen content. // Represents set of restrictions applied to on-screen content.
......
...@@ -24,6 +24,8 @@ class MockDlpContentManager : public DlpContentManager { ...@@ -24,6 +24,8 @@ class MockDlpContentManager : public DlpContentManager {
DlpContentRestrictionSet(const GURL&)); DlpContentRestrictionSet(const GURL&));
MOCK_METHOD1(OnVisibilityChanged, void(content::WebContents*)); MOCK_METHOD1(OnVisibilityChanged, void(content::WebContents*));
MOCK_CONST_METHOD1(IsScreenshotRestricted, bool(const ScreenshotArea& area)); MOCK_CONST_METHOD1(IsScreenshotRestricted, bool(const ScreenshotArea& area));
MOCK_CONST_METHOD1(IsScreenCaptureRestricted,
bool(const content::DesktopMediaID& media_id));
}; };
} // namespace policy } // namespace policy
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "ash/shell.h" #include "ash/shell.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_content_manager.h"
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
...@@ -233,7 +234,16 @@ void DesktopCaptureAccessHandler::ProcessScreenCaptureAccessRequest( ...@@ -233,7 +234,16 @@ void DesktopCaptureAccessHandler::ProcessScreenCaptureAccessRequest(
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
screen_id = content::DesktopMediaID::RegisterNativeWindow( screen_id = content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_SCREEN, content::DesktopMediaID::TYPE_SCREEN,
ash::Shell::Get()->GetPrimaryRootWindow()); primary_root_window_for_testing_
? primary_root_window_for_testing_
: ash::Shell::Get()->GetPrimaryRootWindow());
if (policy::DlpContentManager::Get()->IsScreenCaptureRestricted(
screen_id)) {
std::move(callback).Run(
devices, blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
std::move(ui));
return;
}
#else // defined(OS_CHROMEOS) #else // defined(OS_CHROMEOS)
screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
webrtc::kFullDesktopScreenId); webrtc::kFullDesktopScreenId);
...@@ -368,6 +378,16 @@ void DesktopCaptureAccessHandler::HandleRequest( ...@@ -368,6 +378,16 @@ void DesktopCaptureAccessHandler::HandleRequest(
std::move(ui)); std::move(ui));
return; return;
} }
#if defined(OS_CHROMEOS)
{
if (policy::DlpContentManager::Get()->IsScreenCaptureRestricted(media_id)) {
std::move(callback).Run(
devices, blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
std::move(ui));
return;
}
}
#endif
#if defined(OS_MAC) #if defined(OS_MAC)
if (media_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS && if (media_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS &&
system_media_permissions::CheckSystemScreenCapturePermission() != system_media_permissions::CheckSystemScreenCapturePermission() !=
......
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
#include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
#if defined(OS_CHROMEOS)
namespace aura {
class Window;
}
#endif
namespace extensions { namespace extensions {
class Extension; class Extension;
} }
...@@ -99,6 +105,10 @@ class DesktopCaptureAccessHandler : public CaptureAccessHandlerBase, ...@@ -99,6 +105,10 @@ class DesktopCaptureAccessHandler : public CaptureAccessHandlerBase,
RequestsQueues pending_requests_; RequestsQueues pending_requests_;
content::NotificationRegistrar notifications_registrar_; content::NotificationRegistrar notifications_registrar_;
#if defined(OS_CHROMEOS)
aura::Window* primary_root_window_for_testing_ = nullptr;
#endif
DISALLOW_COPY_AND_ASSIGN(DesktopCaptureAccessHandler); DISALLOW_COPY_AND_ASSIGN(DesktopCaptureAccessHandler);
}; };
......
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/dlp/dlp_content_manager.h"
#endif // defined(OS_CHROMEOS)
#if defined(OS_MAC) #if defined(OS_MAC)
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h" #include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
#endif #endif
...@@ -249,6 +253,15 @@ void DisplayMediaAccessHandler::OnPickerDialogResults( ...@@ -249,6 +253,15 @@ void DisplayMediaAccessHandler::OnPickerDialogResults(
request_result = request_result =
blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE; blink::mojom::MediaStreamRequestResult::TAB_CAPTURE_FAILURE;
} }
#if defined(OS_CHROMEOS)
if (request_result == blink::mojom::MediaStreamRequestResult::OK) {
if (policy::DlpContentManager::Get()->IsScreenCaptureRestricted(
media_id)) {
request_result =
blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
}
}
#endif
if (request_result == blink::mojom::MediaStreamRequestResult::OK) { if (request_result == blink::mojom::MediaStreamRequestResult::OK) {
const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay( const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay(
web_contents->GetLastCommittedURL(), web_contents->GetLastCommittedURL(),
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#endif #endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/dlp/mock_dlp_content_manager.h"
#endif
class DisplayMediaAccessHandlerTest : public ChromeRenderViewHostTestHarness { class DisplayMediaAccessHandlerTest : public ChromeRenderViewHostTestHarness {
public: public:
DisplayMediaAccessHandlerTest() {} DisplayMediaAccessHandlerTest() {}
...@@ -160,6 +164,30 @@ TEST_F(DisplayMediaAccessHandlerTest, PermissionDenied) { ...@@ -160,6 +164,30 @@ TEST_F(DisplayMediaAccessHandlerTest, PermissionDenied) {
EXPECT_EQ(0u, devices.size()); EXPECT_EQ(0u, devices.size());
} }
#if defined(OS_CHROMEOS)
TEST_F(DisplayMediaAccessHandlerTest, DlpRestricted) {
const content::DesktopMediaID media_id(content::DesktopMediaID::TYPE_SCREEN,
content::DesktopMediaID::kFakeId);
// Setup Data Leak Prevention restriction.
policy::MockDlpContentManager mock_dlp_content_manager;
policy::DlpContentManager::SetDlpContentManagerForTesting(
&mock_dlp_content_manager);
EXPECT_CALL(mock_dlp_content_manager, IsScreenCaptureRestricted(media_id))
.Times(1)
.WillOnce(testing::Return(true));
blink::mojom::MediaStreamRequestResult result;
blink::MediaStreamDevices devices;
ProcessRequest(media_id, &result, &devices, /*request_audio=*/false);
EXPECT_EQ(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, result);
EXPECT_EQ(0u, devices.size());
policy::DlpContentManager::ResetDlpContentManagerForTesting();
}
#endif
TEST_F(DisplayMediaAccessHandlerTest, UpdateMediaRequestStateWithClosing) { TEST_F(DisplayMediaAccessHandlerTest, UpdateMediaRequestStateWithClosing) {
const int render_process_id = 0; const int render_process_id = 0;
const int render_frame_id = 0; const int render_frame_id = 0;
......
...@@ -12,15 +12,19 @@ ...@@ -12,15 +12,19 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "extensions/common/permissions/permissions_data.h" #include "extensions/common/permissions/permissions_data.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h" #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
TabCaptureAccessHandler::TabCaptureAccessHandler() { #if defined(OS_CHROMEOS)
} #include "chrome/browser/chromeos/policy/dlp/dlp_content_manager.h"
#endif // defined(OS_CHROMEOS)
TabCaptureAccessHandler::~TabCaptureAccessHandler() { TabCaptureAccessHandler::TabCaptureAccessHandler() = default;
}
TabCaptureAccessHandler::~TabCaptureAccessHandler() = default;
bool TabCaptureAccessHandler::SupportsStreamType( bool TabCaptureAccessHandler::SupportsStreamType(
content::WebContents* web_contents, content::WebContents* web_contents,
...@@ -63,6 +67,23 @@ void TabCaptureAccessHandler::HandleRequest( ...@@ -63,6 +67,23 @@ void TabCaptureAccessHandler::HandleRequest(
std::move(ui)); std::move(ui));
return; return;
} }
#if defined(OS_CHROMEOS)
if (request.video_type ==
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE) {
content::DesktopMediaID media_id(
content::DesktopMediaID::TYPE_WEB_CONTENTS, /*id=*/0,
content::WebContentsMediaCaptureId(request.render_process_id,
request.render_frame_id));
if (policy::DlpContentManager::Get()->IsScreenCaptureRestricted(media_id)) {
std::move(callback).Run(
devices, blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
std::move(ui));
return;
}
}
#endif
// |extension| may be null if the tabCapture starts with // |extension| may be null if the tabCapture starts with
// tabCapture.getMediaStreamId(). // tabCapture.getMediaStreamId().
// TODO(crbug.com/831722): Deprecate tabCaptureRegistry soon. // TODO(crbug.com/831722): Deprecate tabCaptureRegistry soon.
......
// Copyright 2020 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/media/webrtc/tab_capture_access_handler.h"
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
#include "chrome/browser/media/webrtc/fake_desktop_media_picker_factory.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/policy/dlp/mock_dlp_content_manager.h"
#endif
class TabCaptureAccessHandlerTest : public ChromeRenderViewHostTestHarness {
public:
TabCaptureAccessHandlerTest() = default;
~TabCaptureAccessHandlerTest() override = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
access_handler_ = std::make_unique<TabCaptureAccessHandler>();
}
void ProcessRequest(
const content::DesktopMediaID& fake_desktop_media_id_response,
blink::mojom::MediaStreamRequestResult* request_result,
blink::MediaStreamDevices* devices_result) {
content::MediaStreamRequest request(
web_contents()->GetMainFrame()->GetProcess()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID(), /*page_request_id=*/0,
GURL("http://origin/"), /*user_gesture=*/false,
blink::MEDIA_GENERATE_STREAM,
/*requested_audio_device_id=*/std::string(),
/*requested_video_device_id=*/std::string(),
blink::mojom::MediaStreamType::NO_SERVICE,
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
/*disable_local_echo=*/false,
/*request_pan_tilt_zoom_permission=*/false);
base::RunLoop wait_loop;
content::MediaResponseCallback callback = base::BindOnce(
[](base::RunLoop* wait_loop,
blink::mojom::MediaStreamRequestResult* request_result,
blink::MediaStreamDevices* devices_result,
const blink::MediaStreamDevices& devices,
blink::mojom::MediaStreamRequestResult result,
std::unique_ptr<content::MediaStreamUI> ui) {
*request_result = result;
*devices_result = devices;
wait_loop->Quit();
},
&wait_loop, request_result, devices_result);
access_handler_->HandleRequest(web_contents(), request, std::move(callback),
/*extension=*/nullptr);
wait_loop.Run();
access_handler_.reset();
}
protected:
std::unique_ptr<TabCaptureAccessHandler> access_handler_;
};
TEST_F(TabCaptureAccessHandlerTest, PermissionGiven) {
const content::DesktopMediaID source(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(
web_contents()->GetMainFrame()->GetProcess()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID()));
extensions::TabCaptureRegistry::Get(profile())->AddRequest(
web_contents(), /*extension_id=*/"", /*is_anonymous=*/false,
GURL("http://origin/"), source, /*extension_name=*/"", web_contents());
blink::mojom::MediaStreamRequestResult result;
blink::MediaStreamDevices devices;
ProcessRequest(source, &result, &devices);
EXPECT_EQ(blink::mojom::MediaStreamRequestResult::OK, result);
EXPECT_EQ(1u, devices.size());
EXPECT_EQ(blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
devices[0].type);
}
#if defined(OS_CHROMEOS)
TEST_F(TabCaptureAccessHandlerTest, DlpRestricted) {
const content::DesktopMediaID source(
content::DesktopMediaID::TYPE_WEB_CONTENTS,
content::DesktopMediaID::kNullId,
content::WebContentsMediaCaptureId(
web_contents()->GetMainFrame()->GetProcess()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID()));
// Setup Data Leak Prevention restriction.
policy::MockDlpContentManager mock_dlp_content_manager;
policy::DlpContentManager::SetDlpContentManagerForTesting(
&mock_dlp_content_manager);
EXPECT_CALL(mock_dlp_content_manager, IsScreenCaptureRestricted(source))
.Times(1)
.WillOnce(testing::Return(true));
extensions::TabCaptureRegistry::Get(profile())->AddRequest(
web_contents(), /*extension_id=*/"", /*is_anonymous=*/false,
GURL("http://origin/"), source, /*extension_name=*/"", web_contents());
blink::mojom::MediaStreamRequestResult result;
blink::MediaStreamDevices devices;
ProcessRequest(source, &result, &devices);
EXPECT_EQ(blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED, result);
EXPECT_EQ(0u, devices.size());
}
#endif
...@@ -4384,6 +4384,7 @@ test("unit_tests") { ...@@ -4384,6 +4384,7 @@ test("unit_tests") {
"../browser/media/webrtc/display_media_access_handler_unittest.cc", "../browser/media/webrtc/display_media_access_handler_unittest.cc",
"../browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc", "../browser/media/webrtc/media_capture_devices_dispatcher_unittest.cc",
"../browser/media/webrtc/media_stream_capture_indicator_unittest.cc", "../browser/media/webrtc/media_stream_capture_indicator_unittest.cc",
"../browser/media/webrtc/tab_capture_access_handler_unittest.cc",
"../browser/media/webrtc/tab_desktop_media_list_unittest.cc", "../browser/media/webrtc/tab_desktop_media_list_unittest.cc",
"../browser/media/webrtc/webrtc_event_log_manager_common_unittest.cc", "../browser/media/webrtc/webrtc_event_log_manager_common_unittest.cc",
"../browser/media/webrtc/webrtc_event_log_manager_unittest.cc", "../browser/media/webrtc/webrtc_event_log_manager_unittest.cc",
......
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