Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / managed / managed_user_authenticator.cc
blob5fae224d67b89b14706c3cabbfcf55078123aa20
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"
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_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;
23 namespace chromeos {
25 namespace {
27 // Records status and calls resolver->Resolve().
28 void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt,
29 scoped_refptr<ManagedUserAuthenticator> resolver,
30 bool success,
31 cryptohome::MountError return_code) {
32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
33 attempt->RecordCryptohomeStatus(success, return_code);
34 resolver->Resolve();
37 // Records status and calls resolver->Resolve().
38 void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt* attempt,
39 scoped_refptr<ManagedUserAuthenticator> resolver,
40 bool success,
41 const std::string& result) {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
43 attempt->RecordHash(result);
44 resolver->Resolve();
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,
52 bool success,
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,
61 int flags,
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(
67 attempt->username,
68 ParallelAuthenticator::HashPassword(attempt->password, system_salt),
69 flags,
70 base::Bind(&TriggerResolveWithLoginTimeMarker,
71 "CryptohomeMount-LMU-End",
72 attempt,
73 resolver));
75 cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
76 attempt->username,
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(
89 attempt->username,
90 ParallelAuthenticator::HashPassword(attempt->password, system_salt),
91 ParallelAuthenticator::HashPassword(master_key, system_salt),
92 base::Bind(&TriggerResolveWithLoginTimeMarker,
93 "CryptohomeAddKey-LMU-End",
94 attempt,
95 resolver));
98 } // namespace
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(
112 base::Bind(&Mount,
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(
127 base::Bind(&Mount,
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(
143 base::Bind(&AddKey,
144 current_state_.get(),
145 scoped_refptr<ManagedUserAuthenticator>(this),
146 master_key));
149 void ManagedUserAuthenticator::OnAuthenticationSuccess(
150 const std::string& mount_hash,
151 bool add_key) {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153 VLOG(1) << "Locally managed user authentication success";
154 if (consumer_) {
155 if (add_key)
156 consumer_->OnAddKeySuccess();
157 else
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";
166 if (consumer_)
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;
174 switch (state) {
175 case CONTINUE:
176 // These are intermediate states; we need more info from a request that
177 // is still pending.
178 break;
179 case FAILED_MOUNT:
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(
184 BrowserThread::UI,
185 FROM_HERE,
186 base::Bind(
187 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
188 break;
189 case NO_MOUNT:
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(
194 BrowserThread::UI,
195 FROM_HERE,
196 base::Bind(
197 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
198 break;
199 case FAILED_TPM:
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(
204 BrowserThread::UI,
205 FROM_HERE,
206 base::Bind(
207 &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
208 break;
209 case SUCCESS:
210 VLOG(2) << "Locally managed user login";
211 BrowserThread::PostTask(
212 BrowserThread::UI,
213 FROM_HERE,
214 base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess,
215 this,
216 current_state_->hash(),
217 current_state_->add_key));
218 break;
219 default:
220 NOTREACHED();
221 break;
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())
233 return CONTINUE;
234 if (!current_state_->add_key && !current_state_->hash_obtained())
235 return CONTINUE;
237 AuthState state;
239 if (current_state_->cryptohome_outcome())
240 state = ResolveCryptohomeSuccessState();
241 else
242 state = ResolveCryptohomeFailureState();
244 DCHECK(current_state_->cryptohome_complete());
245 DCHECK(current_state_->hash_obtained() || current_state_->add_key);
246 return state;
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.
255 return FAILED_TPM;
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.
262 return NO_MOUNT;
265 return FAILED_MOUNT;
268 ManagedUserAuthenticator::AuthState
269 ManagedUserAuthenticator::ResolveCryptohomeSuccessState() {
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 return SUCCESS;
274 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username,
275 const std::string& password,
276 bool add_key_attempt)
277 : username(username),
278 password(password),
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;
300 hash_ = hash;
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));
326 return hash_;
329 } // namespace chromeos