blob: a1f9589ddac2cebfbae5dd2dc7f77fb92fb0b27f [file] [log] [blame]
// Copyright 2014 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 "components/user_manager/user.h"
#include <stddef.h>
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user_manager.h"
#include "google_apis/gaia/gaia_auth_util.h"
namespace user_manager {
namespace {
// Must be in sync with histogram enum UserTypeChanged in enums.xml.
// The values must never be changed (only new ones can be added) as they
// are stored in UMA logs.
enum class UserTypeChangeHistogram {
UNKNOWN_FATAL = 0,
REGULAR_TO_CHILD = 1,
CHILD_TO_REGULAR = 2,
COUNT, // Not a value, just a count of other values.
};
void UMAUserTypeChanged(const UserTypeChangeHistogram value) {
UMA_HISTOGRAM_ENUMERATION("UserManager.UserTypeChanged", value,
UserTypeChangeHistogram::COUNT);
}
// Returns account name portion of an email.
std::string GetUserName(const std::string& email) {
std::string::size_type i = email.find('@');
if (i == 0 || i == std::string::npos) {
return email;
}
return email.substr(0, i);
}
} // namespace
// static
bool User::TypeHasGaiaAccount(UserType user_type) {
return user_type == USER_TYPE_REGULAR ||
user_type == USER_TYPE_CHILD;
}
// Also used for regular supervised users.
class RegularUser : public User {
public:
RegularUser(const AccountId& account_id, const UserType user_type);
~RegularUser() override;
// Overridden from User:
UserType GetType() const override;
void UpdateType(UserType user_type) override;
bool CanSyncImage() const override;
private:
bool is_child_;
DISALLOW_COPY_AND_ASSIGN(RegularUser);
};
class ActiveDirectoryUser : public RegularUser {
public:
explicit ActiveDirectoryUser(const AccountId& account_id);
~ActiveDirectoryUser() override;
// Overridden from User:
UserType GetType() const override;
bool CanSyncImage() const override;
};
class GuestUser : public User {
public:
explicit GuestUser(const AccountId& guest_account_id);
~GuestUser() override;
// Overridden from User:
UserType GetType() const override;
private:
DISALLOW_COPY_AND_ASSIGN(GuestUser);
};
class DeviceLocalAccountUserBase : public User {
public:
// User:
bool IsAffiliated() const override;
protected:
explicit DeviceLocalAccountUserBase(const AccountId& account_id);
~DeviceLocalAccountUserBase() override;
// User:
void SetAffiliation(bool) override;
bool IsDeviceLocalAccount() const override;
private:
DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountUserBase);
};
class KioskAppUser : public DeviceLocalAccountUserBase {
public:
explicit KioskAppUser(const AccountId& kiosk_app_account_id);
~KioskAppUser() override;
// Overridden from User:
UserType GetType() const override;
private:
DISALLOW_COPY_AND_ASSIGN(KioskAppUser);
};
class ArcKioskAppUser : public DeviceLocalAccountUserBase {
public:
explicit ArcKioskAppUser(const AccountId& arc_kiosk_account_id);
~ArcKioskAppUser() override;
// Overridden from User:
UserType GetType() const override;
private:
DISALLOW_COPY_AND_ASSIGN(ArcKioskAppUser);
};
class SupervisedUser : public User {
public:
explicit SupervisedUser(const AccountId& account_id);
~SupervisedUser() override;
// Overridden from User:
UserType GetType() const override;
std::string display_email() const override;
private:
DISALLOW_COPY_AND_ASSIGN(SupervisedUser);
};
class PublicAccountUser : public DeviceLocalAccountUserBase {
public:
explicit PublicAccountUser(const AccountId& account_id);
~PublicAccountUser() override;
// Overridden from User:
UserType GetType() const override;
private:
DISALLOW_COPY_AND_ASSIGN(PublicAccountUser);
};
User::User(const AccountId& account_id)
: account_id_(account_id), user_image_(new UserImage) {}
User::~User() {}
std::string User::GetDisplayEmail() const {
return display_email();
}
base::string16 User::GetDisplayName() const {
// Fallback to the email account name in case display name haven't been set.
return display_name_.empty() ? base::UTF8ToUTF16(GetAccountName(true))
: display_name_;
}
base::string16 User::GetGivenName() const {
return given_name_;
}
const gfx::ImageSkia& User::GetImage() const {
return user_image_->image();
}
const AccountId& User::GetAccountId() const {
return account_id_;
}
void User::UpdateType(UserType user_type) {
UMAUserTypeChanged(UserTypeChangeHistogram::UNKNOWN_FATAL);
LOG(FATAL) << "Unsupported user type change " << GetType() << "=>"
<< user_type;
}
bool User::HasGaiaAccount() const {
return TypeHasGaiaAccount(GetType());
}
bool User::IsActiveDirectoryUser() const {
return GetType() == user_manager::USER_TYPE_ACTIVE_DIRECTORY;
}
bool User::IsSupervised() const {
UserType type = GetType();
return type == USER_TYPE_SUPERVISED ||
type == USER_TYPE_CHILD;
}
bool User::IsChild() const {
return GetType() == USER_TYPE_CHILD;
}
std::string User::GetAccountName(bool use_display_email) const {
if (use_display_email && !display_email_.empty())
return GetUserName(display_email_);
else
return GetUserName(account_id_.GetUserEmail());
}
bool User::HasDefaultImage() const {
return UserManager::Get()->IsValidDefaultUserImageId(image_index_);
}
bool User::CanSyncImage() const {
return false;
}
std::string User::display_email() const {
return display_email_;
}
bool User::can_lock() const {
return can_lock_;
}
std::string User::username_hash() const {
return username_hash_;
}
bool User::is_logged_in() const {
return is_logged_in_;
}
bool User::is_active() const {
return is_active_;
}
bool User::has_gaia_account() const {
static_assert(user_manager::NUM_USER_TYPES == 9,
"NUM_USER_TYPES should equal 9");
switch (GetType()) {
case user_manager::USER_TYPE_REGULAR:
case user_manager::USER_TYPE_CHILD:
return true;
case user_manager::USER_TYPE_GUEST:
case user_manager::USER_TYPE_PUBLIC_ACCOUNT:
case user_manager::USER_TYPE_SUPERVISED:
case user_manager::USER_TYPE_KIOSK_APP:
case user_manager::USER_TYPE_ARC_KIOSK_APP:
case user_manager::USER_TYPE_ACTIVE_DIRECTORY:
return false;
default:
NOTREACHED();
}
return false;
}
void User::AddProfileCreatedObserver(base::OnceClosure on_profile_created) {
DCHECK(!profile_is_created_);
on_profile_created_observers_.push_back(std::move(on_profile_created));
}
bool User::IsAffiliated() const {
return is_affiliated_;
}
void User::SetProfileIsCreated() {
profile_is_created_ = true;
for (auto& callback : on_profile_created_observers_)
std::move(callback).Run();
on_profile_created_observers_.clear();
}
void User::SetAffiliation(bool is_affiliated) {
is_affiliated_ = is_affiliated;
}
bool User::IsDeviceLocalAccount() const {
return false;
}
User* User::CreateRegularUser(const AccountId& account_id,
const UserType user_type) {
if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
return new ActiveDirectoryUser(account_id);
return new RegularUser(account_id, user_type);
}
User* User::CreateGuestUser(const AccountId& guest_account_id) {
return new GuestUser(guest_account_id);
}
User* User::CreateKioskAppUser(const AccountId& kiosk_app_account_id) {
return new KioskAppUser(kiosk_app_account_id);
}
User* User::CreateArcKioskAppUser(const AccountId& arc_kiosk_account_id) {
return new ArcKioskAppUser(arc_kiosk_account_id);
}
User* User::CreateSupervisedUser(const AccountId& account_id) {
return new SupervisedUser(account_id);
}
User* User::CreatePublicAccountUser(const AccountId& account_id) {
return new PublicAccountUser(account_id);
}
void User::SetAccountLocale(const std::string& resolved_account_locale) {
account_locale_.reset(new std::string(resolved_account_locale));
}
void User::SetImage(std::unique_ptr<UserImage> user_image, int image_index) {
user_image_ = std::move(user_image);
image_index_ = image_index;
image_is_stub_ = false;
image_is_loading_ = false;
DCHECK(HasDefaultImage() || user_image_->has_image_bytes());
}
void User::SetImageURL(const GURL& image_url) {
user_image_->set_url(image_url);
}
void User::SetStubImage(std::unique_ptr<UserImage> stub_user_image,
int image_index,
bool is_loading) {
user_image_ = std::move(stub_user_image);
image_index_ = image_index;
image_is_stub_ = true;
image_is_loading_ = is_loading;
}
UserType ActiveDirectoryUser::GetType() const {
return user_manager::USER_TYPE_ACTIVE_DIRECTORY;
}
bool ActiveDirectoryUser::CanSyncImage() const {
return false;
}
RegularUser::RegularUser(const AccountId& account_id, const UserType user_type)
: User(account_id), is_child_(user_type == USER_TYPE_CHILD) {
if (user_type != USER_TYPE_CHILD && user_type != USER_TYPE_REGULAR &&
user_type != USER_TYPE_ACTIVE_DIRECTORY) {
LOG(FATAL) << "Invalid user type " << user_type;
}
set_can_lock(true);
set_display_email(account_id.GetUserEmail());
}
ActiveDirectoryUser::ActiveDirectoryUser(const AccountId& account_id)
: RegularUser(account_id, user_manager::USER_TYPE_ACTIVE_DIRECTORY) {}
RegularUser::~RegularUser() {
}
ActiveDirectoryUser::~ActiveDirectoryUser() {}
UserType RegularUser::GetType() const {
return is_child_ ? user_manager::USER_TYPE_CHILD :
user_manager::USER_TYPE_REGULAR;
}
void RegularUser::UpdateType(UserType user_type) {
const UserType current_type = GetType();
// Can only change between regular and child.
if ((user_type == user_manager::USER_TYPE_CHILD ||
user_type == user_manager::USER_TYPE_REGULAR) &&
(current_type == user_manager::USER_TYPE_CHILD ||
current_type == user_manager::USER_TYPE_REGULAR)) {
// We want all the other type changes to crash, that is why this check is
// not at the top level.
if (user_type == current_type)
return;
const bool old_is_child = is_child_;
is_child_ = user_type == user_manager::USER_TYPE_CHILD;
LOG(WARNING) << "User type has changed: " << current_type
<< " (is_child=" << old_is_child << ") => " << user_type
<< " (is_child=" << is_child_ << ")";
UMAUserTypeChanged(is_child_ ? UserTypeChangeHistogram::REGULAR_TO_CHILD
: UserTypeChangeHistogram::CHILD_TO_REGULAR);
return;
}
// Fail with LOG(FATAL).
User::UpdateType(user_type);
}
bool RegularUser::CanSyncImage() const {
return true;
}
GuestUser::GuestUser(const AccountId& guest_account_id)
: User(guest_account_id) {
set_display_email(std::string());
}
GuestUser::~GuestUser() {
}
UserType GuestUser::GetType() const {
return user_manager::USER_TYPE_GUEST;
}
DeviceLocalAccountUserBase::DeviceLocalAccountUserBase(
const AccountId& account_id) : User(account_id) {
}
DeviceLocalAccountUserBase::~DeviceLocalAccountUserBase() {
}
bool DeviceLocalAccountUserBase::IsAffiliated() const {
return true;
}
void DeviceLocalAccountUserBase::SetAffiliation(bool) {
// Device local accounts are always affiliated. No affiliation modification
// must happen.
NOTREACHED();
}
bool DeviceLocalAccountUserBase::IsDeviceLocalAccount() const {
return true;
}
KioskAppUser::KioskAppUser(const AccountId& kiosk_app_account_id)
: DeviceLocalAccountUserBase(kiosk_app_account_id) {
set_display_email(kiosk_app_account_id.GetUserEmail());
}
KioskAppUser::~KioskAppUser() {
}
UserType KioskAppUser::GetType() const {
return user_manager::USER_TYPE_KIOSK_APP;
}
ArcKioskAppUser::ArcKioskAppUser(const AccountId& arc_kiosk_account_id)
: DeviceLocalAccountUserBase(arc_kiosk_account_id) {
set_display_email(arc_kiosk_account_id.GetUserEmail());
}
ArcKioskAppUser::~ArcKioskAppUser() {
}
UserType ArcKioskAppUser::GetType() const {
return user_manager::USER_TYPE_ARC_KIOSK_APP;
}
SupervisedUser::SupervisedUser(const AccountId& account_id) : User(account_id) {
set_can_lock(true);
}
SupervisedUser::~SupervisedUser() {
}
UserType SupervisedUser::GetType() const {
return user_manager::USER_TYPE_SUPERVISED;
}
std::string SupervisedUser::display_email() const {
return base::UTF16ToUTF8(display_name());
}
PublicAccountUser::PublicAccountUser(const AccountId& account_id)
: DeviceLocalAccountUserBase(account_id) {}
PublicAccountUser::~PublicAccountUser() {
}
UserType PublicAccountUser::GetType() const {
return user_manager::USER_TYPE_PUBLIC_ACCOUNT;
}
} // namespace user_manager