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