Commit 013c4006 authored by Rohan Pavone's avatar Rohan Pavone Committed by Commit Bot

[Permissions] Checks if permissions should be overridden.

Determines if platform supports overridden status of permission by
querying PermissionControllerDelegate. Since most delegates have static
permission statuses, this queries the permission status by default.
Overridden classes, such as PermissionManager (used for Chrome) and
WebTestPermissionManager, have dynamic permission settings which are
queried in a different fashion. If permission is not supported, this
is indicated. PermissionControllerImpl, which controls overrides,
uses this decision to choose whether or not to override, which is
then forwarded to the callee. Browser.setPermission uses this to
indicate if setting permission failed/succeeded. Browser.grantPermission
ignores the result.

Design doc: go/chromedriver-permissions-ext

Bug: 976308
Change-Id: I0124ea1b2238a33c379476b74d6ef322327413a2
Tested: Adds unit tests to each affected level.
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1752176
Commit-Queue: Rohan Pavone <rohpavone@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689139}
parent b6bb8c6c
...@@ -208,22 +208,9 @@ PermissionResult PermissionContextBase::GetPermissionStatus( ...@@ -208,22 +208,9 @@ PermissionResult PermissionContextBase::GetPermissionStatus(
PermissionStatusSource::KILL_SWITCH); PermissionStatusSource::KILL_SWITCH);
} }
if (IsRestrictedToSecureOrigins()) { if (!IsPermissionAvailableToOrigins(requesting_origin, embedding_origin)) {
if (!content::IsOriginSecure(requesting_origin)) { return PermissionResult(CONTENT_SETTING_BLOCK,
return PermissionResult(CONTENT_SETTING_BLOCK, PermissionStatusSource::INSECURE_ORIGIN);
PermissionStatusSource::INSECURE_ORIGIN);
}
// TODO(raymes): We should check the entire chain of embedders here whenever
// possible as this corresponds to the requirements of the secure contexts
// spec and matches what is implemented in blink. Right now we just check
// the top level and requesting origins. Note: chrome-extension:// origins
// are currently exempt from checking the embedder chain. crbug.com/530507.
if (!requesting_origin.SchemeIs(extensions::kExtensionScheme) &&
!content::IsOriginSecure(embedding_origin)) {
return PermissionResult(CONTENT_SETTING_BLOCK,
PermissionStatusSource::INSECURE_ORIGIN);
}
} }
// Check whether the feature is enabled for the frame by feature policy. We // Check whether the feature is enabled for the frame by feature policy. We
...@@ -273,6 +260,25 @@ PermissionResult PermissionContextBase::GetPermissionStatus( ...@@ -273,6 +260,25 @@ PermissionResult PermissionContextBase::GetPermissionStatus(
return PermissionResult(content_setting, PermissionStatusSource::UNSPECIFIED); return PermissionResult(content_setting, PermissionStatusSource::UNSPECIFIED);
} }
bool PermissionContextBase::IsPermissionAvailableToOrigins(
const GURL& requesting_origin,
const GURL& embedding_origin) const {
if (IsRestrictedToSecureOrigins()) {
if (!content::IsOriginSecure(requesting_origin))
return false;
// TODO(raymes): We should check the entire chain of embedders here whenever
// possible as this corresponds to the requirements of the secure contexts
// spec and matches what is implemented in blink. Right now we just check
// the top level and requesting origins. Note: chrome-extension:// origins
// are currently exempt from checking the embedder chain. crbug.com/530507.
if (!requesting_origin.SchemeIs(extensions::kExtensionScheme) &&
!content::IsOriginSecure(embedding_origin))
return false;
}
return true;
}
PermissionResult PermissionContextBase::UpdatePermissionStatusWithDeviceStatus( PermissionResult PermissionContextBase::UpdatePermissionStatusWithDeviceStatus(
PermissionResult result, PermissionResult result,
const GURL& requesting_origin, const GURL& requesting_origin,
......
...@@ -85,6 +85,10 @@ class PermissionContextBase : public KeyedService { ...@@ -85,6 +85,10 @@ class PermissionContextBase : public KeyedService {
const GURL& requesting_origin, const GURL& requesting_origin,
const GURL& embedding_origin) const; const GURL& embedding_origin) const;
// Returns whether the permission is usable by requesting/embedding origins.
bool IsPermissionAvailableToOrigins(const GURL& requesting_origin,
const GURL& embedding_origin) const;
// Update |result| with any modifications based on the device state. For // Update |result| with any modifications based on the device state. For
// example, if |result| is ALLOW but Chrome does not have the relevant // example, if |result| is ALLOW but Chrome does not have the relevant
// permission at the device level, but will prompt the user, return ASK. // permission at the device level, but will prompt the user, return ASK.
......
...@@ -168,6 +168,21 @@ class TestKillSwitchPermissionContext : public TestPermissionContext { ...@@ -168,6 +168,21 @@ class TestKillSwitchPermissionContext : public TestPermissionContext {
DISALLOW_COPY_AND_ASSIGN(TestKillSwitchPermissionContext); DISALLOW_COPY_AND_ASSIGN(TestKillSwitchPermissionContext);
}; };
class TestSecureOriginRestrictedPermissionContext
: public TestPermissionContext {
public:
TestSecureOriginRestrictedPermissionContext(
Profile* profile,
const ContentSettingsType content_settings_type)
: TestPermissionContext(profile, content_settings_type) {}
protected:
bool IsRestrictedToSecureOrigins() const override { return true; }
private:
DISALLOW_COPY_AND_ASSIGN(TestSecureOriginRestrictedPermissionContext);
};
class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness { class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness {
protected: protected:
PermissionContextBaseTests() {} PermissionContextBaseTests() {}
...@@ -567,6 +582,32 @@ class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness { ...@@ -567,6 +582,32 @@ class PermissionContextBaseTests : public ChromeRenderViewHostTestHarness {
EXPECT_TRUE(permission_context.IsPermissionKillSwitchOn()); EXPECT_TRUE(permission_context.IsPermissionKillSwitchOn());
} }
void TestSecureOriginRestrictedPermissionContextCheck(
const std::string& requesting_url_spec,
const std::string& embedding_url_spec,
bool expect_allowed) {
GURL requesting_origin(requesting_url_spec);
GURL embedding_origin(embedding_url_spec);
TestSecureOriginRestrictedPermissionContext permission_context(
profile(), CONTENT_SETTINGS_TYPE_GEOLOCATION);
bool result = permission_context.IsPermissionAvailableToOrigins(
requesting_origin, embedding_origin);
EXPECT_EQ(expect_allowed, result)
<< "test case (requesting, embedding): (" << requesting_url_spec << ", "
<< embedding_url_spec << ") with secure-origin requirement"
<< " on";
// With no secure-origin limitation, this check should always return pass.
TestPermissionContext new_context(profile(),
CONTENT_SETTINGS_TYPE_GEOLOCATION);
result = new_context.IsPermissionAvailableToOrigins(requesting_origin,
embedding_origin);
EXPECT_EQ(true, result)
<< "test case (requesting, embedding): (" << requesting_url_spec << ", "
<< embedding_url_spec << ") with secure-origin requirement"
<< " off";
}
// Don't call this more than once in the same test, as it persists data to // Don't call this more than once in the same test, as it persists data to
// HostContentSettingsMap. // HostContentSettingsMap.
void TestParallelRequests(ContentSetting response) { void TestParallelRequests(ContentSetting response) {
...@@ -726,6 +767,65 @@ TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) { ...@@ -726,6 +767,65 @@ TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) {
TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); TestGlobalPermissionsKillSwitch(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
} }
// Tests that secure origins are examined if switch is on, or ignored if off.
TEST_F(PermissionContextBaseTests,
TestSecureOriginRestrictedPermissionContextSwitch) {
struct {
std::string requesting_url_spec;
std::string embedding_url_spec;
bool expect_permission_allowed;
} kTestCases[] = {
// Secure-origins that should be allowed.
{"https://google.com", "https://foo.com",
/*expect_allowed=*/true},
{"https://www.bar.com", "https://foo.com",
/*expect_allowed=*/true},
{"https://localhost", "http://localhost",
/*expect_allowed=*/true},
{"http://localhost", "https://google.com",
/*expect_allowed=*/true},
{"https://google.com", "http://localhost",
/*expect_allowed=*/true},
{"https://foo.com", "file://some-file",
/*expect_allowed=*/true},
{"file://some-file", "https://foo.com",
/*expect_allowed=*/true},
{"https://foo.com", "about:blank",
/*expect_allowed=*/true},
{"about:blank", "https://foo.com",
/*expect_allowed=*/true},
// Extensions are exempt from checking the embedder chain.
{"chrome-extension://some-extension", "http://not-secure.com",
/*expect_allowed=*/true},
// Insecure-origins that should be blocked.
{"http://foo.com", "file://some-file",
/*expect_allowed=*/false},
{"fake://foo.com", "about:blank",
/*expect_allowed=*/false},
{"http://localhost", "http://foo.com",
/*expect_allowed=*/false},
{"http://localhost", "foo.com",
/*expect_allowed=*/false},
{"http://bar.com", "https://foo.com",
/*expect_permission_allowed=*/false},
{"https://foo.com", "http://bar.com",
/*expect_permission_allowed=*/false},
{"http://localhost", "http://foo.com",
/*expect_permission_allowed=*/false},
{"http://foo.com", "http://localhost",
/*expect_permission_allowed=*/false},
{"bar.com", "https://foo.com", /*expect_permission_allowed=*/false},
{"https://foo.com", "bar.com", /*expect_permission_allowed=*/false}};
for (const auto& test_case : kTestCases) {
TestSecureOriginRestrictedPermissionContextCheck(
test_case.requesting_url_spec, test_case.embedding_url_spec,
test_case.expect_permission_allowed);
}
}
TEST_F(PermissionContextBaseTests, TestParallelRequestsAllowed) { TEST_F(PermissionContextBaseTests, TestParallelRequestsAllowed) {
TestParallelRequests(CONTENT_SETTING_ALLOW); TestParallelRequests(CONTENT_SETTING_ALLOW);
} }
......
...@@ -104,7 +104,10 @@ ContentSetting PermissionStatusToContentSetting(PermissionStatus status) { ...@@ -104,7 +104,10 @@ ContentSetting PermissionStatusToContentSetting(PermissionStatus status) {
} }
// Helper method to convert PermissionType to ContentSettingType. // Helper method to convert PermissionType to ContentSettingType.
ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { // If PermissionType is not supported or found, returns
// CONTENT_SETTINGS_TYPE_DEFAULT.
ContentSettingsType PermissionTypeToContentSettingSafe(
PermissionType permission) {
switch (permission) { switch (permission) {
case PermissionType::MIDI: case PermissionType::MIDI:
return CONTENT_SETTINGS_TYPE_MIDI; return CONTENT_SETTINGS_TYPE_MIDI;
...@@ -118,7 +121,6 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { ...@@ -118,7 +121,6 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) {
#if defined(OS_ANDROID) || defined(OS_CHROMEOS) #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
return CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER; return CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER;
#else #else
NOTIMPLEMENTED();
break; break;
#endif #endif
case PermissionType::DURABLE_STORAGE: case PermissionType::DURABLE_STORAGE:
...@@ -152,15 +154,22 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) { ...@@ -152,15 +154,22 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) {
case PermissionType::WAKE_LOCK_SYSTEM: case PermissionType::WAKE_LOCK_SYSTEM:
return CONTENT_SETTINGS_TYPE_WAKE_LOCK_SYSTEM; return CONTENT_SETTINGS_TYPE_WAKE_LOCK_SYSTEM;
case PermissionType::NUM: case PermissionType::NUM:
// This will hit the NOTREACHED below.
break; break;
} }
NOTREACHED() << "Unknown content setting for permission "
<< static_cast<int>(permission);
return CONTENT_SETTINGS_TYPE_DEFAULT; return CONTENT_SETTINGS_TYPE_DEFAULT;
} }
// Helper method to convert PermissionType to ContentSettingType.
ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) {
ContentSettingsType content_setting =
PermissionTypeToContentSettingSafe(permission);
DCHECK_NE(content_setting, CONTENT_SETTINGS_TYPE_DEFAULT)
<< "Unknown content setting for permission "
<< static_cast<int>(permission);
return content_setting;
}
void SubscriptionCallbackWrapper( void SubscriptionCallbackWrapper(
base::OnceCallback<void(PermissionStatus)> callback, base::OnceCallback<void(PermissionStatus)> callback,
ContentSetting content_setting) { ContentSetting content_setting) {
...@@ -603,6 +612,16 @@ PermissionStatus PermissionManager::GetPermissionStatusForFrame( ...@@ -603,6 +612,16 @@ PermissionStatus PermissionManager::GetPermissionStatusForFrame(
return ContentSettingToPermissionStatus(result.content_setting); return ContentSettingToPermissionStatus(result.content_setting);
} }
bool PermissionManager::IsPermissionOverridableByDevTools(
content::PermissionType permission,
const GURL& origin) {
ContentSettingsType type = PermissionTypeToContentSettingSafe(permission);
PermissionContextBase* context = GetPermissionContext(type);
return context && !context->IsPermissionKillSwitchOn() &&
context->IsPermissionAvailableToOrigins(origin, origin);
}
int PermissionManager::SubscribePermissionStatusChange( int PermissionManager::SubscribePermissionStatusChange(
PermissionType permission, PermissionType permission,
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
...@@ -747,8 +766,10 @@ void PermissionManager::SetPermissionOverridesForDevTools( ...@@ -747,8 +766,10 @@ void PermissionManager::SetPermissionOverridesForDevTools(
const PermissionOverrides& overrides) { const PermissionOverrides& overrides) {
ContentSettingsTypeOverrides result; ContentSettingsTypeOverrides result;
for (const auto& item : overrides) { for (const auto& item : overrides) {
result[PermissionTypeToContentSetting(item.first)] = ContentSettingsType content_setting =
PermissionStatusToContentSetting(item.second); PermissionTypeToContentSettingSafe(item.first);
if (content_setting != CONTENT_SETTINGS_TYPE_DEFAULT)
result[content_setting] = PermissionStatusToContentSetting(item.second);
} }
devtools_permission_overrides_[url::Origin::Create(origin)] = devtools_permission_overrides_[url::Origin::Create(origin)] =
std::move(result); std::move(result);
......
...@@ -104,6 +104,8 @@ class PermissionManager : public KeyedService, ...@@ -104,6 +104,8 @@ class PermissionManager : public KeyedService,
content::PermissionType permission, content::PermissionType permission,
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin) override; const GURL& requesting_origin) override;
bool IsPermissionOverridableByDevTools(content::PermissionType permission,
const GURL& origin) override;
int SubscribePermissionStatusChange( int SubscribePermissionStatusChange(
content::PermissionType permission, content::PermissionType permission,
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
......
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/permissions/permission_context_base.h"
#include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/permissions/permission_manager_factory.h"
#include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_request_manager.h"
#include "chrome/browser/permissions/permission_result.h" #include "chrome/browser/permissions/permission_result.h"
...@@ -22,6 +24,7 @@ ...@@ -22,6 +24,7 @@
#include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/permission_type.h" #include "content/public/browser/permission_type.h"
#include "content/public/test/navigation_simulator.h" #include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
...@@ -588,6 +591,57 @@ TEST_F(PermissionManagerTest, InsecureOrigin) { ...@@ -588,6 +591,57 @@ TEST_F(PermissionManagerTest, InsecureOrigin) {
EXPECT_EQ(PermissionStatusSource::UNSPECIFIED, result.source); EXPECT_EQ(PermissionStatusSource::UNSPECIFIED, result.source);
} }
TEST_F(PermissionManagerTest, InsecureOriginIsNotOverridable) {
const GURL kInsecureOrigin("http://example.com/geolocation");
const GURL kSecureOrigin("https://example.com/geolocation");
EXPECT_FALSE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, kInsecureOrigin));
EXPECT_TRUE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, kSecureOrigin));
}
TEST_F(PermissionManagerTest, MissingContextIsNotOverridable) {
// Permissions that are not implemented should be denied overridability.
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
EXPECT_FALSE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::PROTECTED_MEDIA_IDENTIFIER,
GURL("http://localhost")));
#endif
EXPECT_TRUE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::MIDI_SYSEX, GURL("http://localhost")));
}
TEST_F(PermissionManagerTest, KillSwitchOnIsNotOverridable) {
EXPECT_TRUE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, GURL("http://localhost")));
// Turn on kill switch for GEOLOCATION.
base::FieldTrialList field_trial_list(
std::make_unique<base::MockEntropyProvider>());
variations::testing::ClearAllVariationParams();
std::map<std::string, std::string> params;
params[PermissionUtil::GetPermissionString(
CONTENT_SETTINGS_TYPE_GEOLOCATION)] =
PermissionContextBase::kPermissionsKillSwitchBlockedValue;
variations::AssociateVariationParams(
PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup",
params);
base::FieldTrialList::CreateFieldTrial(
PermissionContextBase::kPermissionsKillSwitchFieldStudy, "TestGroup");
EXPECT_FALSE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, GURL("http://localhost")));
// Clean-up.
variations::testing::ClearAllVariationParams();
}
TEST_F(PermissionManagerTest, GetCanonicalOriginSearch) { TEST_F(PermissionManagerTest, GetCanonicalOriginSearch) {
const GURL google_com("https://www.google.com"); const GURL google_com("https://www.google.com");
const GURL google_de("https://www.google.de"); const GURL google_de("https://www.google.de");
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/metrics/histogram_base.h" #include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h" #include "base/metrics/histogram_samples.h"
#include "base/metrics/statistics_recorder.h" #include "base/metrics/statistics_recorder.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/browser/devtools/devtools_manager.h" #include "content/browser/devtools/devtools_manager.h"
...@@ -316,7 +317,14 @@ Response BrowserHandler::SetPermission( ...@@ -316,7 +317,14 @@ Response BrowserHandler::SetPermission(
PermissionControllerImpl* permission_controller = PermissionControllerImpl* permission_controller =
PermissionControllerImpl::FromBrowserContext(browser_context); PermissionControllerImpl::FromBrowserContext(browser_context);
GURL url = GURL(origin).GetOrigin(); GURL url = GURL(origin).GetOrigin();
permission_controller->SetOverrideForDevTools(url, type, permission_status);
PermissionControllerImpl::OverrideStatus status =
permission_controller->SetOverrideForDevTools(url, type,
permission_status);
if (status != PermissionControllerImpl::OverrideStatus::kOverrideSet) {
return Response::InvalidParams(
"Permission can't be granted in current context.");
}
contexts_with_overridden_permissions_.insert( contexts_with_overridden_permissions_.insert(
browser_context_id.fromMaybe(std::string())); browser_context_id.fromMaybe(std::string()));
return Response::OK(); return Response::OK();
...@@ -345,7 +353,13 @@ Response BrowserHandler::GrantPermissions( ...@@ -345,7 +353,13 @@ Response BrowserHandler::GrantPermissions(
PermissionControllerImpl* permission_controller = PermissionControllerImpl* permission_controller =
PermissionControllerImpl::FromBrowserContext(browser_context); PermissionControllerImpl::FromBrowserContext(browser_context);
GURL url = GURL(origin).GetOrigin(); GURL url = GURL(origin).GetOrigin();
permission_controller->GrantOverridesForDevTools(url, internal_permissions); PermissionControllerImpl::OverrideStatus status =
permission_controller->GrantOverridesForDevTools(url,
internal_permissions);
if (status != PermissionControllerImpl::OverrideStatus::kOverrideSet) {
return Response::InvalidParams(
"Permissions can't be granted in current context.");
}
contexts_with_overridden_permissions_.insert( contexts_with_overridden_permissions_.insert(
browser_context_id.fromMaybe("")); browser_context_id.fromMaybe(""));
return Response::OK(); return Response::OK();
......
...@@ -183,10 +183,17 @@ void PermissionControllerImpl::NotifyChangedSubscriptions( ...@@ -183,10 +183,17 @@ void PermissionControllerImpl::NotifyChangedSubscriptions(
callback.Run(); callback.Run();
} }
void PermissionControllerImpl::SetOverrideForDevTools( PermissionControllerImpl::OverrideStatus
PermissionControllerImpl::SetOverrideForDevTools(
const GURL& origin, const GURL& origin,
const PermissionType& permission, const PermissionType& permission,
const blink::mojom::PermissionStatus& status) { const blink::mojom::PermissionStatus& status) {
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (delegate &&
!delegate->IsPermissionOverridableByDevTools(permission, origin)) {
return OverrideStatus::kOverrideNotSet;
}
const auto old_statuses = GetSubscriptionsStatuses(origin); const auto old_statuses = GetSubscriptionsStatuses(origin);
devtools_permission_overrides_.Set(url::Origin::Create(origin), permission, devtools_permission_overrides_.Set(url::Origin::Create(origin), permission,
...@@ -194,11 +201,20 @@ void PermissionControllerImpl::SetOverrideForDevTools( ...@@ -194,11 +201,20 @@ void PermissionControllerImpl::SetOverrideForDevTools(
NotifyChangedSubscriptions(old_statuses); NotifyChangedSubscriptions(old_statuses);
UpdateDelegateOverridesForDevTools(origin); UpdateDelegateOverridesForDevTools(origin);
return OverrideStatus::kOverrideSet;
} }
void PermissionControllerImpl::GrantOverridesForDevTools( PermissionControllerImpl::OverrideStatus
PermissionControllerImpl::GrantOverridesForDevTools(
const GURL& origin, const GURL& origin,
const std::vector<PermissionType>& permissions) { const std::vector<PermissionType>& permissions) {
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (delegate)
for (const auto permission : permissions)
if (!delegate->IsPermissionOverridableByDevTools(permission, origin))
return OverrideStatus::kOverrideNotSet;
const auto old_statuses = GetSubscriptionsStatuses(origin); const auto old_statuses = GetSubscriptionsStatuses(origin);
devtools_permission_overrides_.GrantPermissions(url::Origin::Create(origin), devtools_permission_overrides_.GrantPermissions(url::Origin::Create(origin),
permissions); permissions);
...@@ -208,6 +224,7 @@ void PermissionControllerImpl::GrantOverridesForDevTools( ...@@ -208,6 +224,7 @@ void PermissionControllerImpl::GrantOverridesForDevTools(
NotifyChangedSubscriptions(old_statuses); NotifyChangedSubscriptions(old_statuses);
UpdateDelegateOverridesForDevTools(origin); UpdateDelegateOverridesForDevTools(origin);
return OverrideStatus::kOverrideSet;
} }
void PermissionControllerImpl::ResetOverridesForDevTools() { void PermissionControllerImpl::ResetOverridesForDevTools() {
......
...@@ -27,15 +27,17 @@ class CONTENT_EXPORT PermissionControllerImpl : public PermissionController { ...@@ -27,15 +27,17 @@ class CONTENT_EXPORT PermissionControllerImpl : public PermissionController {
BrowserContext* browser_context); BrowserContext* browser_context);
using PermissionOverrides = DevToolsPermissionOverrides::PermissionOverrides; using PermissionOverrides = DevToolsPermissionOverrides::PermissionOverrides;
enum class OverrideStatus { kOverrideNotSet, kOverrideSet };
// For the given |origin|, grant permissions in |overrides| and reject all // For the given |origin|, grant permissions in |overrides| and reject all
// others. // others.
void GrantOverridesForDevTools( OverrideStatus GrantOverridesForDevTools(
const GURL& origin, const GURL& origin,
const std::vector<PermissionType>& permissions); const std::vector<PermissionType>& permissions);
void SetOverrideForDevTools(const GURL& origin, OverrideStatus SetOverrideForDevTools(
const PermissionType& permission, const GURL& origin,
const blink::mojom::PermissionStatus& status); const PermissionType& permission,
const blink::mojom::PermissionStatus& status);
void ResetOverridesForDevTools(); void ResetOverridesForDevTools();
// PermissionController implementation. // PermissionController implementation.
......
...@@ -22,6 +22,7 @@ namespace content { ...@@ -22,6 +22,7 @@ namespace content {
namespace { namespace {
using ::testing::Unused; using ::testing::Unused;
using OverrideStatus = PermissionControllerImpl::OverrideStatus;
using RequestsCallback = using RequestsCallback =
base::Callback<void(const std::vector<blink::mojom::PermissionStatus>&)>; base::Callback<void(const std::vector<blink::mojom::PermissionStatus>&)>;
...@@ -42,6 +43,8 @@ class MockManagerWithRequests : public MockPermissionManager { ...@@ -42,6 +43,8 @@ class MockManagerWithRequests : public MockPermissionManager {
MOCK_METHOD2(SetPermissionOverridesForDevTools, MOCK_METHOD2(SetPermissionOverridesForDevTools,
void(const GURL& origin, const PermissionOverrides& overrides)); void(const GURL& origin, const PermissionOverrides& overrides));
MOCK_METHOD0(ResetPermissionOverridesForDevTools, void()); MOCK_METHOD0(ResetPermissionOverridesForDevTools, void());
MOCK_METHOD2(IsPermissionOverridableByDevTools,
bool(PermissionType, const GURL&));
private: private:
DISALLOW_COPY_AND_ASSIGN(MockManagerWithRequests); DISALLOW_COPY_AND_ASSIGN(MockManagerWithRequests);
...@@ -57,6 +60,11 @@ class PermissionControllerImplTest : public ::testing::Test { ...@@ -57,6 +60,11 @@ class PermissionControllerImplTest : public ::testing::Test {
} }
~PermissionControllerImplTest() override {} ~PermissionControllerImplTest() override {}
void SetUp() override {
ON_CALL(*mock_manager(), IsPermissionOverridableByDevTools)
.WillByDefault(testing::Return(true));
}
PermissionControllerImpl* permission_controller() { PermissionControllerImpl* permission_controller() {
return permission_controller_.get(); return permission_controller_.get();
} }
...@@ -326,6 +334,90 @@ TEST_F(PermissionControllerImplTest, ...@@ -326,6 +334,90 @@ TEST_F(PermissionControllerImplTest,
blink::mojom::PermissionStatus::ASK); blink::mojom::PermissionStatus::ASK);
} }
TEST_F(PermissionControllerImplTest,
PermissionsCannotBeOverriddenIfNotOverridable) {
GURL kTestOrigin(kTestUrl);
EXPECT_EQ(permission_controller()->SetOverrideForDevTools(
kTestOrigin, PermissionType::GEOLOCATION,
blink::mojom::PermissionStatus::DENIED),
OverrideStatus::kOverrideSet);
// Delegate will be called, but prevents override from being set.
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, testing::_))
.WillOnce(testing::Return(false));
EXPECT_EQ(permission_controller()->SetOverrideForDevTools(
kTestOrigin, PermissionType::GEOLOCATION,
blink::mojom::PermissionStatus::ASK),
OverrideStatus::kOverrideNotSet);
blink::mojom::PermissionStatus status =
permission_controller()->GetPermissionStatus(PermissionType::GEOLOCATION,
kTestOrigin, kTestOrigin);
EXPECT_EQ(status, blink::mojom::PermissionStatus::DENIED);
}
TEST_F(PermissionControllerImplTest,
GrantPermissionsReturnsStatusesBeingSetIfOverridable) {
GURL kTestOrigin(kTestUrl);
permission_controller()->SetOverrideForDevTools(
kTestOrigin, PermissionType::GEOLOCATION,
blink::mojom::PermissionStatus::DENIED);
permission_controller()->SetOverrideForDevTools(
kTestOrigin, PermissionType::MIDI, blink::mojom::PermissionStatus::ASK);
permission_controller()->SetOverrideForDevTools(
kTestOrigin, PermissionType::BACKGROUND_SYNC,
blink::mojom::PermissionStatus::ASK);
// Delegate will be called, but prevents override from being set.
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, testing::_))
.WillOnce(testing::Return(false));
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::MIDI, testing::_))
.WillOnce(testing::Return(true));
// Since one cannot be overridden, none are overridden.
auto result = permission_controller()->GrantOverridesForDevTools(
kTestOrigin, {PermissionType::MIDI, PermissionType::GEOLOCATION,
PermissionType::BACKGROUND_SYNC});
EXPECT_EQ(OverrideStatus::kOverrideNotSet, result);
// Keep original settings as before.
EXPECT_EQ(blink::mojom::PermissionStatus::DENIED,
permission_controller()->GetPermissionStatus(
PermissionType::GEOLOCATION, kTestOrigin, kTestOrigin));
EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
permission_controller()->GetPermissionStatus(
PermissionType::MIDI, kTestOrigin, kTestOrigin));
EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
permission_controller()->GetPermissionStatus(
PermissionType::BACKGROUND_SYNC, kTestOrigin, kTestOrigin));
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::GEOLOCATION, testing::_))
.WillOnce(testing::Return(true));
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::MIDI, testing::_))
.WillOnce(testing::Return(true));
EXPECT_CALL(*mock_manager(), IsPermissionOverridableByDevTools(
PermissionType::BACKGROUND_SYNC, testing::_))
.WillOnce(testing::Return(true));
// If all can be set, overrides will be stored.
result = permission_controller()->GrantOverridesForDevTools(
kTestOrigin, {PermissionType::MIDI, PermissionType::GEOLOCATION,
PermissionType::BACKGROUND_SYNC});
EXPECT_EQ(OverrideStatus::kOverrideSet, result);
EXPECT_EQ(blink::mojom::PermissionStatus::GRANTED,
permission_controller()->GetPermissionStatus(
PermissionType::GEOLOCATION, kTestOrigin, kTestOrigin));
EXPECT_EQ(blink::mojom::PermissionStatus::GRANTED,
permission_controller()->GetPermissionStatus(
PermissionType::MIDI, kTestOrigin, kTestOrigin));
EXPECT_EQ(blink::mojom::PermissionStatus::GRANTED,
permission_controller()->GetPermissionStatus(
PermissionType::BACKGROUND_SYNC, kTestOrigin, kTestOrigin));
}
} // namespace } // namespace
} // namespace content } // namespace content
...@@ -241,6 +241,7 @@ jumbo_source_set("browser_sources") { ...@@ -241,6 +241,7 @@ jumbo_source_set("browser_sources") {
"pepper_flash_settings_helper.h", "pepper_flash_settings_helper.h",
"pepper_vpn_provider_resource_host_proxy.h", "pepper_vpn_provider_resource_host_proxy.h",
"permission_controller.h", "permission_controller.h",
"permission_controller_delegate.cc",
"permission_controller_delegate.h", "permission_controller_delegate.h",
"permission_type.cc", "permission_type.cc",
"permission_type.h", "permission_type.h",
......
// Copyright 2019 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 "content/public/browser/permission_controller_delegate.h"
namespace content {
bool PermissionControllerDelegate::IsPermissionOverridableByDevTools(
PermissionType permission,
const GURL& origin) {
return true;
}
} // namespace content
...@@ -106,6 +106,11 @@ class CONTENT_EXPORT PermissionControllerDelegate { ...@@ -106,6 +106,11 @@ class CONTENT_EXPORT PermissionControllerDelegate {
// Removes overrides that have been set, if any, for all origins. If delegate // Removes overrides that have been set, if any, for all origins. If delegate
// does not maintain own permission set, then nothing happens. // does not maintain own permission set, then nothing happens.
virtual void ResetPermissionOverridesForDevTools() {} virtual void ResetPermissionOverridesForDevTools() {}
// Returns whether permission can be overridden by
// DevToolsPermissionOverrides.
virtual bool IsPermissionOverridableByDevTools(PermissionType permission,
const GURL& origin);
}; };
} // namespace content } // namespace content
......
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