10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 20529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Use of this source code is governed by a BSD-style license that can be 30529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// found in the LICENSE file. 40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/signin/easy_unlock_service_regular.h" 60529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/bind.h" 80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/logging.h" 90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/metrics/field_trial.h" 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/prefs/pref_service.h" 110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/prefs/scoped_user_pref_update.h" 120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/values.h" 130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/extensions/extension_service.h" 140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/profiles/profile.h" 150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/signin/easy_unlock_toggle_flow.h" 160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/signin/screenlock_bridge.h" 170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/ui/extensions/application_launch.h" 180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/common/extensions/extension_constants.h" 19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/pref_names.h" 200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/pref_registry/pref_registry_syncable.h" 210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "content/public/browser/browser_thread.h" 220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/browser/extension_system.h" 230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#if defined(OS_CHROMEOS) 250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "apps/app_lifetime_monitor_factory.h" 260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/thread_task_runner_handle.h" 270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" 280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h" 290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/chromeos/login/session/user_session_manager.h" 300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/chromeos/profiles/profile_helper.h" 310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/user_manager/user_manager.h" 320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#endif 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace { 350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Key name of the local device permit record dictonary in kEasyUnlockPairing. 370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kKeyPermitAccess[] = "permitAccess"; 380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Key name of the remote device list in kEasyUnlockPairing. 400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kKeyDevices[] = "devices"; 410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Key name of the phone public key in a device dictionary. 430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kKeyPhoneId[] = "permitRecord.id"; 440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} // namespace 460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 470529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochEasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile) 480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch : EasyUnlockService(profile), 490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch turn_off_flow_status_(EasyUnlockService::IDLE), 500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch weak_ptr_factory_(this) { 510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 530529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochEasyUnlockServiceRegular::~EasyUnlockServiceRegular() { 540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 560529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochEasyUnlockService::Type EasyUnlockServiceRegular::GetType() const { 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return EasyUnlockService::TYPE_REGULAR; 580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstd::string EasyUnlockServiceRegular::GetUserEmail() const { 610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return ScreenlockBridge::GetAuthenticatedUserEmail(profile()); 620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch} 630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid EasyUnlockServiceRegular::LaunchSetup() { 650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#if defined(OS_CHROMEOS) 670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // Force the user to reauthenticate by showing a modal overlay (similar to the 68 // lock screen). The password obtained from the reauth is cached for a short 69 // period of time and used to create the cryptohome keys for sign-in. 70 if (short_lived_user_context_ && short_lived_user_context_->user_context()) { 71 OpenSetupApp(); 72 } else { 73 bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext( 74 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth, 75 weak_ptr_factory_.GetWeakPtr())); 76 if (!reauth_success) 77 OpenSetupApp(); 78 } 79#else 80 OpenSetupApp(); 81#endif 82} 83 84#if defined(OS_CHROMEOS) 85void EasyUnlockServiceRegular::OnUserContextFromReauth( 86 const chromeos::UserContext& user_context) { 87 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 88 short_lived_user_context_.reset(new chromeos::ShortLivedUserContext( 89 user_context, apps::AppLifetimeMonitorFactory::GetForProfile(profile()), 90 base::ThreadTaskRunnerHandle::Get().get())); 91 92 OpenSetupApp(); 93} 94 95void EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices(bool success) { 96 // If the keys were refreshed successfully, the hardlock state should be 97 // cleared, so Smart Lock can be used normally. Otherwise, we fall back to 98 // a hardlock state to force the user to type in their credentials again. 99 if (success) { 100 SetHardlockStateForUser(GetUserEmail(), 101 EasyUnlockScreenlockStateHandler::NO_HARDLOCK); 102 } 103 104 // Even if the keys refresh suceeded, we still fetch the cryptohome keys as a 105 // sanity check. 106 CheckCryptohomeKeysAndMaybeHardlock(); 107} 108#endif 109 110void EasyUnlockServiceRegular::OpenSetupApp() { 111 ExtensionService* service = 112 extensions::ExtensionSystem::Get(profile())->extension_service(); 113 const extensions::Extension* extension = 114 service->GetExtensionById(extension_misc::kEasyUnlockAppId, false); 115 116 OpenApplication(AppLaunchParams( 117 profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); 118} 119 120const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const { 121 const base::DictionaryValue* pairing_dict = 122 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); 123 const base::DictionaryValue* permit_dict = NULL; 124 if (pairing_dict && 125 pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict)) 126 return permit_dict; 127 128 return NULL; 129} 130 131void EasyUnlockServiceRegular::SetPermitAccess( 132 const base::DictionaryValue& permit) { 133 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(), 134 prefs::kEasyUnlockPairing); 135 pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy()); 136} 137 138void EasyUnlockServiceRegular::ClearPermitAccess() { 139 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(), 140 prefs::kEasyUnlockPairing); 141 pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL); 142} 143 144const base::ListValue* EasyUnlockServiceRegular::GetRemoteDevices() const { 145 const base::DictionaryValue* pairing_dict = 146 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); 147 const base::ListValue* devices = NULL; 148 if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices)) 149 return devices; 150 151 return NULL; 152} 153 154void EasyUnlockServiceRegular::SetRemoteDevices( 155 const base::ListValue& devices) { 156 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(), 157 prefs::kEasyUnlockPairing); 158 pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy()); 159 160#if defined(OS_CHROMEOS) 161 // TODO(tengs): Investigate if we can determine if the remote devices were set 162 // from sync or from the setup app. 163 if (short_lived_user_context_ && short_lived_user_context_->user_context() && 164 !devices.empty()) { 165 // We may already have the password cached, so proceed to create the 166 // cryptohome keys for sign-in or the system will be hardlocked. 167 chromeos::UserContext* user_context = 168 short_lived_user_context_->user_context(); 169 chromeos::EasyUnlockKeyManager* key_manager = 170 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); 171 172 key_manager->RefreshKeys( 173 *user_context, devices, 174 base::Bind(&EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices, 175 weak_ptr_factory_.GetWeakPtr())); 176 } else { 177 CheckCryptohomeKeysAndMaybeHardlock(); 178 } 179#else 180 CheckCryptohomeKeysAndMaybeHardlock(); 181#endif 182} 183 184void EasyUnlockServiceRegular::ClearRemoteDevices() { 185 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(), 186 prefs::kEasyUnlockPairing); 187 pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL); 188 CheckCryptohomeKeysAndMaybeHardlock(); 189} 190 191void EasyUnlockServiceRegular::RunTurnOffFlow() { 192 if (turn_off_flow_status_ == PENDING) 193 return; 194 195 SetTurnOffFlowStatus(PENDING); 196 197 // Currently there should only be one registered phone. 198 // TODO(xiyuan): Revisit this when server supports toggle for all or 199 // there are multiple phones. 200 const base::DictionaryValue* pairing_dict = 201 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing); 202 const base::ListValue* devices_list = NULL; 203 const base::DictionaryValue* first_device = NULL; 204 std::string phone_public_key; 205 if (!pairing_dict || !pairing_dict->GetList(kKeyDevices, &devices_list) || 206 !devices_list || !devices_list->GetDictionary(0, &first_device) || 207 !first_device || 208 !first_device->GetString(kKeyPhoneId, &phone_public_key)) { 209 LOG(WARNING) << "Bad easy unlock pairing data, wiping out local data"; 210 OnTurnOffFlowFinished(true); 211 return; 212 } 213 214 turn_off_flow_.reset(new EasyUnlockToggleFlow( 215 profile(), 216 phone_public_key, 217 false, 218 base::Bind(&EasyUnlockServiceRegular::OnTurnOffFlowFinished, 219 base::Unretained(this)))); 220 turn_off_flow_->Start(); 221} 222 223void EasyUnlockServiceRegular::ResetTurnOffFlow() { 224 turn_off_flow_.reset(); 225 SetTurnOffFlowStatus(IDLE); 226} 227 228EasyUnlockService::TurnOffFlowStatus 229 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const { 230 return turn_off_flow_status_; 231} 232 233std::string EasyUnlockServiceRegular::GetChallenge() const { 234 return std::string(); 235} 236 237std::string EasyUnlockServiceRegular::GetWrappedSecret() const { 238 return std::string(); 239} 240 241void EasyUnlockServiceRegular::RecordEasySignInOutcome( 242 const std::string& user_id, 243 bool success) const { 244 NOTREACHED(); 245} 246 247void EasyUnlockServiceRegular::RecordPasswordLoginEvent( 248 const std::string& user_id) const { 249 NOTREACHED(); 250} 251 252void EasyUnlockServiceRegular::InitializeInternal() { 253 registrar_.Init(profile()->GetPrefs()); 254 registrar_.Add( 255 prefs::kEasyUnlockAllowed, 256 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged, 257 base::Unretained(this))); 258 OnPrefsChanged(); 259} 260 261void EasyUnlockServiceRegular::ShutdownInternal() { 262#if defined(OS_CHROMEOS) 263 short_lived_user_context_.reset(); 264#endif 265 266 turn_off_flow_.reset(); 267 turn_off_flow_status_ = EasyUnlockService::IDLE; 268 registrar_.RemoveAll(); 269} 270 271bool EasyUnlockServiceRegular::IsAllowedInternal() { 272#if defined(OS_CHROMEOS) 273 if (!user_manager::UserManager::Get()->IsLoggedInAsRegularUser()) 274 return false; 275 276 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile())) 277 return false; 278 279 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed)) 280 return false; 281 282 // Respect existing policy and skip finch test. 283 if (!profile()->GetPrefs()->IsManagedPreference(prefs::kEasyUnlockAllowed)) { 284 // It is enabled when the trial exists and is in "Enable" group. 285 return base::FieldTrialList::FindFullName("EasyUnlock") == "Enable"; 286 } 287 288 return true; 289#else 290 // TODO(xiyuan): Revisit when non-chromeos platforms are supported. 291 return false; 292#endif 293} 294 295void EasyUnlockServiceRegular::OnPrefsChanged() { 296 UpdateAppState(); 297} 298 299void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) { 300 turn_off_flow_status_ = status; 301 NotifyTurnOffOperationStatusChanged(); 302} 303 304void EasyUnlockServiceRegular::OnTurnOffFlowFinished(bool success) { 305 turn_off_flow_.reset(); 306 307 if (!success) { 308 SetTurnOffFlowStatus(FAIL); 309 return; 310 } 311 312 ClearRemoteDevices(); 313 SetTurnOffFlowStatus(IDLE); 314 ReloadApp(); 315} 316