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.
5 #include "chrome/browser/chromeos/login/login_utils.h"
11 #include "base/base_paths.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/location.h"
20 #include "base/memory/ref_counted.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/memory/singleton.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/prefs/pref_member.h"
25 #include "base/prefs/pref_service.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/synchronization/lock.h"
29 #include "base/sys_info.h"
30 #include "base/task_runner_util.h"
31 #include "base/threading/worker_pool.h"
32 #include "base/time/time.h"
33 #include "chrome/browser/about_flags.h"
34 #include "chrome/browser/app_mode/app_mode_utils.h"
35 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/browser_shutdown.h"
37 #include "chrome/browser/chrome_notification_types.h"
38 #include "chrome/browser/chromeos/boot_times_loader.h"
39 #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h"
40 #include "chrome/browser/chromeos/login/chrome_restart_request.h"
41 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
42 #include "chrome/browser/chromeos/login/existing_user_controller.h"
43 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
44 #include "chrome/browser/chromeos/login/profile_auth_data.h"
45 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h"
46 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter_factory.h"
47 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
48 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
49 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h"
50 #include "chrome/browser/chromeos/login/startup_utils.h"
51 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
52 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
53 #include "chrome/browser/chromeos/login/user_flow.h"
54 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
55 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
56 #include "chrome/browser/chromeos/profiles/profile_helper.h"
57 #include "chrome/browser/chromeos/settings/cros_settings.h"
58 #include "chrome/browser/extensions/extension_service.h"
59 #include "chrome/browser/first_run/first_run.h"
60 #include "chrome/browser/google/google_brand_chromeos.h"
61 #include "chrome/browser/lifetime/application_lifetime.h"
62 #include "chrome/browser/pref_service_flags_storage.h"
63 #include "chrome/browser/profiles/profile.h"
64 #include "chrome/browser/profiles/profile_manager.h"
65 #include "chrome/browser/rlz/rlz.h"
66 #include "chrome/browser/signin/signin_manager_factory.h"
67 #include "chrome/browser/sync/profile_sync_service.h"
68 #include "chrome/browser/sync/profile_sync_service_factory.h"
69 #include "chrome/browser/ui/app_list/start_page_service.h"
70 #include "chrome/browser/ui/startup/startup_browser_creator.h"
71 #include "chrome/common/chrome_switches.h"
72 #include "chrome/common/logging_chrome.h"
73 #include "chrome/common/pref_names.h"
74 #include "chromeos/chromeos_switches.h"
75 #include "chromeos/cryptohome/cryptohome_util.h"
76 #include "chromeos/dbus/cryptohome_client.h"
77 #include "chromeos/dbus/dbus_method_call_status.h"
78 #include "chromeos/dbus/dbus_thread_manager.h"
79 #include "chromeos/dbus/session_manager_client.h"
80 #include "chromeos/login/auth/user_context.h"
81 #include "chromeos/login/user_names.h"
82 #include "chromeos/settings/cros_settings_names.h"
83 #include "components/signin/core/browser/signin_manager.h"
84 #include "components/user_manager/user.h"
85 #include "components/user_manager/user_manager.h"
86 #include "content/public/browser/browser_thread.h"
87 #include "content/public/browser/notification_service.h"
88 #include "google_apis/gaia/gaia_auth_consumer.h"
89 #include "net/base/network_change_notifier.h"
90 #include "net/url_request/url_request_context.h"
91 #include "net/url_request/url_request_context_getter.h"
94 #if defined(USE_ATHENA)
95 #include "athena/extensions/public/extensions_delegate.h"
96 #include "athena/main/public/athena_launcher.h"
99 using content::BrowserThread;
103 void LogCustomSwitches(const std::set<std::string>& switches) {
106 for (std::set<std::string>::const_iterator it = switches.begin();
107 it != switches.end();
109 VLOG(1) << "Switch leading to restart: '" << *it << "'";
113 } // anonymous namespace
119 // Returns new CommandLine with per-user flags.
120 CommandLine CreatePerSessionCommandLine(Profile* profile) {
121 CommandLine user_flags(CommandLine::NO_PROGRAM);
122 about_flags::PrefServiceFlagsStorage flags_storage_(profile->GetPrefs());
123 about_flags::ConvertFlagsToSwitches(
124 &flags_storage_, &user_flags, about_flags::kAddSentinels);
128 // Returns true if restart is needed to apply per-session flags.
129 bool NeedRestartToApplyPerSessionFlags(
130 const CommandLine& user_flags,
131 std::set<CommandLine::StringType>* out_command_line_difference) {
132 // Don't restart browser if it is not first profile in session.
133 if (user_manager::UserManager::Get()->GetLoggedInUsers().size() != 1)
136 // Only restart if needed and if not going into managed mode.
137 if (user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser())
140 if (about_flags::AreSwitchesIdenticalToCurrentCommandLine(
142 *CommandLine::ForCurrentProcess(),
143 out_command_line_difference)) {
150 bool CanPerformEarlyRestart() {
151 // Desktop build is used for development only. Early restart is not supported.
152 if (!base::SysInfo::IsRunningOnChromeOS())
155 if (!ChromeUserManager::Get()->GetCurrentUserFlow()->
156 SupportsEarlyRestartToApplyFlags()) {
160 const ExistingUserController* controller =
161 ExistingUserController::current_controller();
165 // Early restart is possible only if OAuth token is up to date.
167 if (controller->password_changed())
170 if (controller->auth_mode() != LoginPerformer::AUTH_MODE_INTERNAL)
173 // No early restart if Easy unlock key needs to be updated.
174 if (UserSessionManager::GetInstance()->NeedsToUpdateEasyUnlockKeys())
182 class LoginUtilsImpl : public LoginUtils,
183 public base::SupportsWeakPtr<LoginUtilsImpl>,
184 public UserSessionManagerDelegate {
190 virtual ~LoginUtilsImpl() {
193 // LoginUtils implementation:
194 virtual void RespectLocalePreference(Profile* profile,
195 const base::Closure& callback) OVERRIDE;
196 virtual void DoBrowserLaunch(Profile* profile,
197 LoginDisplayHost* login_host) OVERRIDE;
198 virtual void PrepareProfile(
199 const UserContext& user_context,
200 bool has_auth_cookies,
201 bool has_active_session,
202 LoginUtils::Delegate* delegate) OVERRIDE;
203 virtual void DelegateDeleted(LoginUtils::Delegate* delegate) OVERRIDE;
204 virtual void CompleteOffTheRecordLogin(const GURL& start_url) OVERRIDE;
205 virtual scoped_refptr<Authenticator> CreateAuthenticator(
206 AuthStatusConsumer* consumer) OVERRIDE;
207 virtual bool RestartToApplyPerSessionFlagsIfNeed(Profile* profile,
208 bool early_restart) OVERRIDE;
210 // UserSessionManager::Delegate implementation:
211 virtual void OnProfilePrepared(Profile* profile) OVERRIDE;
212 #if defined(ENABLE_RLZ)
213 virtual void OnRlzInitialized() OVERRIDE;
217 void DoBrowserLaunchInternal(Profile* profile,
218 LoginDisplayHost* login_host,
219 bool locale_pref_checked);
221 static void RunCallbackOnLocaleLoaded(
222 const base::Closure& callback,
223 InputEventsBlocker* input_events_blocker,
224 const std::string& locale,
225 const std::string& loaded_locale,
228 // Attempts restarting the browser process and esures that this does
229 // not happen while we are still fetching new OAuth refresh tokens.
230 void AttemptRestart(Profile* profile);
232 // Has to be scoped_refptr, see comment for CreateAuthenticator(...).
233 scoped_refptr<Authenticator> authenticator_;
235 // Delegate to be fired when the profile will be prepared.
236 LoginUtils::Delegate* delegate_;
238 DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl);
241 class LoginUtilsWrapper {
243 static LoginUtilsWrapper* GetInstance() {
244 return Singleton<LoginUtilsWrapper>::get();
248 base::AutoLock create(create_lock_);
250 reset(new LoginUtilsImpl);
254 void reset(LoginUtils* ptr) {
259 friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
261 LoginUtilsWrapper() {}
263 base::Lock create_lock_;
264 scoped_ptr<LoginUtils> ptr_;
266 DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
269 void LoginUtilsImpl::DoBrowserLaunchInternal(Profile* profile,
270 LoginDisplayHost* login_host,
271 bool locale_pref_checked) {
272 if (browser_shutdown::IsTryingToQuit())
275 if (!locale_pref_checked) {
276 RespectLocalePreference(profile,
277 base::Bind(&LoginUtilsImpl::DoBrowserLaunchInternal,
278 base::Unretained(this),
281 true /* locale_pref_checked */));
285 if (!ChromeUserManager::Get()->GetCurrentUserFlow()->ShouldLaunchBrowser()) {
286 ChromeUserManager::Get()->GetCurrentUserFlow()->LaunchExtraSteps(profile);
290 if (RestartToApplyPerSessionFlagsIfNeed(profile, false))
294 login_host->SetStatusAreaVisible(true);
295 login_host->BeforeSessionStart();
298 BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false);
300 VLOG(1) << "Launching browser...";
301 TRACE_EVENT0("login", "LaunchBrowser");
303 #if defined(USE_ATHENA)
304 athena::ExtensionsDelegate::CreateExtensionsDelegateForChrome(profile);
305 athena::StartAthenaSessionWithContext(profile);
307 StartupBrowserCreator browser_creator;
309 chrome::startup::IsFirstRun first_run = first_run::IsChromeFirstRun() ?
310 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
312 browser_creator.LaunchBrowser(*CommandLine::ForCurrentProcess(),
315 chrome::startup::IS_PROCESS_STARTUP,
319 // Triggers app launcher start page service to load start page web contents.
320 app_list::StartPageService::Get(profile);
323 // Mark login host for deletion after browser starts. This
324 // guarantees that the message loop will be referenced by the
325 // browser before it is dereferenced by the login host.
327 login_host->Finalize();
328 user_manager::UserManager::Get()->SessionStarted();
329 chromeos::BootTimesLoader::Get()->LoginDone(
330 user_manager::UserManager::Get()->IsCurrentUserNew());
334 void LoginUtilsImpl::RunCallbackOnLocaleLoaded(
335 const base::Closure& callback,
336 InputEventsBlocker* /* input_events_blocker */,
337 const std::string& /* locale */,
338 const std::string& /* loaded_locale */,
339 const bool /* success */) {
343 void LoginUtilsImpl::RespectLocalePreference(Profile* profile,
344 const base::Closure& callback) {
345 if (browser_shutdown::IsTryingToQuit())
348 user_manager::User* const user =
349 ProfileHelper::Get()->GetUserByProfile(profile);
350 scoped_ptr<locale_util::SwitchLanguageCallback> locale_switched_callback(
351 new locale_util::SwitchLanguageCallback(base::Bind(
352 &LoginUtilsImpl::RunCallbackOnLocaleLoaded,
354 base::Owned(new InputEventsBlocker)))); // Block UI events until
355 // the ResourceBundle is
357 if (!UserSessionManager::GetInstance()->RespectLocalePreference(
360 locale_switched_callback.Pass())) {
365 void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
366 LoginDisplayHost* login_host) {
367 DoBrowserLaunchInternal(profile, login_host, false /* locale_pref_checked */);
370 void LoginUtilsImpl::PrepareProfile(
371 const UserContext& user_context,
372 bool has_auth_cookies,
373 bool has_active_session,
374 LoginUtils::Delegate* delegate) {
375 // TODO(nkostylev): We have to initialize LoginUtils delegate as long
376 // as it coexist with SessionManager.
377 delegate_ = delegate;
379 // For the transition part LoginUtils will just delegate profile
380 // creation and initialization to SessionManager. Later LoginUtils will be
381 // removed and all LoginUtils clients will just work with SessionManager
383 UserSessionManager::GetInstance()->StartSession(
384 user_context, authenticator_, has_auth_cookies, has_active_session, this);
387 void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) {
388 if (delegate_ == delegate)
392 bool LoginUtilsImpl::RestartToApplyPerSessionFlagsIfNeed(Profile* profile,
393 bool early_restart) {
394 if (ProfileHelper::IsSigninProfile(profile))
397 if (early_restart && !CanPerformEarlyRestart())
400 const CommandLine user_flags(CreatePerSessionCommandLine(profile));
401 std::set<CommandLine::StringType> command_line_difference;
402 if (!NeedRestartToApplyPerSessionFlags(user_flags, &command_line_difference))
405 LogCustomSwitches(command_line_difference);
407 about_flags::ReportCustomFlags("Login.CustomFlags", command_line_difference);
409 CommandLine::StringVector flags;
410 // argv[0] is the program name |CommandLine::NO_PROGRAM|.
411 flags.assign(user_flags.argv().begin() + 1, user_flags.argv().end());
412 LOG(WARNING) << "Restarting to apply per-session flags...";
413 DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser(
414 user_manager::UserManager::Get()->GetActiveUser()->email(), flags);
415 AttemptRestart(profile);
419 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) {
420 VLOG(1) << "Completing incognito login";
422 // For guest session we ask session manager to restart Chrome with --bwsi
423 // flag. We keep only some of the arguments of this process.
424 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
425 CommandLine command_line(browser_command_line.GetProgram());
426 std::string cmd_line_str =
427 GetOffTheRecordCommandLine(start_url,
428 StartupUtils::IsOobeCompleted(),
429 browser_command_line,
432 // This makes sure that Chrome restarts with no per-session flags. The guest
433 // profile will always have empty set of per-session flags. If this is not
434 // done and device owner has some per-session flags, when Chrome is relaunched
435 // the guest profile session flags will not match the current command line and
436 // another restart will be attempted in order to reset the user flags for the
438 const CommandLine user_flags(CommandLine::NO_PROGRAM);
439 if (!about_flags::AreSwitchesIdenticalToCurrentCommandLine(
441 *CommandLine::ForCurrentProcess(),
443 DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser(
444 chromeos::login::kGuestUserName,
445 CommandLine::StringVector());
448 RestartChrome(cmd_line_str);
451 scoped_refptr<Authenticator> LoginUtilsImpl::CreateAuthenticator(
452 AuthStatusConsumer* consumer) {
453 // Screen locker needs new Authenticator instance each time.
454 if (ScreenLocker::default_screen_locker()) {
455 if (authenticator_.get())
456 authenticator_->SetConsumer(NULL);
457 authenticator_ = NULL;
460 if (authenticator_.get() == NULL) {
461 authenticator_ = new ChromeCryptohomeAuthenticator(consumer);
463 // TODO(nkostylev): Fix this hack by improving Authenticator dependencies.
464 authenticator_->SetConsumer(consumer);
466 return authenticator_;
469 void LoginUtilsImpl::OnProfilePrepared(Profile* profile) {
471 delegate_->OnProfilePrepared(profile);
474 #if defined(ENABLE_RLZ)
475 void LoginUtilsImpl::OnRlzInitialized() {
477 delegate_->OnRlzInitialized();
481 void LoginUtilsImpl::AttemptRestart(Profile* profile) {
482 if (UserSessionManager::GetInstance()
483 ->CheckEasyUnlockKeyOps(
484 base::Bind(&LoginUtilsImpl::AttemptRestart,
485 base::Unretained(this),
490 if (UserSessionManager::GetInstance()->GetSigninSessionRestoreStrategy() !=
491 OAuth2LoginManager::RESTORE_FROM_COOKIE_JAR) {
492 chrome::AttemptRestart();
496 // We can't really quit if the session restore process that mints new
497 // refresh token is still in progress.
498 OAuth2LoginManager* login_manager =
499 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile);
500 if (login_manager->state() !=
501 OAuth2LoginManager::SESSION_RESTORE_PREPARING &&
502 login_manager->state() !=
503 OAuth2LoginManager::SESSION_RESTORE_IN_PROGRESS) {
504 chrome::AttemptRestart();
508 LOG(WARNING) << "Attempting browser restart during session restore.";
509 UserSessionManager::GetInstance()->set_exit_after_session_restore(true);
513 LoginUtils* LoginUtils::Get() {
514 return LoginUtilsWrapper::GetInstance()->get();
518 void LoginUtils::Set(LoginUtils* mock) {
519 LoginUtilsWrapper::GetInstance()->reset(mock);
523 bool LoginUtils::IsWhitelisted(const std::string& username,
524 bool* wildcard_match) {
525 // Skip whitelist check for tests.
526 if (CommandLine::ForCurrentProcess()->HasSwitch(
527 chromeos::switches::kOobeSkipPostLogin)) {
531 CrosSettings* cros_settings = CrosSettings::Get();
532 bool allow_new_user = false;
533 cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
536 return cros_settings->FindEmailInList(
537 kAccountsPrefUsers, username, wildcard_match);
540 } // namespace chromeos