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
LogCustomSwitches(const std::set<std::string> & switches)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.
CreatePerSessionCommandLine(Profile * profile)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.
NeedRestartToApplyPerSessionFlags(const CommandLine & user_flags,std::set<CommandLine::StringType> * out_command_line_difference)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
CanPerformEarlyRestart()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:
LoginUtilsImpl()186 LoginUtilsImpl()
187 : delegate_(NULL) {
188 }
189
~LoginUtilsImpl()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:
GetInstance()243 static LoginUtilsWrapper* GetInstance() {
244 return Singleton<LoginUtilsWrapper>::get();
245 }
246
get()247 LoginUtils* get() {
248 base::AutoLock create(create_lock_);
249 if (!ptr_.get())
250 reset(new LoginUtilsImpl);
251 return ptr_.get();
252 }
253
reset(LoginUtils * ptr)254 void reset(LoginUtils* ptr) {
255 ptr_.reset(ptr);
256 }
257
258 private:
259 friend struct DefaultSingletonTraits<LoginUtilsWrapper>;
260
LoginUtilsWrapper()261 LoginUtilsWrapper() {}
262
263 base::Lock create_lock_;
264 scoped_ptr<LoginUtils> ptr_;
265
266 DISALLOW_COPY_AND_ASSIGN(LoginUtilsWrapper);
267 };
268
DoBrowserLaunchInternal(Profile * profile,LoginDisplayHost * login_host,bool locale_pref_checked)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
RunCallbackOnLocaleLoaded(const base::Closure & callback,InputEventsBlocker *,const std::string &,const std::string &,const bool)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
RespectLocalePreference(Profile * profile,const base::Closure & callback)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
DoBrowserLaunch(Profile * profile,LoginDisplayHost * login_host)365 void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
366 LoginDisplayHost* login_host) {
367 DoBrowserLaunchInternal(profile, login_host, false /* locale_pref_checked */);
368 }
369
PrepareProfile(const UserContext & user_context,bool has_auth_cookies,bool has_active_session,LoginUtils::Delegate * delegate)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
DelegateDeleted(LoginUtils::Delegate * delegate)387 void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) {
388 if (delegate_ == delegate)
389 delegate_ = NULL;
390 }
391
RestartToApplyPerSessionFlagsIfNeed(Profile * profile,bool early_restart)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
CompleteOffTheRecordLogin(const GURL & start_url)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
CreateAuthenticator(AuthStatusConsumer * consumer)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
OnProfilePrepared(Profile * profile)469 void LoginUtilsImpl::OnProfilePrepared(Profile* profile) {
470 if (delegate_)
471 delegate_->OnProfilePrepared(profile);
472 }
473
474 #if defined(ENABLE_RLZ)
OnRlzInitialized()475 void LoginUtilsImpl::OnRlzInitialized() {
476 if (delegate_)
477 delegate_->OnRlzInitialized();
478 }
479 #endif
480
AttemptRestart(Profile * profile)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
Get()513 LoginUtils* LoginUtils::Get() {
514 return LoginUtilsWrapper::GetInstance()->get();
515 }
516
517 // static
Set(LoginUtils * mock)518 void LoginUtils::Set(LoginUtils* mock) {
519 LoginUtilsWrapper::GetInstance()->reset(mock);
520 }
521
522 // static
IsWhitelisted(const std::string & username,bool * wildcard_match)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