login_utils.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 <vector>
9
10#include "base/chromeos/chromeos_version.h"
11#include "base/command_line.h"
12#include "base/compiler_specific.h"
13#include "base/file_util.h"
14#include "base/files/file_path.h"
15#include "base/location.h"
16#include "base/memory/ref_counted.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/memory/singleton.h"
19#include "base/memory/weak_ptr.h"
20#include "base/path_service.h"
21#include "base/prefs/pref_member.h"
22#include "base/prefs/pref_registry_simple.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/task_runner_util.h"
28#include "base/threading/worker_pool.h"
29#include "base/time.h"
30#include "chrome/browser/about_flags.h"
31#include "chrome/browser/app_mode/app_mode_utils.h"
32#include "chrome/browser/browser_process.h"
33#include "chrome/browser/browser_shutdown.h"
34#include "chrome/browser/chromeos/boot_times_loader.h"
35#include "chrome/browser/chromeos/input_method/input_method_util.h"
36#include "chrome/browser/chromeos/login/chrome_restart_request.h"
37#include "chrome/browser/chromeos/login/language_switch_menu.h"
38#include "chrome/browser/chromeos/login/login_display_host.h"
39#include "chrome/browser/chromeos/login/oauth_login_manager.h"
40#include "chrome/browser/chromeos/login/parallel_authenticator.h"
41#include "chrome/browser/chromeos/login/profile_auth_data.h"
42#include "chrome/browser/chromeos/login/screen_locker.h"
43#include "chrome/browser/chromeos/login/user_manager.h"
44#include "chrome/browser/chromeos/settings/cros_settings.h"
45#include "chrome/browser/chromeos/settings/cros_settings_names.h"
46#include "chrome/browser/extensions/extension_service.h"
47#include "chrome/browser/first_run/first_run.h"
48#include "chrome/browser/google/google_util_chromeos.h"
49#include "chrome/browser/lifetime/application_lifetime.h"
50#include "chrome/browser/managed_mode/managed_mode.h"
51#include "chrome/browser/pref_service_flags_storage.h"
52#include "chrome/browser/profiles/profile.h"
53#include "chrome/browser/profiles/profile_manager.h"
54#include "chrome/browser/rlz/rlz.h"
55#include "chrome/browser/signin/signin_manager.h"
56#include "chrome/browser/signin/signin_manager_factory.h"
57#include "chrome/browser/signin/token_service.h"
58#include "chrome/browser/signin/token_service_factory.h"
59#include "chrome/browser/sync/profile_sync_service.h"
60#include "chrome/browser/sync/profile_sync_service_factory.h"
61#include "chrome/browser/ui/startup/startup_browser_creator.h"
62#include "chrome/common/chrome_notification_types.h"
63#include "chrome/common/chrome_paths.h"
64#include "chrome/common/chrome_switches.h"
65#include "chrome/common/logging_chrome.h"
66#include "chrome/common/pref_names.h"
67#include "chromeos/chromeos_switches.h"
68#include "chromeos/cryptohome/cryptohome_library.h"
69#include "chromeos/dbus/dbus_thread_manager.h"
70#include "chromeos/dbus/session_manager_client.h"
71#include "chromeos/ime/input_method_manager.h"
72#include "content/public/browser/browser_thread.h"
73#include "content/public/browser/notification_service.h"
74#include "google_apis/gaia/gaia_auth_consumer.h"
75#include "googleurl/src/gurl.h"
76#include "net/base/network_change_notifier.h"
77#include "net/url_request/url_request_context.h"
78#include "net/url_request/url_request_context_getter.h"
79
80using content::BrowserThread;
81
82namespace chromeos {
83
84namespace {
85
86#if defined(ENABLE_RLZ)
87// Flag file that disables RLZ tracking, when present.
88const base::FilePath::CharType kRLZDisabledFlagName[] =
89    FILE_PATH_LITERAL(".rlz_disabled");
90
91base::FilePath GetRlzDisabledFlagPath() {
92  return file_util::GetHomeDir().Append(kRLZDisabledFlagName);
93}
94#endif
95
96}  // namespace
97
98class LoginUtilsImpl
99    : public LoginUtils,
100      public OAuthLoginManager::Delegate,
101      public net::NetworkChangeNotifier::ConnectionTypeObserver,
102      public base::SupportsWeakPtr<LoginUtilsImpl> {
103 public:
104  LoginUtilsImpl()
105      : using_oauth_(false),
106        has_web_auth_cookies_(false),
107        login_manager_(OAuthLoginManager::Create(this)),
108        delegate_(NULL),
109        should_restore_auth_session_(false),
110        session_restore_strategy_(
111            OAuthLoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) {
112    net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
113  }
114
115  virtual ~LoginUtilsImpl() {
116    net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
117  }
118
119  // LoginUtils implementation:
120  virtual void DoBrowserLaunch(Profile* profile,
121                               LoginDisplayHost* login_host) OVERRIDE;
122  virtual void PrepareProfile(
123      const UserContext& user_context,
124      const std::string& display_email,
125      bool using_oauth,
126      bool has_cookies,
127      bool has_active_session,
128      LoginUtils::Delegate* delegate) OVERRIDE;
129  virtual void DelegateDeleted(LoginUtils::Delegate* delegate) OVERRIDE;
130  virtual void CompleteOffTheRecordLogin(const GURL& start_url) OVERRIDE;
131  virtual void SetFirstLoginPrefs(PrefService* prefs) OVERRIDE;
132  virtual scoped_refptr<Authenticator> CreateAuthenticator(
133      LoginStatusConsumer* consumer) OVERRIDE;
134  virtual void RestoreAuthenticationSession(Profile* profile) OVERRIDE;
135  virtual void StopBackgroundFetchers() OVERRIDE;
136  virtual void InitRlzDelayed(Profile* user_profile) OVERRIDE;
137
138  // OAuthLoginManager::Delegate overrides.
139  virtual void OnCompletedMergeSession() OVERRIDE;
140  virtual void OnCompletedAuthentication(Profile* user_profile) OVERRIDE;
141  virtual void OnFoundStoredTokens() OVERRIDE;
142
143  // net::NetworkChangeNotifier::ConnectionTypeObserver overrides.
144  virtual void OnConnectionTypeChanged(
145      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
146
147 private:
148  // Restarts OAuth session authentication check.
149  void KickStartAuthentication(Profile* profile);
150
151  // Check user's profile for kApplicationLocale setting.
152  void RespectLocalePreference(Profile* pref);
153
154  // Callback for Profile::CREATE_STATUS_CREATED profile state.
155  // Initializes basic preferences for newly created profile. Any other
156  // early profile initialization that needs to happen before
157  // ProfileManager::DoFinalInit() gets called is done here.
158  void InitProfilePreferences(Profile* user_profile);
159
160  // Callback for asynchronous profile creation.
161  void OnProfileCreated(Profile* profile,
162                        Profile::CreateStatus status);
163
164  // Callback for Profile::CREATE_STATUS_INITIALIZED profile state.
165  // Profile is created, extensions and promo resources are initialized.
166  void UserProfileInitialized(Profile* user_profile);
167
168  // Callback to resume profile creation after transferring auth data from
169  // the authentication profile.
170  void CompleteProfileCreate(Profile* user_profile);
171
172  // Finalized profile preparation.
173  void FinalizePrepareProfile(Profile* user_profile);
174
175  // Initializes member variables needed for session restore process via
176  // OAuthLoginManager.
177  void InitSessionRestoreStrategy();
178
179  // Restores GAIA auth cookies for the created user profile from OAuth2 token.
180  void RestoreAuthSession(Profile* user_profile,
181                          bool restore_from_auth_cookies);
182
183  // Callback when managed mode preferences have been applied.
184  void EnteredManagedMode(bool success);
185
186  // Initializes RLZ. If |disabled| is true, RLZ pings are disabled.
187  void InitRlz(Profile* user_profile, bool disabled);
188
189  // Starts signing related services. Initiates TokenService token retrieval.
190  void StartSignedInServices(Profile* profile);
191
192  UserContext user_context_;
193  bool using_oauth_;
194  // True if the authentication profile's cookie jar should contain
195  // authentication cookies from the authentication extension log in flow.
196  bool has_web_auth_cookies_;
197  // Has to be scoped_refptr, see comment for CreateAuthenticator(...).
198  scoped_refptr<Authenticator> authenticator_;
199  scoped_ptr<OAuthLoginManager> login_manager_;
200
201  // Delegate to be fired when the profile will be prepared.
202  LoginUtils::Delegate* delegate_;
203
204  // True if should restore authentication session when notified about
205  // online state change.
206  bool should_restore_auth_session_;
207
208  // Sesion restore strategy.
209  OAuthLoginManager::SessionRestoreStrategy session_restore_strategy_;
210  // OAuth2 refresh token for session restore.
211  std::string oauth2_refresh_token_;
212
213  DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
214};
215
216class LoginUtilsWrapper {
217 public:
218  static LoginUtilsWrapper* GetInstance() {
219    return Singleton<LoginUtilsWrapper>::get();
220  }
221
222  LoginUtils* get() {
223    base::AutoLock create(create_lock_);
224    if (!ptr_.get())
225      reset(new LoginUtilsImpl);
226    return ptr_.get();
227  }
228
229  void reset(LoginUtils* ptr) {
230    ptr_.reset(ptr);
231  }
232
233 private:
234  friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
235
236  LoginUtilsWrapper() {}
237
238  base::Lock create_lock_;
239  scoped_ptr<LoginUtils> ptr_;
240
241  DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
242};
243
244void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
245                                     LoginDisplayHost* login_host) {
246  if (browser_shutdown::IsTryingToQuit())
247    return;
248
249  if (!UserManager::Get()->GetCurrentUserFlow()->ShouldLaunchBrowser()) {
250    UserManager::Get()->GetCurrentUserFlow()->LaunchExtraSteps(profile);
251    return;
252  }
253
254  CommandLine user_flags(CommandLine::NO_PROGRAM);
255  about_flags::PrefServiceFlagsStorage flags_storage_(profile->GetPrefs());
256  about_flags::ConvertFlagsToSwitches(&flags_storage_, &user_flags);
257  if (!about_flags::AreSwitchesIdenticalToCurrentCommandLine(
258          user_flags, *CommandLine::ForCurrentProcess())) {
259    CommandLine::StringVector flags;
260    // argv[0] is the program name |CommandLine::NO_PROGRAM|.
261    flags.assign(user_flags.argv().begin() + 1, user_flags.argv().end());
262    VLOG(1) << "Restarting to apply per-session flags...";
263    DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser(
264        UserManager::Get()->GetActiveUser()->email(), flags);
265    chrome::ExitCleanly();
266    return;
267  }
268
269  if (login_host) {
270    login_host->SetStatusAreaVisible(true);
271    login_host->BeforeSessionStart();
272  }
273
274  BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false);
275
276  VLOG(1) << "Launching browser...";
277  StartupBrowserCreator browser_creator;
278  int return_code;
279  chrome::startup::IsFirstRun first_run = first_run::IsChromeFirstRun() ?
280      chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
281
282  browser_creator.LaunchBrowser(*CommandLine::ForCurrentProcess(),
283                                profile,
284                                base::FilePath(),
285                                chrome::startup::IS_PROCESS_STARTUP,
286                                first_run,
287                                &return_code);
288
289  // Mark login host for deletion after browser starts.  This
290  // guarantees that the message loop will be referenced by the
291  // browser before it is dereferenced by the login host.
292  if (login_host)
293    login_host->Finalize();
294  UserManager::Get()->SessionStarted();
295}
296
297void LoginUtilsImpl::PrepareProfile(
298    const UserContext& user_context,
299    const std::string& display_email,
300    bool using_oauth,
301    bool has_cookies,
302    bool has_active_session,
303    LoginUtils::Delegate* delegate) {
304  BootTimesLoader* btl = BootTimesLoader::Get();
305
306  VLOG(1) << "Completing login for " << user_context.username;
307
308  if (!has_active_session) {
309    btl->AddLoginTimeMarker("StartSession-Start", false);
310    DBusThreadManager::Get()->GetSessionManagerClient()->StartSession(
311        user_context.username);
312    btl->AddLoginTimeMarker("StartSession-End", false);
313  }
314
315  btl->AddLoginTimeMarker("UserLoggedIn-Start", false);
316  UserManager* user_manager = UserManager::Get();
317  user_manager->UserLoggedIn(user_context.username,
318                             user_context.username_hash,
319                             false);
320  btl->AddLoginTimeMarker("UserLoggedIn-End", false);
321
322  // Switch log file as soon as possible.
323  if (base::chromeos::IsRunningOnChromeOS())
324    logging::RedirectChromeLogging(*(CommandLine::ForCurrentProcess()));
325
326  // Update user's displayed email.
327  if (!display_email.empty())
328    user_manager->SaveUserDisplayEmail(user_context.username, display_email);
329
330  user_context_ = user_context;
331
332  using_oauth_ = using_oauth;
333  has_web_auth_cookies_ = has_cookies;
334  delegate_ = delegate;
335  InitSessionRestoreStrategy();
336
337  // The default profile will have been changed because the ProfileManager
338  // will process the notification that the UserManager sends out so
339  // username_hash has been already propogated to ProfileManager.
340  ProfileManager::CreateDefaultProfileAsync(
341      base::Bind(&LoginUtilsImpl::OnProfileCreated, AsWeakPtr()));
342}
343
344void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) {
345  if (delegate_ == delegate)
346    delegate_ = NULL;
347}
348
349void LoginUtilsImpl::InitProfilePreferences(Profile* user_profile) {
350  if (UserManager::Get()->IsCurrentUserNew())
351    SetFirstLoginPrefs(user_profile->GetPrefs());
352
353  if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
354    user_profile->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
355  } else {
356    // Make sure that the google service username is properly set (we do this
357    // on every sign in, not just the first login, to deal with existing
358    // profiles that might not have it set yet).
359    StringPrefMember google_services_username;
360    google_services_username.Init(prefs::kGoogleServicesUsername,
361                                  user_profile->GetPrefs());
362    google_services_username.SetValue(
363        UserManager::Get()->GetLoggedInUser()->display_email());
364  }
365
366  // Make sure we flip every profile to not share proxies if the user hasn't
367  // specified so explicitly.
368  const PrefService::Preference* use_shared_proxies_pref =
369      user_profile->GetPrefs()->FindPreference(prefs::kUseSharedProxies);
370  if (use_shared_proxies_pref->IsDefaultValue())
371    user_profile->GetPrefs()->SetBoolean(prefs::kUseSharedProxies, false);
372
373  RespectLocalePreference(user_profile);
374}
375
376void LoginUtilsImpl::InitSessionRestoreStrategy() {
377  CommandLine* command_line = CommandLine::ForCurrentProcess();
378  bool in_app_mode = chrome::IsRunningInForcedAppMode();
379
380  // Are we in kiosk app mode?
381  if (in_app_mode) {
382    if (command_line->HasSwitch(::switches::kAppModeOAuth2Token)) {
383      oauth2_refresh_token_ = command_line->GetSwitchValueASCII(
384          ::switches::kAppModeOAuth2Token);
385    }
386
387    if (command_line->HasSwitch(::switches::kAppModeAuthCode)) {
388      user_context_.auth_code = command_line->GetSwitchValueASCII(
389          ::switches::kAppModeAuthCode);
390    }
391
392    DCHECK(!has_web_auth_cookies_);
393    if (!user_context_.auth_code.empty()) {
394      session_restore_strategy_ = OAuthLoginManager::RESTORE_FROM_AUTH_CODE;
395    } else if (!oauth2_refresh_token_.empty()) {
396      session_restore_strategy_ =
397          OAuthLoginManager::RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN;
398    } else {
399      session_restore_strategy_ =
400          OAuthLoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
401    }
402    return;
403  }
404
405  if (has_web_auth_cookies_) {
406    session_restore_strategy_ = OAuthLoginManager::RESTORE_FROM_COOKIE_JAR;
407  } else if (!user_context_.auth_code.empty()) {
408    session_restore_strategy_ = OAuthLoginManager::RESTORE_FROM_AUTH_CODE;
409  } else {
410    session_restore_strategy_ =
411        OAuthLoginManager::RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
412  }
413}
414
415
416void LoginUtilsImpl::OnProfileCreated(
417    Profile* user_profile,
418    Profile::CreateStatus status) {
419  CHECK(user_profile);
420
421  switch (status) {
422    case Profile::CREATE_STATUS_INITIALIZED:
423      UserProfileInitialized(user_profile);
424      break;
425    case Profile::CREATE_STATUS_CREATED:
426      InitProfilePreferences(user_profile);
427      break;
428    case Profile::CREATE_STATUS_LOCAL_FAIL:
429    case Profile::CREATE_STATUS_REMOTE_FAIL:
430    case Profile::CREATE_STATUS_CANCELED:
431    case Profile::MAX_CREATE_STATUS:
432      NOTREACHED();
433      break;
434  }
435}
436
437void LoginUtilsImpl::UserProfileInitialized(Profile* user_profile) {
438  BootTimesLoader* btl = BootTimesLoader::Get();
439  btl->AddLoginTimeMarker("UserProfileGotten", false);
440
441  if (using_oauth_) {
442    // Transfer proxy authentication cache, cookies (optionally) and server
443    // bound certs from the profile that was used for authentication.  This
444    // profile contains cookies that auth extension should have already put in
445    // place that will ensure that the newly created session is authenticated
446    // for the websites that work with the used authentication schema.
447    ProfileAuthData::Transfer(authenticator_->authentication_profile(),
448                              user_profile,
449                              has_web_auth_cookies_,  // transfer_cookies
450                              base::Bind(
451                                  &LoginUtilsImpl::CompleteProfileCreate,
452                                  AsWeakPtr(),
453                                  user_profile));
454    return;
455  }
456
457  if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
458    // Apply managed mode first.
459    ManagedMode::EnterManagedMode(
460        user_profile,
461        base::Bind(&LoginUtilsImpl::EnteredManagedMode, AsWeakPtr()));
462  } else {
463    FinalizePrepareProfile(user_profile);
464  }
465}
466
467void LoginUtilsImpl::EnteredManagedMode(bool success) {
468  // TODO(nkostylev): What if entering managed mode fails?
469  FinalizePrepareProfile(ProfileManager::GetDefaultProfile());
470}
471
472void LoginUtilsImpl::CompleteProfileCreate(Profile* user_profile) {
473  RestoreAuthSession(user_profile, has_web_auth_cookies_);
474  FinalizePrepareProfile(user_profile);
475}
476
477void LoginUtilsImpl::RestoreAuthSession(Profile* user_profile,
478                                        bool restore_from_auth_cookies) {
479  CHECK((authenticator_.get() && authenticator_->authentication_profile()) ||
480        !restore_from_auth_cookies);
481  if (!login_manager_.get())
482    return;
483
484  if (chrome::IsRunningInForcedAppMode())
485    return;
486
487  UserManager::Get()->SetMergeSessionState(
488      UserManager::MERGE_STATUS_IN_PROCESS);
489
490  // Remove legacy OAuth1 token if we have one. If it's valid, we should already
491  // have OAuth2 refresh token in TokenService that could be used to retrieve
492  // all other tokens and user_context.
493  login_manager_->RestoreSession(
494      user_profile,
495      authenticator_.get() && authenticator_->authentication_profile()
496          ? authenticator_->authentication_profile()->GetRequestContext()
497          : NULL,
498      session_restore_strategy_,
499      oauth2_refresh_token_,
500      user_context_.auth_code);
501}
502
503void LoginUtilsImpl::FinalizePrepareProfile(Profile* user_profile) {
504  BootTimesLoader* btl = BootTimesLoader::Get();
505  // Own TPM device if, for any reason, it has not been done in EULA
506  // wizard screen.
507  CryptohomeLibrary* cryptohome = CryptohomeLibrary::Get();
508  btl->AddLoginTimeMarker("TPMOwn-Start", false);
509  if (cryptohome->TpmIsEnabled() && !cryptohome->TpmIsBeingOwned()) {
510    if (cryptohome->TpmIsOwned()) {
511      cryptohome->TpmClearStoredPassword();
512    } else {
513      cryptohome->TpmCanAttemptOwnership();
514    }
515  }
516  btl->AddLoginTimeMarker("TPMOwn-End", false);
517
518  user_profile->OnLogin();
519
520  // Send the notification before creating the browser so additional objects
521  // that need the profile (e.g. the launcher) can be created first.
522  content::NotificationService::current()->Notify(
523      chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
524      content::NotificationService::AllSources(),
525      content::Details<Profile>(user_profile));
526
527  InitRlzDelayed(user_profile);
528
529  // TODO(altimofeev): This pointer should probably never be NULL, but it looks
530  // like LoginUtilsImpl::OnProfileCreated() may be getting called before
531  // LoginUtilsImpl::PrepareProfile() has set |delegate_| when Chrome is killed
532  // during shutdown in tests -- see http://crosbug.com/18269.  Replace this
533  // 'if' statement with a CHECK(delegate_) once the underlying issue is
534  // resolved.
535  if (delegate_)
536    delegate_->OnProfilePrepared(user_profile);
537}
538
539void LoginUtilsImpl::InitRlzDelayed(Profile* user_profile) {
540#if defined(ENABLE_RLZ)
541  if (!g_browser_process->local_state()->HasPrefPath(prefs::kRLZBrand)) {
542    // Read brand code asynchronously from an OEM file and repost ourselves.
543    google_util::chromeos::SetBrandFromFile(
544        base::Bind(&LoginUtilsImpl::InitRlzDelayed, AsWeakPtr(), user_profile));
545    return;
546  }
547  base::PostTaskAndReplyWithResult(
548      base::WorkerPool::GetTaskRunner(false),
549      FROM_HERE,
550      base::Bind(&file_util::PathExists, GetRlzDisabledFlagPath()),
551      base::Bind(&LoginUtilsImpl::InitRlz, AsWeakPtr(), user_profile));
552#endif
553}
554
555void LoginUtilsImpl::InitRlz(Profile* user_profile, bool disabled) {
556#if defined(ENABLE_RLZ)
557  PrefService* local_state = g_browser_process->local_state();
558  if (disabled) {
559    // Empty brand code means an organic install (no RLZ pings are sent).
560    google_util::chromeos::ClearBrandForCurrentSession();
561  }
562  if (disabled != local_state->GetBoolean(prefs::kRLZDisabled)) {
563    // When switching to RLZ enabled/disabled state, clear all recorded events.
564    RLZTracker::ClearRlzState();
565    local_state->SetBoolean(prefs::kRLZDisabled, disabled);
566  }
567  // Init the RLZ library.
568  int ping_delay = user_profile->GetPrefs()->GetInteger(
569      first_run::GetPingDelayPrefName().c_str());
570  // Negative ping delay means to send ping immediately after a first search is
571  // recorded.
572  RLZTracker::InitRlzFromProfileDelayed(
573      user_profile, UserManager::Get()->IsCurrentUserNew(),
574      ping_delay < 0, base::TimeDelta::FromMilliseconds(abs(ping_delay)));
575  if (delegate_)
576    delegate_->OnRlzInitialized(user_profile);
577#endif
578}
579
580void LoginUtilsImpl::StartSignedInServices(Profile* user_profile) {
581  // Fetch/Create the SigninManager - this will cause the TokenService to load
582  // tokens for the currently signed-in user if the SigninManager hasn't
583  // already been initialized.
584  SigninManagerBase* signin =
585      SigninManagerFactory::GetForProfile(user_profile);
586  DCHECK(signin);
587  // Make sure SigninManager is connected to our current user (this should
588  // happen automatically because we set kGoogleServicesUsername in
589  // OnProfileCreated()).
590  DCHECK_EQ(UserManager::Get()->GetLoggedInUser()->display_email(),
591            signin->GetAuthenticatedUsername());
592  static bool initialized = false;
593  if (!initialized) {
594    initialized = true;
595    // Notify the sync service that signin was successful. Note: Since the sync
596    // service is lazy-initialized, we need to make sure it has been created.
597    ProfileSyncService* sync_service =
598        ProfileSyncServiceFactory::GetInstance()->GetForProfile(user_profile);
599    // We may not always have a passphrase (for example, on a restart after a
600    // browser crash). Only notify the sync service if we have a passphrase,
601    // so it can do any required re-encryption.
602    if (!user_context_.password.empty() && sync_service) {
603      GoogleServiceSigninSuccessDetails details(
604          signin->GetAuthenticatedUsername(),
605          user_context_.password);
606      content::NotificationService::current()->Notify(
607          chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
608          content::Source<Profile>(user_profile),
609          content::Details<const GoogleServiceSigninSuccessDetails>(&details));
610    }
611  }
612  user_context_.password.clear();
613  user_context_.auth_code.clear();
614}
615
616void LoginUtilsImpl::RespectLocalePreference(Profile* profile) {
617  DCHECK(profile != NULL);
618  PrefService* prefs = profile->GetPrefs();
619  DCHECK(prefs != NULL);
620  if (g_browser_process == NULL)
621    return;
622
623  std::string pref_locale = prefs->GetString(prefs::kApplicationLocale);
624  if (pref_locale.empty())
625    pref_locale = prefs->GetString(prefs::kApplicationLocaleBackup);
626  if (pref_locale.empty())
627    pref_locale = g_browser_process->GetApplicationLocale();
628  DCHECK(!pref_locale.empty());
629  profile->ChangeAppLocale(pref_locale, Profile::APP_LOCALE_CHANGED_VIA_LOGIN);
630  // Here we don't enable keyboard layouts. Input methods are set up when
631  // the user first logs in. Then the user may customize the input methods.
632  // Hence changing input methods here, just because the user's UI language
633  // is different from the login screen UI language, is not desirable. Note
634  // that input method preferences are synced, so users can use their
635  // farovite input methods as soon as the preferences are synced.
636  LanguageSwitchMenu::SwitchLanguage(pref_locale);
637}
638
639void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
640  VLOG(1) << "Completing incognito login";
641
642  // For guest session we ask session manager to restart Chrome with --bwsi
643  // flag. We keep only some of the arguments of this process.
644  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
645  CommandLine command_line(browser_command_line.GetProgram());
646  std::string cmd_line_str = GetOffTheRecordCommandLine(start_url,
647                                                        browser_command_line,
648                                                        &command_line);
649
650  RestartChrome(cmd_line_str);
651}
652
653void LoginUtilsImpl::SetFirstLoginPrefs(PrefService* prefs) {
654  VLOG(1) << "Setting first login prefs";
655  BootTimesLoader* btl = BootTimesLoader::Get();
656  std::string locale = g_browser_process->GetApplicationLocale();
657
658  // First, we'll set kLanguagePreloadEngines.
659  input_method::InputMethodManager* manager =
660      input_method::InputMethodManager::Get();
661  std::vector<std::string> input_method_ids;
662  manager->GetInputMethodUtil()->GetFirstLoginInputMethodIds(
663      locale, manager->GetCurrentInputMethod(), &input_method_ids);
664  // Save the input methods in the user's preferences.
665  StringPrefMember language_preload_engines;
666  language_preload_engines.Init(prefs::kLanguagePreloadEngines,
667                                prefs);
668  language_preload_engines.SetValue(JoinString(input_method_ids, ','));
669  btl->AddLoginTimeMarker("IMEStarted", false);
670
671  // Second, we'll set kLanguagePreferredLanguages.
672  std::vector<std::string> language_codes;
673  // The current locale should be on the top.
674  language_codes.push_back(locale);
675
676  // Add input method IDs based on the input methods, as there may be
677  // input methods that are unrelated to the current locale. Example: the
678  // hardware keyboard layout xkb:us::eng is used for logging in, but the
679  // UI language is set to French. In this case, we should set "fr,en"
680  // to the preferred languages preference.
681  std::vector<std::string> candidates;
682  manager->GetInputMethodUtil()->GetLanguageCodesFromInputMethodIds(
683      input_method_ids, &candidates);
684  for (size_t i = 0; i < candidates.size(); ++i) {
685    const std::string& candidate = candidates[i];
686    // Skip if it's already in language_codes.
687    if (std::count(language_codes.begin(), language_codes.end(),
688                   candidate) == 0) {
689      language_codes.push_back(candidate);
690    }
691  }
692  // Save the preferred languages in the user's preferences.
693  StringPrefMember language_preferred_languages;
694  language_preferred_languages.Init(prefs::kLanguagePreferredLanguages,
695                                    prefs);
696  language_preferred_languages.SetValue(JoinString(language_codes, ','));
697}
698
699scoped_refptr<Authenticator> LoginUtilsImpl::CreateAuthenticator(
700    LoginStatusConsumer* consumer) {
701  // Screen locker needs new Authenticator instance each time.
702  if (ScreenLocker::default_screen_locker()) {
703    if (authenticator_.get())
704      authenticator_->SetConsumer(NULL);
705    authenticator_ = NULL;
706  }
707
708  if (authenticator_.get() == NULL) {
709    authenticator_ = new ParallelAuthenticator(consumer);
710  } else {
711    // TODO(nkostylev): Fix this hack by improving Authenticator dependencies.
712    authenticator_->SetConsumer(consumer);
713  }
714  return authenticator_;
715}
716
717void LoginUtilsImpl::RestoreAuthenticationSession(Profile* user_profile) {
718  // We don't need to restore session for demo/guest/stub/public account users.
719  if (!UserManager::Get()->IsUserLoggedIn() ||
720      UserManager::Get()->IsLoggedInAsGuest() ||
721      UserManager::Get()->IsLoggedInAsPublicAccount() ||
722      UserManager::Get()->IsLoggedInAsDemoUser() ||
723      UserManager::Get()->IsLoggedInAsStub()) {
724    return;
725  }
726
727  if (!net::NetworkChangeNotifier::IsOffline()) {
728    should_restore_auth_session_ = false;
729    RestoreAuthSession(user_profile, false);
730  } else {
731    // Even if we're online we should wait till initial
732    // OnConnectionTypeChanged() call. Otherwise starting fetchers too early may
733    // end up cancelling all request when initial network connection type is
734    // processed. See http://crbug.com/121643.
735    should_restore_auth_session_ = true;
736  }
737}
738
739void LoginUtilsImpl::StopBackgroundFetchers() {
740  login_manager_.reset();
741}
742
743void LoginUtilsImpl::OnCompletedAuthentication(Profile* user_profile) {
744  StartSignedInServices(user_profile);
745}
746
747void LoginUtilsImpl::OnCompletedMergeSession() {
748  UserManager::Get()->SetMergeSessionState(UserManager::MERGE_STATUS_DONE);
749}
750
751void LoginUtilsImpl::OnFoundStoredTokens() {
752  // We don't need authenticator instance any more since its cookie jar
753  // is not going to needed to mint OAuth tokens. Reset it so that
754  // ScreenLocker would create a separate instance.
755  authenticator_ = NULL;
756}
757
758void LoginUtilsImpl::OnConnectionTypeChanged(
759    net::NetworkChangeNotifier::ConnectionType type) {
760  if (!login_manager_.get())
761    return;
762
763  if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
764      UserManager::Get()->IsUserLoggedIn()) {
765    if (login_manager_->state() ==
766            OAuthLoginManager::SESSION_RESTORE_IN_PROGRESS) {
767      // If we come online for the first time after successful offline login,
768      // we need to kick off OAuth token verification process again.
769      login_manager_->ContinueSessionRestore();
770    } else if (should_restore_auth_session_) {
771      should_restore_auth_session_ = false;
772      Profile* user_profile = ProfileManager::GetDefaultProfile();
773      RestoreAuthSession(user_profile, has_web_auth_cookies_);
774    }
775  }
776}
777
778// static
779void LoginUtils::RegisterPrefs(PrefRegistrySimple* registry) {
780  registry->RegisterBooleanPref(prefs::kFactoryResetRequested, false);
781  registry->RegisterStringPref(prefs::kRLZBrand, std::string());
782  registry->RegisterBooleanPref(prefs::kRLZDisabled, false);
783}
784
785// static
786LoginUtils* LoginUtils::Get() {
787  return LoginUtilsWrapper::GetInstance()->get();
788}
789
790// static
791void LoginUtils::Set(LoginUtils* mock) {
792  LoginUtilsWrapper::GetInstance()->reset(mock);
793}
794
795// static
796bool LoginUtils::IsWhitelisted(const std::string& username) {
797  CrosSettings* cros_settings = CrosSettings::Get();
798  bool allow_new_user = false;
799  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
800  if (allow_new_user)
801    return true;
802  return cros_settings->FindEmailInList(kAccountsPrefUsers, username);
803}
804
805}  // namespace chromeos
806