1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/app_mode/kiosk_profile_loader.h"
7 #include "base/logging.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h"
11 #include "base/sys_info.h"
12 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
13 #include "chrome/browser/chromeos/login/auth/chrome_login_performer.h"
14 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
15 #include "chrome/browser/chromeos/login/login_utils.h"
16 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
17 #include "chrome/browser/chromeos/settings/cros_settings.h"
18 #include "chrome/browser/lifetime/application_lifetime.h"
19 #include "chromeos/cryptohome/async_method_caller.h"
20 #include "chromeos/dbus/cryptohome_client.h"
21 #include "chromeos/dbus/dbus_thread_manager.h"
22 #include "chromeos/login/auth/auth_status_consumer.h"
23 #include "chromeos/login/auth/user_context.h"
24 #include "chromeos/login/user_names.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "google_apis/gaia/gaia_auth_util.h"
28 using content::BrowserThread
;
34 KioskAppLaunchError::Error
LoginFailureToKioskAppLaunchError(
35 const AuthFailure
& error
) {
36 switch (error
.reason()) {
37 case AuthFailure::COULD_NOT_MOUNT_TMPFS
:
38 case AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME
:
39 return KioskAppLaunchError::UNABLE_TO_MOUNT
;
40 case AuthFailure::DATA_REMOVAL_FAILED
:
41 return KioskAppLaunchError::UNABLE_TO_REMOVE
;
42 case AuthFailure::USERNAME_HASH_FAILED
:
43 return KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH
;
46 return KioskAppLaunchError::UNABLE_TO_MOUNT
;
52 ////////////////////////////////////////////////////////////////////////////////
53 // KioskProfileLoader::CryptohomedChecker ensures cryptohome daemon is up
54 // and running by issuing an IsMounted call. If the call does not go through
55 // and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
56 // some time out and at the maximum five times before it gives up. Upon
57 // success, it resumes the launch by logging in as a kiosk mode account.
59 class KioskProfileLoader::CryptohomedChecker
60 : public base::SupportsWeakPtr
<CryptohomedChecker
> {
62 explicit CryptohomedChecker(KioskProfileLoader
* loader
)
66 ~CryptohomedChecker() {}
69 chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
70 base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted
,
75 void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status
,
77 if (call_status
!= chromeos::DBUS_METHOD_CALL_SUCCESS
) {
78 const int kMaxRetryTimes
= 5;
80 if (retry_count_
> kMaxRetryTimes
) {
81 LOG(ERROR
) << "Could not talk to cryptohomed for launching kiosk app.";
82 ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING
);
86 const int retry_delay_in_milliseconds
= 500 * (1 << retry_count_
);
87 base::MessageLoop::current()->PostDelayedTask(
89 base::Bind(&CryptohomedChecker::StartCheck
, AsWeakPtr()),
90 base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds
));
95 LOG(ERROR
) << "Cryptohome is mounted before launching kiosk app.";
97 // Proceed only when cryptohome is not mounded or running on dev box.
98 if (!is_mounted
|| !base::SysInfo::IsRunningOnChromeOS())
99 ReportCheckResult(KioskAppLaunchError::NONE
);
101 ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED
);
104 void ReportCheckResult(KioskAppLaunchError::Error error
) {
105 if (error
== KioskAppLaunchError::NONE
)
106 loader_
->LoginAsKioskAccount();
108 loader_
->ReportLaunchResult(error
);
111 KioskProfileLoader
* loader_
;
114 DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker
);
118 ////////////////////////////////////////////////////////////////////////////////
119 // KioskProfileLoader
121 KioskProfileLoader::KioskProfileLoader(const std::string
& app_user_id
,
122 bool use_guest_mount
,
124 : user_id_(app_user_id
),
125 use_guest_mount_(use_guest_mount
),
126 delegate_(delegate
) {}
128 KioskProfileLoader::~KioskProfileLoader() {}
130 void KioskProfileLoader::Start() {
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
132 login_performer_
.reset();
133 cryptohomed_checker_
.reset(new CryptohomedChecker(this));
134 cryptohomed_checker_
->StartCheck();
137 void KioskProfileLoader::LoginAsKioskAccount() {
138 login_performer_
.reset(new ChromeLoginPerformer(this));
139 login_performer_
->LoginAsKioskAccount(user_id_
, use_guest_mount_
);
142 void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error
) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
145 if (error
!= KioskAppLaunchError::NONE
) {
146 delegate_
->OnProfileLoadFailed(error
);
150 void KioskProfileLoader::OnAuthSuccess(const UserContext
& user_context
) {
151 // LoginPerformer will delete itself.
152 login_performer_
->set_delegate(NULL
);
153 ignore_result(login_performer_
.release());
155 // If we are launching a demo session, we need to start MountGuest with the
156 // guest username; this is because there are several places in the cros code
157 // which rely on the username sent to cryptohome to be $guest. Back in Chrome
158 // we switch this back to the demo user name to correctly identify this
159 // user as a demo user.
160 UserContext context
= user_context
;
161 if (context
.GetUserID() == chromeos::login::kGuestUserName
)
162 context
.SetUserID(DemoAppLauncher::kDemoUserName
);
163 LoginUtils::Get()->PrepareProfile(context
,
164 false, // has_auth_cookies
165 false, // has_active_session
169 void KioskProfileLoader::OnAuthFailure(const AuthFailure
& error
) {
170 ReportLaunchResult(LoginFailureToKioskAppLaunchError(error
));
173 void KioskProfileLoader::WhiteListCheckFailed(const std::string
& email
) {
177 void KioskProfileLoader::PolicyLoadFailed() {
178 ReportLaunchResult(KioskAppLaunchError::POLICY_LOAD_FAILED
);
181 void KioskProfileLoader::OnOnlineChecked(
182 const std::string
& email
, bool success
) {
186 void KioskProfileLoader::OnProfilePrepared(Profile
* profile
,
187 bool browser_launched
) {
188 // This object could be deleted any time after successfully reporting
189 // a profile load, so invalidate the LoginUtils delegate now.
190 LoginUtils::Get()->DelegateDeleted(this);
192 delegate_
->OnProfileLoaded(profile
);
193 ReportLaunchResult(KioskAppLaunchError::NONE
);
196 } // namespace chromeos