Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / supervised / supervised_user_authentication.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/supervised/supervised_user_authentication.h"
6
7 #include "base/base64.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/macros.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
15 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
16 #include "chrome/browser/chromeos/profiles/profile_helper.h"
17 #include "chromeos/cryptohome/signed_secret.pb.h"
18 #include "chromeos/login/auth/key.h"
19 #include "components/user_manager/user.h"
20 #include "components/user_manager/user_manager.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "crypto/hmac.h"
23 #include "crypto/random.h"
24 #include "crypto/symmetric_key.h"
25
26 namespace chromeos {
27
28 namespace {
29
30 // Byte size of hash salt.
31 const unsigned kSaltSize = 32;
32
33 // Size of key signature.
34 const unsigned kHMACKeySizeInBits = 256;
35 const int kSignatureLength = 32;
36
37 // Size of master key (in bytes).
38 const int kMasterKeySize = 32;
39
40 std::string CreateSalt() {
41     char result[kSaltSize];
42     crypto::RandBytes(&result, sizeof(result));
43     return base::StringToLowerASCII(base::HexEncode(
44         reinterpret_cast<const void*>(result),
45         sizeof(result)));
46 }
47
48 std::string BuildRawHMACKey() {
49   scoped_ptr<crypto::SymmetricKey> key(crypto::SymmetricKey::GenerateRandomKey(
50       crypto::SymmetricKey::AES, kHMACKeySizeInBits));
51   std::string raw_result, result;
52   key->GetRawKey(&raw_result);
53   base::Base64Encode(raw_result, &result);
54   return result;
55 }
56
57 base::DictionaryValue* LoadPasswordData(base::FilePath profile_dir) {
58   JSONFileValueSerializer serializer(profile_dir.Append(kPasswordUpdateFile));
59   std::string error_message;
60   int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
61   scoped_ptr<base::Value> value(
62       serializer.Deserialize(&error_code, &error_message));
63   if (JSONFileValueSerializer::JSON_NO_ERROR != error_code) {
64     LOG(ERROR) << "Could not deserialize password data, error = " << error_code
65                << " / " << error_message;
66     return NULL;
67   }
68   base::DictionaryValue* result;
69   if (!value->GetAsDictionary(&result)) {
70     LOG(ERROR) << "Stored password data is not a dictionary";
71     return NULL;
72   }
73   ignore_result(value.release());
74   return result;
75 }
76
77 void OnPasswordDataLoaded(
78     const SupervisedUserAuthentication::PasswordDataCallback& success_callback,
79     const base::Closure& failure_callback,
80     base::DictionaryValue* value) {
81   if (!value) {
82     failure_callback.Run();
83     return;
84   }
85   success_callback.Run(value);
86   delete value;
87 }
88
89 }  // namespace
90
91 SupervisedUserAuthentication::SupervisedUserAuthentication(
92     SupervisedUserManager* owner)
93       : owner_(owner),
94         stable_schema_(SCHEMA_SALT_HASHED) {
95 }
96
97 SupervisedUserAuthentication::~SupervisedUserAuthentication() {}
98
99 SupervisedUserAuthentication::Schema
100 SupervisedUserAuthentication::GetStableSchema() {
101   return stable_schema_;
102 }
103
104 UserContext SupervisedUserAuthentication::TransformKey(
105     const UserContext& context) {
106   UserContext result = context;
107   int user_schema = GetPasswordSchema(context.GetUserID());
108   if (user_schema == SCHEMA_PLAIN)
109     return result;
110
111   if (user_schema == SCHEMA_SALT_HASHED) {
112     base::DictionaryValue holder;
113     std::string salt;
114     owner_->GetPasswordInformation(context.GetUserID(), &holder);
115     holder.GetStringWithoutPathExpansion(kSalt, &salt);
116     DCHECK(!salt.empty());
117     Key* const key = result.GetKey();
118     key->Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, salt);
119     key->SetLabel(kCryptohomeSupervisedUserKeyLabel);
120     result.SetIsUsingOAuth(false);
121     return result;
122   }
123   NOTREACHED() << "Unknown password schema for " << context.GetUserID();
124   return context;
125 }
126
127 bool SupervisedUserAuthentication::FillDataForNewUser(
128     const std::string& user_id,
129     const std::string& password,
130     base::DictionaryValue* password_data,
131     base::DictionaryValue* extra_data) {
132   Schema schema = stable_schema_;
133   if (schema == SCHEMA_PLAIN)
134     return false;
135
136   if (schema == SCHEMA_SALT_HASHED) {
137     password_data->SetIntegerWithoutPathExpansion(kSchemaVersion, schema);
138     std::string salt = CreateSalt();
139     password_data->SetStringWithoutPathExpansion(kSalt, salt);
140     int revision = kMinPasswordRevision;
141     password_data->SetIntegerWithoutPathExpansion(kPasswordRevision, revision);
142     Key key(password);
143     key.Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, salt);
144     const std::string salted_password = key.GetSecret();
145     const std::string base64_signature_key = BuildRawHMACKey();
146     const std::string base64_signature =
147         BuildPasswordSignature(salted_password, revision, base64_signature_key);
148     password_data->SetStringWithoutPathExpansion(kEncryptedPassword,
149                                                  salted_password);
150     password_data->SetStringWithoutPathExpansion(kPasswordSignature,
151                                                  base64_signature);
152
153     extra_data->SetStringWithoutPathExpansion(kPasswordEncryptionKey,
154                                               BuildRawHMACKey());
155     extra_data->SetStringWithoutPathExpansion(kPasswordSignatureKey,
156                                               base64_signature_key);
157     return true;
158   }
159   NOTREACHED();
160   return false;
161 }
162
163 std::string SupervisedUserAuthentication::GenerateMasterKey() {
164   char master_key_bytes[kMasterKeySize];
165   crypto::RandBytes(&master_key_bytes, sizeof(master_key_bytes));
166   return base::StringToLowerASCII(
167       base::HexEncode(reinterpret_cast<const void*>(master_key_bytes),
168                       sizeof(master_key_bytes)));
169 }
170
171 void SupervisedUserAuthentication::StorePasswordData(
172     const std::string& user_id,
173     const base::DictionaryValue& password_data) {
174   base::DictionaryValue holder;
175   owner_->GetPasswordInformation(user_id, &holder);
176   const base::Value* value;
177   if (password_data.GetWithoutPathExpansion(kSchemaVersion, &value))
178       holder.SetWithoutPathExpansion(kSchemaVersion, value->DeepCopy());
179   if (password_data.GetWithoutPathExpansion(kSalt, &value))
180       holder.SetWithoutPathExpansion(kSalt, value->DeepCopy());
181   if (password_data.GetWithoutPathExpansion(kPasswordRevision, &value))
182       holder.SetWithoutPathExpansion(kPasswordRevision, value->DeepCopy());
183   owner_->SetPasswordInformation(user_id, &holder);
184 }
185
186 SupervisedUserAuthentication::Schema
187 SupervisedUserAuthentication::GetPasswordSchema(
188   const std::string& user_id) {
189   base::DictionaryValue holder;
190
191   owner_->GetPasswordInformation(user_id, &holder);
192   // Default version.
193   int schema_version_index;
194   Schema schema_version = SCHEMA_PLAIN;
195   if (holder.GetIntegerWithoutPathExpansion(kSchemaVersion,
196                                             &schema_version_index)) {
197     schema_version = static_cast<Schema>(schema_version_index);
198   }
199   return schema_version;
200 }
201
202 bool SupervisedUserAuthentication::NeedPasswordChange(
203     const std::string& user_id,
204     const base::DictionaryValue* password_data) {
205   base::DictionaryValue local;
206   owner_->GetPasswordInformation(user_id, &local);
207   int local_schema = SCHEMA_PLAIN;
208   int local_revision = kMinPasswordRevision;
209   int updated_schema = SCHEMA_PLAIN;
210   int updated_revision = kMinPasswordRevision;
211   local.GetIntegerWithoutPathExpansion(kSchemaVersion, &local_schema);
212   local.GetIntegerWithoutPathExpansion(kPasswordRevision, &local_revision);
213   password_data->GetIntegerWithoutPathExpansion(kSchemaVersion,
214                                                 &updated_schema);
215   password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
216                                                 &updated_revision);
217   if (updated_schema > local_schema)
218     return true;
219   DCHECK_EQ(updated_schema, local_schema);
220   return updated_revision > local_revision;
221 }
222
223 void SupervisedUserAuthentication::ScheduleSupervisedPasswordChange(
224     const std::string& supervised_user_id,
225     const base::DictionaryValue* password_data) {
226   const user_manager::User* user =
227       user_manager::UserManager::Get()->FindUser(supervised_user_id);
228   base::FilePath profile_path = ProfileHelper::GetProfilePathByUserIdHash(
229       user->username_hash());
230   JSONFileValueSerializer serializer(profile_path.Append(kPasswordUpdateFile));
231   if (!serializer.Serialize(*password_data)) {
232     LOG(ERROR) << "Failed to schedule password update for supervised user "
233                << supervised_user_id;
234     UMA_HISTOGRAM_ENUMERATION(
235         "ManagedUsers.ChromeOS.PasswordChange",
236         SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_STORE_DATA,
237         SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
238     return;
239   }
240   base::DictionaryValue holder;
241   owner_->GetPasswordInformation(supervised_user_id, &holder);
242   holder.SetBoolean(kRequirePasswordUpdate, true);
243   owner_->SetPasswordInformation(supervised_user_id, &holder);
244 }
245
246 bool SupervisedUserAuthentication::HasScheduledPasswordUpdate(
247     const std::string& user_id) {
248   base::DictionaryValue holder;
249   owner_->GetPasswordInformation(user_id, &holder);
250   bool require_update = false;
251   holder.GetBoolean(kRequirePasswordUpdate, &require_update);
252   return require_update;
253 }
254
255 void SupervisedUserAuthentication::ClearScheduledPasswordUpdate(
256     const std::string& user_id) {
257   base::DictionaryValue holder;
258   owner_->GetPasswordInformation(user_id, &holder);
259   holder.SetBoolean(kRequirePasswordUpdate, false);
260   owner_->SetPasswordInformation(user_id, &holder);
261 }
262
263 bool SupervisedUserAuthentication::HasIncompleteKey(
264     const std::string& user_id) {
265   base::DictionaryValue holder;
266   owner_->GetPasswordInformation(user_id, &holder);
267   bool incomplete_key = false;
268   holder.GetBoolean(kHasIncompleteKey, &incomplete_key);
269   return incomplete_key;
270 }
271
272 void SupervisedUserAuthentication::MarkKeyIncomplete(const std::string& user_id,
273                                                      bool incomplete) {
274   base::DictionaryValue holder;
275   owner_->GetPasswordInformation(user_id, &holder);
276   holder.SetBoolean(kHasIncompleteKey, incomplete);
277   owner_->SetPasswordInformation(user_id, &holder);
278 }
279
280 void SupervisedUserAuthentication::LoadPasswordUpdateData(
281     const std::string& user_id,
282     const PasswordDataCallback& success_callback,
283     const base::Closure& failure_callback) {
284   const user_manager::User* user =
285       user_manager::UserManager::Get()->FindUser(user_id);
286   base::FilePath profile_path =
287       ProfileHelper::GetProfilePathByUserIdHash(user->username_hash());
288   PostTaskAndReplyWithResult(
289       content::BrowserThread::GetBlockingPool(),
290       FROM_HERE,
291       base::Bind(&LoadPasswordData, profile_path),
292       base::Bind(&OnPasswordDataLoaded, success_callback, failure_callback));
293 }
294
295 std::string SupervisedUserAuthentication::BuildPasswordSignature(
296     const std::string& password,
297     int revision,
298     const std::string& base64_signature_key) {
299   ac::chrome::managedaccounts::account::Secret secret;
300   secret.set_revision(revision);
301   secret.set_secret(password);
302   std::string buffer;
303   if (!secret.SerializeToString(&buffer))
304     LOG(FATAL) << "Protobuf::SerializeToString failed";
305   std::string signature_key;
306   base::Base64Decode(base64_signature_key, &signature_key);
307
308   crypto::HMAC hmac(crypto::HMAC::SHA256);
309   if (!hmac.Init(signature_key))
310     LOG(FATAL) << "HMAC::Init failed";
311
312   unsigned char out_bytes[kSignatureLength];
313   if (!hmac.Sign(buffer, out_bytes, sizeof(out_bytes)))
314     LOG(FATAL) << "HMAC::Sign failed";
315
316   std::string raw_result(out_bytes, out_bytes + sizeof(out_bytes));
317
318   std::string result;
319   base::Base64Encode(raw_result, &result);
320   return result;
321 }
322
323 }  // namespace chromeos