Unwind the URL-based experiment IDs.
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service_regular.cc
bloba7f8ea9568613448e73a1a1a5fbbb29121bfd9ab
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.
5 #include "chrome/browser/signin/easy_unlock_service_regular.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/sys_info.h"
12 #include "base/values.h"
13 #include "base/version.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17 #include "chrome/browser/signin/screenlock_bridge.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/common/chrome_version_info.h"
20 #include "chrome/common/extensions/api/easy_unlock_private.h"
21 #include "chrome/common/extensions/extension_constants.h"
22 #include "chrome/common/pref_names.h"
23 #include "chromeos/login/user_names.h"
24 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "components/proximity_auth/cryptauth/cryptauth_access_token_fetcher.h"
26 #include "components/proximity_auth/cryptauth/cryptauth_client_impl.h"
27 #include "components/proximity_auth/switches.h"
28 #include "components/signin/core/browser/profile_oauth2_token_service.h"
29 #include "components/signin/core/browser/signin_manager.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "extensions/browser/event_router.h"
32 #include "extensions/common/constants.h"
34 #if defined(OS_CHROMEOS)
35 #include "apps/app_lifetime_monitor_factory.h"
36 #include "base/thread_task_runner_handle.h"
37 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
38 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h"
39 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
40 #include "chrome/browser/chromeos/profiles/profile_helper.h"
41 #include "components/user_manager/user_manager.h"
42 #endif
44 namespace {
46 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
47 const char kKeyPermitAccess[] = "permitAccess";
49 // Key name of the remote device list in kEasyUnlockPairing.
50 const char kKeyDevices[] = "devices";
52 // Constructs the DeviceClassifier message that is sent to CryptAuth for all API
53 // requests.
54 cryptauth::DeviceClassifier GetDeviceClassifier() {
55 cryptauth::DeviceClassifier device_classifier;
57 #if defined(OS_CHROMEOS)
58 int32 major_version, minor_version, bugfix_version;
59 // TODO(tengs): base::OperatingSystemVersionNumbers only works for ChromeOS.
60 // We need to get different numbers for other platforms.
61 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
62 &bugfix_version);
63 device_classifier.set_device_os_version_code(major_version);
64 device_classifier.set_device_type(cryptauth::CHROME);
65 #endif
67 chrome::VersionInfo version_info;
68 const std::vector<uint32_t>& version_components =
69 base::Version(version_info.Version()).components();
70 if (version_components.size() > 0)
71 device_classifier.set_device_software_version_code(version_components[0]);
73 device_classifier.set_device_software_package(version_info.Name());
74 return device_classifier;
77 } // namespace
79 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile)
80 : EasyUnlockService(profile),
81 turn_off_flow_status_(EasyUnlockService::IDLE),
82 will_unlock_using_easy_unlock_(false),
83 lock_screen_last_shown_timestamp_(base::TimeTicks::Now()),
84 weak_ptr_factory_(this) {
87 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
90 EasyUnlockService::Type EasyUnlockServiceRegular::GetType() const {
91 return EasyUnlockService::TYPE_REGULAR;
94 std::string EasyUnlockServiceRegular::GetUserEmail() const {
95 return ScreenlockBridge::GetAuthenticatedUserEmail(profile());
98 void EasyUnlockServiceRegular::LaunchSetup() {
99 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
100 #if defined(OS_CHROMEOS)
101 // Force the user to reauthenticate by showing a modal overlay (similar to the
102 // lock screen). The password obtained from the reauth is cached for a short
103 // period of time and used to create the cryptohome keys for sign-in.
104 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
105 OpenSetupApp();
106 } else {
107 bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext(
108 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth,
109 weak_ptr_factory_.GetWeakPtr()));
110 if (!reauth_success)
111 OpenSetupApp();
113 #else
114 OpenSetupApp();
115 #endif
118 #if defined(OS_CHROMEOS)
119 void EasyUnlockServiceRegular::OnUserContextFromReauth(
120 const chromeos::UserContext& user_context) {
121 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
122 short_lived_user_context_.reset(new chromeos::ShortLivedUserContext(
123 user_context, apps::AppLifetimeMonitorFactory::GetForProfile(profile()),
124 base::ThreadTaskRunnerHandle::Get().get()));
126 OpenSetupApp();
128 // Use this opportunity to clear the crytohome keys if it was not already
129 // cleared earlier.
130 const base::ListValue* devices = GetRemoteDevices();
131 if (!devices || devices->empty()) {
132 chromeos::EasyUnlockKeyManager* key_manager =
133 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
134 key_manager->RefreshKeys(
135 user_context, base::ListValue(),
136 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
137 weak_ptr_factory_.GetWeakPtr(),
138 EasyUnlockScreenlockStateHandler::NO_PAIRING));
142 void EasyUnlockServiceRegular::SetHardlockAfterKeyOperation(
143 EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
144 bool success) {
145 if (success)
146 SetHardlockStateForUser(GetUserEmail(), state_on_success);
148 // Even if the refresh keys operation suceeded, we still fetch and check the
149 // cryptohome keys against the keys in local preferences as a sanity check.
150 CheckCryptohomeKeysAndMaybeHardlock();
152 #endif
154 const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const {
155 const base::DictionaryValue* pairing_dict =
156 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
157 const base::DictionaryValue* permit_dict = NULL;
158 if (pairing_dict &&
159 pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict))
160 return permit_dict;
162 return NULL;
165 void EasyUnlockServiceRegular::SetPermitAccess(
166 const base::DictionaryValue& permit) {
167 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
168 prefs::kEasyUnlockPairing);
169 pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy());
172 void EasyUnlockServiceRegular::ClearPermitAccess() {
173 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
174 prefs::kEasyUnlockPairing);
175 pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
178 const base::ListValue* EasyUnlockServiceRegular::GetRemoteDevices() const {
179 const base::DictionaryValue* pairing_dict =
180 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
181 const base::ListValue* devices = NULL;
182 if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices))
183 return devices;
185 return NULL;
188 void EasyUnlockServiceRegular::SetRemoteDevices(
189 const base::ListValue& devices) {
190 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
191 prefs::kEasyUnlockPairing);
192 if (devices.empty())
193 pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
194 else
195 pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy());
197 #if defined(OS_CHROMEOS)
198 // TODO(tengs): Investigate if we can determine if the remote devices were set
199 // from sync or from the setup app.
200 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
201 // We may already have the password cached, so proceed to create the
202 // cryptohome keys for sign-in or the system will be hardlocked.
203 chromeos::UserSessionManager::GetInstance()
204 ->GetEasyUnlockKeyManager()
205 ->RefreshKeys(
206 *short_lived_user_context_->user_context(), devices,
207 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
208 weak_ptr_factory_.GetWeakPtr(),
209 EasyUnlockScreenlockStateHandler::NO_HARDLOCK));
210 } else {
211 CheckCryptohomeKeysAndMaybeHardlock();
213 #else
214 CheckCryptohomeKeysAndMaybeHardlock();
215 #endif
218 void EasyUnlockServiceRegular::RunTurnOffFlow() {
219 if (turn_off_flow_status_ == PENDING)
220 return;
221 DCHECK(!cryptauth_client_);
223 SetTurnOffFlowStatus(PENDING);
225 proximity_auth::CryptAuthClientFactoryImpl factory(
226 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
227 SigninManagerFactory::GetForProfile(profile())
228 ->GetAuthenticatedAccountId(),
229 profile()->GetRequestContext(), GetDeviceClassifier());
230 cryptauth_client_ = factory.CreateInstance();
232 cryptauth::ToggleEasyUnlockRequest request;
233 request.set_enable(false);
234 request.set_apply_to_all(true);
235 cryptauth_client_->ToggleEasyUnlock(
236 request,
237 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete,
238 weak_ptr_factory_.GetWeakPtr()),
239 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed,
240 weak_ptr_factory_.GetWeakPtr()));
243 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
244 cryptauth_client_.reset();
245 SetTurnOffFlowStatus(IDLE);
248 EasyUnlockService::TurnOffFlowStatus
249 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
250 return turn_off_flow_status_;
253 std::string EasyUnlockServiceRegular::GetChallenge() const {
254 return std::string();
257 std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
258 return std::string();
261 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
262 const std::string& user_id,
263 bool success) const {
264 NOTREACHED();
267 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
268 const std::string& user_id) const {
269 NOTREACHED();
272 void EasyUnlockServiceRegular::StartAutoPairing(
273 const AutoPairingResultCallback& callback) {
274 if (!auto_pairing_callback_.is_null()) {
275 LOG(ERROR)
276 << "Start auto pairing when there is another auto pairing requested.";
277 callback.Run(false, std::string());
278 return;
281 auto_pairing_callback_ = callback;
283 scoped_ptr<base::ListValue> args(new base::ListValue());
284 scoped_ptr<extensions::Event> event(new extensions::Event(
285 extensions::api::easy_unlock_private::OnStartAutoPairing::kEventName,
286 args.Pass()));
287 extensions::EventRouter::Get(profile())->DispatchEventWithLazyListener(
288 extension_misc::kEasyUnlockAppId, event.Pass());
291 void EasyUnlockServiceRegular::SetAutoPairingResult(
292 bool success,
293 const std::string& error) {
294 DCHECK(!auto_pairing_callback_.is_null());
296 auto_pairing_callback_.Run(success, error);
297 auto_pairing_callback_.Reset();
300 void EasyUnlockServiceRegular::InitializeInternal() {
301 ScreenlockBridge::Get()->AddObserver(this);
302 registrar_.Init(profile()->GetPrefs());
303 registrar_.Add(
304 prefs::kEasyUnlockAllowed,
305 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
306 base::Unretained(this)));
307 registrar_.Add(prefs::kEasyUnlockProximityRequired,
308 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
309 base::Unretained(this)));
310 OnPrefsChanged();
313 void EasyUnlockServiceRegular::ShutdownInternal() {
314 #if defined(OS_CHROMEOS)
315 short_lived_user_context_.reset();
316 #endif
318 turn_off_flow_status_ = EasyUnlockService::IDLE;
319 registrar_.RemoveAll();
320 ScreenlockBridge::Get()->RemoveObserver(this);
323 bool EasyUnlockServiceRegular::IsAllowedInternal() const {
324 #if defined(OS_CHROMEOS)
325 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
326 if (!user_manager->IsLoggedInAsUserWithGaiaAccount())
327 return false;
329 // TODO(tengs): Ephemeral accounts generate a new enrollment every time they
330 // are added, so disable Smart Lock to reduce enrollments on server. However,
331 // ephemeral accounts can be locked, so we should revisit this use case.
332 if (user_manager->IsCurrentUserNonCryptohomeDataEphemeral())
333 return false;
335 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
336 return false;
338 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
339 return false;
341 return true;
342 #else
343 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
344 return false;
345 #endif
348 void EasyUnlockServiceRegular::OnWillFinalizeUnlock(bool success) {
349 will_unlock_using_easy_unlock_ = success;
352 void EasyUnlockServiceRegular::OnSuspendDone() {
353 lock_screen_last_shown_timestamp_ = base::TimeTicks::Now();
356 void EasyUnlockServiceRegular::OnScreenDidLock(
357 ScreenlockBridge::LockHandler::ScreenType screen_type) {
358 will_unlock_using_easy_unlock_ = false;
359 lock_screen_last_shown_timestamp_ = base::TimeTicks::Now();
362 void EasyUnlockServiceRegular::OnScreenDidUnlock(
363 ScreenlockBridge::LockHandler::ScreenType screen_type) {
364 // Notifications of signin screen unlock events can also reach this code path;
365 // disregard them.
366 if (screen_type != ScreenlockBridge::LockHandler::LOCK_SCREEN)
367 return;
369 // Only record metrics for users who have enabled the feature.
370 if (IsEnabled()) {
371 EasyUnlockAuthEvent event =
372 will_unlock_using_easy_unlock_
373 ? EASY_UNLOCK_SUCCESS
374 : GetPasswordAuthEvent();
375 RecordEasyUnlockScreenUnlockEvent(event);
377 if (will_unlock_using_easy_unlock_) {
378 RecordEasyUnlockScreenUnlockDuration(
379 base::TimeTicks::Now() - lock_screen_last_shown_timestamp_);
383 will_unlock_using_easy_unlock_ = false;
386 void EasyUnlockServiceRegular::OnFocusedUserChanged(
387 const std::string& user_id) {
388 // Nothing to do.
391 void EasyUnlockServiceRegular::OnPrefsChanged() {
392 SyncProfilePrefsToLocalState();
393 UpdateAppState();
396 void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
397 turn_off_flow_status_ = status;
398 NotifyTurnOffOperationStatusChanged();
401 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete(
402 const cryptauth::ToggleEasyUnlockResponse& response) {
403 cryptauth_client_.reset();
405 SetRemoteDevices(base::ListValue());
406 SetTurnOffFlowStatus(IDLE);
407 ReloadAppAndLockScreen();
410 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed(
411 const std::string& error_message) {
412 LOG(WARNING) << "Failed to turn off Smart Lock: " << error_message;
413 SetTurnOffFlowStatus(FAIL);
416 void EasyUnlockServiceRegular::SyncProfilePrefsToLocalState() {
417 PrefService* local_state =
418 g_browser_process ? g_browser_process->local_state() : NULL;
419 PrefService* profile_prefs = profile()->GetPrefs();
420 if (!local_state || !profile_prefs)
421 return;
423 // Create the dictionary of Easy Unlock preferences for the current user. The
424 // items in the dictionary are the same profile prefs used for Easy Unlock.
425 scoped_ptr<base::DictionaryValue> user_prefs_dict(
426 new base::DictionaryValue());
427 user_prefs_dict->SetBooleanWithoutPathExpansion(
428 prefs::kEasyUnlockProximityRequired,
429 profile_prefs->GetBoolean(prefs::kEasyUnlockProximityRequired));
431 DictionaryPrefUpdate update(local_state,
432 prefs::kEasyUnlockLocalStateUserPrefs);
433 std::string user_email = GetUserEmail();
434 update->SetWithoutPathExpansion(user_email, user_prefs_dict.Pass());