blob: 4bcae9ab6eaf1ce365bc51efef8aaa5fb9183605 [file] [log] [blame]
// Copyright 2018 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/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "build/build_config.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "components/safe_browsing/content/web_ui/safe_browsing_ui.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/browser_process_platform_part_chromeos.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#else
#include "chrome/browser/policy/browser_dm_token_storage.h"
#include "chrome/browser/policy/chrome_browser_cloud_management_controller.h"
#endif
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/binary_upload_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/common/extensions/api/safe_browsing_private.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/cloud_policy_util.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/proto/webprotect.pb.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#if defined(OS_CHROMEOS)
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#endif
#include "content/public/browser/browser_context.h"
#include "extensions/browser/event_router.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
namespace {
#if defined(OS_CHROMEOS)
const char kActiveDirectoryPolicyClientDescription[] = "an Active Directory";
const char kPolicyClientDescription[] = "any";
const char kUserPolicyClientDescription[] = "a user";
#else
const char kChromeBrowserCloudManagementClientDescription[] =
"a machine-level user";
#endif
} // namespace
namespace extensions {
const base::Feature SafeBrowsingPrivateEventRouter::kRealtimeReportingFeature{
"SafeBrowsingRealtimeReporting", base::FEATURE_DISABLED_BY_DEFAULT};
// Key names used with when building the dictionary to pass to the real-time
// reporting API.
const char SafeBrowsingPrivateEventRouter::kKeyUrl[] = "url";
const char SafeBrowsingPrivateEventRouter::kKeyUserName[] = "userName";
const char SafeBrowsingPrivateEventRouter::kKeyIsPhishingUrl[] =
"isPhishingUrl";
const char SafeBrowsingPrivateEventRouter::kKeyProfileUserName[] =
"profileUserName";
const char SafeBrowsingPrivateEventRouter::kKeyFileName[] = "fileName";
const char SafeBrowsingPrivateEventRouter::kKeyDownloadDigestSha256[] =
"downloadDigestSha256";
const char SafeBrowsingPrivateEventRouter::kKeyReason[] = "reason";
const char SafeBrowsingPrivateEventRouter::kKeyNetErrorCode[] = "netErrorCode";
const char SafeBrowsingPrivateEventRouter::kKeyClickedThrough[] =
"clickedThrough";
const char SafeBrowsingPrivateEventRouter::kKeyTriggeredRules[] =
"triggeredRules";
const char SafeBrowsingPrivateEventRouter::kKeyThreatType[] = "threatType";
const char SafeBrowsingPrivateEventRouter::kKeyContentType[] = "contentType";
const char SafeBrowsingPrivateEventRouter::kKeyContentSize[] = "contentSize";
const char SafeBrowsingPrivateEventRouter::kKeyTrigger[] = "trigger";
const char SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent[] =
"passwordReuseEvent";
const char SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent[] =
"passwordChangedEvent";
const char SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent[] =
"dangerousDownloadEvent";
const char SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent[] =
"interstitialEvent";
const char SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent[] =
"sensitiveDataEvent";
const char SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent[] =
"unscannedFileEvent";
const char SafeBrowsingPrivateEventRouter::kTriggerFileDownload[] =
"FILE_DOWNLOAD";
const char SafeBrowsingPrivateEventRouter::kTriggerFileUpload[] = "FILE_UPLOAD";
const char SafeBrowsingPrivateEventRouter::kTriggerWebContentUpload[] =
"WEB_CONTENT_UPLOAD";
SafeBrowsingPrivateEventRouter::SafeBrowsingPrivateEventRouter(
content::BrowserContext* context)
: context_(context) {
event_router_ = EventRouter::Get(context_);
// g_browser_process and/or g_browser_process->local_state() may be null
// in tests.
if (g_browser_process && g_browser_process->local_state()) {
RealtimeReportingPrefChanged(std::string());
registrar_.Init(g_browser_process->local_state());
registrar_.Add(
prefs::kUnsafeEventsReportingEnabled,
base::BindRepeating(
&SafeBrowsingPrivateEventRouter::RealtimeReportingPrefChanged,
base::Unretained(this)));
}
}
SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {}
void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
const GURL& url,
const std::string& user_name,
bool is_phishing_url) {
api::safe_browsing_private::PolicySpecifiedPasswordReuse params;
params.url = url.spec();
params.user_name = user_name;
params.is_phishing_url = is_phishing_url;
// |event_router_| can be null in tests.
if (event_router_) {
auto event_value = std::make_unique<base::ListValue>();
event_value->Append(params.ToValue());
auto extension_event = std::make_unique<Event>(
events::
SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_REUSE_DETECTED,
api::safe_browsing_private::OnPolicySpecifiedPasswordReuseDetected::
kEventName,
std::move(event_value));
event_router_->BroadcastEvent(std::move(extension_event));
}
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyPasswordReuseEvent,
base::BindOnce(
[](const std::string& url, const std::string& user_name,
const bool is_phishing_url, const std::string& profile_user_name) {
// Convert |params| to a real-time event dictionary
// and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyUserName, user_name);
event.SetBoolKey(kKeyIsPhishingUrl, is_phishing_url);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
return event;
},
params.url, params.user_name, params.is_phishing_url,
GetProfileUserName()));
}
void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordChanged(
const std::string& user_name) {
// |event_router_| can be null in tests.
if (event_router_) {
auto event_value = std::make_unique<base::ListValue>();
event_value->Append(std::make_unique<base::Value>(user_name));
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_CHANGED,
api::safe_browsing_private::OnPolicySpecifiedPasswordChanged::
kEventName,
std::move(event_value));
event_router_->BroadcastEvent(std::move(extension_event));
}
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(kKeyPasswordChangedEvent,
base::BindOnce(
[](const std::string& user_name,
const std::string& profile_user_name) {
// Convert |params| to a real-time event dictionary
// and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUserName, user_name);
event.SetStringKey(kKeyProfileUserName,
profile_user_name);
return event;
},
user_name, GetProfileUserName()));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadOpened(
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const int64_t content_size) {
api::safe_browsing_private::DangerousDownloadInfo params;
params.url = url.spec();
params.file_name = file_name;
params.download_digest_sha256 = download_digest_sha256;
params.user_name = GetProfileUserName();
// |event_router_| can be null in tests.
if (event_router_) {
auto event_value = std::make_unique<base::ListValue>();
event_value->Append(params.ToValue());
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_DANGEROUS_DOWNLOAD_OPENED,
api::safe_browsing_private::OnDangerousDownloadOpened::kEventName,
std::move(event_value));
event_router_->BroadcastEvent(std::move(extension_event));
}
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyDangerousDownloadEvent,
base::BindOnce(
[](const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& user_name, const std::string& mime_type,
const int64_t content_size) {
// Convert |params| to a real-time event dictionary and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, user_name);
event.SetStringKey(kKeyContentType, mime_type);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, kTriggerFileDownload);
return event;
},
params.url, params.file_name, params.download_digest_sha256,
params.user_name, mime_type, content_size));
}
void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialShown(
const GURL& url,
const std::string& reason,
int net_error_code) {
api::safe_browsing_private::InterstitialInfo params;
params.url = url.spec();
params.reason = reason;
if (net_error_code < 0) {
params.net_error_code =
std::make_unique<std::string>(base::NumberToString(net_error_code));
}
params.user_name = GetProfileUserName();
// |event_router_| can be null in tests.
if (event_router_) {
auto event_value = std::make_unique<base::ListValue>();
event_value->Append(params.ToValue());
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_SHOWN,
api::safe_browsing_private::OnSecurityInterstitialShown::kEventName,
std::move(event_value));
event_router_->BroadcastEvent(std::move(extension_event));
}
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyInterstitialEvent,
base::BindOnce(
[](const std::string& url, const std::string& reason,
int net_error_code, const std::string& user_name) {
// Convert |params| to a real-time event dictionary and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyReason, reason);
event.SetIntKey(kKeyNetErrorCode, net_error_code);
event.SetStringKey(kKeyProfileUserName, user_name);
event.SetBoolKey(kKeyClickedThrough, false);
return event;
},
params.url, params.reason, net_error_code, params.user_name));
}
void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialProceeded(
const GURL& url,
const std::string& reason,
int net_error_code) {
api::safe_browsing_private::InterstitialInfo params;
params.url = url.spec();
params.reason = reason;
if (net_error_code < 0) {
params.net_error_code =
std::make_unique<std::string>(base::NumberToString(net_error_code));
}
params.user_name = GetProfileUserName();
// |event_router_| can be null in tests.
if (event_router_) {
auto event_value = std::make_unique<base::ListValue>();
event_value->Append(params.ToValue());
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_PROCEEDED,
api::safe_browsing_private::OnSecurityInterstitialProceeded::kEventName,
std::move(event_value));
event_router_->BroadcastEvent(std::move(extension_event));
}
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyInterstitialEvent,
base::BindOnce(
[](const std::string& url, const std::string& reason,
int net_error_code, const std::string& user_name) {
// Convert |params| to a real-time event dictionary and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyReason, reason);
event.SetIntKey(kKeyNetErrorCode, net_error_code);
event.SetStringKey(kKeyProfileUserName, user_name);
event.SetBoolKey(kKeyClickedThrough, true);
return event;
},
params.url, params.reason, net_error_code, params.user_name));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDeepScanningResult(
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& threat_type,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size) {
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyDangerousDownloadEvent,
base::BindOnce(
[](const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& profile_user_name,
const std::string& threat_type, const std::string& mime_type,
const std::string& trigger, const int64_t content_size) {
// Create a real-time event dictionary from the arguments and
// report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
event.SetStringKey(kKeyThreatType, threat_type);
event.SetStringKey(kKeyContentType, mime_type);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, trigger);
return event;
},
url.spec(), file_name, download_digest_sha256, GetProfileUserName(),
threat_type, mime_type, trigger, content_size));
}
void SafeBrowsingPrivateEventRouter::OnSensitiveDataEvent(
const safe_browsing::DlpDeepScanningVerdict& verdict,
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const int64_t content_size) {
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeySensitiveDataEvent,
base::BindOnce(
[](const safe_browsing::DlpDeepScanningVerdict& verdict,
const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& profile_user_name, const std::string& mime_type,
const std::string& trigger, const int64_t content_size) {
// Create a real-time event dictionary from the arguments and
// report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
event.SetStringKey(kKeyContentType, mime_type);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, trigger);
base::ListValue triggered_rules;
for (auto rule : verdict.triggered_rules()) {
triggered_rules.AppendString(rule.rule_name());
}
event.SetKey(kKeyTriggeredRules, std::move(triggered_rules));
return event;
},
verdict, url.spec(), file_name, download_digest_sha256,
GetProfileUserName(), mime_type, trigger, content_size));
}
void SafeBrowsingPrivateEventRouter::OnUnscannedFileEvent(
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& mime_type,
const std::string& trigger,
const std::string& reason,
const int64_t content_size) {
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyUnscannedFileEvent,
base::BindOnce(
[](const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& profile_user_name, const std::string& mime_type,
const std::string& trigger, const std::string& reason,
const int64_t content_size) {
// Create a real-time event dictionary from the arguments and
// report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
event.SetStringKey(kKeyContentType, mime_type);
event.SetStringKey(kKeyReason, reason);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, trigger);
return event;
},
url.spec(), file_name, download_digest_sha256, GetProfileUserName(),
mime_type, trigger, reason, content_size));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarning(
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& threat_type,
const std::string& mime_type,
const int64_t content_size) {
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyDangerousDownloadEvent,
base::BindOnce(
[](const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& profile_user_name,
const std::string& threat_type, const std::string& mime_type,
const int64_t content_size) {
// Create a real-time event dictionary and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
event.SetStringKey(kKeyThreatType, threat_type);
event.SetBoolKey(kKeyClickedThrough, false);
event.SetStringKey(kKeyContentType, mime_type);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, kTriggerFileDownload);
return event;
},
url.spec(), file_name, download_digest_sha256, GetProfileUserName(),
threat_type, mime_type, content_size));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarningBypassed(
const GURL& url,
const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& threat_type,
const std::string& mime_type,
const int64_t content_size) {
if (!IsRealtimeReportingEnabled())
return;
ReportRealtimeEvent(
kKeyDangerousDownloadEvent,
base::BindOnce(
[](const std::string& url, const std::string& file_name,
const std::string& download_digest_sha256,
const std::string& profile_user_name,
const std::string& threat_type, const std::string& mime_type,
const int64_t content_size) {
// Create a real-time event dictionary and report it.
base::Value event(base::Value::Type::DICTIONARY);
event.SetStringKey(kKeyUrl, url);
event.SetStringKey(kKeyFileName, file_name);
event.SetStringKey(kKeyDownloadDigestSha256,
download_digest_sha256);
event.SetStringKey(kKeyProfileUserName, profile_user_name);
event.SetStringKey(kKeyThreatType, threat_type);
event.SetBoolKey(kKeyClickedThrough, true);
event.SetStringKey(kKeyContentType, mime_type);
// |content_size| can be set to -1 to indicate an unknown size, in
// which case the field is not set.
if (content_size >= 0)
event.SetIntKey(kKeyContentSize, content_size);
event.SetStringKey(kKeyTrigger, kTriggerFileDownload);
return event;
},
url.spec(), file_name, download_digest_sha256, GetProfileUserName(),
threat_type, mime_type, content_size));
}
// static
bool SafeBrowsingPrivateEventRouter::ShouldInitRealtimeReportingClient() {
if (!base::FeatureList::IsEnabled(kRealtimeReportingFeature)) {
DVLOG(2) << "Safe browsing real-time reporting is not enabled.";
return false;
}
if (!IsRealtimeReportingAvailable()) {
DVLOG(1) << "Safe browsing real-time event reporting is only available for "
"managed browsers or devices.";
return false;
}
return true;
}
void SafeBrowsingPrivateEventRouter::SetCloudPolicyClientForTesting(
policy::CloudPolicyClient* client) {
DCHECK_EQ(nullptr, client_);
client_ = client;
}
void SafeBrowsingPrivateEventRouter::InitRealtimeReportingClient() {
// If already initialized, do nothing.
if (client_) {
DVLOG(2) << "Safe browsing real-time event reporting already initialized.";
return;
}
if (!ShouldInitRealtimeReportingClient())
return;
// |identity_manager_| may be null in tests. If there is no identity
// manager don't enable the real-time reporting API since the router won't
// be able to fill in all the info needed for the reports.
identity_manager_ = IdentityManagerFactory::GetForProfile(
Profile::FromBrowserContext(context_));
if (!identity_manager_) {
DVLOG(2) << "Safe browsing real-time event requires an identity manager.";
return;
}
// |device_management_service| may be null in tests. If there is no device
// management service don't enable the real-time reporting API since the
// router won't be able to create the reporting server client below.
policy::DeviceManagementService* device_management_service =
g_browser_process->browser_policy_connector()
->device_management_service();
if (!device_management_service) {
DVLOG(2) << "Safe browsing real-time event requires a device management "
"service.";
return;
}
if (g_browser_process) {
binary_upload_service_ =
g_browser_process->safe_browsing_service()->GetBinaryUploadService(
Profile::FromBrowserContext(context_));
IfAuthorized(base::BindOnce(
&SafeBrowsingPrivateEventRouter::InitRealtimeReportingClientCallback,
weak_ptr_factory_.GetWeakPtr(), device_management_service));
}
}
void SafeBrowsingPrivateEventRouter::InitRealtimeReportingClientCallback(
policy::DeviceManagementService* device_management_service,
bool authorized) {
// Don't initialize the client if the browser cannot upload data.
if (!authorized) {
LOG(WARNING) << "The client is not authorized to do safe browsing "
"real-time event reporting.";
return;
}
policy::CloudPolicyClient* client = nullptr;
std::string policy_client_desc;
#if defined(OS_CHROMEOS)
policy_client_desc = kPolicyClientDescription;
auto* user = GetChromeOSUser();
if (user) {
auto* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
DCHECK(profile);
if (user->IsActiveDirectoryUser()) {
// TODO(crbug.com/1012048): Handle AD, likely through crbug.com/1012170.
policy_client_desc = kActiveDirectoryPolicyClientDescription;
} else {
policy_client_desc = kUserPolicyClientDescription;
auto* policy_manager = profile->GetUserCloudPolicyManagerChromeOS();
if (policy_manager)
client = policy_manager->core()->client();
}
} else {
LOG(ERROR) << "Could not determine who the user is.";
}
#else
policy_client_desc = kChromeBrowserCloudManagementClientDescription;
// Make sure we have a DM token to proceed. During the lifetime of a running
// chrome browser, this can only change from empty to non-empty. There are
// no cases where chrome starts with a dm token and then it goes away.
// When chrome starts without a dm token and determines that one is needed,
// browser startup is blocked until it is retrieved or an error occurs. In
// the latter case, chrome won't try to retrieve it again until the next
// restart.
//
// Therefore, it is OK to retrieve the dm token once here on initialization
// of the router to determine if real-time reporting can be enabled or not.
policy::DMToken dm_token =
policy::BrowserDMTokenStorage::Get()->RetrieveDMToken();
std::string client_id =
policy::BrowserDMTokenStorage::Get()->RetrieveClientId();
if (!dm_token.is_valid())
return;
// Make sure DeviceManagementService has been initialized.
device_management_service->ScheduleInitialization(0);
private_client_ = std::make_unique<policy::CloudPolicyClient>(
/*machine_id=*/std::string(), /*machine_model=*/std::string(),
/*brand_code=*/std::string(), /*ethernet_mac_address=*/std::string(),
/*dock_mac_address=*/std::string(), /*manufacture_date=*/std::string(),
device_management_service, g_browser_process->shared_url_loader_factory(),
nullptr, policy::CloudPolicyClient::DeviceDMTokenCallback());
client = private_client_.get();
if (!client->is_registered()) {
client->SetupRegistration(
dm_token.value(), client_id,
/*user_affiliation_ids=*/std::vector<std::string>());
}
#endif
OnCloudPolicyClientAvailable(policy_client_desc, client);
}
void SafeBrowsingPrivateEventRouter::OnCloudPolicyClientAvailable(
const std::string& policy_client_desc,
policy::CloudPolicyClient* client) {
client_ = client;
if (client_ == nullptr) {
LOG(ERROR) << "Could not obtain " << policy_client_desc
<< " for safe browsing real-time event reporting.";
return;
}
VLOG(1) << "Ready for safe browsing real-time event reporting.";
}
bool SafeBrowsingPrivateEventRouter::IsRealtimeReportingEnabled() {
// g_browser_process and/or g_browser_process->local_state() may be null
// in tests.
return g_browser_process && g_browser_process->local_state() &&
g_browser_process->local_state()->GetBoolean(
prefs::kUnsafeEventsReportingEnabled);
}
void SafeBrowsingPrivateEventRouter::RealtimeReportingPrefChanged(
const std::string& pref) {
// If the reporting policy has been turned on, try to initialized now.
if (IsRealtimeReportingEnabled())
InitRealtimeReportingClient();
}
void SafeBrowsingPrivateEventRouter::IfAuthorized(
base::OnceCallback<void(bool)> cont) {
if (binary_upload_service_) {
binary_upload_service_->IsAuthorized(std::move(cont));
}
}
void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(
const std::string& name,
EventBuilder event_builder) {
IfAuthorized(base::BindOnce(
&SafeBrowsingPrivateEventRouter::ReportRealtimeEventCallback,
weak_ptr_factory_.GetWeakPtr(), name, std::move(event_builder)));
}
void SafeBrowsingPrivateEventRouter::ReportRealtimeEventCallback(
const std::string& name,
EventBuilder event_builder,
bool authorized) {
// Ignore the event if we know we can't report it.
if (!authorized) {
DVLOG(2) << "Safe browsing real-time reporting is not authorized.";
return;
}
// |client_| should be set when authorized is true.
DCHECK(client_);
// Format the current time (UTC) in RFC3339 format.
base::Time::Exploded now_exploded;
base::Time::Now().UTCExplode(&now_exploded);
std::string now_str = base::StringPrintf(
"%d-%02d-%02dT%02d:%02d:%02d.%03dZ", now_exploded.year,
now_exploded.month, now_exploded.day_of_month, now_exploded.hour,
now_exploded.minute, now_exploded.second, now_exploded.millisecond);
base::Value wrapper(base::Value::Type::DICTIONARY);
wrapper.SetStringKey("time", now_str);
wrapper.SetKey(name, std::move(event_builder).Run());
// Show the report on chrome://safe-browsing, if appropriate.
safe_browsing::WebUIInfoSingleton::GetInstance()->AddToReportingEvents(
wrapper);
base::Value event_list(base::Value::Type::LIST);
event_list.Append(std::move(wrapper));
client_->UploadRealtimeReport(
policy::RealtimeReportingJobConfiguration::BuildReport(
std::move(event_list),
reporting::GetContext(Profile::FromBrowserContext(context_))),
base::DoNothing());
}
std::string SafeBrowsingPrivateEventRouter::GetProfileUserName() const {
// |identity_manager_| may be null is some tests.
return identity_manager_ && identity_manager_->HasPrimaryAccount()
? identity_manager_->GetPrimaryAccountInfo().email
: std::string();
}
#if defined(OS_CHROMEOS)
// static
const user_manager::User* SafeBrowsingPrivateEventRouter::GetChromeOSUser() {
return user_manager::UserManager::IsInitialized()
? user_manager::UserManager::Get()->GetPrimaryUser()
: nullptr;
}
#endif
bool SafeBrowsingPrivateEventRouter::IsRealtimeReportingAvailable() {
#if defined(OS_CHROMEOS)
// The device must be managed.
if (!g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->IsEnterpriseManaged())
return false;
// The Chrome OS user must be afiliated with the device.
auto* user = GetChromeOSUser();
if (!user || !user->IsAffiliated())
return false;
// And that user must be managed.
auto* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
return profile && profile->GetProfilePolicyConnector()->IsManaged();
#else
return policy::ChromeBrowserCloudManagementController::IsEnabled();
#endif
}
} // namespace extensions