Replace GPOs with CBCM for local content analysis.
Bug: b:257248802
Change-Id: I97c89d925a372c50f67df4b83362a9279afe5410
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4067361
Commit-Queue: Roger Tawa <[email protected]>
Reviewed-by: Dominique Fauteux-Chapleau <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1109556}
diff --git a/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.cc b/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.cc
index 6b64393..0f6aa39 100644
--- a/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.cc
+++ b/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.cc
@@ -190,14 +190,14 @@
settings.block_password_protected_files = block_password_protected_files_;
settings.block_large_files = block_large_files_;
settings.block_unsupported_file_types = block_unsupported_file_types_;
- if (analysis_config_->url) {
+ if (is_cloud_analysis()) {
CloudAnalysisSettings cloud_settings;
cloud_settings.analysis_url = GURL(analysis_config_->url);
DCHECK(cloud_settings.analysis_url.is_valid());
settings.cloud_or_local_settings =
CloudOrLocalAnalysisSettings(std::move(cloud_settings));
} else {
- DCHECK(analysis_config_->local_path);
+ DCHECK(is_local_analysis());
LocalAnalysisSettings local_settings;
local_settings.local_path = analysis_config_->local_path;
local_settings.user_specific = analysis_config_->user_specific;
@@ -286,6 +286,14 @@
return tags_.find(tag) != tags_.end() && tags_.at(tag).requires_justification;
}
+bool AnalysisServiceSettings::is_cloud_analysis() const {
+ return analysis_config_ && analysis_config_->url != nullptr;
+}
+
+bool AnalysisServiceSettings::is_local_analysis() const {
+ return analysis_config_ && analysis_config_->local_path != nullptr;
+}
+
void AnalysisServiceSettings::AddUrlPatternSettings(
const base::Value::Dict& url_settings_dict,
bool enabled,
diff --git a/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.h b/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.h
index 6c64a18f..86641b8a 100644
--- a/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.h
+++ b/chrome/browser/enterprise/connectors/analysis/analysis_service_settings.h
@@ -56,6 +56,10 @@
std::string service_provider_name() const { return service_provider_name_; }
+ // Helpers for convenient check of the underlying variant.
+ bool is_cloud_analysis() const;
+ bool is_local_analysis() const;
+
const AnalysisConfig* GetAnalysisConfig() const { return analysis_config_; }
private:
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.cc b/chrome/browser/enterprise/connectors/connectors_manager.cc
index 6cb3695..6670568 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.cc
+++ b/chrome/browser/enterprise/connectors/connectors_manager.cc
@@ -7,8 +7,10 @@
#include <memory>
#include "base/check.h"
+#include "base/feature_list.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h"
#include "chrome/browser/enterprise/connectors/reporting/browser_crash_event_router.h"
#include "chrome/browser/enterprise/connectors/reporting/extension_install_event_router.h"
#include "components/prefs/pref_service.h"
@@ -36,11 +38,21 @@
ConnectorsManager::~ConnectorsManager() = default;
bool ConnectorsManager::IsConnectorEnabled(AnalysisConnector connector) const {
- if (analysis_connector_settings_.count(connector) == 1)
- return true;
+ if (analysis_connector_settings_.count(connector) == 0 &&
+ prefs()->HasPrefPath(ConnectorPref(connector))) {
+ CacheAnalysisConnectorPolicy(connector);
+ }
- const char* pref = ConnectorPref(connector);
- return pref && pref_change_registrar_.prefs()->HasPrefPath(pref);
+ if (analysis_connector_settings_.count(connector) != 1) {
+ return false;
+ }
+
+ // If the connector is for local content analysis, make sure it is also
+ // enabled by flags. For now, only one connector is supported at a time.
+ const auto& settings = analysis_connector_settings_.at(connector)[0];
+
+ return settings.is_cloud_analysis() ||
+ base::FeatureList::IsEnabled(kLocalContentAnalysisEnabled);
}
bool ConnectorsManager::IsConnectorEnabled(ReportingConnector connector) const {
@@ -48,7 +60,7 @@
return true;
const char* pref = ConnectorPref(connector);
- return pref && pref_change_registrar_.prefs()->HasPrefPath(pref);
+ return pref && prefs()->HasPrefPath(pref);
}
absl::optional<ReportingSettings> ConnectorsManager::GetReportingSettings(
@@ -130,15 +142,14 @@
}
void ConnectorsManager::CacheAnalysisConnectorPolicy(
- AnalysisConnector connector) {
+ AnalysisConnector connector) const {
analysis_connector_settings_.erase(connector);
// Connectors with non-existing policies should not reach this code.
const char* pref = ConnectorPref(connector);
DCHECK(pref);
- const base::Value::List& policy_value =
- pref_change_registrar_.prefs()->GetList(pref);
+ const base::Value::List& policy_value = prefs()->GetList(pref);
for (const base::Value& service_settings : policy_value)
analysis_connector_settings_[connector].emplace_back(
service_settings, *service_provider_config_);
@@ -152,8 +163,7 @@
const char* pref = ConnectorPref(connector);
DCHECK(pref);
- const base::Value::List& policy_value =
- pref_change_registrar_.prefs()->GetList(pref);
+ const base::Value::List& policy_value = prefs()->GetList(pref);
for (const base::Value& service_settings : policy_value)
reporting_connector_settings_[connector].emplace_back(
service_settings, *service_provider_config_);
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.h b/chrome/browser/enterprise/connectors/connectors_manager.h
index 91bba9f..5072a5287 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.h
+++ b/chrome/browser/enterprise/connectors/connectors_manager.h
@@ -97,7 +97,7 @@
AnalysisConnector connector);
// Read and cache the policy corresponding to |connector|.
- void CacheAnalysisConnectorPolicy(AnalysisConnector connector);
+ void CacheAnalysisConnectorPolicy(AnalysisConnector connector) const;
void CacheReportingConnectorPolicy(ReportingConnector connector);
// Sets up |pref_change_registrar_|. Used by the constructor and
@@ -112,13 +112,19 @@
absl::optional<ReportingSettings> GetReportingSettingsFromConnectorPolicy(
ReportingConnector connector);
+ PrefService* prefs() { return pref_change_registrar_.prefs(); }
+
+ const PrefService* prefs() const { return pref_change_registrar_.prefs(); }
+
// Cached values of available service providers. This information validates
// the Connector policies have a valid provider.
raw_ptr<const ServiceProviderConfig> service_provider_config_;
// Cached values of the connector policies. Updated when a connector is first
- // used or when a policy is updated.
- AnalysisConnectorsSettings analysis_connector_settings_;
+ // used or when a policy is updated. Analysis connectors settings are
+ // mutable because they maybe updated by a call to IsConnectorEnabled(),
+ // which is a const method.
+ mutable AnalysisConnectorsSettings analysis_connector_settings_;
ReportingConnectorsSettings reporting_connector_settings_;
// Used to track changes of connector policies and propagate them in
diff --git a/chrome/browser/enterprise/connectors/connectors_manager_unittest.cc b/chrome/browser/enterprise/connectors/connectors_manager_unittest.cc
index 1083a7c..c20bf06 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager_unittest.cc
+++ b/chrome/browser/enterprise/connectors/connectors_manager_unittest.cc
@@ -14,6 +14,7 @@
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
@@ -165,6 +166,45 @@
std::set<std::string> expected_mime_types_;
};
+// Platform policies should only act as a kill switch.
+class ConnectorsManagerLocalAnalysisPolicyTest
+ : public ConnectorsManagerTest,
+ public testing::WithParamInterface<
+ std::tuple<AnalysisConnector, bool, bool>> {
+ protected:
+ AnalysisConnector connector() const { return std::get<0>(GetParam()); }
+ bool enable_feature() const { return std::get<1>(GetParam()); }
+ bool set_policy() const { return std::get<2>(GetParam()); }
+};
+
+TEST_P(ConnectorsManagerLocalAnalysisPolicyTest, Test) {
+ if (enable_feature()) {
+ scoped_feature_list_.InitWithFeatures({kLocalContentAnalysisEnabled}, {});
+ } else {
+ scoped_feature_list_.InitWithFeatures({}, {kLocalContentAnalysisEnabled});
+ }
+
+ std::unique_ptr<ScopedConnectorPref> scoped_pref =
+ set_policy() ? std::make_unique<ScopedConnectorPref>(
+ pref_service(), ConnectorPref(connector()),
+ kNormalLocalAnalysisSettingsPref)
+ : nullptr;
+
+ ConnectorsManager manager(
+ std::make_unique<BrowserCrashEventRouter>(profile_),
+ std::make_unique<ExtensionInstallEventRouter>(profile_), pref_service(),
+ GetServiceProviderConfig());
+ EXPECT_EQ(enable_feature() && set_policy(),
+ manager.IsConnectorEnabled(connector()));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ConnectorsManagerLocalAnalysisPolicyTest,
+ ConnectorsManagerLocalAnalysisPolicyTest,
+ testing::Combine(testing::ValuesIn(kAllAnalysisConnectors),
+ testing::Bool(),
+ testing::Bool()));
+
class ConnectorsManagerConnectorPoliciesTest
: public ConnectorsManagerTest,
public testing::WithParamInterface<
diff --git a/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.cc b/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.cc
index 4821d35c..fbb317f 100644
--- a/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.cc
+++ b/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.cc
@@ -4,9 +4,7 @@
#include "chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler.h"
-#include "base/feature_list.h"
#include "base/values.h"
-#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h"
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/enterprise/connectors/service_provider_config.h"
#include "components/policy/core/browser/policy_error_map.h"
@@ -18,71 +16,6 @@
namespace enterprise_connectors {
-namespace {
-
-bool IsContentAnalysisPref(const char* pref) {
- return pref == kOnFileAttachedPref || pref == kOnFileDownloadedPref ||
- pref == kOnBulkDataEntryPref || pref == kOnPrintPref;
-}
-
-bool CanUseNonCloudPolicySource(const char* pref,
- const policy::PolicyMap::Entry* policy) {
- DCHECK(policy);
-
- // The condition below is a quick fix to avoid accessing feature state before
- // FeatureList initialization, because that results in a crash.
- //
- // TODO(crbug.com/1381113): Instead of this quick fix, move code that depends
- // on feature state after FeatureList initialization.
- if (base::FeatureList::GetInstance()) {
- if (!base::FeatureList::IsEnabled(kLocalContentAnalysisEnabled))
- return false;
- } else {
- if (kLocalContentAnalysisEnabled.default_state ==
- base::FEATURE_DISABLED_BY_DEFAULT) {
- return false;
- }
- }
-
- // Only content analysis policies with a LCA provider are exempt from using
- // cloud policies.
- if (!IsContentAnalysisPref(pref))
- return false;
-
- const base::Value* value = policy->value_unsafe();
- if (!value)
- return false;
-
- // Content analysis policies have the following format:
- // [
- // {
- // "service_provider": "foo",
- // "other_param_1": { ... },
- // "other_param_2": { ... },
- // },
- // ]
- //
- // So we simply need to validate that the service provider is valid for LCA.
- if (!value->is_list() || value->GetList().empty())
- return false;
-
- const base::Value::List& configs = value->GetList();
- if (!configs[0].is_dict() ||
- !configs[0].GetDict().FindString("service_provider")) {
- return false;
- }
-
- const std::string* service_provider =
- configs[0].GetDict().FindString("service_provider");
- const ServiceProviderConfig* service_providers = GetServiceProviderConfig();
-
- return service_providers->count(*service_provider) &&
- service_providers->at(*service_provider).analysis &&
- service_providers->at(*service_provider).analysis->local_path;
-}
-
-} // namespace
-
EnterpriseConnectorsPolicyHandler::EnterpriseConnectorsPolicyHandler(
const char* policy_name,
const char* pref_path,
@@ -115,8 +48,7 @@
if (!policy)
return true;
- if (!CanUseNonCloudPolicySource(pref_path_, policy) &&
- policy->source != policy::POLICY_SOURCE_CLOUD &&
+ if (policy->source != policy::POLICY_SOURCE_CLOUD &&
policy->source != policy::POLICY_SOURCE_CLOUD_FROM_ASH) {
errors->AddError(policy_name(), IDS_POLICY_CLOUD_SOURCE_ONLY_ERROR);
return false;
diff --git a/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler_unittest.cc b/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler_unittest.cc
index c7cd65c..2d6f474 100644
--- a/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler_unittest.cc
+++ b/chrome/browser/enterprise/connectors/enterprise_connectors_policy_handler_unittest.cc
@@ -8,9 +8,7 @@
#include <tuple>
#include "base/json/json_reader.h"
-#include "base/test/scoped_feature_list.h"
#include "base/values.h"
-#include "chrome/browser/enterprise/connectors/analysis/content_analysis_features.h"
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/policy_map.h"
@@ -188,40 +186,19 @@
class EnterpriseConnectorsPolicyHandlerLocalTest
: public EnterpriseConnectorsPolicyHandlerTestBase,
- public testing::TestWithParam<
- std::tuple<const char*, const char*, bool>> {
+ public testing::TestWithParam<std::tuple<const char*, const char*>> {
public:
- EnterpriseConnectorsPolicyHandlerLocalTest() {
- if (enable_feature())
- scoped_feature_list_.InitAndEnableFeature(kLocalContentAnalysisEnabled);
- }
+ EnterpriseConnectorsPolicyHandlerLocalTest() = default;
const char* policy() const override { return std::get<0>(GetParam()); }
const char* policy_pref() const { return std::get<1>(GetParam()); }
- bool enable_feature() const { return std::get<2>(GetParam()); }
bool policy_is_valid() const {
if (policy() == kEmptyPolicy)
return true;
- if (!enable_feature())
- return false;
-
- if (policy_pref() != kOnFileAttachedPref ||
- policy_pref() != kOnFileDownloadedPref ||
- policy_pref() != kOnBulkDataEntryPref ||
-#if BUILDFLAG(IS_CHROMEOS)
- policy_pref() != kOnFileTransferPref ||
-#endif
- policy_pref() != kOnPrintPref) {
- return false;
- }
-
- return policy() == kValidLocalContentAnalysisPolicy;
+ return false;
}
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(EnterpriseConnectorsPolicyHandlerLocalTest, Test) {
@@ -248,7 +225,9 @@
INSTANTIATE_TEST_SUITE_P(
EnterpriseConnectorsPolicyHandlerLocalTest,
EnterpriseConnectorsPolicyHandlerLocalTest,
- testing::Combine(testing::Values(kValidLocalContentAnalysisPolicy,
+ testing::Combine(testing::Values(kValidPolicy,
+ kInvalidPolicy,
+ kValidLocalContentAnalysisPolicy,
kInvalidProviderLocalContentAnalysisPolicy,
kFakeProviderLocalContentAnalysisPolicy,
kEmptyPolicy),
@@ -259,7 +238,6 @@
#if BUILDFLAG(IS_CHROMEOS)
kOnFileTransferPref,
#endif
- kOnSecurityEventPref),
- testing::Bool()));
+ kOnSecurityEventPref)));
} // namespace enterprise_connectors