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"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/values.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/proximity_auth_facade.h"
15 #include "chrome/browser/signin/signin_manager_factory.h"
16 #include "chrome/common/extensions/api/easy_unlock_private.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/pref_names.h"
19 #include "chromeos/login/user_names.h"
20 #include "components/pref_registry/pref_registry_syncable.h"
21 #include "components/proximity_auth/cryptauth/cryptauth_access_token_fetcher.h"
22 #include "components/proximity_auth/cryptauth/cryptauth_client_impl.h"
23 #include "components/proximity_auth/screenlock_bridge.h"
24 #include "components/proximity_auth/switches.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "extensions/browser/event_router.h"
28 #include "extensions/common/constants.h"
29 #include "google_apis/gaia/gaia_auth_util.h"
31 #if defined(OS_CHROMEOS)
32 #include "apps/app_lifetime_monitor_factory.h"
33 #include "base/thread_task_runner_handle.h"
34 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
35 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h"
36 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
37 #include "chrome/browser/chromeos/profiles/profile_helper.h"
38 #include "components/user_manager/user_manager.h"
43 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
44 const char kKeyPermitAccess
[] = "permitAccess";
46 // Key name of the remote device list in kEasyUnlockPairing.
47 const char kKeyDevices
[] = "devices";
51 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile
* profile
)
52 : EasyUnlockService(profile
),
53 turn_off_flow_status_(EasyUnlockService::IDLE
),
54 will_unlock_using_easy_unlock_(false),
55 lock_screen_last_shown_timestamp_(base::TimeTicks::Now()),
56 weak_ptr_factory_(this) {
59 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
62 EasyUnlockService::Type
EasyUnlockServiceRegular::GetType() const {
63 return EasyUnlockService::TYPE_REGULAR
;
66 std::string
EasyUnlockServiceRegular::GetUserEmail() const {
67 const SigninManagerBase
* signin_manager
=
68 SigninManagerFactory::GetForProfileIfExists(profile());
69 // |profile| has to be a signed-in profile with SigninManager already
70 // created. Otherwise, just crash to collect stack.
71 DCHECK(signin_manager
);
72 const std::string user_email
= signin_manager
->GetAuthenticatedUsername();
73 return user_email
.empty() ? user_email
: gaia::CanonicalizeEmail(user_email
);
76 void EasyUnlockServiceRegular::LaunchSetup() {
77 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
78 #if defined(OS_CHROMEOS)
79 // Force the user to reauthenticate by showing a modal overlay (similar to the
80 // lock screen). The password obtained from the reauth is cached for a short
81 // period of time and used to create the cryptohome keys for sign-in.
82 if (short_lived_user_context_
&& short_lived_user_context_
->user_context()) {
85 bool reauth_success
= chromeos::EasyUnlockReauth::ReauthForUserContext(
86 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth
,
87 weak_ptr_factory_
.GetWeakPtr()));
96 #if defined(OS_CHROMEOS)
97 void EasyUnlockServiceRegular::OnUserContextFromReauth(
98 const chromeos::UserContext
& user_context
) {
99 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
100 short_lived_user_context_
.reset(new chromeos::ShortLivedUserContext(
101 user_context
, apps::AppLifetimeMonitorFactory::GetForProfile(profile()),
102 base::ThreadTaskRunnerHandle::Get().get()));
106 // Use this opportunity to clear the crytohome keys if it was not already
108 const base::ListValue
* devices
= GetRemoteDevices();
109 if (!devices
|| devices
->empty()) {
110 chromeos::EasyUnlockKeyManager
* key_manager
=
111 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
112 key_manager
->RefreshKeys(
113 user_context
, base::ListValue(),
114 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation
,
115 weak_ptr_factory_
.GetWeakPtr(),
116 EasyUnlockScreenlockStateHandler::NO_PAIRING
));
120 void EasyUnlockServiceRegular::SetHardlockAfterKeyOperation(
121 EasyUnlockScreenlockStateHandler::HardlockState state_on_success
,
124 SetHardlockStateForUser(GetUserEmail(), state_on_success
);
126 // Even if the refresh keys operation suceeded, we still fetch and check the
127 // cryptohome keys against the keys in local preferences as a sanity check.
128 CheckCryptohomeKeysAndMaybeHardlock();
132 const base::DictionaryValue
* EasyUnlockServiceRegular::GetPermitAccess() const {
133 const base::DictionaryValue
* pairing_dict
=
134 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing
);
135 const base::DictionaryValue
* permit_dict
= NULL
;
137 pairing_dict
->GetDictionary(kKeyPermitAccess
, &permit_dict
))
143 void EasyUnlockServiceRegular::SetPermitAccess(
144 const base::DictionaryValue
& permit
) {
145 DictionaryPrefUpdate
pairing_update(profile()->GetPrefs(),
146 prefs::kEasyUnlockPairing
);
147 pairing_update
->SetWithoutPathExpansion(kKeyPermitAccess
, permit
.DeepCopy());
150 void EasyUnlockServiceRegular::ClearPermitAccess() {
151 DictionaryPrefUpdate
pairing_update(profile()->GetPrefs(),
152 prefs::kEasyUnlockPairing
);
153 pairing_update
->RemoveWithoutPathExpansion(kKeyPermitAccess
, NULL
);
156 const base::ListValue
* EasyUnlockServiceRegular::GetRemoteDevices() const {
157 const base::DictionaryValue
* pairing_dict
=
158 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing
);
159 const base::ListValue
* devices
= NULL
;
160 if (pairing_dict
&& pairing_dict
->GetList(kKeyDevices
, &devices
))
166 void EasyUnlockServiceRegular::SetRemoteDevices(
167 const base::ListValue
& devices
) {
168 DictionaryPrefUpdate
pairing_update(profile()->GetPrefs(),
169 prefs::kEasyUnlockPairing
);
171 pairing_update
->RemoveWithoutPathExpansion(kKeyDevices
, NULL
);
173 pairing_update
->SetWithoutPathExpansion(kKeyDevices
, devices
.DeepCopy());
175 #if defined(OS_CHROMEOS)
176 // TODO(tengs): Investigate if we can determine if the remote devices were set
177 // from sync or from the setup app.
178 if (short_lived_user_context_
&& short_lived_user_context_
->user_context()) {
179 // We may already have the password cached, so proceed to create the
180 // cryptohome keys for sign-in or the system will be hardlocked.
181 chromeos::UserSessionManager::GetInstance()
182 ->GetEasyUnlockKeyManager()
184 *short_lived_user_context_
->user_context(), devices
,
185 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation
,
186 weak_ptr_factory_
.GetWeakPtr(),
187 EasyUnlockScreenlockStateHandler::NO_HARDLOCK
));
189 CheckCryptohomeKeysAndMaybeHardlock();
192 CheckCryptohomeKeysAndMaybeHardlock();
196 void EasyUnlockServiceRegular::RunTurnOffFlow() {
197 if (turn_off_flow_status_
== PENDING
)
199 DCHECK(!cryptauth_client_
);
201 SetTurnOffFlowStatus(PENDING
);
203 scoped_ptr
<proximity_auth::CryptAuthClientFactory
> factory
=
204 CreateCryptAuthClientFactory();
205 cryptauth_client_
= factory
->CreateInstance();
207 cryptauth::ToggleEasyUnlockRequest request
;
208 request
.set_enable(false);
209 request
.set_apply_to_all(true);
210 cryptauth_client_
->ToggleEasyUnlock(
212 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete
,
213 weak_ptr_factory_
.GetWeakPtr()),
214 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed
,
215 weak_ptr_factory_
.GetWeakPtr()));
218 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
219 cryptauth_client_
.reset();
220 SetTurnOffFlowStatus(IDLE
);
223 EasyUnlockService::TurnOffFlowStatus
224 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
225 return turn_off_flow_status_
;
228 std::string
EasyUnlockServiceRegular::GetChallenge() const {
229 return std::string();
232 std::string
EasyUnlockServiceRegular::GetWrappedSecret() const {
233 return std::string();
236 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
237 const std::string
& user_id
,
238 bool success
) const {
242 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
243 const std::string
& user_id
) const {
247 void EasyUnlockServiceRegular::StartAutoPairing(
248 const AutoPairingResultCallback
& callback
) {
249 if (!auto_pairing_callback_
.is_null()) {
251 << "Start auto pairing when there is another auto pairing requested.";
252 callback
.Run(false, std::string());
256 auto_pairing_callback_
= callback
;
258 scoped_ptr
<base::ListValue
> args(new base::ListValue());
259 scoped_ptr
<extensions::Event
> event(new extensions::Event(
260 extensions::api::easy_unlock_private::OnStartAutoPairing::kEventName
,
262 extensions::EventRouter::Get(profile())->DispatchEventWithLazyListener(
263 extension_misc::kEasyUnlockAppId
, event
.Pass());
266 void EasyUnlockServiceRegular::SetAutoPairingResult(
268 const std::string
& error
) {
269 DCHECK(!auto_pairing_callback_
.is_null());
271 auto_pairing_callback_
.Run(success
, error
);
272 auto_pairing_callback_
.Reset();
275 void EasyUnlockServiceRegular::InitializeInternal() {
276 GetScreenlockBridgeInstance()->AddObserver(this);
277 registrar_
.Init(profile()->GetPrefs());
279 prefs::kEasyUnlockAllowed
,
280 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged
,
281 base::Unretained(this)));
282 registrar_
.Add(prefs::kEasyUnlockProximityRequired
,
283 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged
,
284 base::Unretained(this)));
288 void EasyUnlockServiceRegular::ShutdownInternal() {
289 #if defined(OS_CHROMEOS)
290 short_lived_user_context_
.reset();
293 turn_off_flow_status_
= EasyUnlockService::IDLE
;
294 registrar_
.RemoveAll();
295 GetScreenlockBridgeInstance()->RemoveObserver(this);
298 bool EasyUnlockServiceRegular::IsAllowedInternal() const {
299 #if defined(OS_CHROMEOS)
300 user_manager::UserManager
* user_manager
= user_manager::UserManager::Get();
301 if (!user_manager
->IsLoggedInAsUserWithGaiaAccount())
304 // TODO(tengs): Ephemeral accounts generate a new enrollment every time they
305 // are added, so disable Smart Lock to reduce enrollments on server. However,
306 // ephemeral accounts can be locked, so we should revisit this use case.
307 if (user_manager
->IsCurrentUserNonCryptohomeDataEphemeral())
310 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
313 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed
))
318 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
323 void EasyUnlockServiceRegular::OnWillFinalizeUnlock(bool success
) {
324 will_unlock_using_easy_unlock_
= success
;
327 void EasyUnlockServiceRegular::OnSuspendDone() {
328 lock_screen_last_shown_timestamp_
= base::TimeTicks::Now();
331 void EasyUnlockServiceRegular::OnScreenDidLock(
332 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type
) {
333 will_unlock_using_easy_unlock_
= false;
334 lock_screen_last_shown_timestamp_
= base::TimeTicks::Now();
337 void EasyUnlockServiceRegular::OnScreenDidUnlock(
338 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type
) {
339 // Notifications of signin screen unlock events can also reach this code path;
341 if (screen_type
!= proximity_auth::ScreenlockBridge::LockHandler::LOCK_SCREEN
)
344 // Only record metrics for users who have enabled the feature.
346 EasyUnlockAuthEvent event
=
347 will_unlock_using_easy_unlock_
348 ? EASY_UNLOCK_SUCCESS
349 : GetPasswordAuthEvent();
350 RecordEasyUnlockScreenUnlockEvent(event
);
352 if (will_unlock_using_easy_unlock_
) {
353 RecordEasyUnlockScreenUnlockDuration(
354 base::TimeTicks::Now() - lock_screen_last_shown_timestamp_
);
358 will_unlock_using_easy_unlock_
= false;
361 void EasyUnlockServiceRegular::OnFocusedUserChanged(
362 const std::string
& user_id
) {
366 void EasyUnlockServiceRegular::OnPrefsChanged() {
367 SyncProfilePrefsToLocalState();
371 void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status
) {
372 turn_off_flow_status_
= status
;
373 NotifyTurnOffOperationStatusChanged();
376 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete(
377 const cryptauth::ToggleEasyUnlockResponse
& response
) {
378 cryptauth_client_
.reset();
380 SetRemoteDevices(base::ListValue());
381 SetTurnOffFlowStatus(IDLE
);
382 ReloadAppAndLockScreen();
385 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed(
386 const std::string
& error_message
) {
387 LOG(WARNING
) << "Failed to turn off Smart Lock: " << error_message
;
388 SetTurnOffFlowStatus(FAIL
);
391 void EasyUnlockServiceRegular::SyncProfilePrefsToLocalState() {
392 PrefService
* local_state
=
393 g_browser_process
? g_browser_process
->local_state() : NULL
;
394 PrefService
* profile_prefs
= profile()->GetPrefs();
395 if (!local_state
|| !profile_prefs
)
398 // Create the dictionary of Easy Unlock preferences for the current user. The
399 // items in the dictionary are the same profile prefs used for Easy Unlock.
400 scoped_ptr
<base::DictionaryValue
> user_prefs_dict(
401 new base::DictionaryValue());
402 user_prefs_dict
->SetBooleanWithoutPathExpansion(
403 prefs::kEasyUnlockProximityRequired
,
404 profile_prefs
->GetBoolean(prefs::kEasyUnlockProximityRequired
));
406 DictionaryPrefUpdate
update(local_state
,
407 prefs::kEasyUnlockLocalStateUserPrefs
);
408 std::string user_email
= GetUserEmail();
409 update
->SetWithoutPathExpansion(user_email
, user_prefs_dict
.Pass());