Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / supervised / supervised_user_login_flow.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_login_flow.h"
6
7 #include "base/base64.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/login/login_utils.h"
14 #include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
15 #include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
16 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h"
17 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
18 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
19 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
20 #include "chrome/browser/chromeos/login/wizard_controller.h"
21 #include "chromeos/login/auth/key.h"
22 #include "components/user_manager/user_manager.h"
23 #include "content/public/browser/browser_thread.h"
24
25 using content::BrowserThread;
26
27 namespace chromeos {
28
29 SupervisedUserLoginFlow::SupervisedUserLoginFlow(
30     const std::string& user_id)
31     : ExtendedUserFlow(user_id),
32       data_loaded_(false),
33       weak_factory_(this) {
34 }
35
36 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
37
38 bool SupervisedUserLoginFlow::CanLockScreen() {
39   return true;
40 }
41
42 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() {
43   return data_loaded_;
44 }
45
46 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() {
47   return true;
48 }
49
50 bool SupervisedUserLoginFlow::HandleLoginFailure(const AuthFailure& failure) {
51   return false;
52 }
53
54 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
55   return false;
56 }
57
58 void SupervisedUserLoginFlow::HandleOAuthTokenStatusChange(
59     user_manager::User::OAuthTokenStatus status) {
60 }
61
62 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(
63     const std::string& token) {
64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65   ConfigureSync(token);
66 }
67
68 void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) {
69   data_loaded_ = true;
70
71   // TODO(antrim): add error handling (no token loaded).
72   // See also: http://crbug.com/312751
73   ChromeUserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
74       profile_, token);
75   SupervisedUserAuthentication* auth =
76       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
77
78   if (auth->HasScheduledPasswordUpdate(user_id())) {
79     auth->LoadPasswordUpdateData(
80         user_id(),
81         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
82                    weak_factory_.GetWeakPtr()),
83         base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
84                    weak_factory_.GetWeakPtr()));
85     return;
86   }
87   Finish();
88 }
89
90 void SupervisedUserLoginFlow::HandleLoginSuccess(
91     const UserContext& login_context) {
92   context_ = login_context;
93 }
94
95 void SupervisedUserLoginFlow::OnPasswordChangeDataLoaded(
96     const base::DictionaryValue* password_data) {
97   // Edge case, when manager has signed in and already updated the password.
98   SupervisedUserAuthentication* auth =
99       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
100   if (!auth->NeedPasswordChange(user_id(), password_data)) {
101     VLOG(1) << "Password already changed for " << user_id();
102     auth->ClearScheduledPasswordUpdate(user_id());
103     Finish();
104     return;
105   }
106
107   // Two cases now - we can currently have either old-style password, or new
108   // password.
109   std::string base64_signature;
110   std::string signature;
111   std::string password;
112   int revision = 0;
113   int schema = 0;
114   bool success = password_data->GetStringWithoutPathExpansion(
115       kPasswordSignature, &base64_signature);
116   success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
117                                                            &revision);
118   success &=
119       password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema);
120   success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword,
121                                                           &password);
122   if (!success) {
123     LOG(ERROR) << "Incomplete data for password change";
124
125     UMA_HISTOGRAM_ENUMERATION(
126         "ManagedUsers.ChromeOS.PasswordChange",
127         SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA,
128         SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
129     Finish();
130     return;
131   }
132   base::Base64Decode(base64_signature, &signature);
133   scoped_ptr<base::DictionaryValue> data_copy(password_data->DeepCopy());
134   cryptohome::KeyDefinition key(password,
135                                 kCryptohomeSupervisedUserKeyLabel,
136                                 kCryptohomeSupervisedUserKeyPrivileges);
137
138   authenticator_ = new ExtendedAuthenticator(this);
139   SupervisedUserAuthentication::Schema current_schema =
140       auth->GetPasswordSchema(user_id());
141
142   key.revision = revision;
143
144   if (SupervisedUserAuthentication::SCHEMA_PLAIN == current_schema) {
145     // We need to add new key, and block old one. As we don't actually have
146     // signature key, use Migrate privilege instead of AuthorizedUpdate.
147     key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
148
149     VLOG(1) << "Adding new schema key";
150     DCHECK(context_.GetKey()->GetLabel().empty());
151     authenticator_->AddKey(context_,
152                            key,
153                            false /* no key exists */,
154                            base::Bind(&SupervisedUserLoginFlow::OnNewKeyAdded,
155                                       weak_factory_.GetWeakPtr(),
156                                       Passed(&data_copy)));
157   } else if (SupervisedUserAuthentication::SCHEMA_SALT_HASHED ==
158              current_schema) {
159     VLOG(1) << "Updating the key";
160
161     if (auth->HasIncompleteKey(user_id())) {
162       // We need to use Migrate instead of Authorized Update privilege.
163       key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
164     }
165     // Just update the key.
166     DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel);
167     authenticator_->UpdateKeyAuthorized(
168         context_,
169         key,
170         signature,
171         base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated,
172                    weak_factory_.GetWeakPtr(),
173                    Passed(&data_copy)));
174   } else {
175     NOTREACHED() << "Unsupported password schema";
176   }
177 }
178
179 void SupervisedUserLoginFlow::OnNewKeyAdded(
180     scoped_ptr<base::DictionaryValue> password_data) {
181   VLOG(1) << "New key added";
182   SupervisedUserAuthentication* auth =
183       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
184   auth->StorePasswordData(user_id(), *password_data.get());
185   auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
186   authenticator_->RemoveKey(
187       context_,
188       kLegacyCryptohomeSupervisedUserKeyLabel,
189       base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved,
190                  weak_factory_.GetWeakPtr()));
191 }
192
193 void SupervisedUserLoginFlow::OnOldKeyRemoved() {
194   UMA_HISTOGRAM_ENUMERATION(
195       "ManagedUsers.ChromeOS.PasswordChange",
196       SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
197       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
198   Finish();
199 }
200
201 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
202   LOG(ERROR) << "Could not load data for password change";
203
204   UMA_HISTOGRAM_ENUMERATION(
205       "ManagedUsers.ChromeOS.PasswordChange",
206       SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA,
207       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
208   Finish();
209 }
210
211 void SupervisedUserLoginFlow::OnAuthenticationFailure(
212     ExtendedAuthenticator::AuthState state) {
213   LOG(ERROR) << "Authentication error during password change";
214
215   UMA_HISTOGRAM_ENUMERATION(
216       "ManagedUsers.ChromeOS.PasswordChange",
217       SupervisedUserAuthentication::
218           PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE,
219       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
220   Finish();
221 }
222
223 void SupervisedUserLoginFlow::OnPasswordUpdated(
224     scoped_ptr<base::DictionaryValue> password_data) {
225   VLOG(1) << "Updated password for supervised user";
226
227   SupervisedUserAuthentication* auth =
228       ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
229
230   // Incomplete state is not there in password_data, carry it from old state.
231   bool was_incomplete = auth->HasIncompleteKey(user_id());
232   auth->StorePasswordData(user_id(), *password_data.get());
233   if (was_incomplete)
234     auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
235
236   UMA_HISTOGRAM_ENUMERATION(
237       "ManagedUsers.ChromeOS.PasswordChange",
238       SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
239       SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
240   Finish();
241 }
242
243 void SupervisedUserLoginFlow::Finish() {
244   LoginUtils::Get()->DoBrowserLaunch(profile_, host());
245   profile_ = NULL;
246   UnregisterFlowSoon();
247 }
248
249 void SupervisedUserLoginFlow::LaunchExtraSteps(
250     Profile* profile) {
251   profile_ = profile;
252   ChromeUserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken(
253       profile,
254       base::Bind(&SupervisedUserLoginFlow::OnSyncSetupDataLoaded,
255                  weak_factory_.GetWeakPtr()));
256 }
257
258 }  // namespace chromeos