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/auth/key.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/ui/login_display_host_impl.h" 19 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h" 20 #include "chrome/browser/chromeos/login/users/user_manager.h" 21 #include "chrome/browser/chromeos/login/wizard_controller.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( 50 const LoginFailure& failure) { 51 return false; 52 } 53 54 bool SupervisedUserLoginFlow::HandlePasswordChangeDetected() { 55 return false; 56 } 57 58 void SupervisedUserLoginFlow::HandleOAuthTokenStatusChange( 59 User::OAuthTokenStatus status) { 60 } 61 62 void SupervisedUserLoginFlow::OnSyncSetupDataLoaded( 63 const std::string& token) { 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 65 ConfigureSync(token); 66 } 67 68 void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) { 69 data_loaded_ = true; 70 71 // TODO(antrim): add error handling (no token loaded). 72 // See also: http://crbug.com/312751 73 UserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken( 74 profile_, token); 75 SupervisedUserAuthentication* auth = 76 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication(); 77 78 if (auth->HasScheduledPasswordUpdate(user_id())) { 79 auth->LoadPasswordUpdateData( 80 user_id(), 81 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded, 82 weak_factory_.GetWeakPtr()), 83 base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed, 84 weak_factory_.GetWeakPtr())); 85 return; 86 } 87 Finish(); 88 } 89 90 void SupervisedUserLoginFlow::HandleLoginSuccess( 91 const UserContext& login_context) { 92 context_ = login_context; 93 } 94 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 UserManager::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()); 103 Finish(); 104 return; 105 } 106 107 // Two cases now - we can currently have either old-style password, or new 108 // password. 109 std::string base64_signature; 110 std::string signature; 111 std::string password; 112 int revision = 0; 113 int schema = 0; 114 bool success = password_data->GetStringWithoutPathExpansion( 115 kPasswordSignature, &base64_signature); 116 success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision, 117 &revision); 118 success &= 119 password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema); 120 success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword, 121 &password); 122 if (!success) { 123 LOG(ERROR) << "Incomplete data for password change"; 124 125 UMA_HISTOGRAM_ENUMERATION( 126 "ManagedUsers.ChromeOS.PasswordChange", 127 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA, 128 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE); 129 Finish(); 130 return; 131 } 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); 137 138 authenticator_ = new ExtendedAuthenticator(this); 139 SupervisedUserAuthentication::Schema current_schema = 140 auth->GetPasswordSchema(user_id()); 141 142 key.revision = revision; 143 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; 148 149 VLOG(1) << "Adding new schema key"; 150 DCHECK(context_.GetKey()->GetLabel().empty()); 151 authenticator_->AddKey(context_, 152 key, 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 == 158 current_schema) { 159 VLOG(1) << "Updating the key"; 160 161 if (auth->HasIncompleteKey(user_id())) { 162 // We need to use Migrate instead of Authorized Update privilege. 163 key.privileges = kCryptohomeSupervisedUserIncompleteKeyPrivileges; 164 } 165 // Just update the key. 166 DCHECK_EQ(context_.GetKey()->GetLabel(), kCryptohomeSupervisedUserKeyLabel); 167 authenticator_->UpdateKeyAuthorized( 168 context_, 169 key, 170 signature, 171 base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated, 172 weak_factory_.GetWeakPtr(), 173 Passed(&data_copy))); 174 } else { 175 NOTREACHED() << "Unsupported password schema"; 176 } 177 } 178 179 void SupervisedUserLoginFlow::OnNewKeyAdded( 180 scoped_ptr<base::DictionaryValue> password_data) { 181 VLOG(1) << "New key added"; 182 SupervisedUserAuthentication* auth = 183 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication(); 184 auth->StorePasswordData(user_id(), *password_data.get()); 185 auth->MarkKeyIncomplete(user_id(), true /* incomplete */); 186 authenticator_->RemoveKey( 187 context_, 188 kLegacyCryptohomeSupervisedUserKeyLabel, 189 base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved, 190 weak_factory_.GetWeakPtr())); 191 } 192 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); 198 Finish(); 199 } 200 201 void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() { 202 LOG(ERROR) << "Could not load data for password change"; 203 204 UMA_HISTOGRAM_ENUMERATION( 205 "ManagedUsers.ChromeOS.PasswordChange", 206 SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA, 207 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE); 208 Finish(); 209 } 210 211 void SupervisedUserLoginFlow::OnAuthenticationFailure( 212 ExtendedAuthenticator::AuthState state) { 213 LOG(ERROR) << "Authentication error during password change"; 214 215 UMA_HISTOGRAM_ENUMERATION( 216 "ManagedUsers.ChromeOS.PasswordChange", 217 SupervisedUserAuthentication:: 218 PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE, 219 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE); 220 Finish(); 221 } 222 223 void SupervisedUserLoginFlow::OnPasswordUpdated( 224 scoped_ptr<base::DictionaryValue> password_data) { 225 VLOG(1) << "Updated password for supervised user"; 226 227 SupervisedUserAuthentication* auth = 228 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication(); 229 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()); 233 if (was_incomplete) 234 auth->MarkKeyIncomplete(user_id(), true /* incomplete */); 235 236 UMA_HISTOGRAM_ENUMERATION( 237 "ManagedUsers.ChromeOS.PasswordChange", 238 SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION, 239 SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE); 240 Finish(); 241 } 242 243 void SupervisedUserLoginFlow::Finish() { 244 LoginUtils::Get()->DoBrowserLaunch(profile_, host()); 245 profile_ = NULL; 246 UnregisterFlowSoon(); 247 } 248 249 void SupervisedUserLoginFlow::LaunchExtraSteps( 250 Profile* profile) { 251 profile_ = profile; 252 UserManager::Get()->GetSupervisedUserManager()->LoadSupervisedUserToken( 253 profile, 254 base::Bind( 255 &SupervisedUserLoginFlow::OnSyncSetupDataLoaded, 256 weak_factory_.GetWeakPtr())); 257 } 258 259 } // namespace chromeos 260