Commit 40cc157c authored by Paul Meyer's avatar Paul Meyer Committed by Commit Bot

Allow feature policy to be controlled via Origin Trial.

This patch adds a "Frobulate" feature policy to test being
controlled via the Frobulate sample origin trial.

Bug: 925097
Change-Id: I8f85926546dc0eafd3f882273af87bbc79a321b2
Reviewed-on: https://chromium-review.googlesource.com/c/1435534
Commit-Queue: Paul Meyer <paulmeyer@chromium.org>
Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarIan Clelland <iclelland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#628441}
parent bac84a74
......@@ -103,6 +103,8 @@ enum FeaturePolicyFeature {
kWakeLock = 31,
// Controls access to font-display attribute in @font-face CSS rule
kFontDisplay = 32,
// Sample Origin Trial enabled feature. This is used only for testing.
kFrobulate = 41,
// These are the defined sandbox features implemented as policy-controlled
// features.
......
......@@ -6324,7 +6324,7 @@ void Document::ApplyFeaturePolicyFromHeader(
UseCounter::Count(*this, WebFeature::kFeaturePolicyHeader);
Vector<String> messages;
const ParsedFeaturePolicy& declared_policy = ParseFeaturePolicyHeader(
feature_policy_header, GetSecurityOrigin(), &messages);
feature_policy_header, GetSecurityOrigin(), &messages, this);
for (auto& message : messages) {
AddConsoleMessage(
ConsoleMessage::Create(kSecurityMessageSource, kErrorMessageLevel,
......@@ -6388,7 +6388,7 @@ void Document::ApplyReportOnlyFeaturePolicyFromHeader(
UseCounter::Count(*this, WebFeature::kFeaturePolicyReportOnlyHeader);
Vector<String> messages;
const ParsedFeaturePolicy& report_only_policy = ParseFeaturePolicyHeader(
feature_policy_report_only_header, GetSecurityOrigin(), &messages);
feature_policy_report_only_header, GetSecurityOrigin(), &messages, this);
for (auto& message : messages) {
AddConsoleMessage(ConsoleMessage::Create(
kSecurityMessageSource, kErrorMessageLevel,
......
......@@ -7,6 +7,8 @@
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
......@@ -18,12 +20,39 @@
namespace blink {
namespace {
// Returns true if this feature is currently disabled by an origin trial (it is
// origin trial controlled, and the origin trial is not enabled).
bool IsOriginTrialDisabled(const String& feature_name,
const ExecutionContext* execution_context) {
bool (*origin_trial_enabled)(const blink::ExecutionContext*);
// All origin trial controlled features should be listed here.
if (feature_name == "frobulate") {
origin_trial_enabled = origin_trials::OriginTrialsSampleAPIEnabled;
} else {
return false;
}
// Impossible to know without an ExecutionContext, so block.
if (!execution_context)
return true;
// Check whether this feature's origin trial is enabled, and block otherwise.
DCHECK(origin_trial_enabled);
return !origin_trial_enabled(execution_context);
}
} // namespace
ParsedFeaturePolicy ParseFeaturePolicyHeader(
const String& policy,
scoped_refptr<const SecurityOrigin> origin,
Vector<String>* messages) {
Vector<String>* messages,
ExecutionContext* execution_context) {
return ParseFeaturePolicy(policy, origin, nullptr, messages,
GetDefaultFeatureNameMap());
GetDefaultFeatureNameMap(), execution_context);
}
ParsedFeaturePolicy ParseFeaturePolicyAttribute(
......@@ -42,7 +71,7 @@ ParsedFeaturePolicy ParseFeaturePolicy(
scoped_refptr<const SecurityOrigin> src_origin,
Vector<String>* messages,
const FeatureNameMap& feature_names,
Document* document) {
ExecutionContext* execution_context) {
ParsedFeaturePolicy allowlists;
BitVector features_specified(
static_cast<int>(mojom::FeaturePolicyFeature::kMaxValue) + 1);
......@@ -65,6 +94,7 @@ ParsedFeaturePolicy ParseFeaturePolicy(
// Empty policy. Skip.
if (tokens.IsEmpty())
continue;
String feature_name = tokens[0];
if (!feature_names.Contains(feature_name)) {
if (messages) {
......@@ -73,6 +103,14 @@ ParsedFeaturePolicy ParseFeaturePolicy(
continue;
}
if (IsOriginTrialDisabled(feature_name, execution_context)) {
if (messages) {
messages->push_back("Origin trial controlled feature not enabled: '" +
tokens[0] + "'.");
}
continue;
}
mojom::FeaturePolicyFeature feature = feature_names.at(feature_name);
// If a policy has already been specified for the current feature, drop
// the new policy.
......@@ -81,6 +119,7 @@ ParsedFeaturePolicy ParseFeaturePolicy(
// Count the use of this feature policy.
if (src_origin) {
Document* document = DynamicTo<Document>(execution_context);
if (!document || !document->IsParsedFeaturePolicy(feature)) {
UMA_HISTOGRAM_ENUMERATION("Blink.UseCounter.FeaturePolicy.Allow",
feature);
......
......@@ -19,6 +19,7 @@
namespace blink {
class Document;
class ExecutionContext;
// Returns a map between feature name (string) and mojom::FeaturePolicyFeature
// (enum).
......@@ -26,15 +27,17 @@ typedef HashMap<String, mojom::FeaturePolicyFeature> FeatureNameMap;
CORE_EXPORT const FeatureNameMap& GetDefaultFeatureNameMap();
// Converts a header policy string into a vector of allowlists, one for each
// feature specified. Unrecognized features are filtered out. If |messages|
// is not null, then any message in the input will cause a warning message to be
// appended to it.
// feature specified. Unrecognized features are filtered out. If |messages| is
// not null, then any message in the input will cause a warning message to be
// appended to it. The optional ExecutionContext is used to determine if any
// origin trials affect the parsing.
// Example of a feature policy string:
// "vibrate a.com b.com; fullscreen 'none'; payment 'self', payment *".
CORE_EXPORT ParsedFeaturePolicy
ParseFeaturePolicyHeader(const String& policy,
scoped_refptr<const SecurityOrigin>,
Vector<String>* messages);
Vector<String>* messages,
ExecutionContext* execution_context = nullptr);
// Converts a container policy string into a vector of allowlists, given self
// and src origins provided, one for each feature specified. Unrecognized
......@@ -52,14 +55,16 @@ ParseFeaturePolicyAttribute(const String& policy,
// Converts a feature policy string into a vector of allowlists (see comments
// above), with an explicit FeatureNameMap. This algorithm is called by both
// header policy parsing and container policy parsing. |self_origin|,
// |src_origin|, and |document| are nullable.
// |src_origin|, and |execution_context| are nullable. The optional
// ExecutionContext is used to determine if any origin trials affect the
// parsing.
CORE_EXPORT ParsedFeaturePolicy
ParseFeaturePolicy(const String& policy,
scoped_refptr<const SecurityOrigin> self_origin,
scoped_refptr<const SecurityOrigin> src_origin,
Vector<String>* messages,
const FeatureNameMap& feature_names,
Document* document = nullptr);
ExecutionContext* execution_context = nullptr);
// Returns true iff any declaration in the policy is for the given feature.
CORE_EXPORT bool IsFeatureDeclared(mojom::FeaturePolicyFeature,
......
......@@ -9,10 +9,12 @@
#include "third_party/blink/public/common/origin_trials/trial_token.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/feature_policy/feature_policy.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html/html_meta_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/platform/testing/histogram_tester.h"
......@@ -222,4 +224,32 @@ TEST_F(OriginTrialContextTest, ParseHeaderValue_NotCommaSeparated) {
EXPECT_FALSE(OriginTrialContext::ParseHeaderValue("\"foo\" bar"));
}
TEST_F(OriginTrialContextTest, FeaturePolicy) {
// Create a dummy document with an OriginTrialContext.
std::unique_ptr<DummyPageHolder> dummy = DummyPageHolder::Create();
Document* document = &dummy->GetDocument();
OriginTrialContext* context = OriginTrialContext::FromOrCreate(document);
// Enable the sample origin trial API ("Frobulate").
context->AddFeature(origin_trials::kOriginTrialsSampleAPITrialName);
EXPECT_TRUE(
context->IsTrialEnabled(origin_trials::kOriginTrialsSampleAPITrialName));
// Make a mock feature name map with "frobulate".
FeatureNameMap feature_map;
feature_map.Set("frobulate", mojom::FeaturePolicyFeature::kFrobulate);
// Attempt to parse the "frobulate" feature policy. This will only work if the
// feature policy is successfully enabled via the origin trial.
scoped_refptr<const SecurityOrigin> security_origin =
SecurityOrigin::CreateFromString(kFrobulateEnabledOrigin);
Vector<String> messages;
ParsedFeaturePolicy result;
result = ParseFeaturePolicy("frobulate", security_origin, nullptr, &messages,
feature_map, document);
EXPECT_TRUE(messages.IsEmpty());
ASSERT_EQ(1u, result.size());
EXPECT_EQ(mojom::FeaturePolicyFeature::kFrobulate, result[0].feature);
}
} // namespace blink
......@@ -21542,6 +21542,7 @@ Called by update_net_error_codes.py.-->
<int value="38" label="Modals"/>
<int value="39" label="OrientationLock"/>
<int value="40" label="Presentation"/>
<int value="41" label="Frobulate"/>
</enum>
<enum name="FeedbackSource">
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