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