Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / extended_authenticator.cc
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.
4
5 #include "chrome/browser/chromeos/login/extended_authenticator.h"
6
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/login_status_consumer.h"
12 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
13 #include "chromeos/cryptohome/async_method_caller.h"
14 #include "chromeos/cryptohome/cryptohome_parameters.h"
15 #include "chromeos/cryptohome/homedir_methods.h"
16 #include "chromeos/cryptohome/system_salt_getter.h"
17 #include "chromeos/dbus/cryptohome_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "crypto/sha2.h"
21 #include "google_apis/gaia/gaia_auth_util.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 using content::BrowserThread;
25
26 namespace chromeos {
27
28 namespace {
29
30 void RecordStartMarker(const std::string& marker) {
31   std::string full_marker = "Cryptohome-";
32   full_marker.append(marker);
33   full_marker.append("-Start");
34   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
35 }
36
37 void RecordEndMarker(const std::string& marker) {
38   std::string full_marker = "Cryptohome-";
39   full_marker.append(marker);
40   full_marker.append("-End");
41   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(full_marker, false);
42 }
43
44 }  // namespace
45
46 ExtendedAuthenticator::ExtendedAuthenticator(AuthStatusConsumer* consumer)
47     : salt_obtained_(false), consumer_(consumer), old_consumer_(NULL) {
48   SystemSaltGetter::Get()->GetSystemSalt(
49       base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
50 }
51
52 ExtendedAuthenticator::ExtendedAuthenticator(LoginStatusConsumer* consumer)
53     : salt_obtained_(false), consumer_(NULL), old_consumer_(consumer) {
54   SystemSaltGetter::Get()->GetSystemSalt(
55       base::Bind(&ExtendedAuthenticator::OnSaltObtained, this));
56 }
57
58 ExtendedAuthenticator::~ExtendedAuthenticator() {}
59
60 void ExtendedAuthenticator::SetConsumer(LoginStatusConsumer* consumer) {
61   old_consumer_ = consumer;
62 }
63
64 void ExtendedAuthenticator::OnSaltObtained(const std::string& system_salt) {
65   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66
67   salt_obtained_ = true;
68   system_salt_ = system_salt;
69   for (size_t i = 0; i < hashing_queue_.size(); i++) {
70     hashing_queue_[i].Run(system_salt);
71   }
72   hashing_queue_.clear();
73 }
74
75 void ExtendedAuthenticator::AuthenticateToMount(
76     const UserContext& context,
77     const HashSuccessCallback& success_callback) {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79   TransformContext(context,
80                    base::Bind(&ExtendedAuthenticator::DoAuthenticateToMount,
81                               this,
82                               success_callback));
83 }
84
85 void ExtendedAuthenticator::AuthenticateToCheck(
86     const UserContext& context,
87     const base::Closure& success_callback) {
88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89
90   TransformContext(context,
91                    base::Bind(&ExtendedAuthenticator::DoAuthenticateToCheck,
92                               this,
93                               success_callback));
94 }
95
96 void ExtendedAuthenticator::CreateMount(
97     const std::string& user_id,
98     const std::vector<cryptohome::KeyDefinition>& keys,
99     const HashSuccessCallback& success_callback) {
100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101
102   RecordStartMarker("MountEx");
103
104   std::string canonicalized = gaia::CanonicalizeEmail(user_id);
105   cryptohome::Identification id(canonicalized);
106   cryptohome::Authorization auth(keys.front());
107   cryptohome::MountParameters mount(false);
108   for (size_t i = 0; i < keys.size(); i++) {
109     mount.create_keys.push_back(keys[i]);
110   }
111   UserContext context(user_id, keys.front().key, std::string());
112   context.key_label = keys.front().label;
113
114   cryptohome::HomedirMethods::GetInstance()->MountEx(
115       id,
116       auth,
117       mount,
118       base::Bind(&ExtendedAuthenticator::OnMountComplete,
119                  this,
120                  "MountEx",
121                  context,
122                  success_callback));
123 }
124
125 void ExtendedAuthenticator::AddKey(const UserContext& context,
126                                    const cryptohome::KeyDefinition& key,
127                                    bool replace_existing,
128                                    const base::Closure& success_callback) {
129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
130   TransformContext(context,
131                    base::Bind(&ExtendedAuthenticator::DoAddKey,
132                               this,
133                               key,
134                               replace_existing,
135                               success_callback));
136 }
137
138 void ExtendedAuthenticator::UpdateKeyAuthorized(
139     const UserContext& context,
140     const cryptohome::KeyDefinition& key,
141     const std::string& signature,
142     const base::Closure& success_callback) {
143   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144   TransformContext(context,
145                    base::Bind(&ExtendedAuthenticator::DoUpdateKeyAuthorized,
146                               this,
147                               key,
148                               signature,
149                               success_callback));
150 }
151
152 void ExtendedAuthenticator::RemoveKey(const UserContext& context,
153                                       const std::string& key_to_remove,
154                                       const base::Closure& success_callback) {
155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156   TransformContext(context,
157                    base::Bind(&ExtendedAuthenticator::DoRemoveKey,
158                               this,
159                               key_to_remove,
160                               success_callback));
161 }
162
163 void ExtendedAuthenticator::DoAuthenticateToMount(
164     const HashSuccessCallback& success_callback,
165     const UserContext& user_context) {
166   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167
168   RecordStartMarker("MountEx");
169
170   std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
171   cryptohome::Identification id(canonicalized);
172   cryptohome::Authorization auth(user_context.password, user_context.key_label);
173   cryptohome::MountParameters mount(false);
174
175   cryptohome::HomedirMethods::GetInstance()->MountEx(
176       id,
177       auth,
178       mount,
179       base::Bind(&ExtendedAuthenticator::OnMountComplete,
180                  this,
181                  "MountEx",
182                  user_context,
183                  success_callback));
184 }
185
186 void ExtendedAuthenticator::DoAuthenticateToCheck(
187     const base::Closure& success_callback,
188     const UserContext& user_context) {
189   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
190
191   RecordStartMarker("CheckKeyEx");
192
193   std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
194   cryptohome::Identification id(canonicalized);
195   cryptohome::Authorization auth(user_context.password, user_context.key_label);
196
197   cryptohome::HomedirMethods::GetInstance()->CheckKeyEx(
198       id,
199       auth,
200       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
201                  this,
202                  "CheckKeyEx",
203                  user_context,
204                  success_callback));
205 }
206
207 void ExtendedAuthenticator::DoAddKey(const cryptohome::KeyDefinition& key,
208                                      bool replace_existing,
209                                      const base::Closure& success_callback,
210                                      const UserContext& user_context) {
211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212
213   RecordStartMarker("AddKeyEx");
214
215   std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
216   cryptohome::Identification id(canonicalized);
217   cryptohome::Authorization auth(user_context.password, user_context.key_label);
218
219   cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
220       id,
221       auth,
222       key,
223       replace_existing,
224       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
225                  this,
226                  "AddKeyEx",
227                  user_context,
228                  success_callback));
229 }
230
231 void ExtendedAuthenticator::DoUpdateKeyAuthorized(
232     const cryptohome::KeyDefinition& key,
233     const std::string& signature,
234     const base::Closure& success_callback,
235     const UserContext& user_context) {
236   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237   RecordStartMarker("UpdateKeyAuthorized");
238
239   std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
240   cryptohome::Identification id(canonicalized);
241   cryptohome::Authorization auth(user_context.password, user_context.key_label);
242
243   cryptohome::HomedirMethods::GetInstance()->UpdateKeyEx(
244       id,
245       auth,
246       key,
247       signature,
248       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
249                  this,
250                  "UpdateKeyAuthorized",
251                  user_context,
252                  success_callback));
253 }
254
255 void ExtendedAuthenticator::DoRemoveKey(const std::string& key_to_remove,
256                                         const base::Closure& success_callback,
257                                         const UserContext& user_context) {
258   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
259
260   RecordStartMarker("RemoveKeyEx");
261
262   std::string canonicalized = gaia::CanonicalizeEmail(user_context.username);
263   cryptohome::Identification id(canonicalized);
264   cryptohome::Authorization auth(user_context.password, user_context.key_label);
265
266   cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
267       id,
268       auth,
269       key_to_remove,
270       base::Bind(&ExtendedAuthenticator::OnOperationComplete,
271                  this,
272                  "RemoveKeyEx",
273                  user_context,
274                  success_callback));
275 }
276
277 void ExtendedAuthenticator::OnMountComplete(
278     const std::string& time_marker,
279     const UserContext& user_context,
280     const HashSuccessCallback& success_callback,
281     bool success,
282     cryptohome::MountError return_code,
283     const std::string& mount_hash) {
284   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
285
286   RecordEndMarker(time_marker);
287   UserContext copy;
288   copy.CopyFrom(user_context);
289   copy.username_hash = mount_hash;
290   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
291     success_callback.Run(mount_hash);
292     if (old_consumer_)
293       old_consumer_->OnLoginSuccess(copy);
294     return;
295   }
296   AuthState state = FAILED_MOUNT;
297   if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
298       return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
299       return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
300     state = FAILED_TPM;
301   }
302   if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
303     state = NO_MOUNT;
304   }
305   if (consumer_)
306     consumer_->OnAuthenticationFailure(state);
307   if (old_consumer_) {
308     LoginFailure failure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME);
309     old_consumer_->OnLoginFailure(failure);
310   }
311 }
312
313 void ExtendedAuthenticator::OnOperationComplete(
314     const std::string& time_marker,
315     const UserContext& user_context,
316     const base::Closure& success_callback,
317     bool success,
318     cryptohome::MountError return_code) {
319   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320
321   RecordEndMarker(time_marker);
322   if (return_code == cryptohome::MOUNT_ERROR_NONE) {
323     if (!success_callback.is_null())
324       success_callback.Run();
325     if (old_consumer_)
326       old_consumer_->OnLoginSuccess(user_context);
327     return;
328   }
329
330   AuthState state = FAILED_MOUNT;
331
332   if (return_code == cryptohome::MOUNT_ERROR_TPM_COMM_ERROR ||
333       return_code == cryptohome::MOUNT_ERROR_TPM_DEFEND_LOCK ||
334       return_code == cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
335     state = FAILED_TPM;
336   }
337
338   if (return_code == cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST)
339     state = NO_MOUNT;
340
341   if (consumer_)
342     consumer_->OnAuthenticationFailure(state);
343
344   if (old_consumer_) {
345     LoginFailure failure(LoginFailure::UNLOCK_FAILED);
346     old_consumer_->OnLoginFailure(failure);
347   }
348 }
349
350 void ExtendedAuthenticator::HashPasswordWithSalt(
351     const std::string& password,
352     const HashSuccessCallback& success_callback) {
353   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
354   DCHECK(consumer_) << "This is a part of new API";
355
356   DoHashWithSalt(password, success_callback, system_salt_);
357 }
358
359 void ExtendedAuthenticator::TransformContext(const UserContext& user_context,
360                                              const ContextCallback& callback) {
361   if (!user_context.need_password_hashing) {
362     callback.Run(user_context);
363   } else {
364     DoHashWithSalt(user_context.password,
365                    base::Bind(&ExtendedAuthenticator::DidTransformContext,
366                               this,
367                               user_context,
368                               callback),
369                    system_salt_);
370   }
371 }
372
373 void ExtendedAuthenticator::DidTransformContext(
374     const UserContext& user_context,
375     const ContextCallback& callback,
376     const std::string& hashed_password) {
377   DCHECK(user_context.need_password_hashing);
378   UserContext context;
379   context.CopyFrom(user_context);
380   context.password = hashed_password;
381   context.need_password_hashing = false;
382   callback.Run(context);
383 }
384
385 void ExtendedAuthenticator::DoHashWithSalt(const std::string& password,
386                                            const HashSuccessCallback& callback,
387                                            const std::string& system_salt) {
388   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
389
390   if (salt_obtained_) {
391     std::string hash =
392         ParallelAuthenticator::HashPassword(password, system_salt);
393     callback.Run(hash);
394     return;
395   }
396   hashing_queue_.push_back(base::Bind(
397       &ExtendedAuthenticator::DoHashWithSalt, this, password, callback));
398 }
399
400 }  // namespace chromeos