Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2012 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/login/login_utils.h"
      6 
      7 #include <algorithm>
      8 #include <set>
      9 #include <vector>
     10 
     11 #include "base/base_paths.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/compiler_specific.h"
     15 #include "base/file_util.h"
     16 #include "base/files/file_path.h"
     17 #include "base/location.h"
     18 #include "base/memory/ref_counted.h"
     19 #include "base/memory/scoped_ptr.h"
     20 #include "base/memory/singleton.h"
     21 #include "base/memory/weak_ptr.h"
     22 #include "base/prefs/pref_member.h"
     23 #include "base/prefs/pref_service.h"
     24 #include "base/strings/string_util.h"
     25 #include "base/strings/utf_string_conversions.h"
     26 #include "base/synchronization/lock.h"
     27 #include "base/sys_info.h"
     28 #include "base/task_runner_util.h"
     29 #include "base/threading/worker_pool.h"
     30 #include "base/time/time.h"
     31 #include "chrome/browser/about_flags.h"
     32 #include "chrome/browser/app_mode/app_mode_utils.h"
     33 #include "chrome/browser/browser_process.h"
     34 #include "chrome/browser/browser_shutdown.h"
     35 #include "chrome/browser/chrome_notification_types.h"
     36 #include "chrome/browser/chromeos/boot_times_loader.h"
     37 #include "chrome/browser/chromeos/login/auth/parallel_authenticator.h"
     38 #include "chrome/browser/chromeos/login/auth/user_context.h"
     39 #include "chrome/browser/chromeos/login/chrome_restart_request.h"
     40 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
     41 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
     42 #include "chrome/browser/chromeos/login/profile_auth_data.h"
     43 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h"
     44 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter_factory.h"
     45 #include "chrome/browser/chromeos/login/session/session_manager.h"
     46 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
     47 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h"
     48 #include "chrome/browser/chromeos/login/startup_utils.h"
     49 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
     50 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
     51 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
     52 #include "chrome/browser/chromeos/login/users/user.h"
     53 #include "chrome/browser/chromeos/login/users/user_manager.h"
     54 #include "chrome/browser/chromeos/settings/cros_settings.h"
     55 #include "chrome/browser/extensions/extension_service.h"
     56 #include "chrome/browser/first_run/first_run.h"
     57 #include "chrome/browser/google/google_brand_chromeos.h"
     58 #include "chrome/browser/lifetime/application_lifetime.h"
     59 #include "chrome/browser/pref_service_flags_storage.h"
     60 #include "chrome/browser/profiles/profile.h"
     61 #include "chrome/browser/profiles/profile_manager.h"
     62 #include "chrome/browser/rlz/rlz.h"
     63 #include "chrome/browser/signin/signin_manager_factory.h"
     64 #include "chrome/browser/sync/profile_sync_service.h"
     65 #include "chrome/browser/sync/profile_sync_service_factory.h"
     66 #include "chrome/browser/ui/app_list/start_page_service.h"
     67 #include "chrome/browser/ui/startup/startup_browser_creator.h"
     68 #include "chrome/common/chrome_switches.h"
     69 #include "chrome/common/logging_chrome.h"
     70 #include "chrome/common/pref_names.h"
     71 #include "chromeos/chromeos_switches.h"
     72 #include "chromeos/cryptohome/cryptohome_util.h"
     73 #include "chromeos/dbus/cryptohome_client.h"
     74 #include "chromeos/dbus/dbus_method_call_status.h"
     75 #include "chromeos/dbus/dbus_thread_manager.h"
     76 #include "chromeos/dbus/session_manager_client.h"
     77 #include "chromeos/settings/cros_settings_names.h"
     78 #include "components/signin/core/browser/signin_manager.h"
     79 #include "content/public/browser/browser_thread.h"
     80 #include "content/public/browser/notification_service.h"
     81 #include "google_apis/gaia/gaia_auth_consumer.h"
     82 #include "net/base/network_change_notifier.h"
     83 #include "net/url_request/url_request_context.h"
     84 #include "net/url_request/url_request_context_getter.h"
     85 #include "url/gurl.h"
     86 
     87 using content::BrowserThread;
     88 
     89 namespace chromeos {
     90 
     91 struct DoBrowserLaunchOnLocaleLoadedData;
     92 
     93 class LoginUtilsImpl
     94     : public LoginUtils,
     95       public base::SupportsWeakPtr<LoginUtilsImpl>,
     96       public SessionManager::Delegate {
     97  public:
     98   LoginUtilsImpl()
     99       : delegate_(NULL) {
    100   }
    101 
    102   virtual ~LoginUtilsImpl() {
    103   }
    104 
    105   // LoginUtils implementation:
    106   virtual void DoBrowserLaunch(Profile* profile,
    107                                LoginDisplayHost* login_host) OVERRIDE;
    108   virtual void PrepareProfile(
    109       const UserContext& user_context,
    110       bool has_cookies,
    111       bool has_active_session,
    112       LoginUtils::Delegate* delegate) OVERRIDE;
    113   virtual void DelegateDeleted(LoginUtils::Delegate* delegate) OVERRIDE;
    114   virtual void CompleteOffTheRecordLogin(const GURL& start_url) OVERRIDE;
    115   virtual scoped_refptr<Authenticator> CreateAuthenticator(
    116       LoginStatusConsumer* consumer) OVERRIDE;
    117 
    118   // SessionManager::Delegate implementation:
    119    virtual void OnProfilePrepared(Profile* profile) OVERRIDE;
    120  #if defined(ENABLE_RLZ)
    121    virtual void OnRlzInitialized() OVERRIDE;
    122  #endif
    123 
    124  private:
    125   // DoBrowserLaunch is split into two parts.
    126   // This one is called after asynchronous locale switch.
    127   void DoBrowserLaunchOnLocaleLoadedImpl(Profile* profile,
    128                                          LoginDisplayHost* login_host);
    129 
    130   // Callback for locale_util::SwitchLanguage().
    131   static void DoBrowserLaunchOnLocaleLoaded(
    132       scoped_ptr<DoBrowserLaunchOnLocaleLoadedData> context,
    133       const std::string& locale,
    134       const std::string& loaded_locale,
    135       const bool success);
    136 
    137   // Attempts restarting the browser process and esures that this does
    138   // not happen while we are still fetching new OAuth refresh tokens.
    139   void AttemptRestart(Profile* profile);
    140 
    141   // Has to be scoped_refptr, see comment for CreateAuthenticator(...).
    142   scoped_refptr<Authenticator> authenticator_;
    143 
    144   // Delegate to be fired when the profile will be prepared.
    145   LoginUtils::Delegate* delegate_;
    146 
    147   DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
    148 };
    149 
    150 class LoginUtilsWrapper {
    151  public:
    152   static LoginUtilsWrapper* GetInstance() {
    153     return Singleton<LoginUtilsWrapper>::get();
    154   }
    155 
    156   LoginUtils* get() {
    157     base::AutoLock create(create_lock_);
    158     if (!ptr_.get())
    159       reset(new LoginUtilsImpl);
    160     return ptr_.get();
    161   }
    162 
    163   void reset(LoginUtils* ptr) {
    164     ptr_.reset(ptr);
    165   }
    166 
    167  private:
    168   friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
    169 
    170   LoginUtilsWrapper() {}
    171 
    172   base::Lock create_lock_;
    173   scoped_ptr<LoginUtils> ptr_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
    176 };
    177 
    178 struct DoBrowserLaunchOnLocaleLoadedData {
    179   DoBrowserLaunchOnLocaleLoadedData(LoginUtilsImpl* login_utils_impl,
    180                                     Profile* profile,
    181                                     LoginDisplayHost* display_host)
    182       : login_utils_impl(login_utils_impl),
    183         profile(profile),
    184         display_host(display_host) {}
    185 
    186   LoginUtilsImpl* login_utils_impl;
    187   Profile* profile;
    188   chromeos::LoginDisplayHost* display_host;
    189 
    190   // Block UI events untill ResourceBundle is reloaded.
    191   InputEventsBlocker input_events_blocker;
    192 };
    193 
    194 // static
    195 void LoginUtilsImpl::DoBrowserLaunchOnLocaleLoaded(
    196     scoped_ptr<DoBrowserLaunchOnLocaleLoadedData> context,
    197     const std::string& /* locale */,
    198     const std::string& /* loaded_locale */,
    199     const bool /* success */) {
    200   context->login_utils_impl->DoBrowserLaunchOnLocaleLoadedImpl(
    201       context->profile, context->display_host);
    202 }
    203 
    204 // Called from DoBrowserLaunch() or from
    205 // DoBrowserLaunchOnLocaleLoaded() depending on
    206 // if locale switch was needed.
    207 void LoginUtilsImpl::DoBrowserLaunchOnLocaleLoadedImpl(
    208     Profile* profile,
    209     LoginDisplayHost* login_host) {
    210   if (!UserManager::Get()->GetCurrentUserFlow()->ShouldLaunchBrowser()) {
    211     UserManager::Get()->GetCurrentUserFlow()->LaunchExtraSteps(profile);
    212     return;
    213   }
    214 
    215   CommandLine user_flags(CommandLine::NO_PROGRAM);
    216   about_flags::PrefServiceFlagsStorage flags_storage_(profile->GetPrefs());
    217   about_flags::ConvertFlagsToSwitches(&flags_storage_, &user_flags,
    218                                       about_flags::kAddSentinels);
    219   // Only restart if needed and if not going into managed mode.
    220   // Don't restart browser if it is not first profile in session.
    221   if (UserManager::Get()->GetLoggedInUsers().size() == 1 &&
    222       !UserManager::Get()->IsLoggedInAsLocallyManagedUser() &&
    223       !about_flags::AreSwitchesIdenticalToCurrentCommandLine(
    224           user_flags, *CommandLine::ForCurrentProcess())) {
    225     CommandLine::StringVector flags;
    226     // argv[0] is the program name |CommandLine::NO_PROGRAM|.
    227     flags.assign(user_flags.argv().begin() + 1, user_flags.argv().end());
    228     VLOG(1) << "Restarting to apply per-session flags...";
    229     DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser(
    230         UserManager::Get()->GetActiveUser()->email(), flags);
    231     AttemptRestart(profile);
    232     return;
    233   }
    234 
    235   if (login_host) {
    236     login_host->SetStatusAreaVisible(true);
    237     login_host->BeforeSessionStart();
    238   }
    239 
    240   BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false);
    241 
    242   VLOG(1) << "Launching browser...";
    243   StartupBrowserCreator browser_creator;
    244   int return_code;
    245   chrome::startup::IsFirstRun first_run = first_run::IsChromeFirstRun() ?
    246       chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
    247 
    248   browser_creator.LaunchBrowser(*CommandLine::ForCurrentProcess(),
    249                                 profile,
    250                                 base::FilePath(),
    251                                 chrome::startup::IS_PROCESS_STARTUP,
    252                                 first_run,
    253                                 &return_code);
    254 
    255   // Triggers app launcher start page service to load start page web contents.
    256   app_list::StartPageService::Get(profile);
    257 
    258   // Mark login host for deletion after browser starts.  This
    259   // guarantees that the message loop will be referenced by the
    260   // browser before it is dereferenced by the login host.
    261   if (login_host)
    262     login_host->Finalize();
    263   UserManager::Get()->SessionStarted();
    264   chromeos::BootTimesLoader::Get()->LoginDone(
    265       chromeos::UserManager::Get()->IsCurrentUserNew());
    266 }
    267 
    268 void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
    269                                      LoginDisplayHost* login_host) {
    270   if (browser_shutdown::IsTryingToQuit())
    271     return;
    272 
    273   User* const user = UserManager::Get()->GetUserByProfile(profile);
    274   scoped_ptr<DoBrowserLaunchOnLocaleLoadedData> data(
    275       new DoBrowserLaunchOnLocaleLoadedData(this, profile, login_host));
    276 
    277   scoped_ptr<locale_util::SwitchLanguageCallback> callback(
    278       new locale_util::SwitchLanguageCallback(
    279           base::Bind(&LoginUtilsImpl::DoBrowserLaunchOnLocaleLoaded,
    280                      base::Passed(data.Pass()))));
    281   if (!UserManager::Get()->
    282       RespectLocalePreference(profile, user, callback.Pass())) {
    283     DoBrowserLaunchOnLocaleLoadedImpl(profile, login_host);
    284   }
    285 }
    286 
    287 void LoginUtilsImpl::PrepareProfile(
    288     const UserContext& user_context,
    289     bool has_cookies,
    290     bool has_active_session,
    291     LoginUtils::Delegate* delegate) {
    292   // TODO(nkostylev): We have to initialize LoginUtils delegate as long
    293   // as it coexist with SessionManager.
    294   delegate_ = delegate;
    295 
    296   // For the transition part LoginUtils will just delegate profile
    297   // creation and initialization to SessionManager. Later LoginUtils will be
    298   // removed and all LoginUtils clients will just work with SessionManager
    299   // directly.
    300   SessionManager::GetInstance()->StartSession(user_context,
    301                                               authenticator_,
    302                                               has_cookies,
    303                                               has_active_session,
    304                                               this);
    305 }
    306 
    307 void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) {
    308   if (delegate_ == delegate)
    309     delegate_ = NULL;
    310 }
    311 
    312 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
    313   VLOG(1) << "Completing incognito login";
    314 
    315   // For guest session we ask session manager to restart Chrome with --bwsi
    316   // flag. We keep only some of the arguments of this process.
    317   const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
    318   CommandLine command_line(browser_command_line.GetProgram());
    319   std::string cmd_line_str =
    320       GetOffTheRecordCommandLine(start_url,
    321                                  StartupUtils::IsOobeCompleted(),
    322                                  browser_command_line,
    323                                  &command_line);
    324 
    325   RestartChrome(cmd_line_str);
    326 }
    327 
    328 scoped_refptr<Authenticator> LoginUtilsImpl::CreateAuthenticator(
    329     LoginStatusConsumer* consumer) {
    330   // Screen locker needs new Authenticator instance each time.
    331   if (ScreenLocker::default_screen_locker()) {
    332     if (authenticator_.get())
    333       authenticator_->SetConsumer(NULL);
    334     authenticator_ = NULL;
    335   }
    336 
    337   if (authenticator_.get() == NULL) {
    338     authenticator_ = new ParallelAuthenticator(consumer);
    339   } else {
    340     // TODO(nkostylev): Fix this hack by improving Authenticator dependencies.
    341     authenticator_->SetConsumer(consumer);
    342   }
    343   return authenticator_;
    344 }
    345 
    346 void LoginUtilsImpl::OnProfilePrepared(Profile* profile) {
    347   if (delegate_)
    348     delegate_->OnProfilePrepared(profile);
    349 }
    350 
    351 #if defined(ENABLE_RLZ)
    352 void LoginUtilsImpl::OnRlzInitialized() {
    353   if (delegate_)
    354     delegate_->OnRlzInitialized();
    355 }
    356 #endif
    357 
    358 void LoginUtilsImpl::AttemptRestart(Profile* profile) {
    359   if (SessionManager::GetInstance()->GetSigninSessionRestoreStrategy() !=
    360       OAuth2LoginManager::RESTORE_FROM_COOKIE_JAR) {
    361     chrome::AttemptRestart();
    362     return;
    363   }
    364 
    365   // We can't really quit if the session restore process that mints new
    366   // refresh token is still in progress.
    367   OAuth2LoginManager* login_manager =
    368       OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile);
    369   if (login_manager->state() !=
    370           OAuth2LoginManager::SESSION_RESTORE_PREPARING &&
    371       login_manager->state() !=
    372           OAuth2LoginManager::SESSION_RESTORE_IN_PROGRESS) {
    373     chrome::AttemptRestart();
    374     return;
    375   }
    376 
    377   LOG(WARNING) << "Attempting browser restart during session restore.";
    378   SessionManager::GetInstance()->set_exit_after_session_restore(true);
    379 }
    380 
    381 // static
    382 LoginUtils* LoginUtils::Get() {
    383   return LoginUtilsWrapper::GetInstance()->get();
    384 }
    385 
    386 // static
    387 void LoginUtils::Set(LoginUtils* mock) {
    388   LoginUtilsWrapper::GetInstance()->reset(mock);
    389 }
    390 
    391 // static
    392 bool LoginUtils::IsWhitelisted(const std::string& username,
    393                                bool* wildcard_match) {
    394   // Skip whitelist check for tests.
    395   if (CommandLine::ForCurrentProcess()->HasSwitch(
    396       chromeos::switches::kOobeSkipPostLogin)) {
    397     return true;
    398   }
    399 
    400   CrosSettings* cros_settings = CrosSettings::Get();
    401   bool allow_new_user = false;
    402   cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
    403   if (allow_new_user)
    404     return true;
    405   return cros_settings->FindEmailInList(
    406       kAccountsPrefUsers, username, wildcard_match);
    407 }
    408 
    409 }  // namespace chromeos
    410