Home | History | Annotate | Download | only in profiles
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/profiles/profile_helper.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/command_line.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     11 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/profiles/profile_manager.h"
     14 #include "chrome/browser/profiles/profiles_state.h"
     15 #include "chrome/common/chrome_constants.h"
     16 #include "chrome/common/chrome_switches.h"
     17 #include "chromeos/chromeos_switches.h"
     18 #include "components/user_manager/user.h"
     19 #include "components/user_manager/user_manager.h"
     20 #include "content/public/browser/browser_thread.h"
     21 
     22 namespace chromeos {
     23 
     24 namespace {
     25 
     26 // As defined in /chromeos/dbus/cryptohome_client.cc.
     27 static const char kUserIdHashSuffix[] = "-hash";
     28 
     29 bool ShouldAddProfileDirPrefix(const std::string& user_id_hash) {
     30   // Do not add profile dir prefix for legacy profile dir and test
     31   // user profile. The reason of not adding prefix for test user profile
     32   // is to keep the promise that TestingProfile::kTestUserProfileDir and
     33   // chrome::kTestUserProfileDir are always in sync. Otherwise,
     34   // TestingProfile::kTestUserProfileDir needs to be dynamically calculated
     35   // based on whether multi profile is enabled or not.
     36   return user_id_hash != chrome::kLegacyProfileDir &&
     37       user_id_hash != chrome::kTestUserProfileDir;
     38 }
     39 
     40 class UsernameHashMatcher {
     41  public:
     42   explicit UsernameHashMatcher(const std::string& h) : username_hash(h) {}
     43   bool operator()(const user_manager::User* user) const {
     44     return user->username_hash() == username_hash;
     45   }
     46 
     47  private:
     48   const std::string& username_hash;
     49 };
     50 
     51 }  // anonymous namespace
     52 
     53 // static
     54 bool ProfileHelper::enable_profile_to_user_testing = false;
     55 bool ProfileHelper::always_return_primary_user_for_testing = false;
     56 
     57 ////////////////////////////////////////////////////////////////////////////////
     58 // ProfileHelper, public
     59 
     60 ProfileHelper::ProfileHelper()
     61     : signin_profile_clear_requested_(false) {
     62 }
     63 
     64 ProfileHelper::~ProfileHelper() {
     65   // Checking whether UserManager is initialized covers case
     66   // when ScopedTestUserManager is used.
     67   if (user_manager::UserManager::IsInitialized())
     68     user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
     69 }
     70 
     71 // static
     72 ProfileHelper* ProfileHelper::Get() {
     73   return g_browser_process->platform_part()->profile_helper();
     74 }
     75 
     76 // static
     77 Profile* ProfileHelper::GetProfileByUserIdHash(
     78     const std::string& user_id_hash) {
     79   ProfileManager* profile_manager = g_browser_process->profile_manager();
     80   return profile_manager->GetProfile(GetProfilePathByUserIdHash(user_id_hash));
     81 }
     82 
     83 // static
     84 base::FilePath ProfileHelper::GetProfilePathByUserIdHash(
     85     const std::string& user_id_hash) {
     86   // Fails for KioskTest.InstallAndLaunchApp test - crbug.com/238985
     87   // Will probably fail for Guest session / restart after a crash -
     88   // crbug.com/238998
     89   // TODO(nkostylev): Remove this check once these bugs are fixed.
     90   DCHECK(!user_id_hash.empty());
     91   ProfileManager* profile_manager = g_browser_process->profile_manager();
     92   base::FilePath profile_path = profile_manager->user_data_dir();
     93 
     94   return profile_path.Append(GetUserProfileDir(user_id_hash));
     95 }
     96 
     97 // static
     98 base::FilePath ProfileHelper::GetSigninProfileDir() {
     99   ProfileManager* profile_manager = g_browser_process->profile_manager();
    100   base::FilePath user_data_dir = profile_manager->user_data_dir();
    101   return user_data_dir.AppendASCII(chrome::kInitialProfile);
    102 }
    103 
    104 // static
    105 Profile* ProfileHelper::GetSigninProfile() {
    106   ProfileManager* profile_manager = g_browser_process->profile_manager();
    107   return profile_manager->GetProfile(GetSigninProfileDir())->
    108       GetOffTheRecordProfile();
    109 }
    110 
    111 // static
    112 std::string ProfileHelper::GetUserIdHashFromProfile(Profile* profile) {
    113   if (!profile)
    114     return std::string();
    115 
    116   std::string profile_dir = profile->GetPath().BaseName().value();
    117 
    118   // Don't strip prefix if the dir is not supposed to be prefixed.
    119   if (!ShouldAddProfileDirPrefix(profile_dir))
    120     return profile_dir;
    121 
    122   // Check that profile directory starts with the correct prefix.
    123   std::string prefix(chrome::kProfileDirPrefix);
    124   if (profile_dir.find(prefix) != 0) {
    125     // This happens when creating a TestingProfile in browser tests.
    126     return std::string();
    127   }
    128 
    129   return profile_dir.substr(prefix.length(),
    130                             profile_dir.length() - prefix.length());
    131 }
    132 
    133 // static
    134 base::FilePath ProfileHelper::GetUserProfileDir(
    135     const std::string& user_id_hash) {
    136   CHECK(!user_id_hash.empty());
    137   return ShouldAddProfileDirPrefix(user_id_hash)
    138              ? base::FilePath(chrome::kProfileDirPrefix + user_id_hash)
    139              : base::FilePath(user_id_hash);
    140 }
    141 
    142 // static
    143 bool ProfileHelper::IsSigninProfile(Profile* profile) {
    144   return profile->GetPath().BaseName().value() == chrome::kInitialProfile;
    145 }
    146 
    147 // static
    148 bool ProfileHelper::IsOwnerProfile(Profile* profile) {
    149   if (!profile)
    150     return false;
    151   user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
    152   if (!user)
    153     return false;
    154 
    155   return user->email() == user_manager::UserManager::Get()->GetOwnerEmail();
    156 }
    157 
    158 // static
    159 bool ProfileHelper::IsPrimaryProfile(Profile* profile) {
    160   if (!profile)
    161     return false;
    162   user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
    163   if (!user)
    164     return false;
    165   return user == user_manager::UserManager::Get()->GetPrimaryUser();
    166 }
    167 
    168 void ProfileHelper::ProfileStartup(Profile* profile, bool process_startup) {
    169   // Initialize Chrome OS preferences like touch pad sensitivity. For the
    170   // preferences to work in the guest mode, the initialization has to be
    171   // done after |profile| is switched to the incognito profile (which
    172   // is actually GuestSessionProfile in the guest mode). See the
    173   // GetOffTheRecordProfile() call above.
    174   profile->InitChromeOSPreferences();
    175 
    176   // Add observer so we can see when the first profile's session restore is
    177   // completed. After that, we won't need the default profile anymore.
    178   if (!IsSigninProfile(profile) &&
    179       user_manager::UserManager::Get()->IsLoggedInAsRegularUser() &&
    180       !user_manager::UserManager::Get()->IsLoggedInAsStub()) {
    181     chromeos::OAuth2LoginManager* login_manager =
    182         chromeos::OAuth2LoginManagerFactory::GetInstance()->GetForProfile(
    183             profile);
    184     if (login_manager)
    185       login_manager->AddObserver(this);
    186   }
    187 }
    188 
    189 base::FilePath ProfileHelper::GetActiveUserProfileDir() {
    190   return ProfileHelper::GetUserProfileDir(active_user_id_hash_);
    191 }
    192 
    193 void ProfileHelper::Initialize() {
    194   user_manager::UserManager::Get()->AddSessionStateObserver(this);
    195 }
    196 
    197 void ProfileHelper::ClearSigninProfile(const base::Closure& on_clear_callback) {
    198   on_clear_callbacks_.push_back(on_clear_callback);
    199   if (signin_profile_clear_requested_)
    200     return;
    201   ProfileManager* profile_manager = g_browser_process->profile_manager();
    202   // Check if signin profile was loaded.
    203   if (!profile_manager->GetProfileByPath(GetSigninProfileDir())) {
    204     OnBrowsingDataRemoverDone();
    205     return;
    206   }
    207   signin_profile_clear_requested_ = true;
    208   BrowsingDataRemover* remover =
    209       BrowsingDataRemover::CreateForUnboundedRange(GetSigninProfile());
    210   remover->AddObserver(this);
    211   remover->Remove(BrowsingDataRemover::REMOVE_SITE_DATA,
    212                   BrowsingDataHelper::ALL);
    213 }
    214 
    215 Profile* ProfileHelper::GetProfileByUser(const user_manager::User* user) {
    216   // This map is non-empty only in tests.
    217   if (!user_to_profile_for_testing_.empty()) {
    218     std::map<const user_manager::User*, Profile*>::const_iterator it =
    219         user_to_profile_for_testing_.find(user);
    220     return it == user_to_profile_for_testing_.end() ? NULL : it->second;
    221   }
    222 
    223   if (!user->is_profile_created())
    224     return NULL;
    225   Profile* profile =
    226       ProfileHelper::GetProfileByUserIdHash(user->username_hash());
    227 
    228   // GetActiveUserProfile() or GetProfileByUserIdHash() returns a new instance
    229   // of ProfileImpl(), but actually its OffTheRecordProfile() should be used.
    230   if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
    231     profile = profile->GetOffTheRecordProfile();
    232 
    233   return profile;
    234 }
    235 
    236 Profile* ProfileHelper::GetProfileByUserUnsafe(const user_manager::User* user) {
    237   // This map is non-empty only in tests.
    238   if (!user_to_profile_for_testing_.empty()) {
    239     std::map<const user_manager::User*, Profile*>::const_iterator it =
    240         user_to_profile_for_testing_.find(user);
    241     return it == user_to_profile_for_testing_.end() ? NULL : it->second;
    242   }
    243 
    244   Profile* profile = NULL;
    245   if (user->is_profile_created()) {
    246     profile = ProfileHelper::GetProfileByUserIdHash(user->username_hash());
    247   } else {
    248     LOG(WARNING) << "ProfileHelper::GetProfileByUserUnsafe is called when "
    249                     "|user|'s profile is not created. It probably means that "
    250                     "something is wrong with a calling code. Please report in "
    251                     "http://crbug.com/361528 if you see this message. user_id: "
    252                  << user->email();
    253     profile = ProfileManager::GetActiveUserProfile();
    254   }
    255 
    256   // GetActiveUserProfile() or GetProfileByUserIdHash() returns a new instance
    257   // of ProfileImpl(), but actually its OffTheRecordProfile() should be used.
    258   if (profile && user_manager::UserManager::Get()->IsLoggedInAsGuest())
    259     profile = profile->GetOffTheRecordProfile();
    260   return profile;
    261 }
    262 
    263 user_manager::User* ProfileHelper::GetUserByProfile(Profile* profile) {
    264   // This map is non-empty only in tests.
    265   if (enable_profile_to_user_testing || !user_list_for_testing_.empty()) {
    266     if (always_return_primary_user_for_testing)
    267       return const_cast<user_manager::User*>(
    268           user_manager::UserManager::Get()->GetPrimaryUser());
    269 
    270     const std::string& user_name = profile->GetProfileName();
    271     for (user_manager::UserList::const_iterator it =
    272              user_list_for_testing_.begin();
    273          it != user_list_for_testing_.end();
    274          ++it) {
    275       if ((*it)->email() == user_name)
    276         return *it;
    277     }
    278 
    279     // In case of test setup we should always default to primary user.
    280     return const_cast<user_manager::User*>(
    281         user_manager::UserManager::Get()->GetPrimaryUser());
    282   }
    283 
    284   DCHECK(!content::BrowserThread::IsThreadInitialized(
    285              content::BrowserThread::UI) ||
    286          content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    287   if (ProfileHelper::IsSigninProfile(profile))
    288     return NULL;
    289 
    290   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
    291 
    292   // Special case for non-CrOS tests that do create several profiles
    293   // and don't really care about mapping to the real user.
    294   // Without multi-profiles on Chrome OS such tests always got active_user_.
    295   // Now these tests will specify special flag to continue working.
    296   // In future those tests can get a proper CrOS configuration i.e. register
    297   // and login several users if they want to work with an additional profile.
    298   if (CommandLine::ForCurrentProcess()->HasSwitch(
    299           switches::kIgnoreUserProfileMappingForTests)) {
    300     return user_manager->GetActiveUser();
    301   }
    302 
    303   const std::string username_hash =
    304       ProfileHelper::GetUserIdHashFromProfile(profile);
    305   const user_manager::UserList& users = user_manager->GetUsers();
    306   const user_manager::UserList::const_iterator pos = std::find_if(
    307       users.begin(), users.end(), UsernameHashMatcher(username_hash));
    308   if (pos != users.end())
    309     return *pos;
    310 
    311   // Many tests do not have their users registered with UserManager and
    312   // runs here. If |active_user_| matches |profile|, returns it.
    313   const user_manager::User* active_user = user_manager->GetActiveUser();
    314   return active_user &&
    315                  ProfileHelper::GetProfilePathByUserIdHash(
    316                      active_user->username_hash()) == profile->GetPath()
    317              ? const_cast<user_manager::User*>(active_user)
    318              : NULL;
    319 }
    320 
    321 ////////////////////////////////////////////////////////////////////////////////
    322 // ProfileHelper, BrowsingDataRemover::Observer implementation:
    323 
    324 void ProfileHelper::OnBrowsingDataRemoverDone() {
    325   signin_profile_clear_requested_ = false;
    326   for (size_t i = 0; i < on_clear_callbacks_.size(); ++i) {
    327     if (!on_clear_callbacks_[i].is_null())
    328       on_clear_callbacks_[i].Run();
    329   }
    330   on_clear_callbacks_.clear();
    331 }
    332 
    333 ////////////////////////////////////////////////////////////////////////////////
    334 // ProfileHelper, OAuth2LoginManager::Observer implementation:
    335 
    336 void ProfileHelper::OnSessionRestoreStateChanged(
    337     Profile* user_profile,
    338     OAuth2LoginManager::SessionRestoreState state) {
    339   if (state == OAuth2LoginManager::SESSION_RESTORE_DONE ||
    340       state == OAuth2LoginManager::SESSION_RESTORE_FAILED ||
    341       state == OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED) {
    342     chromeos::OAuth2LoginManager* login_manager =
    343         chromeos::OAuth2LoginManagerFactory::GetInstance()->
    344             GetForProfile(user_profile);
    345     login_manager->RemoveObserver(this);
    346     ClearSigninProfile(base::Closure());
    347   }
    348 }
    349 
    350 ////////////////////////////////////////////////////////////////////////////////
    351 // ProfileHelper, UserManager::UserSessionStateObserver implementation:
    352 
    353 void ProfileHelper::ActiveUserHashChanged(const std::string& hash) {
    354   active_user_id_hash_ = hash;
    355 }
    356 
    357 void ProfileHelper::SetProfileToUserMappingForTesting(
    358     user_manager::User* user) {
    359   user_list_for_testing_.push_back(user);
    360 }
    361 
    362 // static
    363 void ProfileHelper::SetProfileToUserForTestingEnabled(bool enabled) {
    364   enable_profile_to_user_testing = enabled;
    365 }
    366 
    367 // static
    368 void ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(bool value) {
    369   always_return_primary_user_for_testing = true;
    370   ProfileHelper::SetProfileToUserForTestingEnabled(true);
    371 }
    372 
    373 void ProfileHelper::SetUserToProfileMappingForTesting(
    374     const user_manager::User* user,
    375     Profile* profile) {
    376   user_to_profile_for_testing_[user] = profile;
    377 }
    378 
    379 // static
    380 std::string ProfileHelper::GetUserIdHashByUserIdForTesting(
    381     const std::string& user_id) {
    382   return user_id + kUserIdHashSuffix;
    383 }
    384 
    385 }  // namespace chromeos
    386