Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / supervised / supervised_user_authenticator.cc
bloba0f9eab12e33d41df22317281adbc87270dc3f8a
1 // Copyright 2014 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/supervised/supervised_user_authenticator.h"
7 #include "base/bind.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/chromeos/boot_times_recorder.h"
11 #include "chromeos/cryptohome/async_method_caller.h"
12 #include "chromeos/cryptohome/cryptohome_parameters.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 "chromeos/login/auth/key.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "crypto/sha2.h"
19 #include "google_apis/gaia/gaia_auth_util.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
22 using content::BrowserThread;
24 namespace chromeos {
26 namespace {
28 // Records status and calls resolver->Resolve().
29 void TriggerResolve(SupervisedUserAuthenticator::AuthAttempt* attempt,
30 scoped_refptr<SupervisedUserAuthenticator> resolver,
31 bool success,
32 cryptohome::MountError return_code) {
33 DCHECK_CURRENTLY_ON(BrowserThread::UI);
34 attempt->RecordCryptohomeStatus(success, return_code);
35 resolver->Resolve();
38 // Records status and calls resolver->Resolve().
39 void TriggerResolveResult(SupervisedUserAuthenticator::AuthAttempt* attempt,
40 scoped_refptr<SupervisedUserAuthenticator> resolver,
41 bool success,
42 const std::string& result) {
43 DCHECK_CURRENTLY_ON(BrowserThread::UI);
44 attempt->RecordHash(result);
45 resolver->Resolve();
48 // Calls TriggerResolve while adding login time marker.
49 void TriggerResolveWithLoginTimeMarker(
50 const std::string& marker_name,
51 SupervisedUserAuthenticator::AuthAttempt* attempt,
52 scoped_refptr<SupervisedUserAuthenticator> resolver,
53 bool success,
54 cryptohome::MountError return_code) {
55 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(marker_name, false);
56 TriggerResolve(attempt, resolver, success, return_code);
59 // Calls cryptohome's mount method.
60 void Mount(SupervisedUserAuthenticator::AuthAttempt* attempt,
61 scoped_refptr<SupervisedUserAuthenticator> resolver,
62 int flags,
63 const std::string& system_salt) {
64 DCHECK_CURRENTLY_ON(BrowserThread::UI);
65 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
66 "CryptohomeMount-LMU-Start", false);
68 Key key(attempt->password);
69 key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
70 cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount(
71 attempt->username,
72 key.GetSecret(),
73 flags,
74 base::Bind(&TriggerResolveWithLoginTimeMarker,
75 "CryptohomeMount-LMU-End",
76 attempt,
77 resolver));
79 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
80 attempt->username,
81 base::Bind(&TriggerResolveResult, attempt, resolver));
84 // Calls cryptohome's addKey method.
85 void AddKey(SupervisedUserAuthenticator::AuthAttempt* attempt,
86 scoped_refptr<SupervisedUserAuthenticator> resolver,
87 const std::string& plain_text_master_key,
88 const std::string& system_salt) {
89 DCHECK_CURRENTLY_ON(BrowserThread::UI);
90 chromeos::BootTimesRecorder::Get()->AddLoginTimeMarker(
91 "CryptohomeAddKey-LMU-Start", false);
93 Key user_key(attempt->password);
94 user_key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
95 Key master_key(plain_text_master_key);
96 master_key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
97 cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey(
98 attempt->username,
99 user_key.GetSecret(),
100 master_key.GetSecret(),
101 base::Bind(&TriggerResolveWithLoginTimeMarker,
102 "CryptohomeAddKey-LMU-End",
103 attempt,
104 resolver));
107 } // namespace
109 SupervisedUserAuthenticator::SupervisedUserAuthenticator(
110 AuthStatusConsumer* consumer)
111 : consumer_(consumer) {}
113 void SupervisedUserAuthenticator::AuthenticateToMount(
114 const std::string& username,
115 const std::string& password) {
116 std::string canonicalized = gaia::CanonicalizeEmail(username);
118 current_state_.reset(new SupervisedUserAuthenticator::AuthAttempt(
119 canonicalized, password, false));
121 SystemSaltGetter::Get()->GetSystemSalt(
122 base::Bind(&Mount,
123 current_state_.get(),
124 scoped_refptr<SupervisedUserAuthenticator>(this),
125 cryptohome::MOUNT_FLAGS_NONE));
128 void SupervisedUserAuthenticator::AuthenticateToCreate(
129 const std::string& username,
130 const std::string& password) {
131 std::string canonicalized = gaia::CanonicalizeEmail(username);
133 current_state_.reset(new SupervisedUserAuthenticator::AuthAttempt(
134 canonicalized, password, false));
136 SystemSaltGetter::Get()->GetSystemSalt(
137 base::Bind(&Mount,
138 current_state_.get(),
139 scoped_refptr<SupervisedUserAuthenticator>(this),
140 cryptohome::CREATE_IF_MISSING));
143 void SupervisedUserAuthenticator::AddMasterKey(
144 const std::string& username,
145 const std::string& password,
146 const std::string& master_key) {
147 std::string canonicalized = gaia::CanonicalizeEmail(username);
149 current_state_.reset(new SupervisedUserAuthenticator::AuthAttempt(
150 canonicalized, password, true));
152 SystemSaltGetter::Get()->GetSystemSalt(
153 base::Bind(&AddKey,
154 current_state_.get(),
155 scoped_refptr<SupervisedUserAuthenticator>(this),
156 master_key));
159 void SupervisedUserAuthenticator::OnAuthenticationSuccess(
160 const std::string& mount_hash,
161 bool add_key) {
162 DCHECK_CURRENTLY_ON(BrowserThread::UI);
163 VLOG(1) << "Supervised user authentication success";
164 if (consumer_) {
165 if (add_key)
166 consumer_->OnAddKeySuccess();
167 else
168 consumer_->OnMountSuccess(mount_hash);
172 void SupervisedUserAuthenticator::OnAuthenticationFailure(
173 SupervisedUserAuthenticator::AuthState state) {
174 DCHECK_CURRENTLY_ON(BrowserThread::UI);
175 LOG(WARNING) << "Supervised user authentication failure";
176 if (consumer_)
177 consumer_->OnAuthenticationFailure(state);
180 void SupervisedUserAuthenticator::Resolve() {
181 DCHECK_CURRENTLY_ON(BrowserThread::UI);
182 SupervisedUserAuthenticator::AuthState state = ResolveState();
183 VLOG(1) << "Resolved state to: " << state;
184 switch (state) {
185 case CONTINUE:
186 // These are intermediate states; we need more info from a request that
187 // is still pending.
188 break;
189 case FAILED_MOUNT:
190 // In this case, whether login succeeded or not, we can't log
191 // the user in because their data is horked. So, override with
192 // the appropriate failure.
193 BrowserThread::PostTask(
194 BrowserThread::UI,
195 FROM_HERE,
196 base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
197 this,
198 state));
199 break;
200 case NO_MOUNT:
201 // In this case, whether login succeeded or not, we can't log
202 // the user in because no data exist. So, override with
203 // the appropriate failure.
204 BrowserThread::PostTask(
205 BrowserThread::UI,
206 FROM_HERE,
207 base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
208 this,
209 state));
210 break;
211 case FAILED_TPM:
212 // In this case, we tried to create/mount cryptohome and failed
213 // because of the critical TPM error.
214 // Chrome will notify user and request reboot.
215 BrowserThread::PostTask(
216 BrowserThread::UI,
217 FROM_HERE,
218 base::Bind(&SupervisedUserAuthenticator::OnAuthenticationFailure,
219 this,
220 state));
221 break;
222 case SUCCESS:
223 VLOG(2) << "Supervised user login";
224 BrowserThread::PostTask(
225 BrowserThread::UI,
226 FROM_HERE,
227 base::Bind(&SupervisedUserAuthenticator::OnAuthenticationSuccess,
228 this,
229 current_state_->hash(),
230 current_state_->add_key));
231 break;
232 default:
233 NOTREACHED();
234 break;
238 SupervisedUserAuthenticator::~SupervisedUserAuthenticator() {}
240 SupervisedUserAuthenticator::AuthState
241 SupervisedUserAuthenticator::ResolveState() {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
243 // If we haven't mounted the user's home dir yet, we can't be done.
244 // We never get past here if a cryptohome op is still pending.
245 // This is an important invariant.
246 if (!current_state_->cryptohome_complete())
247 return CONTINUE;
248 if (!current_state_->add_key && !current_state_->hash_obtained())
249 return CONTINUE;
251 AuthState state;
253 if (current_state_->cryptohome_outcome())
254 state = ResolveCryptohomeSuccessState();
255 else
256 state = ResolveCryptohomeFailureState();
258 DCHECK(current_state_->cryptohome_complete());
259 DCHECK(current_state_->hash_obtained() || current_state_->add_key);
260 return state;
263 SupervisedUserAuthenticator::AuthState
264 SupervisedUserAuthenticator::ResolveCryptohomeFailureState() {
265 DCHECK_CURRENTLY_ON(BrowserThread::UI);
266 LOG(ERROR) << "Failed to authenticate supervised user, code: "
267 << current_state_->cryptohome_code();
268 if (current_state_->cryptohome_code() ==
269 cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
270 // Critical TPM error detected, reboot needed.
271 return FAILED_TPM;
274 if (current_state_->cryptohome_code() ==
275 cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
276 // If we tried a mount but the user did not exist, then we should wait
277 // for online login to succeed and try again with the "create" flag set.
278 return NO_MOUNT;
281 return FAILED_MOUNT;
284 SupervisedUserAuthenticator::AuthState
285 SupervisedUserAuthenticator::ResolveCryptohomeSuccessState() {
286 DCHECK_CURRENTLY_ON(BrowserThread::UI);
287 return SUCCESS;
290 SupervisedUserAuthenticator::AuthAttempt::AuthAttempt(
291 const std::string& username,
292 const std::string& password,
293 bool add_key_attempt)
294 : username(username),
295 password(password),
296 add_key(add_key_attempt),
297 cryptohome_complete_(false),
298 cryptohome_outcome_(false),
299 hash_obtained_(false),
300 cryptohome_code_(cryptohome::MOUNT_ERROR_NONE) {}
302 SupervisedUserAuthenticator::AuthAttempt::~AuthAttempt() {}
304 void SupervisedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus(
305 bool cryptohome_outcome,
306 cryptohome::MountError cryptohome_code) {
307 DCHECK_CURRENTLY_ON(BrowserThread::UI);
308 cryptohome_complete_ = true;
309 cryptohome_outcome_ = cryptohome_outcome;
310 cryptohome_code_ = cryptohome_code;
313 void SupervisedUserAuthenticator::AuthAttempt::RecordHash(
314 const std::string& hash) {
315 DCHECK_CURRENTLY_ON(BrowserThread::UI);
316 hash_obtained_ = true;
317 hash_ = hash;
320 bool SupervisedUserAuthenticator::AuthAttempt::cryptohome_complete() {
321 DCHECK_CURRENTLY_ON(BrowserThread::UI);
322 return cryptohome_complete_;
325 bool SupervisedUserAuthenticator::AuthAttempt::cryptohome_outcome() {
326 DCHECK_CURRENTLY_ON(BrowserThread::UI);
327 return cryptohome_outcome_;
330 cryptohome::MountError
331 SupervisedUserAuthenticator::AuthAttempt::cryptohome_code() {
332 DCHECK_CURRENTLY_ON(BrowserThread::UI);
333 return cryptohome_code_;
336 bool SupervisedUserAuthenticator::AuthAttempt::hash_obtained() {
337 DCHECK_CURRENTLY_ON(BrowserThread::UI);
338 return hash_obtained_;
341 std::string SupervisedUserAuthenticator::AuthAttempt::hash() {
342 DCHECK_CURRENTLY_ON(BrowserThread::UI);
343 return hash_;
346 } // namespace chromeos