| OLD | NEW |
| (Empty) |
| 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_utils.h" | |
| 14 #include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h
" | |
| 15 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_sc
reen.h" | |
| 16 #include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h
" | |
| 17 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" | |
| 18 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h" | |
| 19 #include "chrome/browser/chromeos/login/users/user_manager.h" | |
| 20 #include "chrome/browser/chromeos/login/wizard_controller.h" | |
| 21 #include "chromeos/login/auth/key.h" | |
| 22 #include "content/public/browser/browser_thread.h" | |
| 23 | |
| 24 using content::BrowserThread; | |
| 25 | |
| 26 namespace chromeos { | |
| 27 | |
| 28 SupervisedUserLoginFlow::SupervisedUserLoginFlow( | |
| 29 const std::string& user_id) | |
| 30 : ExtendedUserFlow(user_id), | |
| 31 data_loaded_(false), | |
| 32 weak_factory_(this) { | |
| 33 } | |
| 34 | |
| 35 SupervisedUserLoginFlow::~SupervisedUserLoginFlow() {} | |
| 36 | |
| 37 bool SupervisedUserLoginFlow::CanLockScreen() { | |
| 38 return true; | |
| 39 } | |
| 40 | |
| 41 bool SupervisedUserLoginFlow::ShouldLaunchBrowser() { | |
| 42 return data_loaded_; | |
| 43 } | |
| 44 | |
| 45 bool SupervisedUserLoginFlow::ShouldSkipPostLoginScreens() { | |
| 46 return true; | |
| 47 } | |
| 48 | |
| 49 bool SupervisedUserLoginFlow::HandleLoginFailure(const AuthFailure& 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_ = 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 kCryptohomeSupervisedUserKeyLabel, | |
| 135 kCryptohomeSupervisedUserKeyPrivileges); | |
| 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 = kCryptohomeSupervisedUserIncompleteKeyPrivileges; | |
| 147 | |
| 148 VLOG(1) << "Adding new schema key"; | |
| 149 DCHECK(context_.GetKey()->GetLabel().empty()); | |
| 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 = kCryptohomeSupervisedUserIncompleteKeyPrivileges; | |
| 163 } | |
| 164 // Just update the key. | |
| 165 DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel); | |
| 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 kLegacyCryptohomeSupervisedUserKeyLabel, | |
| 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 | |
| OLD | NEW |