blob: 3a801f2f881ad9288e0f9667bc1077192803de2c [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/enterprise/util/managed_browser_utils.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/containers/fixed_flat_set.h"
#include "base/feature_list.h"
#include "base/notreached.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.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/common/pref_names.h"
#include "components/certificate_matching/certificate_principal_pattern.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "net/base/host_port_pair.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/client_cert_identity.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_ANDROID)
#include <jni.h>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "chrome/browser/enterprise/util/jni_headers/ManagedBrowserUtils_jni.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/browser/ui/managed_ui.h"
#include "components/enterprise/browser/reporting/common_pref_names.h"
#endif // BUILDFLAG(IS_ANDROID)
namespace chrome {
namespace enterprise_util {
namespace {
// Returns client certificate auto-selection filters configured for the given
// URL in |ContentSettingsType::AUTO_SELECT_CERTIFICATE| content setting. The
// format of the returned filters corresponds to the "filter" property of the
// AutoSelectCertificateForUrls policy as documented at policy_templates.json.
base::Value::List GetCertAutoSelectionFilters(Profile* profile,
const GURL& requesting_url) {
HostContentSettingsMap* host_content_settings_map =
HostContentSettingsMapFactory::GetForProfile(profile);
base::Value setting = host_content_settings_map->GetWebsiteSetting(
requesting_url, requesting_url,
ContentSettingsType::AUTO_SELECT_CERTIFICATE, nullptr);
if (!setting.is_dict())
return {};
base::Value::List* filters = setting.GetDict().FindList("filters");
if (!filters) {
// |setting_dict| has the wrong format (e.g. single filter instead of a
// list of filters). This content setting is only provided by
// the |PolicyProvider|, which should always set it to a valid format.
// Therefore, delete the invalid value.
host_content_settings_map->SetWebsiteSettingDefaultScope(
requesting_url, requesting_url,
ContentSettingsType::AUTO_SELECT_CERTIFICATE, base::Value());
return {};
}
return std::move(*filters);
}
// Returns whether the client certificate matches any of the auto-selection
// filters. Returns false when there's no valid filter.
bool CertMatchesSelectionFilters(
const net::ClientCertIdentity& client_cert,
const base::Value::List& auto_selection_filters) {
for (const auto& filter : auto_selection_filters) {
if (!filter.is_dict()) {
// The filter has a wrong format, so ignore it. Note that reporting of
// schema violations, like this, to UI is already implemented in the
// policy handler - see configuration_policy_handler_list_factory.cc.
continue;
}
auto issuer_pattern = certificate_matching::CertificatePrincipalPattern::
ParseFromOptionalDict(filter.GetDict().FindDict("ISSUER"), "CN", "L",
"O", "OU");
auto subject_pattern = certificate_matching::CertificatePrincipalPattern::
ParseFromOptionalDict(filter.GetDict().FindDict("SUBJECT"), "CN", "L",
"O", "OU");
if (issuer_pattern.Matches(client_cert.certificate()->issuer()) &&
subject_pattern.Matches(client_cert.certificate()->subject())) {
return true;
}
}
return false;
}
} // namespace
bool IsBrowserManaged(Profile* profile) {
DCHECK(profile);
return policy::ManagementServiceFactory::GetForProfile(profile)->IsManaged();
}
std::string GetDomainFromEmail(const std::string& email) {
size_t email_separator_pos = email.find('@');
bool is_email = email_separator_pos != std::string::npos &&
email_separator_pos < email.length() - 1;
if (!is_email)
return std::string();
return gaia::ExtractDomainName(email);
}
GURL GetRequestingUrl(const net::HostPortPair host_port_pair) {
return GURL("https://" + host_port_pair.ToString());
}
void AutoSelectCertificates(
Profile* profile,
const GURL& requesting_url,
net::ClientCertIdentityList client_certs,
net::ClientCertIdentityList* matching_client_certs,
net::ClientCertIdentityList* nonmatching_client_certs) {
matching_client_certs->clear();
nonmatching_client_certs->clear();
const base::Value::List auto_selection_filters =
GetCertAutoSelectionFilters(profile, requesting_url);
for (auto& client_cert : client_certs) {
if (CertMatchesSelectionFilters(*client_cert, auto_selection_filters))
matching_client_certs->push_back(std::move(client_cert));
else
nonmatching_client_certs->push_back(std::move(client_cert));
}
}
bool IsMachinePolicyPref(const std::string& pref_name) {
const PrefService::Preference* pref =
g_browser_process->local_state()->FindPreference(pref_name);
return pref && pref->IsManaged();
}
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(prefs::kManagedAutoSelectCertificateForUrls);
}
void SetUserAcceptedAccountManagement(Profile* profile, bool accepted) {
// Some tests do not have a profile manager.
if (!g_browser_process->profile_manager())
return;
ProfileManager* profile_manager = g_browser_process->profile_manager();
ProfileAttributesEntry* entry =
profile_manager->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
if (entry)
entry->SetUserAcceptedAccountManagement(accepted);
}
bool UserAcceptedAccountManagement(Profile* profile) {
// Some tests do not have a profile manager.
if (!g_browser_process->profile_manager())
return false;
ProfileAttributesEntry* entry =
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
return entry && entry->UserAcceptedAccountManagement();
}
bool ProfileCanBeManaged(Profile* profile) {
// Some tests do not have a profile manager.
if (!g_browser_process->profile_manager())
return false;
ProfileAttributesEntry* entry =
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
return entry && entry->CanBeManaged();
}
ManagementEnvironment GetManagementEnvironment(
Profile* profile,
const AccountInfo& account_info) {
if (!UserAcceptedAccountManagement(profile)) {
return ManagementEnvironment::kNone;
}
// TODO (b/322796016): Add check for school using account_info
return ManagementEnvironment::kWork;
}
bool IsKnownConsumerDomain(const std::string& email_domain) {
// List of consumer-only domains from the server side logic. See
// `KNOWN_INVALID_DOMAINS` from GetAgencySignupStateProducerModule.java.
// Sharing this in open source Chromium code was green-lighted according to
// https://chromium-review.googlesource.com/c/chromium/src/+/2945029/comment/d8731200_4064534e/
static constexpr auto kKnownConsumerDomains =
base::MakeFixedFlatSet<base::StringPiece>({"123mail.org",
"150mail.com",
"150ml.com",
"16mail.com",
"2-mail.com",
"2trom.com",
"4email.net",
"50mail.com",
"aapt.net.au",
"accountant.com",
"acdcfan.com",
"activist.com",
"adam.com.au",
"adexec.com",
"africamail.com",
"aircraftmail.com",
"airpost.net",
"allergist.com",
"allmail.net",
"alumni.com",
"alumnidirector.com",
"angelic.com",
"anonymous.to",
"aol.com",
"appraiser.net",
"archaeologist.com",
"arcticmail.com",
"artlover.com",
"asia-mail.com",
"asia.com",
"atheist.com",
"auctioneer.net",
"australiamail.com",
"bartender.net",
"bellair.net",
"berlin.com",
"bestmail.us",
"bigpond.com",
"bigpond.com.au",
"bigpond.net.au",
"bikerider.com",
"birdlover.com",
"blader.com",
"boardermail.com",
"brazilmail.com",
"brew-master.com", // nocheck
"brew-meister.com",
"bsdmail.com",
"californiamail.com",
"cash4u.com",
"catlover.com",
"cheerful.com",
"chef.net",
"chemist.com",
"chinamail.com",
"clerk.com",
"clubmember.org",
"cluemail.com",
"collector.org",
"columnist.com",
"comcast.net",
"comic.com",
"computer4u.com",
"consultant.com",
"contractor.net",
"coolsite.net",
"counsellor.com",
"cutey.com",
"cyber-wizard.com",
"cyberdude.com",
"cybergal.com",
"cyberservices.com",
"dallasmail.com",
"dbzmail.com",
"deliveryman.com",
"diplomats.com",
"disciples.com",
"discofan.com",
"disposable.com",
"dispostable.com",
"dodo.com.au",
"doglover.com",
"doramail.com",
"dr.com",
"dublin.com",
"dutchmail.com",
"earthlink.net",
"elitemail.org",
"elvisfan.com",
"email.com",
"emailcorner.net",
"emailengine.net",
"emailengine.org",
"emailgroups.net",
"emailplus.org",
"emailuser.net",
"eml.cc",
"engineer.com",
"englandmail.com",
"europe.com",
"europemail.com",
"everymail.net",
"everyone.net",
"execs.com",
"exemail.com.au",
"f-m.fm",
"facebook.com",
"fast-email.com",
"fast-mail.org",
"fastem.com",
"fastemail.us",
"fastemailer.com",
"fastest.cc",
"fastimap.com",
"fastmail.cn",
"fastmail.co.uk",
"fastmail.com.au",
"fastmail.es",
"fastmail.fm",
"fastmail.im",
"fastmail.in",
"fastmail.jp",
"fastmail.mx",
"fastmail.net",
"fastmail.nl",
"fastmail.se",
"fastmail.to",
"fastmail.tw",
"fastmail.us",
"fastmailbox.net",
"fastmessaging.com",
"fastservice.com",
"fea.st",
"financier.com",
"fireman.net",
"flashmail.com",
"fmail.co.uk",
"fmailbox.com",
"fmgirl.com",
"fmguy.com",
"ftml.net",
"galaxyhit.com",
"gardener.com",
"geologist.com",
"germanymail.com",
"gmail.com",
"gmx.com",
"googlemail.com",
"graduate.org",
"graphic-designer.com",
"greenmail.net",
"groupmail.com",
"guerillamail.com",
"h-mail.us",
"hackermail.com",
"hailmail.net",
"hairdresser.net",
"hilarious.com",
"hiphopfan.com",
"homemail.com",
"hot-shot.com",
"hotmail.co.uk",
"hotmail.com",
"hotmail.fr",
"hotmail.it",
"housemail.com",
"humanoid.net",
"hushmail.com",
"icloud.com",
"iinet.net.au",
"imap-mail.com",
"imap.cc",
"imapmail.org",
"iname.com",
"inbox.com",
"innocent.com",
"inorbit.com",
"inoutbox.com",
"instruction.com",
"instructor.net",
"insurer.com",
"internet-e-mail.com",
"internet-mail.org",
"internetemails.net",
"internetmailing.net",
"internode.on.net",
"iprimus.com.au",
"irelandmail.com",
"israelmail.com",
"italymail.com",
"jetemail.net",
"job4u.com",
"journalist.com",
"justemail.net",
"keromail.com",
"kissfans.com",
"kittymail.com",
"koreamail.com",
"lawyer.com",
"legislator.com",
"letterboxes.org",
"linuxmail.org",
"live.co.uk",
"live.com",
"live.com.au",
"lobbyist.com",
"lovecat.com",
"lycos.com",
"mac.com",
"madonnafan.com",
"mail-central.com",
"mail-me.com",
"mail-page.com",
"mail.com",
"mail.ru",
"mailandftp.com",
"mailas.com",
"mailbolt.com",
"mailc.net",
"mailcan.com",
"mailforce.net",
"mailftp.com",
"mailhaven.com",
"mailinator.com",
"mailingaddress.org",
"mailite.com",
"mailmight.com",
"mailnew.com",
"mailsent.net",
"mailservice.ms",
"mailup.net",
"mailworks.org",
"marchmail.com",
"me.com",
"metalfan.com",
"mexicomail.com",
"minister.com",
"ml1.net",
"mm.st",
"moscowmail.com",
"msn.com",
"munich.com",
"musician.org",
"muslim.com",
"myfastmail.com",
"mymacmail.com",
"myself.com",
"net-shopping.com",
"netspace.net.au",
"ninfan.com",
"nonpartisan.com",
"nospammail.net",
"null.net",
"nycmail.com",
"oath.com",
"onebox.com",
"operamail.com",
"optician.com",
"optusnet.com.au",
"orthodontist.net",
"outlook.com",
"ownmail.net",
"pacific-ocean.com",
"pacificwest.com",
"pediatrician.com",
"petlover.com",
"petml.com",
"photographer.net",
"physicist.net",
"planetmail.com",
"planetmail.net",
"polandmail.com",
"politician.com",
"post.com",
"postinbox.com",
"postpro.net",
"presidency.com",
"priest.com",
"programmer.net",
"proinbox.com",
"promessage.com",
"protestant.com",
"publicist.com",
"qmail.com",
"qq.com",
"qualityservice.com",
"radiologist.net",
"ravemail.com",
"realemail.net",
"reallyfast.biz",
"reallyfast.info",
"realtyagent.com",
"reborn.com",
"rediff.com",
"reggaefan.com",
"registerednurses.com",
"reincarnate.com",
"religious.com",
"repairman.com",
"representative.com",
"rescueteam.com",
"rocketmail.com",
"rocketship.com",
"runbox.com",
"rushpost.com",
"safrica.com",
"saintly.com",
"salesperson.net",
"samerica.com",
"sanfranmail.com",
"scientist.com",
"scotlandmail.com",
"secretary.net",
"sent.as",
"sent.at",
"sent.com",
"seznam.cz",
"snakebite.com",
"socialworker.net",
"sociologist.com",
"solution4u.com",
"songwriter.net",
"spainmail.com",
"spamgourmet.com",
"speedpost.net",
"speedymail.org",
"ssl-mail.com",
"surgical.net",
"swedenmail.com",
"swift-mail.com",
"swissmail.com",
"teachers.org",
"tech-center.com",
"techie.com",
"technologist.com",
"telstra.com",
"telstra.com.au",
"the-fastest.net",
"the-quickest.com",
"theinternetemail.com",
"theplate.com",
"therapist.net",
"toke.com",
"toothfairy.com",
"torontomail.com",
"tpg.com.au",
"trashmail.net",
"tvstar.com",
"umpire.com",
"usa.com",
"uymail.com",
"veryfast.biz",
"veryspeedy.net",
"virginbroadband.com.au",
"warpmail.net",
"webname.com",
"westnet.com.au",
"windowslive.com",
"worker.com",
"workmail.com",
"writeme.com",
"xsmail.com",
"xtra.co.nz",
"y7mail.com",
"yahoo.ae",
"yahoo.at",
"yahoo.be",
"yahoo.ca",
"yahoo.ch",
"yahoo.cn",
"yahoo.co.id",
"yahoo.co.il",
"yahoo.co.in",
"yahoo.co.jp",
"yahoo.co.kr",
"yahoo.co.nz",
"yahoo.co.th",
"yahoo.co.uk",
"yahoo.co.za",
"yahoo.com",
"yahoo.com.ar",
"yahoo.com.au",
"yahoo.com.br",
"yahoo.com.cn",
"yahoo.com.co",
"yahoo.com.hk",
"yahoo.com.mx",
"yahoo.com.my",
"yahoo.com.ph",
"yahoo.com.sg",
"yahoo.com.tr",
"yahoo.com.tw",
"yahoo.com.vn",
"yahoo.cz",
"yahoo.de",
"yahoo.dk",
"yahoo.es",
"yahoo.fi",
"yahoo.fr",
"yahoo.gr",
"yahoo.hu",
"yahoo.ie",
"yahoo.in",
"yahoo.it",
"yahoo.nl",
"yahoo.no",
"yahoo.pl",
"yahoo.pt",
"yahoo.ro",
"yahoo.ru",
"yahoo.se",
"yandex.ru",
"yepmail.net",
"ymail.com",
"your-mail.com",
"zoho.com"});
return kKnownConsumerDomains.contains(email_domain);
}
#if BUILDFLAG(IS_ANDROID)
std::string GetBrowserManagerName(Profile* profile) {
DCHECK(profile);
// @TODO(https://crbug.com/1227786): There are some use-cases where the
// expected behavior of chrome://management is to show more than one domain.
std::optional<std::string> manager = GetAccountManagerIdentity(profile);
if (!manager &&
base::FeatureList::IsEnabled(features::kFlexOrgManagementDisclosure)) {
manager = GetDeviceManagerIdentity();
}
return manager.value_or(std::string());
}
// static
jboolean JNI_ManagedBrowserUtils_IsBrowserManaged(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& profile) {
return IsBrowserManaged(ProfileAndroid::FromProfileAndroid(profile));
}
// static
base::android::ScopedJavaLocalRef<jstring>
JNI_ManagedBrowserUtils_GetBrowserManagerName(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& profile) {
return base::android::ConvertUTF8ToJavaString(
env, GetBrowserManagerName(ProfileAndroid::FromProfileAndroid(profile)));
}
// static
jboolean JNI_ManagedBrowserUtils_IsReportingEnabled(JNIEnv* env) {
return g_browser_process->local_state()->GetBoolean(
enterprise_reporting::kCloudReportingEnabled);
}
#endif // BUILDFLAG(IS_ANDROID)
} // namespace enterprise_util
} // namespace chrome