Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / login_utils.cc
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