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/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" 92 #include "url/gurl.h" 93 94 #if defined(USE_ATHENA) 95 #include "athena/extensions/public/extensions_delegate.h" 96 #include "athena/main/public/athena_launcher.h" 97 #endif 98 99 using content::BrowserThread; 100 101 namespace { 102 103 void LogCustomSwitches(const std::set<std::string>& switches) { 104 if (!VLOG_IS_ON(1)) 105 return; 106 for (std::set<std::string>::const_iterator it = switches.begin(); 107 it != switches.end(); 108 ++it) { 109 VLOG(1) << "Switch leading to restart: '" << *it << "'"; 110 } 111 } 112 113 } // anonymous namespace 114 115 namespace chromeos { 116 117 namespace { 118 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); 125 return user_flags; 126 } 127 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) 134 return false; 135 136 // Only restart if needed and if not going into managed mode. 137 if (user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) 138 return false; 139 140 if (about_flags::AreSwitchesIdenticalToCurrentCommandLine( 141 user_flags, 142 *CommandLine::ForCurrentProcess(), 143 out_command_line_difference)) { 144 return false; 145 } 146 147 return true; 148 } 149 150 bool CanPerformEarlyRestart() { 151 // Desktop build is used for development only. Early restart is not supported. 152 if (!base::SysInfo::IsRunningOnChromeOS()) 153 return false; 154 155 if (!ChromeUserManager::Get()->GetCurrentUserFlow()-> 156 SupportsEarlyRestartToApplyFlags()) { 157 return false; 158 } 159 160 const ExistingUserController* controller = 161 ExistingUserController::current_controller(); 162 if (!controller) 163 return true; 164 165 // Early restart is possible only if OAuth token is up to date. 166 167 if (controller->password_changed()) 168 return false; 169 170 if (controller->auth_mode() != LoginPerformer::AUTH_MODE_INTERNAL) 171 return false; 172 173 // No early restart if Easy unlock key needs to be updated. 174 if (UserSessionManager::GetInstance()->NeedsToUpdateEasyUnlockKeys()) 175 return false; 176 177 return true; 178 } 179 180 } // namespace 181 182 class LoginUtilsImpl : public LoginUtils, 183 public base::SupportsWeakPtr<LoginUtilsImpl>, 184 public UserSessionManagerDelegate { 185 public: 186 LoginUtilsImpl() 187 : delegate_(NULL) { 188 } 189 190 virtual ~LoginUtilsImpl() { 191 } 192 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; 209 210 // UserSessionManager::Delegate implementation: 211 virtual void OnProfilePrepared(Profile* profile) OVERRIDE; 212 #if defined(ENABLE_RLZ) 213 virtual void OnRlzInitialized() OVERRIDE; 214 #endif 215 216 private: 217 void DoBrowserLaunchInternal(Profile* profile, 218 LoginDisplayHost* login_host, 219 bool locale_pref_checked); 220 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, 226 const bool success); 227 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); 231 232 // Has to be scoped_refptr, see comment for CreateAuthenticator(...). 233 scoped_refptr<Authenticator> authenticator_; 234 235 // Delegate to be fired when the profile will be prepared. 236 LoginUtils::Delegate* delegate_; 237 238 DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl); 239 }; 240 241 class LoginUtilsWrapper { 242 public: 243 static LoginUtilsWrapper* GetInstance() { 244 return Singleton<LoginUtilsWrapper>::get(); 245 } 246 247 LoginUtils* get() { 248 base::AutoLock create(create_lock_); 249 if (!ptr_.get()) 250 reset(new LoginUtilsImpl); 251 return ptr_.get(); 252 } 253 254 void reset(LoginUtils* ptr) { 255 ptr_.reset(ptr); 256 } 257 258 private: 259 friend struct DefaultSingletonTraits<LoginUtilsWrapper>; 260 261 LoginUtilsWrapper() {} 262 263 base::Lock create_lock_; 264 scoped_ptr<LoginUtils> ptr_; 265 266 DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper); 267 }; 268 269 void LoginUtilsImpl::DoBrowserLaunchInternal(Profile* profile, 270 LoginDisplayHost* login_host, 271 bool locale_pref_checked) { 272 if (browser_shutdown::IsTryingToQuit()) 273 return; 274 275 if (!locale_pref_checked) { 276 RespectLocalePreference(profile, 277 base::Bind(&LoginUtilsImpl::DoBrowserLaunchInternal, 278 base::Unretained(this), 279 profile, 280 login_host, 281 true /* locale_pref_checked */)); 282 return; 283 } 284 285 if (!ChromeUserManager::Get()->GetCurrentUserFlow()->ShouldLaunchBrowser()) { 286 ChromeUserManager::Get()->GetCurrentUserFlow()->LaunchExtraSteps(profile); 287 return; 288 } 289 290 if (RestartToApplyPerSessionFlagsIfNeed(profile, false)) 291 return; 292 293 if (login_host) { 294 login_host->SetStatusAreaVisible(true); 295 login_host->BeforeSessionStart(); 296 } 297 298 BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false); 299 300 VLOG(1) << "Launching browser..."; 301 TRACE_EVENT0("login", "LaunchBrowser"); 302 303 #if defined(USE_ATHENA) 304 athena::ExtensionsDelegate::CreateExtensionsDelegateForChrome(profile); 305 athena::StartAthenaSessionWithContext(profile); 306 #else 307 StartupBrowserCreator browser_creator; 308 int return_code; 309 chrome::startup::IsFirstRun first_run = first_run::IsChromeFirstRun() ? 310 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN; 311 312 browser_creator.LaunchBrowser(*CommandLine::ForCurrentProcess(), 313 profile, 314 base::FilePath(), 315 chrome::startup::IS_PROCESS_STARTUP, 316 first_run, 317 &return_code); 318 319 // Triggers app launcher start page service to load start page web contents. 320 app_list::StartPageService::Get(profile); 321 #endif 322 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. 326 if (login_host) 327 login_host->Finalize(); 328 user_manager::UserManager::Get()->SessionStarted(); 329 chromeos::BootTimesLoader::Get()->LoginDone( 330 user_manager::UserManager::Get()->IsCurrentUserNew()); 331 } 332 333 // static 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 */) { 340 callback.Run(); 341 } 342 343 void LoginUtilsImpl::RespectLocalePreference(Profile* profile, 344 const base::Closure& callback) { 345 if (browser_shutdown::IsTryingToQuit()) 346 return; 347 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, 353 callback, 354 base::Owned(new InputEventsBlocker)))); // Block UI events until 355 // the ResourceBundle is 356 // reloaded. 357 if (!UserSessionManager::GetInstance()->RespectLocalePreference( 358 profile, 359 user, 360 locale_switched_callback.Pass())) { 361 callback.Run(); 362 } 363 } 364 365 void LoginUtilsImpl::DoBrowserLaunch(Profile* profile, 366 LoginDisplayHost* login_host) { 367 DoBrowserLaunchInternal(profile, login_host, false /* locale_pref_checked */); 368 } 369 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; 378 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 382 // directly. 383 UserSessionManager::GetInstance()->StartSession( 384 user_context, authenticator_, has_auth_cookies, has_active_session, this); 385 } 386 387 void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) { 388 if (delegate_ == delegate) 389 delegate_ = NULL; 390 } 391 392 bool LoginUtilsImpl::RestartToApplyPerSessionFlagsIfNeed(Profile* profile, 393 bool early_restart) { 394 if (ProfileHelper::IsSigninProfile(profile)) 395 return false; 396 397 if (early_restart && !CanPerformEarlyRestart()) 398 return false; 399 400 const CommandLine user_flags(CreatePerSessionCommandLine(profile)); 401 std::set<CommandLine::StringType> command_line_difference; 402 if (!NeedRestartToApplyPerSessionFlags(user_flags, &command_line_difference)) 403 return false; 404 405 LogCustomSwitches(command_line_difference); 406 407 about_flags::ReportCustomFlags("Login.CustomFlags", command_line_difference); 408 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); 416 return true; 417 } 418 419 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) { 420 VLOG(1) << "Completing incognito login"; 421 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, 430 &command_line); 431 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 437 // guest user. 438 const CommandLine user_flags(CommandLine::NO_PROGRAM); 439 if (!about_flags::AreSwitchesIdenticalToCurrentCommandLine( 440 user_flags, 441 *CommandLine::ForCurrentProcess(), 442 NULL)) { 443 DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser( 444 chromeos::login::kGuestUserName, 445 CommandLine::StringVector()); 446 } 447 448 RestartChrome(cmd_line_str); 449 } 450 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; 458 } 459 460 if (authenticator_.get() == NULL) { 461 authenticator_ = new ChromeCryptohomeAuthenticator(consumer); 462 } else { 463 // TODO(nkostylev): Fix this hack by improving Authenticator dependencies. 464 authenticator_->SetConsumer(consumer); 465 } 466 return authenticator_; 467 } 468 469 void LoginUtilsImpl::OnProfilePrepared(Profile* profile) { 470 if (delegate_) 471 delegate_->OnProfilePrepared(profile); 472 } 473 474 #if defined(ENABLE_RLZ) 475 void LoginUtilsImpl::OnRlzInitialized() { 476 if (delegate_) 477 delegate_->OnRlzInitialized(); 478 } 479 #endif 480 481 void LoginUtilsImpl::AttemptRestart(Profile* profile) { 482 if (UserSessionManager::GetInstance() 483 ->CheckEasyUnlockKeyOps( 484 base::Bind(&LoginUtilsImpl::AttemptRestart, 485 base::Unretained(this), 486 profile))) { 487 return; 488 } 489 490 if (UserSessionManager::GetInstance()->GetSigninSessionRestoreStrategy() != 491 OAuth2LoginManager::RESTORE_FROM_COOKIE_JAR) { 492 chrome::AttemptRestart(); 493 return; 494 } 495 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(); 505 return; 506 } 507 508 LOG(WARNING) << "Attempting browser restart during session restore."; 509 UserSessionManager::GetInstance()->set_exit_after_session_restore(true); 510 } 511 512 // static 513 LoginUtils* LoginUtils::Get() { 514 return LoginUtilsWrapper::GetInstance()->get(); 515 } 516 517 // static 518 void LoginUtils::Set(LoginUtils* mock) { 519 LoginUtilsWrapper::GetInstance()->reset(mock); 520 } 521 522 // static 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)) { 528 return true; 529 } 530 531 CrosSettings* cros_settings = CrosSettings::Get(); 532 bool allow_new_user = false; 533 cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user); 534 if (allow_new_user) 535 return true; 536 return cros_settings->FindEmailInList( 537 kAccountsPrefUsers, username, wildcard_match); 538 } 539 540 } // namespace chromeos 541