Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service_regular.cc
bloba8157eff6570296b96ff03cc83042a68136b40a1
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/values.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/signin_manager_factory.h"
15 #include "chrome/common/extensions/api/easy_unlock_private.h"
16 #include "chrome/common/extensions/extension_constants.h"
17 #include "chrome/common/pref_names.h"
18 #include "chromeos/login/user_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "components/proximity_auth/cryptauth/cryptauth_access_token_fetcher.h"
21 #include "components/proximity_auth/cryptauth/cryptauth_client_impl.h"
22 #include "components/proximity_auth/screenlock_bridge.h"
23 #include "components/proximity_auth/switches.h"
24 #include "components/signin/core/browser/signin_manager.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "extensions/browser/event_router.h"
27 #include "extensions/common/constants.h"
28 #include "google_apis/gaia/gaia_auth_util.h"
30 #if defined(OS_CHROMEOS)
31 #include "apps/app_lifetime_monitor_factory.h"
32 #include "base/thread_task_runner_handle.h"
33 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
34 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h"
35 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
36 #include "chrome/browser/chromeos/profiles/profile_helper.h"
37 #include "components/user_manager/user_manager.h"
38 #endif
40 namespace {
42 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
43 const char kKeyPermitAccess[] = "permitAccess";
45 // Key name of the remote device list in kEasyUnlockPairing.
46 const char kKeyDevices[] = "devices";
48 } // namespace
50 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile)
51 : EasyUnlockService(profile),
52 turn_off_flow_status_(EasyUnlockService::IDLE),
53 will_unlock_using_easy_unlock_(false),
54 lock_screen_last_shown_timestamp_(base::TimeTicks::Now()),
55 weak_ptr_factory_(this) {
58 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
61 EasyUnlockService::Type EasyUnlockServiceRegular::GetType() const {
62 return EasyUnlockService::TYPE_REGULAR;
65 std::string EasyUnlockServiceRegular::GetUserEmail() const {
66 const SigninManagerBase* signin_manager =
67 SigninManagerFactory::GetForProfileIfExists(profile());
68 // |profile| has to be a signed-in profile with SigninManager already
69 // created. Otherwise, just crash to collect stack.
70 DCHECK(signin_manager);
71 const std::string user_email = signin_manager->GetAuthenticatedUsername();
72 return user_email.empty() ? user_email : gaia::CanonicalizeEmail(user_email);
75 void EasyUnlockServiceRegular::LaunchSetup() {
76 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
77 #if defined(OS_CHROMEOS)
78 // Force the user to reauthenticate by showing a modal overlay (similar to the
79 // lock screen). The password obtained from the reauth is cached for a short
80 // period of time and used to create the cryptohome keys for sign-in.
81 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
82 OpenSetupApp();
83 } else {
84 bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext(
85 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth,
86 weak_ptr_factory_.GetWeakPtr()));
87 if (!reauth_success)
88 OpenSetupApp();
90 #else
91 OpenSetupApp();
92 #endif
95 #if defined(OS_CHROMEOS)
96 void EasyUnlockServiceRegular::OnUserContextFromReauth(
97 const chromeos::UserContext& user_context) {
98 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
99 short_lived_user_context_.reset(new chromeos::ShortLivedUserContext(
100 user_context, apps::AppLifetimeMonitorFactory::GetForProfile(profile()),
101 base::ThreadTaskRunnerHandle::Get().get()));
103 OpenSetupApp();
105 // Use this opportunity to clear the crytohome keys if it was not already
106 // cleared earlier.
107 const base::ListValue* devices = GetRemoteDevices();
108 if (!devices || devices->empty()) {
109 chromeos::EasyUnlockKeyManager* key_manager =
110 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
111 key_manager->RefreshKeys(
112 user_context, base::ListValue(),
113 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
114 weak_ptr_factory_.GetWeakPtr(),
115 EasyUnlockScreenlockStateHandler::NO_PAIRING));
119 void EasyUnlockServiceRegular::SetHardlockAfterKeyOperation(
120 EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
121 bool success) {
122 if (success)
123 SetHardlockStateForUser(GetUserEmail(), state_on_success);
125 // Even if the refresh keys operation suceeded, we still fetch and check the
126 // cryptohome keys against the keys in local preferences as a sanity check.
127 CheckCryptohomeKeysAndMaybeHardlock();
129 #endif
131 const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const {
132 const base::DictionaryValue* pairing_dict =
133 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
134 const base::DictionaryValue* permit_dict = NULL;
135 if (pairing_dict &&
136 pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict))
137 return permit_dict;
139 return NULL;
142 void EasyUnlockServiceRegular::SetPermitAccess(
143 const base::DictionaryValue& permit) {
144 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
145 prefs::kEasyUnlockPairing);
146 pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy());
149 void EasyUnlockServiceRegular::ClearPermitAccess() {
150 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
151 prefs::kEasyUnlockPairing);
152 pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
155 const base::ListValue* EasyUnlockServiceRegular::GetRemoteDevices() const {
156 const base::DictionaryValue* pairing_dict =
157 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
158 const base::ListValue* devices = NULL;
159 if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices))
160 return devices;
162 return NULL;
165 void EasyUnlockServiceRegular::SetRemoteDevices(
166 const base::ListValue& devices) {
167 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
168 prefs::kEasyUnlockPairing);
169 if (devices.empty())
170 pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
171 else
172 pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy());
174 #if defined(OS_CHROMEOS)
175 // TODO(tengs): Investigate if we can determine if the remote devices were set
176 // from sync or from the setup app.
177 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
178 // We may already have the password cached, so proceed to create the
179 // cryptohome keys for sign-in or the system will be hardlocked.
180 chromeos::UserSessionManager::GetInstance()
181 ->GetEasyUnlockKeyManager()
182 ->RefreshKeys(
183 *short_lived_user_context_->user_context(), devices,
184 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
185 weak_ptr_factory_.GetWeakPtr(),
186 EasyUnlockScreenlockStateHandler::NO_HARDLOCK));
187 } else {
188 CheckCryptohomeKeysAndMaybeHardlock();
190 #else
191 CheckCryptohomeKeysAndMaybeHardlock();
192 #endif
195 void EasyUnlockServiceRegular::RunTurnOffFlow() {
196 if (turn_off_flow_status_ == PENDING)
197 return;
198 DCHECK(!cryptauth_client_);
200 SetTurnOffFlowStatus(PENDING);
202 scoped_ptr<proximity_auth::CryptAuthClientFactory> factory =
203 CreateCryptAuthClientFactory();
204 cryptauth_client_ = factory->CreateInstance();
206 cryptauth::ToggleEasyUnlockRequest request;
207 request.set_enable(false);
208 request.set_apply_to_all(true);
209 cryptauth_client_->ToggleEasyUnlock(
210 request,
211 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete,
212 weak_ptr_factory_.GetWeakPtr()),
213 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed,
214 weak_ptr_factory_.GetWeakPtr()));
217 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
218 cryptauth_client_.reset();
219 SetTurnOffFlowStatus(IDLE);
222 EasyUnlockService::TurnOffFlowStatus
223 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
224 return turn_off_flow_status_;
227 std::string EasyUnlockServiceRegular::GetChallenge() const {
228 return std::string();
231 std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
232 return std::string();
235 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
236 const std::string& user_id,
237 bool success) const {
238 NOTREACHED();
241 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
242 const std::string& user_id) const {
243 NOTREACHED();
246 void EasyUnlockServiceRegular::StartAutoPairing(
247 const AutoPairingResultCallback& callback) {
248 if (!auto_pairing_callback_.is_null()) {
249 LOG(ERROR)
250 << "Start auto pairing when there is another auto pairing requested.";
251 callback.Run(false, std::string());
252 return;
255 auto_pairing_callback_ = callback;
257 scoped_ptr<base::ListValue> args(new base::ListValue());
258 scoped_ptr<extensions::Event> event(new extensions::Event(
259 extensions::events::EASY_UNLOCK_PRIVATE_ON_START_AUTO_PAIRING,
260 extensions::api::easy_unlock_private::OnStartAutoPairing::kEventName,
261 args.Pass()));
262 extensions::EventRouter::Get(profile())->DispatchEventWithLazyListener(
263 extension_misc::kEasyUnlockAppId, event.Pass());
266 void EasyUnlockServiceRegular::SetAutoPairingResult(
267 bool success,
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 proximity_auth::ScreenlockBridge::Get()->AddObserver(this);
277 registrar_.Init(profile()->GetPrefs());
278 registrar_.Add(
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)));
285 OnPrefsChanged();
288 void EasyUnlockServiceRegular::ShutdownInternal() {
289 #if defined(OS_CHROMEOS)
290 short_lived_user_context_.reset();
291 #endif
293 turn_off_flow_status_ = EasyUnlockService::IDLE;
294 registrar_.RemoveAll();
295 proximity_auth::ScreenlockBridge::Get()->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())
302 return false;
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())
308 return false;
310 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
311 return false;
313 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
314 return false;
316 return true;
317 #else
318 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
319 return false;
320 #endif
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;
340 // disregard them.
341 if (screen_type != proximity_auth::ScreenlockBridge::LockHandler::LOCK_SCREEN)
342 return;
344 // Only record metrics for users who have enabled the feature.
345 if (IsEnabled()) {
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) {
363 // Nothing to do.
366 void EasyUnlockServiceRegular::OnPrefsChanged() {
367 SyncProfilePrefsToLocalState();
368 UpdateAppState();
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)
396 return;
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());