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.
5 #include "chrome/browser/chromeos/login/managed/managed_user_authenticator.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/chromeos/boot_times_loader.h"
11 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
12 #include "chromeos/cryptohome/async_method_caller.h"
13 #include "chromeos/cryptohome/system_salt_getter.h"
14 #include "chromeos/dbus/cryptohome_client.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "crypto/sha2.h"
18 #include "google_apis/gaia/gaia_auth_util.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
21 using content::BrowserThread
;
27 // Records status and calls resolver->Resolve().
28 void TriggerResolve(ManagedUserAuthenticator::AuthAttempt
* attempt
,
29 scoped_refptr
<ManagedUserAuthenticator
> resolver
,
31 cryptohome::MountError return_code
) {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
33 attempt
->RecordCryptohomeStatus(success
, return_code
);
37 // Records status and calls resolver->Resolve().
38 void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt
* attempt
,
39 scoped_refptr
<ManagedUserAuthenticator
> resolver
,
41 const std::string
& result
) {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
43 attempt
->RecordHash(result
);
47 // Calls TriggerResolve while adding login time marker.
48 void TriggerResolveWithLoginTimeMarker(
49 const std::string
& marker_name
,
50 ManagedUserAuthenticator::AuthAttempt
* attempt
,
51 scoped_refptr
<ManagedUserAuthenticator
> resolver
,
53 cryptohome::MountError return_code
) {
54 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name
, false);
55 TriggerResolve(attempt
, resolver
, success
, return_code
);
58 // Calls cryptohome's mount method.
59 void Mount(ManagedUserAuthenticator::AuthAttempt
* attempt
,
60 scoped_refptr
<ManagedUserAuthenticator
> resolver
,
62 const std::string
& system_salt
) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
64 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
65 "CryptohomeMount-LMU-Start", false);
66 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount(
68 ParallelAuthenticator::HashPassword(attempt
->password
, system_salt
),
70 base::Bind(&TriggerResolveWithLoginTimeMarker
,
71 "CryptohomeMount-LMU-End",
75 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
77 base::Bind(&TriggerResolveResult
, attempt
, resolver
));
80 // Calls cryptohome's addKey method.
81 void AddKey(ManagedUserAuthenticator::AuthAttempt
* attempt
,
82 scoped_refptr
<ManagedUserAuthenticator
> resolver
,
83 const std::string
& master_key
,
84 const std::string
& system_salt
) {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
86 chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
87 "CryptohomeAddKey-LMU-Start", false);
88 cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey(
90 ParallelAuthenticator::HashPassword(attempt
->password
, system_salt
),
91 ParallelAuthenticator::HashPassword(master_key
, system_salt
),
92 base::Bind(&TriggerResolveWithLoginTimeMarker
,
93 "CryptohomeAddKey-LMU-End",
100 ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer
* consumer
)
101 : consumer_(consumer
) {}
103 void ManagedUserAuthenticator::AuthenticateToMount(
104 const std::string
& username
,
105 const std::string
& password
) {
106 std::string canonicalized
= gaia::CanonicalizeEmail(username
);
108 current_state_
.reset(new ManagedUserAuthenticator::AuthAttempt(
109 canonicalized
, password
, false));
111 SystemSaltGetter::Get()->GetSystemSalt(
113 current_state_
.get(),
114 scoped_refptr
<ManagedUserAuthenticator
>(this),
115 cryptohome::MOUNT_FLAGS_NONE
));
118 void ManagedUserAuthenticator::AuthenticateToCreate(
119 const std::string
& username
,
120 const std::string
& password
) {
121 std::string canonicalized
= gaia::CanonicalizeEmail(username
);
123 current_state_
.reset(new ManagedUserAuthenticator::AuthAttempt(
124 canonicalized
, password
, false));
126 SystemSaltGetter::Get()->GetSystemSalt(
128 current_state_
.get(),
129 scoped_refptr
<ManagedUserAuthenticator
>(this),
130 cryptohome::CREATE_IF_MISSING
));
133 void ManagedUserAuthenticator::AddMasterKey(
134 const std::string
& username
,
135 const std::string
& password
,
136 const std::string
& master_key
) {
137 std::string canonicalized
= gaia::CanonicalizeEmail(username
);
139 current_state_
.reset(new ManagedUserAuthenticator::AuthAttempt(
140 canonicalized
, password
, true));
142 SystemSaltGetter::Get()->GetSystemSalt(
144 current_state_
.get(),
145 scoped_refptr
<ManagedUserAuthenticator
>(this),
149 void ManagedUserAuthenticator::OnAuthenticationSuccess(
150 const std::string
& mount_hash
,
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
153 VLOG(1) << "Locally managed user authentication success";
156 consumer_
->OnAddKeySuccess();
158 consumer_
->OnMountSuccess(mount_hash
);
162 void ManagedUserAuthenticator::OnAuthenticationFailure(
163 ManagedUserAuthenticator::AuthState state
) {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
165 LOG(WARNING
) << "Locally managed user authentication failure";
167 consumer_
->OnAuthenticationFailure(state
);
170 void ManagedUserAuthenticator::Resolve() {
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
172 ManagedUserAuthenticator::AuthState state
= ResolveState();
173 VLOG(1) << "Resolved state to: " << state
;
176 // These are intermediate states; we need more info from a request that
180 // In this case, whether login succeeded or not, we can't log
181 // the user in because their data is horked. So, override with
182 // the appropriate failure.
183 BrowserThread::PostTask(
187 &ManagedUserAuthenticator::OnAuthenticationFailure
, this, state
));
190 // In this case, whether login succeeded or not, we can't log
191 // the user in because no data exist. So, override with
192 // the appropriate failure.
193 BrowserThread::PostTask(
197 &ManagedUserAuthenticator::OnAuthenticationFailure
, this, state
));
200 // In this case, we tried to create/mount cryptohome and failed
201 // because of the critical TPM error.
202 // Chrome will notify user and request reboot.
203 BrowserThread::PostTask(
207 &ManagedUserAuthenticator::OnAuthenticationFailure
, this, state
));
210 VLOG(2) << "Locally managed user login";
211 BrowserThread::PostTask(
214 base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess
,
216 current_state_
->hash(),
217 current_state_
->add_key
));
225 ManagedUserAuthenticator::~ManagedUserAuthenticator() {}
227 ManagedUserAuthenticator::AuthState
ManagedUserAuthenticator::ResolveState() {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
229 // If we haven't mounted the user's home dir yet, we can't be done.
230 // We never get past here if a cryptohome op is still pending.
231 // This is an important invariant.
232 if (!current_state_
->cryptohome_complete())
234 if (!current_state_
->add_key
&& !current_state_
->hash_obtained())
239 if (current_state_
->cryptohome_outcome())
240 state
= ResolveCryptohomeSuccessState();
242 state
= ResolveCryptohomeFailureState();
244 DCHECK(current_state_
->cryptohome_complete());
245 DCHECK(current_state_
->hash_obtained() || current_state_
->add_key
);
249 ManagedUserAuthenticator::AuthState
250 ManagedUserAuthenticator::ResolveCryptohomeFailureState() {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
252 if (current_state_
->cryptohome_code() ==
253 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT
) {
254 // Critical TPM error detected, reboot needed.
258 if (current_state_
->cryptohome_code() ==
259 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST
) {
260 // If we tried a mount but the user did not exist, then we should wait
261 // for online login to succeed and try again with the "create" flag set.
268 ManagedUserAuthenticator::AuthState
269 ManagedUserAuthenticator::ResolveCryptohomeSuccessState() {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
274 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string
& username
,
275 const std::string
& password
,
276 bool add_key_attempt
)
277 : username(username
),
279 add_key(add_key_attempt
),
280 cryptohome_complete_(false),
281 cryptohome_outcome_(false),
282 hash_obtained_(false),
283 cryptohome_code_(cryptohome::MOUNT_ERROR_NONE
) {}
285 ManagedUserAuthenticator::AuthAttempt::~AuthAttempt() {}
287 void ManagedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus(
288 bool cryptohome_outcome
,
289 cryptohome::MountError cryptohome_code
) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
291 cryptohome_complete_
= true;
292 cryptohome_outcome_
= cryptohome_outcome
;
293 cryptohome_code_
= cryptohome_code
;
296 void ManagedUserAuthenticator::AuthAttempt::RecordHash(
297 const std::string
& hash
) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
299 hash_obtained_
= true;
303 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_complete() {
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
305 return cryptohome_complete_
;
308 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_outcome() {
309 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
310 return cryptohome_outcome_
;
313 cryptohome::MountError
314 ManagedUserAuthenticator::AuthAttempt::cryptohome_code() {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
316 return cryptohome_code_
;
319 bool ManagedUserAuthenticator::AuthAttempt::hash_obtained() {
320 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
321 return hash_obtained_
;
324 std::string
ManagedUserAuthenticator::AuthAttempt::hash() {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
329 } // namespace chromeos