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