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.
5 #include "chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h"
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"
25 using content::BrowserThread;
29 SupervisedUserLoginFlow::SupervisedUserLoginFlow(
30 const std::string& user_id)
31 : ExtendedUserFlow(user_id),
36 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
38 bool SupervisedUserLoginFlow::CanLockScreen() {
42 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() {
46 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() {
50 bool SupervisedUserLoginFlow::HandleLoginFailure(const AuthFailure& failure) {
54 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
58 void SupervisedUserLoginFlow::HandleOAuthTokenStatusChange(
59 user_manager::User::OAuthTokenStatus status) {
62 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(
63 const std::string& token) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
68 void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) {
71 // TODO(antrim): add error handling (no token loaded).
72 // See also: http://crbug.com/312751
73 ChromeUserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
75 SupervisedUserAuthentication* auth =
76 ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
78 if (auth->HasScheduledPasswordUpdate(user_id())) {
79 auth->LoadPasswordUpdateData(
81 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
82 weak_factory_.GetWeakPtr()),
83 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
84 weak_factory_.GetWeakPtr()));
90 void SupervisedUserLoginFlow::HandleLoginSuccess(
91 const UserContext& login_context) {
92 context_ = login_context;
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());
107 // Two cases now - we can currently have either old-style password, or new
109 std::string base64_signature;
110 std::string signature;
111 std::string password;
114 bool success = password_data->GetStringWithoutPathExpansion(
115 kPasswordSignature, &base64_signature);
116 success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
119 password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema);
120 success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword,
123 LOG(ERROR) << "Incomplete data for password change";
125 UMA_HISTOGRAM_ENUMERATION(
126 "ManagedUsers.ChromeOS.PasswordChange",
127 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA,
128 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
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);
138 authenticator_ = new ExtendedAuthenticator(this);
139 SupervisedUserAuthentication::Schema current_schema =
140 auth->GetPasswordSchema(user_id());
142 key.revision = revision;
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;
149 VLOG(1) << "Adding new schema key";
150 DCHECK(context_.GetKey()->GetLabel().empty());
151 authenticator_->AddKey(context_,
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 ==
159 VLOG(1) << "Updating the key";
161 if (auth->HasIncompleteKey(user_id())) {
162 // We need to use Migrate instead of Authorized Update privilege.
163 key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
165 // Just update the key.
166 DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel);
167 authenticator_->UpdateKeyAuthorized(
171 base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated,
172 weak_factory_.GetWeakPtr(),
173 Passed(&data_copy)));
175 NOTREACHED() << "Unsupported password schema";
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(
188 kLegacyCryptohomeSupervisedUserKeyLabel,
189 base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved,
190 weak_factory_.GetWeakPtr()));
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);
201 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
202 LOG(ERROR) << "Could not load data for password change";
204 UMA_HISTOGRAM_ENUMERATION(
205 "ManagedUsers.ChromeOS.PasswordChange",
206 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA,
207 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
211 void SupervisedUserLoginFlow::OnAuthenticationFailure(
212 ExtendedAuthenticator::AuthState state) {
213 LOG(ERROR) << "Authentication error during password change";
215 UMA_HISTOGRAM_ENUMERATION(
216 "ManagedUsers.ChromeOS.PasswordChange",
217 SupervisedUserAuthentication::
218 PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE,
219 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
223 void SupervisedUserLoginFlow::OnPasswordUpdated(
224 scoped_ptr<base::DictionaryValue> password_data) {
225 VLOG(1) << "Updated password for supervised user";
227 SupervisedUserAuthentication* auth =
228 ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
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());
234 auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
236 UMA_HISTOGRAM_ENUMERATION(
237 "ManagedUsers.ChromeOS.PasswordChange",
238 SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
239 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
243 void SupervisedUserLoginFlow::Finish() {
244 LoginUtils::Get()->DoBrowserLaunch(profile_, host());
246 UnregisterFlowSoon();
249 void SupervisedUserLoginFlow::LaunchExtraSteps(
252 ChromeUserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken(
254 base::Bind(&SupervisedUserLoginFlow::OnSyncSetupDataLoaded,
255 weak_factory_.GetWeakPtr()));
258 } // namespace chromeos