blob: fdec67da8e8b0054a109cd256ad6ed5d23b6341a [file] [log] [blame]
// Copyright 2017 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/cryptauth/chrome_cryptauth_service.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/sys_info.h"
#include "base/time/default_clock.h"
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/pref_names.h"
#include "components/cryptauth/cryptauth_client.h"
#include "components/cryptauth/cryptauth_client_impl.h"
#include "components/cryptauth/cryptauth_device_manager.h"
#include "components/cryptauth/cryptauth_enroller.h"
#include "components/cryptauth/cryptauth_enroller_impl.h"
#include "components/cryptauth/cryptauth_enrollment_utils.h"
#include "components/cryptauth/cryptauth_gcm_manager_impl.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/secure_message_delegate.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/prefs/pref_service.h"
#include "components/proximity_auth/logging/logging.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/translate/core/browser/translate_download_manager.h"
#include "components/version_info/version_info.h"
#if defined(OS_CHROMEOS)
#include "ash/shell.h"
#include "base/linux_util.h"
#include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/gfx/geometry/rect.h"
#endif
namespace {
std::string GetDeviceId() {
PrefService* local_state =
g_browser_process ? g_browser_process->local_state() : nullptr;
if (!local_state)
return std::string();
std::string device_id = local_state->GetString(prefs::kEasyUnlockDeviceId);
if (device_id.empty()) {
device_id = base::GenerateGUID();
local_state->SetString(prefs::kEasyUnlockDeviceId, device_id);
}
return device_id;
}
cryptauth::DeviceClassifier GetDeviceClassifierImpl() {
cryptauth::DeviceClassifier device_classifier;
#if defined(OS_CHROMEOS)
int32_t major_version;
int32_t minor_version;
int32_t bugfix_version;
// TODO(tengs): base::OperatingSystemVersionNumbers only works for ChromeOS.
// We need to get different numbers for other platforms.
base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
&bugfix_version);
device_classifier.set_device_os_version_code(major_version);
device_classifier.set_device_type(cryptauth::CHROME);
#endif
const std::vector<uint32_t> version_components =
base::Version(version_info::GetVersionNumber()).components();
if (!version_components.empty())
device_classifier.set_device_software_version_code(version_components[0]);
device_classifier.set_device_software_package(version_info::GetProductName());
return device_classifier;
}
cryptauth::GcmDeviceInfo GetGcmDeviceInfo() {
cryptauth::GcmDeviceInfo device_info;
device_info.set_long_device_id(GetDeviceId());
device_info.set_device_type(cryptauth::CHROME);
device_info.set_device_software_version(version_info::GetVersionNumber());
google::protobuf::int64 software_version_code =
cryptauth::HashStringToInt64(version_info::GetLastChange());
device_info.set_device_software_version_code(software_version_code);
ChromeContentBrowserClient chrome_content_browser_client;
device_info.set_locale(chrome_content_browser_client.GetApplicationLocale());
#if defined(OS_CHROMEOS)
device_info.set_device_model(base::SysInfo::GetLsbReleaseBoard());
device_info.set_device_os_version(base::GetLinuxDistro());
// The Chrome OS version tracks the Chrome version, so fill in the same value
// as |device_software_version_code|.
device_info.set_device_os_version_code(software_version_code);
// There may not be a Shell instance in tests.
if (!ash::Shell::HasInstance())
return device_info;
display::DisplayManager* display_manager =
ash::Shell::Get()->display_manager();
int64_t primary_display_id =
display_manager->GetPrimaryDisplayCandidate().id();
display::ManagedDisplayInfo display_info =
display_manager->GetDisplayInfo(primary_display_id);
gfx::Rect bounds = display_info.bounds_in_native();
// TODO(tengs): This is a heuristic to deterimine the DPI of the display, as
// there is no convenient way of getting this information right now.
const double dpi = display_info.device_scale_factor() > 1.0f ? 239.0f : 96.0f;
double width_in_inches = (bounds.width() - bounds.x()) / dpi;
double height_in_inches = (bounds.height() - bounds.y()) / dpi;
double diagonal_in_inches = sqrt(width_in_inches * width_in_inches +
height_in_inches * height_in_inches);
// Note: The unit of this measument is in milli-inches.
device_info.set_device_display_diagonal_mils(diagonal_in_inches * 1000.0);
#else
// TODO(tengs): Fill in device information for other platforms.
#endif
return device_info;
}
std::unique_ptr<cryptauth::CryptAuthClientFactory>
CreateCryptAuthClientFactoryImpl(Profile* profile) {
return base::MakeUnique<cryptauth::CryptAuthClientFactoryImpl>(
ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId(),
profile->GetRequestContext(), GetDeviceClassifierImpl());
}
std::unique_ptr<cryptauth::SecureMessageDelegate>
CreateSecureMessageDelegateImpl() {
#if defined(OS_CHROMEOS)
return base::MakeUnique<chromeos::SecureMessageDelegateChromeOS>();
#else
return nullptr;
#endif
}
class CryptAuthEnrollerFactoryImpl
: public cryptauth::CryptAuthEnrollerFactory {
public:
explicit CryptAuthEnrollerFactoryImpl(Profile* profile) : profile_(profile) {}
std::unique_ptr<cryptauth::CryptAuthEnroller> CreateInstance() override {
return base::MakeUnique<cryptauth::CryptAuthEnrollerImpl>(
CreateCryptAuthClientFactoryImpl(profile_),
CreateSecureMessageDelegateImpl());
}
private:
Profile* profile_;
};
} // namespace
// static
std::unique_ptr<ChromeCryptAuthService> ChromeCryptAuthService::Create(
Profile* profile) {
std::unique_ptr<cryptauth::CryptAuthGCMManager> gcm_manager =
base::MakeUnique<cryptauth::CryptAuthGCMManagerImpl>(
gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(),
profile->GetPrefs());
std::unique_ptr<cryptauth::CryptAuthDeviceManager> device_manager =
base::MakeUnique<cryptauth::CryptAuthDeviceManager>(
base::DefaultClock::GetInstance(),
CreateCryptAuthClientFactoryImpl(profile), gcm_manager.get(),
profile->GetPrefs());
std::unique_ptr<cryptauth::CryptAuthEnrollmentManager> enrollment_manager =
base::MakeUnique<cryptauth::CryptAuthEnrollmentManager>(
base::DefaultClock::GetInstance(),
base::MakeUnique<CryptAuthEnrollerFactoryImpl>(profile),
CreateSecureMessageDelegateImpl(), GetGcmDeviceInfo(),
gcm_manager.get(), profile->GetPrefs());
// Note: ChromeCryptAuthServiceFactory DependsOn(OAuth2TokenServiceFactory),
// so |token_service| is guaranteed to outlast this service.
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
// Note: ChromeCryptAuthServiceFactory DependsOn(OAuth2TokenServiceFactory),
// so |token_service| is guaranteed to outlast this service.
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile);
return base::WrapUnique(new ChromeCryptAuthService(
std::move(gcm_manager), std::move(device_manager),
std::move(enrollment_manager), profile, token_service, signin_manager));
}
ChromeCryptAuthService::ChromeCryptAuthService(
std::unique_ptr<cryptauth::CryptAuthGCMManager> gcm_manager,
std::unique_ptr<cryptauth::CryptAuthDeviceManager> device_manager,
std::unique_ptr<cryptauth::CryptAuthEnrollmentManager> enrollment_manager,
Profile* profile,
OAuth2TokenService* token_service,
SigninManagerBase* signin_manager)
: KeyedService(),
cryptauth::CryptAuthService(),
gcm_manager_(std::move(gcm_manager)),
enrollment_manager_(std::move(enrollment_manager)),
device_manager_(std::move(device_manager)),
profile_(profile),
token_service_(token_service),
signin_manager_(signin_manager),
weak_ptr_factory_(this) {
gcm_manager_->StartListening();
registrar_.Init(profile_->GetPrefs());
registrar_.Add(prefs::kEasyUnlockAllowed,
base::Bind(&ChromeCryptAuthService::OnPrefsChanged,
weak_ptr_factory_.GetWeakPtr()));
#if defined(OS_CHROMEOS)
registrar_.Add(prefs::kInstantTetheringAllowed,
base::Bind(&ChromeCryptAuthService::OnPrefsChanged,
weak_ptr_factory_.GetWeakPtr()));
#endif // defined(OS_CHROMEOS)
if (!signin_manager_->IsAuthenticated()) {
PA_LOG(INFO) << "Profile is not authenticated yet; "
<< "waiting before starting CryptAuth managers.";
signin_manager_->AddObserver(this);
return;
}
std::string account_id = signin_manager_->GetAuthenticatedAccountId();
if (!token_service_->RefreshTokenIsAvailable(account_id)) {
PA_LOG(INFO) << "Refresh token not yet available; "
<< "waiting before starting CryptAuth managers.";
token_service_->AddObserver(this);
return;
}
// Profile is authenticated and there is a refresh token available for the
// authenticated account id.
PerformEnrollmentAndDeviceSyncIfPossible();
}
ChromeCryptAuthService::~ChromeCryptAuthService() {}
void ChromeCryptAuthService::Shutdown() {
signin_manager_->RemoveObserver(this);
token_service_->RemoveObserver(this);
enrollment_manager_.reset();
device_manager_.reset();
gcm_manager_.reset();
}
cryptauth::CryptAuthDeviceManager*
ChromeCryptAuthService::GetCryptAuthDeviceManager() {
return device_manager_.get();
}
cryptauth::CryptAuthEnrollmentManager*
ChromeCryptAuthService::GetCryptAuthEnrollmentManager() {
return enrollment_manager_.get();
}
cryptauth::DeviceClassifier ChromeCryptAuthService::GetDeviceClassifier() {
return GetDeviceClassifierImpl();
}
std::string ChromeCryptAuthService::GetAccountId() {
return signin_manager_->GetAuthenticatedAccountId();
}
std::unique_ptr<cryptauth::SecureMessageDelegate>
ChromeCryptAuthService::CreateSecureMessageDelegate() {
return CreateSecureMessageDelegateImpl();
}
std::unique_ptr<cryptauth::CryptAuthClientFactory>
ChromeCryptAuthService::CreateCryptAuthClientFactory() {
return CreateCryptAuthClientFactoryImpl(profile_);
}
void ChromeCryptAuthService::OnEnrollmentStarted() {}
void ChromeCryptAuthService::OnEnrollmentFinished(bool success) {
if (success)
device_manager_->Start();
else
PA_LOG(ERROR) << "CryptAuth enrollment failed. Device manager was not "
<< " started.";
enrollment_manager_->RemoveObserver(this);
}
void ChromeCryptAuthService::GoogleSigninSucceeded(
const std::string& account_id,
const std::string& username) {
signin_manager_->RemoveObserver(this);
if (!token_service_->RefreshTokenIsAvailable(account_id)) {
PA_LOG(INFO) << "Refresh token not yet available; "
<< "waiting before starting CryptAuth managers.";
token_service_->AddObserver(this);
return;
}
PerformEnrollmentAndDeviceSyncIfPossible();
}
void ChromeCryptAuthService::OnRefreshTokenAvailable(
const std::string& account_id) {
if (account_id == GetAccountId()) {
token_service_->RemoveObserver(this);
PerformEnrollmentAndDeviceSyncIfPossible();
}
}
void ChromeCryptAuthService::PerformEnrollmentAndDeviceSyncIfPossible() {
DCHECK(signin_manager_->IsAuthenticated());
DCHECK(token_service_->RefreshTokenIsAvailable(GetAccountId()));
if (!IsEnrollmentAllowedByPolicy()) {
PA_LOG(INFO) << "CryptAuth enrollment is disabled by enterprise policy.";
return;
}
if (enrollment_manager_->IsEnrollmentValid()) {
device_manager_->Start();
} else {
// If enrollment is not valid, wait for the new enrollment attempt to finish
// before starting CryptAuthDeviceManager. See OnEnrollmentFinished(),
enrollment_manager_->AddObserver(this);
}
// Even if enrollment was valid, CryptAuthEnrollmentManager must be started in
// order to schedule the next enrollment attempt.
enrollment_manager_->Start();
}
bool ChromeCryptAuthService::IsEnrollmentAllowedByPolicy() {
// We allow CryptAuth enrollments if at least one of the features which
// depends on CryptAuth is enabled by enterprise policy.
PrefService* pref_service = profile_->GetPrefs();
bool is_allowed = pref_service->GetBoolean(prefs::kEasyUnlockAllowed);
#if defined(OS_CHROMEOS)
is_allowed |= pref_service->GetBoolean(prefs::kInstantTetheringAllowed);
#endif // defined(OS_CHROMEOS)
return is_allowed;
}
void ChromeCryptAuthService::OnPrefsChanged() {
// Note: We only start the CryptAuth services if a feature was toggled on. In
// the inverse case, we simply leave the services running until the user logs
// off.
PerformEnrollmentAndDeviceSyncIfPossible();
}