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.
5 #include "chrome/browser/chromeos/login/managed/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_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"
23 using content::BrowserThread
;
27 SupervisedUserLoginFlow::SupervisedUserLoginFlow(
28 const std::string
& user_id
)
29 : ExtendedUserFlow(user_id
),
34 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {}
36 bool SupervisedUserLoginFlow::CanLockScreen() {
40 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() {
44 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() {
48 bool SupervisedUserLoginFlow::HandleLoginFailure(
49 const LoginFailure
& failure
) {
53 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() {
57 void SupervisedUserLoginFlow::HandleOAuthTokenStatusChange(
58 User::OAuthTokenStatus status
) {
61 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded(
62 const std::string
& token
) {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
67 void SupervisedUserLoginFlow::ConfigureSync(const std::string
& token
) {
70 // TODO(antrim): add error handling (no token loaded).
71 // See also: http://crbug.com/312751
72 UserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
74 SupervisedUserAuthentication
* auth
=
75 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
77 if (auth
->HasScheduledPasswordUpdate(user_id())) {
78 auth
->LoadPasswordUpdateData(
80 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded
,
81 weak_factory_
.GetWeakPtr()),
82 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed
,
83 weak_factory_
.GetWeakPtr()));
89 void SupervisedUserLoginFlow::HandleLoginSuccess(
90 const UserContext
& login_context
) {
91 context_
.CopyFrom(login_context
);
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());
106 // Two cases now - we can currently have either old-style password, or new
108 std::string base64_signature
;
109 std::string signature
;
110 std::string password
;
113 bool success
= password_data
->GetStringWithoutPathExpansion(
114 kPasswordSignature
, &base64_signature
);
115 success
&= password_data
->GetIntegerWithoutPathExpansion(kPasswordRevision
,
118 password_data
->GetIntegerWithoutPathExpansion(kSchemaVersion
, &schema
);
119 success
&= password_data
->GetStringWithoutPathExpansion(kEncryptedPassword
,
122 LOG(ERROR
) << "Incomplete data for password change";
124 UMA_HISTOGRAM_ENUMERATION(
125 "ManagedUsers.ChromeOS.PasswordChange",
126 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA
,
127 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE
);
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
);
137 authenticator_
= new ExtendedAuthenticator(this);
138 SupervisedUserAuthentication::Schema current_schema
=
139 auth
->GetPasswordSchema(user_id());
141 key
.revision
= revision
;
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
;
148 VLOG(1) << "Adding new schema key";
149 DCHECK(context_
.GetKeyLabel().empty());
150 authenticator_
->AddKey(context_
,
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
==
158 VLOG(1) << "Updating the key";
160 if (auth
->HasIncompleteKey(user_id())) {
161 // We need to use Migrate instead of Authorized Update privilege.
162 key
.privileges
= kCryptohomeManagedUserIncompleteKeyPrivileges
;
164 // Just update the key.
165 DCHECK_EQ(context_
.GetKeyLabel(), kCryptohomeManagedUserKeyLabel
);
166 authenticator_
->UpdateKeyAuthorized(
170 base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated
,
171 weak_factory_
.GetWeakPtr(),
172 Passed(&data_copy
)));
174 NOTREACHED() << "Unsupported password schema";
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(
187 kLegacyCryptohomeManagedUserKeyLabel
,
188 base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved
,
189 weak_factory_
.GetWeakPtr()));
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
);
200 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
201 LOG(ERROR
) << "Could not load data for password change";
203 UMA_HISTOGRAM_ENUMERATION(
204 "ManagedUsers.ChromeOS.PasswordChange",
205 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA
,
206 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE
);
210 void SupervisedUserLoginFlow::OnAuthenticationFailure(
211 ExtendedAuthenticator::AuthState state
) {
212 LOG(ERROR
) << "Authentication error during password change";
214 UMA_HISTOGRAM_ENUMERATION(
215 "ManagedUsers.ChromeOS.PasswordChange",
216 SupervisedUserAuthentication::
217 PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE
,
218 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE
);
222 void SupervisedUserLoginFlow::OnPasswordUpdated(
223 scoped_ptr
<base::DictionaryValue
> password_data
) {
224 VLOG(1) << "Updated password for supervised user";
226 SupervisedUserAuthentication
* auth
=
227 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
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());
233 auth
->MarkKeyIncomplete(user_id(), true /* incomplete */);
235 UMA_HISTOGRAM_ENUMERATION(
236 "ManagedUsers.ChromeOS.PasswordChange",
237 SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION
,
238 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE
);
242 void SupervisedUserLoginFlow::Finish() {
243 LoginUtils::Get()->DoBrowserLaunch(profile_
, host());
245 UnregisterFlowSoon();
248 void SupervisedUserLoginFlow::LaunchExtraSteps(
251 UserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken(
254 &SupervisedUserLoginFlow::OnSyncSetupDataLoaded
,
255 weak_factory_
.GetWeakPtr()));
258 } // namespace chromeos