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/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"
27 using content::BrowserThread;
31 SupervisedUserLoginFlow::SupervisedUserLoginFlow(
32 const std::string& user_id)
33 : ExtendedUserFlow(user_id),
38 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
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);
48 bool SupervisedUserLoginFlow::CanLockScreen() {
52 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() {
56 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() {
60 bool SupervisedUserLoginFlow::SupportsEarlyRestartToApplyFlags() {
64 bool SupervisedUserLoginFlow::HandleLoginFailure(const AuthFailure& failure) {
68 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
72 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(
73 const std::string& token) {
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78 void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) {
81 // TODO(antrim): add error handling (no token loaded).
82 // See also: http://crbug.com/312751
83 ChromeUserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
85 SupervisedUserAuthentication* auth =
86 ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
88 if (auth->HasScheduledPasswordUpdate(user_id())) {
89 auth->LoadPasswordUpdateData(
91 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
92 weak_factory_.GetWeakPtr()),
93 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
94 weak_factory_.GetWeakPtr()));
100 void SupervisedUserLoginFlow::HandleLoginSuccess(
101 const UserContext& login_context) {
102 context_ = login_context;
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());
117 // Two cases now - we can currently have either old-style password, or new
119 std::string base64_signature;
120 std::string signature;
121 std::string password;
124 bool success = password_data->GetStringWithoutPathExpansion(
125 kPasswordSignature, &base64_signature);
126 success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
129 password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema);
130 success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword,
133 LOG(ERROR) << "Incomplete data for password change";
135 UMA_HISTOGRAM_ENUMERATION(
136 "ManagedUsers.ChromeOS.PasswordChange",
137 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA,
138 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
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);
148 authenticator_ = ExtendedAuthenticator::Create(this);
149 SupervisedUserAuthentication::Schema current_schema =
150 auth->GetPasswordSchema(user_id());
152 key.revision = revision;
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;
159 VLOG(1) << "Adding new schema key";
160 DCHECK(context_.GetKey()->GetLabel().empty());
161 authenticator_->AddKey(context_,
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 ==
169 VLOG(1) << "Updating the key";
171 if (auth->HasIncompleteKey(user_id())) {
172 // We need to use Migrate instead of Authorized Update privilege.
173 key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges;
175 // Just update the key.
176 DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel);
177 authenticator_->UpdateKeyAuthorized(
181 base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated,
182 weak_factory_.GetWeakPtr(),
183 Passed(&data_copy)));
185 NOTREACHED() << "Unsupported password schema";
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(
198 kLegacyCryptohomeSupervisedUserKeyLabel,
199 base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved,
200 weak_factory_.GetWeakPtr()));
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);
211 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
212 LOG(ERROR) << "Could not load data for password change";
214 UMA_HISTOGRAM_ENUMERATION(
215 "ManagedUsers.ChromeOS.PasswordChange",
216 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA,
217 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
221 void SupervisedUserLoginFlow::OnAuthenticationFailure(
222 ExtendedAuthenticator::AuthState state) {
223 LOG(ERROR) << "Authentication error during password change";
225 UMA_HISTOGRAM_ENUMERATION(
226 "ManagedUsers.ChromeOS.PasswordChange",
227 SupervisedUserAuthentication::
228 PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE,
229 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
233 void SupervisedUserLoginFlow::OnPasswordUpdated(
234 scoped_ptr<base::DictionaryValue> password_data) {
235 VLOG(1) << "Updated password for supervised user";
237 SupervisedUserAuthentication* auth =
238 ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
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());
244 auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
246 UMA_HISTOGRAM_ENUMERATION(
247 "ManagedUsers.ChromeOS.PasswordChange",
248 SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
249 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
253 void SupervisedUserLoginFlow::Finish() {
254 LoginUtils::Get()->DoBrowserLaunch(profile_, host());
256 UnregisterFlowSoon();
259 void SupervisedUserLoginFlow::LaunchExtraSteps(
262 ChromeUserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken(
264 base::Bind(&SupervisedUserLoginFlow::OnSyncSetupDataLoaded,
265 weak_factory_.GetWeakPtr()));
268 } // namespace chromeos