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