1 // Copyright (c) 2011 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 <vector> 8 9 #include "base/command_line.h" 10 #include "base/file_path.h" 11 #include "base/file_util.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/singleton.h" 14 #include "base/path_service.h" 15 #include "base/string_util.h" 16 #include "base/stringprintf.h" 17 #include "base/synchronization/lock.h" 18 #include "base/threading/thread_restrictions.h" 19 #include "base/time.h" 20 #include "base/utf_string_conversions.h" 21 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/chromeos/boot_times_loader.h" 23 #include "chrome/browser/chromeos/cros/login_library.h" 24 #include "chrome/browser/chromeos/cros/network_library.h" 25 #include "chrome/browser/chromeos/input_method/input_method_util.h" 26 #include "chrome/browser/chromeos/login/background_view.h" 27 #include "chrome/browser/chromeos/login/cookie_fetcher.h" 28 #include "chrome/browser/chromeos/login/google_authenticator.h" 29 #include "chrome/browser/chromeos/login/language_switch_menu.h" 30 #include "chrome/browser/chromeos/login/ownership_service.h" 31 #include "chrome/browser/chromeos/login/parallel_authenticator.h" 32 #include "chrome/browser/chromeos/login/user_image_downloader.h" 33 #include "chrome/browser/chromeos/login/user_manager.h" 34 #include "chrome/browser/chromeos/proxy_config_service.h" 35 #include "chrome/browser/extensions/extension_service.h" 36 #include "chrome/browser/net/chrome_url_request_context.h" 37 #include "chrome/browser/net/gaia/token_service.h" 38 #include "chrome/browser/net/preconnect.h" 39 #include "chrome/browser/net/pref_proxy_config_service.h" 40 #include "chrome/browser/plugin_updater.h" 41 #include "chrome/browser/prefs/pref_member.h" 42 #include "chrome/browser/profiles/profile.h" 43 #include "chrome/browser/profiles/profile_manager.h" 44 #include "chrome/browser/sync/profile_sync_service.h" 45 #include "chrome/browser/ui/browser_init.h" 46 #include "chrome/common/chrome_paths.h" 47 #include "chrome/common/chrome_switches.h" 48 #include "chrome/common/logging_chrome.h" 49 #include "chrome/common/net/gaia/gaia_auth_fetcher.h" 50 #include "chrome/common/net/gaia/gaia_constants.h" 51 #include "chrome/common/pref_names.h" 52 #include "chrome/common/url_constants.h" 53 #include "content/browser/browser_thread.h" 54 #include "googleurl/src/gurl.h" 55 #include "net/base/cookie_store.h" 56 #include "net/proxy/proxy_config_service.h" 57 #include "net/url_request/url_request_context.h" 58 #include "net/url_request/url_request_context_getter.h" 59 #include "views/widget/widget_gtk.h" 60 #include "ui/gfx/gl/gl_switches.h" 61 62 namespace chromeos { 63 64 namespace { 65 66 // Affixes for Auth token received from ClientLogin request. 67 const char kAuthPrefix[] = "Auth="; 68 const char kAuthSuffix[] = "\n"; 69 70 // Increase logging level for Guest mode to avoid LOG(INFO) messages in logs. 71 const char kGuestModeLoggingLevel[] = "1"; 72 73 // Format of command line switch. 74 const char kSwitchFormatString[] = " --%s=\"%s\""; 75 76 // User name which is used in the Guest session. 77 const char kGuestUserName[] = ""; 78 79 // Resets the proxy configuration service for the default request context. 80 class ResetDefaultProxyConfigServiceTask : public Task { 81 public: 82 ResetDefaultProxyConfigServiceTask( 83 net::ProxyConfigService* proxy_config_service) 84 : proxy_config_service_(proxy_config_service) {} 85 virtual ~ResetDefaultProxyConfigServiceTask() {} 86 87 // Task override. 88 virtual void Run() { 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 90 net::URLRequestContextGetter* getter = Profile::GetDefaultRequestContext(); 91 DCHECK(getter); 92 if (getter) { 93 getter->GetURLRequestContext()->proxy_service()->ResetConfigService( 94 proxy_config_service_.release()); 95 } 96 } 97 98 private: 99 scoped_ptr<net::ProxyConfigService> proxy_config_service_; 100 101 DISALLOW_COPY_AND_ASSIGN(ResetDefaultProxyConfigServiceTask); 102 }; 103 104 } // namespace 105 106 class LoginUtilsImpl : public LoginUtils, 107 public ProfileManager::Observer { 108 public: 109 LoginUtilsImpl() 110 : background_view_(NULL) { 111 } 112 113 virtual void PrepareProfile( 114 const std::string& username, 115 const std::string& password, 116 const GaiaAuthConsumer::ClientLoginResult& credentials, 117 bool pending_requests, 118 LoginUtils::Delegate* delegate); 119 120 // Invoked after the tmpfs is successfully mounted. 121 // Launches a browser in the incognito mode. 122 virtual void CompleteOffTheRecordLogin(const GURL& start_url); 123 124 // Invoked when the user is logging in for the first time, or is logging in as 125 // a guest user. 126 virtual void SetFirstLoginPrefs(PrefService* prefs); 127 128 // Creates and returns the authenticator to use. The caller owns the returned 129 // Authenticator and must delete it when done. 130 virtual Authenticator* CreateAuthenticator(LoginStatusConsumer* consumer); 131 132 // Warms the url used by authentication. 133 virtual void PrewarmAuthentication(); 134 135 // Given the credentials try to exchange them for 136 // full-fledged Google authentication cookies. 137 virtual void FetchCookies( 138 Profile* profile, 139 const GaiaAuthConsumer::ClientLoginResult& credentials); 140 141 // Supply credentials for sync and others to use. 142 virtual void FetchTokens( 143 Profile* profile, 144 const GaiaAuthConsumer::ClientLoginResult& credentials); 145 146 // Sets the current background view. 147 virtual void SetBackgroundView(chromeos::BackgroundView* background_view); 148 149 // Gets the current background view. 150 virtual chromeos::BackgroundView* GetBackgroundView(); 151 152 // ProfileManager::Observer implementation: 153 virtual void OnProfileCreated(Profile* profile); 154 155 protected: 156 virtual std::string GetOffTheRecordCommandLine( 157 const GURL& start_url, 158 const CommandLine& base_command_line, 159 CommandLine *command_line); 160 161 private: 162 // Check user's profile for kApplicationLocale setting. 163 void RespectLocalePreference(Profile* pref); 164 165 // The current background view. 166 chromeos::BackgroundView* background_view_; 167 168 std::string username_; 169 std::string password_; 170 GaiaAuthConsumer::ClientLoginResult credentials_; 171 bool pending_requests_; 172 173 // Delegate to be fired when the profile will be prepared. 174 LoginUtils::Delegate* delegate_; 175 176 DISALLOW_COPY_AND_ASSIGN(LoginUtilsImpl); 177 }; 178 179 class LoginUtilsWrapper { 180 public: 181 static LoginUtilsWrapper* GetInstance() { 182 return Singleton<LoginUtilsWrapper>::get(); 183 } 184 185 LoginUtils* get() { 186 base::AutoLock create(create_lock_); 187 if (!ptr_.get()) 188 reset(new LoginUtilsImpl); 189 return ptr_.get(); 190 } 191 192 void reset(LoginUtils* ptr) { 193 ptr_.reset(ptr); 194 } 195 196 private: 197 friend struct DefaultSingletonTraits<LoginUtilsWrapper>; 198 199 LoginUtilsWrapper() {} 200 201 base::Lock create_lock_; 202 scoped_ptr<LoginUtils> ptr_; 203 204 DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper); 205 }; 206 207 void LoginUtilsImpl::PrepareProfile( 208 const std::string& username, 209 const std::string& password, 210 const GaiaAuthConsumer::ClientLoginResult& credentials, 211 bool pending_requests, 212 LoginUtils::Delegate* delegate) { 213 BootTimesLoader* btl = BootTimesLoader::Get(); 214 215 VLOG(1) << "Completing login for " << username; 216 btl->AddLoginTimeMarker("CompletingLogin", false); 217 218 if (CrosLibrary::Get()->EnsureLoaded()) { 219 CrosLibrary::Get()->GetLoginLibrary()->StartSession(username, ""); 220 btl->AddLoginTimeMarker("StartedSession", false); 221 } 222 223 UserManager::Get()->UserLoggedIn(username); 224 btl->AddLoginTimeMarker("UserLoggedIn", false); 225 226 // Switch log file as soon as possible. 227 logging::RedirectChromeLogging(*(CommandLine::ForCurrentProcess())); 228 btl->AddLoginTimeMarker("LoggingRedirected", false); 229 230 username_ = username; 231 password_ = password; 232 credentials_ = credentials; 233 pending_requests_ = pending_requests; 234 delegate_ = delegate; 235 236 // The default profile will have been changed because the ProfileManager 237 // will process the notification that the UserManager sends out. 238 ProfileManager::CreateDefaultProfileAsync(this); 239 } 240 241 void LoginUtilsImpl::OnProfileCreated(Profile* profile) { 242 CHECK(profile); 243 244 BootTimesLoader* btl = BootTimesLoader::Get(); 245 btl->AddLoginTimeMarker("UserProfileGotten", false); 246 247 // Change the proxy configuration service of the default request context to 248 // use the preference configuration from the logged-in profile. This ensures 249 // that requests done through the default context use the proxy configuration 250 // provided by configuration policy. 251 // 252 // Note: Many of the clients of the default request context should probably be 253 // fixed to use the request context of the profile they are associated with. 254 // This includes preconnect, autofill, metrics service to only name a few; 255 // see http://code.google.com/p/chromium/issues/detail?id=64339 for details. 256 // 257 // TODO(mnissler) Revisit when support for device-specific policy arrives, at 258 // which point the default request context can directly be managed through 259 // device policy. 260 net::ProxyConfigService* proxy_config_service = 261 new PrefProxyConfigService( 262 profile->GetProxyConfigTracker(), 263 new chromeos::ProxyConfigService( 264 g_browser_process->chromeos_proxy_config_service_impl())); 265 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 266 new ResetDefaultProxyConfigServiceTask( 267 proxy_config_service)); 268 269 // Since we're doing parallel authentication, only new user sign in 270 // would perform online auth before calling PrepareProfile. 271 // For existing users there's usually a pending online auth request. 272 // Cookies will be fetched after it's is succeeded. 273 if (!pending_requests_) { 274 FetchCookies(profile, credentials_); 275 } 276 277 // Init extension event routers; this normally happens in browser_main 278 // but on Chrome OS it has to be deferred until the user finishes 279 // logging in and the profile is not OTR. 280 if (profile->GetExtensionService() && 281 profile->GetExtensionService()->extensions_enabled()) { 282 profile->GetExtensionService()->InitEventRouters(); 283 } 284 btl->AddLoginTimeMarker("ExtensionsServiceStarted", false); 285 286 // Supply credentials for sync and others to use. Load tokens from disk. 287 TokenService* token_service = profile->GetTokenService(); 288 token_service->Initialize(GaiaConstants::kChromeOSSource, 289 profile); 290 token_service->LoadTokensFromDB(); 291 292 // For existing users there's usually a pending online auth request. 293 // Tokens will be fetched after it's is succeeded. 294 if (!pending_requests_) { 295 FetchTokens(profile, credentials_); 296 } 297 btl->AddLoginTimeMarker("TokensGotten", false); 298 299 // Set the CrOS user by getting this constructor run with the 300 // user's email on first retrieval. 301 profile->GetProfileSyncService(username_)->SetPassphrase(password_, 302 false, 303 true); 304 btl->AddLoginTimeMarker("SyncStarted", false); 305 306 // Own TPM device if, for any reason, it has not been done in EULA 307 // wizard screen. 308 if (CrosLibrary::Get()->EnsureLoaded()) { 309 CryptohomeLibrary* cryptohome = CrosLibrary::Get()->GetCryptohomeLibrary(); 310 if (cryptohome->TpmIsEnabled() && !cryptohome->TpmIsBeingOwned()) { 311 if (cryptohome->TpmIsOwned()) { 312 cryptohome->TpmClearStoredPassword(); 313 } else { 314 cryptohome->TpmCanAttemptOwnership(); 315 } 316 } 317 } 318 btl->AddLoginTimeMarker("TPMOwned", false); 319 320 RespectLocalePreference(profile); 321 322 if (UserManager::Get()->current_user_is_new()) { 323 SetFirstLoginPrefs(profile->GetPrefs()); 324 } 325 326 // Enable/disable plugins based on user preferences. 327 PluginUpdater::GetInstance()->UpdatePluginGroupsStateFromPrefs(profile); 328 btl->AddLoginTimeMarker("PluginsStateUpdated", false); 329 330 // We suck. This is a hack since we do not have the enterprise feature 331 // done yet to pull down policies from the domain admin. We'll take this 332 // out when we get that done properly. 333 // TODO(xiyuan): Remove this once enterprise feature is ready. 334 if (EndsWith(username_, "@google.com", true)) { 335 PrefService* pref_service = profile->GetPrefs(); 336 pref_service->SetBoolean(prefs::kEnableScreenLock, true); 337 } 338 339 profile->OnLogin(); 340 341 delegate_->OnProfilePrepared(profile); 342 343 // TODO(altimofeev): Need to sanitize memory used to store password. 344 password_ = ""; 345 username_ = ""; 346 credentials_ = GaiaAuthConsumer::ClientLoginResult(); 347 } 348 349 void LoginUtilsImpl::FetchCookies( 350 Profile* profile, 351 const GaiaAuthConsumer::ClientLoginResult& credentials) { 352 // Take the credentials passed in and try to exchange them for 353 // full-fledged Google authentication cookies. This is 354 // best-effort; it's possible that we'll fail due to network 355 // troubles or some such. 356 // CookieFetcher will delete itself once done. 357 CookieFetcher* cf = new CookieFetcher(profile); 358 cf->AttemptFetch(credentials.data); 359 BootTimesLoader::Get()->AddLoginTimeMarker("CookieFetchStarted", false); 360 } 361 362 void LoginUtilsImpl::FetchTokens( 363 Profile* profile, 364 const GaiaAuthConsumer::ClientLoginResult& credentials) { 365 TokenService* token_service = profile->GetTokenService(); 366 token_service->UpdateCredentials(credentials); 367 if (token_service->AreCredentialsValid()) { 368 token_service->StartFetchingTokens(); 369 } 370 } 371 372 void LoginUtilsImpl::RespectLocalePreference(Profile* profile) { 373 DCHECK(profile != NULL); 374 PrefService* prefs = profile->GetPrefs(); 375 DCHECK(prefs != NULL); 376 if (g_browser_process == NULL) 377 return; 378 379 std::string pref_locale = prefs->GetString(prefs::kApplicationLocale); 380 if (pref_locale.empty()) 381 pref_locale = prefs->GetString(prefs::kApplicationLocaleBackup); 382 if (pref_locale.empty()) 383 pref_locale = g_browser_process->GetApplicationLocale(); 384 DCHECK(!pref_locale.empty()); 385 profile->ChangeAppLocale(pref_locale, Profile::APP_LOCALE_CHANGED_VIA_LOGIN); 386 // Here we don't enable keyboard layouts. Input methods are set up when 387 // the user first logs in. Then the user may customize the input methods. 388 // Hence changing input methods here, just because the user's UI language 389 // is different from the login screen UI language, is not desirable. Note 390 // that input method preferences are synced, so users can use their 391 // farovite input methods as soon as the preferences are synced. 392 LanguageSwitchMenu::SwitchLanguage(pref_locale); 393 } 394 395 void LoginUtilsImpl::CompleteOffTheRecordLogin(const GURL& start_url) { 396 VLOG(1) << "Completing incognito login"; 397 398 UserManager::Get()->OffTheRecordUserLoggedIn(); 399 400 if (CrosLibrary::Get()->EnsureLoaded()) { 401 // For guest session we ask session manager to restart Chrome with --bwsi 402 // flag. We keep only some of the arguments of this process. 403 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); 404 CommandLine command_line(browser_command_line.GetProgram()); 405 std::string cmd_line_str = 406 GetOffTheRecordCommandLine(start_url, 407 browser_command_line, 408 &command_line); 409 410 CrosLibrary::Get()->GetLoginLibrary()->RestartJob(getpid(), cmd_line_str); 411 } 412 } 413 414 std::string LoginUtilsImpl::GetOffTheRecordCommandLine( 415 const GURL& start_url, 416 const CommandLine& base_command_line, 417 CommandLine* command_line) { 418 static const char* kForwardSwitches[] = { 419 switches::kEnableLogging, 420 switches::kEnableAcceleratedPlugins, 421 switches::kUseGL, 422 switches::kUserDataDir, 423 switches::kScrollPixels, 424 switches::kEnableGView, 425 switches::kNoFirstRun, 426 switches::kLoginProfile, 427 switches::kCompressSystemFeedback, 428 switches::kDisableSeccompSandbox, 429 switches::kPpapiFlashInProcess, 430 switches::kPpapiFlashPath, 431 switches::kPpapiFlashVersion, 432 #if defined(HAVE_XINPUT2) 433 switches::kTouchDevices, 434 #endif 435 }; 436 command_line->CopySwitchesFrom(base_command_line, 437 kForwardSwitches, 438 arraysize(kForwardSwitches)); 439 command_line->AppendSwitch(switches::kGuestSession); 440 command_line->AppendSwitch(switches::kIncognito); 441 command_line->AppendSwitchASCII(switches::kLoggingLevel, 442 kGuestModeLoggingLevel); 443 444 command_line->AppendSwitchASCII(switches::kLoginUser, kGuestUserName); 445 446 if (start_url.is_valid()) 447 command_line->AppendArg(start_url.spec()); 448 449 // Override the value of the homepage that is set in first run mode. 450 // TODO(altimofeev): extend action of the |kNoFirstRun| to cover this case. 451 command_line->AppendSwitchASCII( 452 switches::kHomePage, 453 GURL(chrome::kChromeUINewTabURL).spec()); 454 455 std::string cmd_line_str = command_line->command_line_string(); 456 // Special workaround for the arguments that should be quoted. 457 // Copying switches won't be needed when Guest mode won't need restart 458 // http://crosbug.com/6924 459 if (base_command_line.HasSwitch(switches::kRegisterPepperPlugins)) { 460 cmd_line_str += base::StringPrintf( 461 kSwitchFormatString, 462 switches::kRegisterPepperPlugins, 463 base_command_line.GetSwitchValueNative( 464 switches::kRegisterPepperPlugins).c_str()); 465 } 466 467 return cmd_line_str; 468 } 469 470 void LoginUtilsImpl::SetFirstLoginPrefs(PrefService* prefs) { 471 VLOG(1) << "Setting first login prefs"; 472 BootTimesLoader* btl = BootTimesLoader::Get(); 473 std::string locale = g_browser_process->GetApplicationLocale(); 474 475 // First, we'll set kLanguagePreloadEngines. 476 InputMethodLibrary* library = CrosLibrary::Get()->GetInputMethodLibrary(); 477 std::vector<std::string> input_method_ids; 478 input_method::GetFirstLoginInputMethodIds(locale, 479 library->current_input_method(), 480 &input_method_ids); 481 // Save the input methods in the user's preferences. 482 StringPrefMember language_preload_engines; 483 language_preload_engines.Init(prefs::kLanguagePreloadEngines, 484 prefs, NULL); 485 language_preload_engines.SetValue(JoinString(input_method_ids, ',')); 486 btl->AddLoginTimeMarker("IMEStarted", false); 487 488 // Second, we'll set kLanguagePreferredLanguages. 489 std::vector<std::string> language_codes; 490 // The current locale should be on the top. 491 language_codes.push_back(locale); 492 493 // Add input method IDs based on the input methods, as there may be 494 // input methods that are unrelated to the current locale. Example: the 495 // hardware keyboard layout xkb:us::eng is used for logging in, but the 496 // UI language is set to French. In this case, we should set "fr,en" 497 // to the preferred languages preference. 498 std::vector<std::string> candidates; 499 input_method::GetLanguageCodesFromInputMethodIds( 500 input_method_ids, &candidates); 501 for (size_t i = 0; i < candidates.size(); ++i) { 502 const std::string& candidate = candidates[i]; 503 // Skip if it's already in language_codes. 504 if (std::count(language_codes.begin(), language_codes.end(), 505 candidate) == 0) { 506 language_codes.push_back(candidate); 507 } 508 } 509 // Save the preferred languages in the user's preferences. 510 StringPrefMember language_preferred_languages; 511 language_preferred_languages.Init(prefs::kLanguagePreferredLanguages, 512 prefs, NULL); 513 language_preferred_languages.SetValue(JoinString(language_codes, ',')); 514 prefs->ScheduleSavePersistentPrefs(); 515 } 516 517 Authenticator* LoginUtilsImpl::CreateAuthenticator( 518 LoginStatusConsumer* consumer) { 519 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kParallelAuth)) 520 return new ParallelAuthenticator(consumer); 521 else 522 return new GoogleAuthenticator(consumer); 523 } 524 525 // We use a special class for this so that it can be safely leaked if we 526 // never connect. At shutdown the order is not well defined, and it's possible 527 // for the infrastructure needed to unregister might be unstable and crash. 528 class WarmingObserver : public NetworkLibrary::NetworkManagerObserver { 529 public: 530 WarmingObserver() { 531 NetworkLibrary *netlib = CrosLibrary::Get()->GetNetworkLibrary(); 532 netlib->AddNetworkManagerObserver(this); 533 } 534 535 // If we're now connected, prewarm the auth url. 536 void OnNetworkManagerChanged(NetworkLibrary* netlib) { 537 if (netlib->Connected()) { 538 const int kConnectionsNeeded = 1; 539 chrome_browser_net::PreconnectOnUIThread( 540 GURL(GaiaAuthFetcher::kClientLoginUrl), 541 chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED, 542 kConnectionsNeeded); 543 netlib->RemoveNetworkManagerObserver(this); 544 delete this; 545 } 546 } 547 }; 548 549 void LoginUtilsImpl::PrewarmAuthentication() { 550 if (CrosLibrary::Get()->EnsureLoaded()) { 551 NetworkLibrary *network = CrosLibrary::Get()->GetNetworkLibrary(); 552 if (network->Connected()) { 553 const int kConnectionsNeeded = 1; 554 chrome_browser_net::PreconnectOnUIThread( 555 GURL(GaiaAuthFetcher::kClientLoginUrl), 556 chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED, 557 kConnectionsNeeded); 558 } else { 559 new WarmingObserver(); 560 } 561 } 562 } 563 564 void LoginUtilsImpl::SetBackgroundView(BackgroundView* background_view) { 565 background_view_ = background_view; 566 } 567 568 BackgroundView* LoginUtilsImpl::GetBackgroundView() { 569 return background_view_; 570 } 571 572 LoginUtils* LoginUtils::Get() { 573 return LoginUtilsWrapper::GetInstance()->get(); 574 } 575 576 void LoginUtils::Set(LoginUtils* mock) { 577 LoginUtilsWrapper::GetInstance()->reset(mock); 578 } 579 580 void LoginUtils::DoBrowserLaunch(Profile* profile) { 581 BootTimesLoader::Get()->AddLoginTimeMarker("BrowserLaunched", false); 582 583 // Update command line in case loose values were added. 584 CommandLine::ForCurrentProcess()->InitFromArgv( 585 CommandLine::ForCurrentProcess()->argv()); 586 587 VLOG(1) << "Launching browser..."; 588 BrowserInit browser_init; 589 int return_code; 590 browser_init.LaunchBrowser(*CommandLine::ForCurrentProcess(), 591 profile, 592 FilePath(), 593 true, 594 &return_code); 595 } 596 597 } // namespace chromeos 598