Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service_regular.cc
blobcd967d2a055883353a670a33bd49e86c2d1f5673
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/command_line.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/sys_info.h"
13 #include "base/time/default_clock.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/services/gcm/gcm_profile_service.h"
18 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
19 #include "chrome/browser/signin/chrome_proximity_auth_client.h"
20 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/common/extensions/api/easy_unlock_private.h"
23 #include "chrome/common/extensions/extension_constants.h"
24 #include "chrome/common/pref_names.h"
25 #include "chromeos/login/user_names.h"
26 #include "components/pref_registry/pref_registry_syncable.h"
27 #include "components/proximity_auth/cryptauth/cryptauth_access_token_fetcher.h"
28 #include "components/proximity_auth/cryptauth/cryptauth_client_impl.h"
29 #include "components/proximity_auth/cryptauth/cryptauth_device_manager.h"
30 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
31 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_utils.h"
32 #include "components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h"
33 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
34 #include "components/proximity_auth/cryptauth_enroller_factory_impl.h"
35 #include "components/proximity_auth/logging/logging.h"
36 #include "components/proximity_auth/screenlock_bridge.h"
37 #include "components/proximity_auth/switches.h"
38 #include "components/signin/core/browser/profile_oauth2_token_service.h"
39 #include "components/signin/core/browser/signin_manager.h"
40 #include "components/translate/core/browser/translate_download_manager.h"
41 #include "components/version_info/version_info.h"
42 #include "content/public/browser/browser_thread.h"
43 #include "extensions/browser/event_router.h"
44 #include "extensions/common/constants.h"
45 #include "google_apis/gaia/gaia_auth_util.h"
47 #if defined(OS_CHROMEOS)
48 #include "apps/app_lifetime_monitor_factory.h"
49 #include "ash/display/display_info.h"
50 #include "ash/display/display_manager.h"
51 #include "ash/shell.h"
52 #include "base/linux_util.h"
53 #include "base/thread_task_runner_handle.h"
54 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
55 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h"
56 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
57 #include "chrome/browser/chromeos/profiles/profile_helper.h"
58 #include "components/user_manager/user_manager.h"
59 #endif
61 namespace {
63 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
64 const char kKeyPermitAccess[] = "permitAccess";
66 // Key name of the remote device list in kEasyUnlockPairing.
67 const char kKeyDevices[] = "devices";
69 } // namespace
71 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile)
72 : EasyUnlockService(profile),
73 turn_off_flow_status_(EasyUnlockService::IDLE),
74 will_unlock_using_easy_unlock_(false),
75 lock_screen_last_shown_timestamp_(base::TimeTicks::Now()),
76 weak_ptr_factory_(this) {
79 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
82 proximity_auth::CryptAuthEnrollmentManager*
83 EasyUnlockServiceRegular::GetCryptAuthEnrollmentManager() {
84 return enrollment_manager_.get();
87 proximity_auth::CryptAuthDeviceManager*
88 EasyUnlockServiceRegular::GetCryptAuthDeviceManager() {
89 return device_manager_.get();
92 EasyUnlockService::Type EasyUnlockServiceRegular::GetType() const {
93 return EasyUnlockService::TYPE_REGULAR;
96 std::string EasyUnlockServiceRegular::GetUserEmail() const {
97 const SigninManagerBase* signin_manager =
98 SigninManagerFactory::GetForProfileIfExists(profile());
99 // |profile| has to be a signed-in profile with SigninManager already
100 // created. Otherwise, just crash to collect stack.
101 DCHECK(signin_manager);
102 const std::string user_email =
103 signin_manager->GetAuthenticatedAccountInfo().email;
104 return user_email.empty() ? user_email : gaia::CanonicalizeEmail(user_email);
107 void EasyUnlockServiceRegular::LaunchSetup() {
108 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
109 #if defined(OS_CHROMEOS)
110 // Force the user to reauthenticate by showing a modal overlay (similar to the
111 // lock screen). The password obtained from the reauth is cached for a short
112 // period of time and used to create the cryptohome keys for sign-in.
113 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
114 OpenSetupApp();
115 } else {
116 bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext(
117 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth,
118 weak_ptr_factory_.GetWeakPtr()));
119 if (!reauth_success)
120 OpenSetupApp();
122 #else
123 OpenSetupApp();
124 #endif
127 #if defined(OS_CHROMEOS)
128 void EasyUnlockServiceRegular::OnUserContextFromReauth(
129 const chromeos::UserContext& user_context) {
130 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
131 short_lived_user_context_.reset(new chromeos::ShortLivedUserContext(
132 user_context, apps::AppLifetimeMonitorFactory::GetForProfile(profile()),
133 base::ThreadTaskRunnerHandle::Get().get()));
135 OpenSetupApp();
137 // Use this opportunity to clear the crytohome keys if it was not already
138 // cleared earlier.
139 const base::ListValue* devices = GetRemoteDevices();
140 if (!devices || devices->empty()) {
141 chromeos::EasyUnlockKeyManager* key_manager =
142 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
143 key_manager->RefreshKeys(
144 user_context, base::ListValue(),
145 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
146 weak_ptr_factory_.GetWeakPtr(),
147 EasyUnlockScreenlockStateHandler::NO_PAIRING));
151 void EasyUnlockServiceRegular::SetHardlockAfterKeyOperation(
152 EasyUnlockScreenlockStateHandler::HardlockState state_on_success,
153 bool success) {
154 if (success)
155 SetHardlockStateForUser(GetUserEmail(), state_on_success);
157 // Even if the refresh keys operation suceeded, we still fetch and check the
158 // cryptohome keys against the keys in local preferences as a sanity check.
159 CheckCryptohomeKeysAndMaybeHardlock();
161 #endif
163 const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const {
164 const base::DictionaryValue* pairing_dict =
165 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
166 const base::DictionaryValue* permit_dict = NULL;
167 if (pairing_dict &&
168 pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict))
169 return permit_dict;
171 return NULL;
174 void EasyUnlockServiceRegular::SetPermitAccess(
175 const base::DictionaryValue& permit) {
176 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
177 prefs::kEasyUnlockPairing);
178 pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy());
181 void EasyUnlockServiceRegular::ClearPermitAccess() {
182 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
183 prefs::kEasyUnlockPairing);
184 pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
187 const base::ListValue* EasyUnlockServiceRegular::GetRemoteDevices() const {
188 const base::DictionaryValue* pairing_dict =
189 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
190 const base::ListValue* devices = NULL;
191 if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices))
192 return devices;
193 return NULL;
196 void EasyUnlockServiceRegular::SetRemoteDevices(
197 const base::ListValue& devices) {
198 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
199 prefs::kEasyUnlockPairing);
200 if (devices.empty())
201 pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
202 else
203 pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy());
205 #if defined(OS_CHROMEOS)
206 // TODO(tengs): Investigate if we can determine if the remote devices were set
207 // from sync or from the setup app.
208 if (short_lived_user_context_ && short_lived_user_context_->user_context()) {
209 // We may already have the password cached, so proceed to create the
210 // cryptohome keys for sign-in or the system will be hardlocked.
211 chromeos::UserSessionManager::GetInstance()
212 ->GetEasyUnlockKeyManager()
213 ->RefreshKeys(
214 *short_lived_user_context_->user_context(), devices,
215 base::Bind(&EasyUnlockServiceRegular::SetHardlockAfterKeyOperation,
216 weak_ptr_factory_.GetWeakPtr(),
217 EasyUnlockScreenlockStateHandler::NO_HARDLOCK));
218 } else {
219 CheckCryptohomeKeysAndMaybeHardlock();
221 #else
222 CheckCryptohomeKeysAndMaybeHardlock();
223 #endif
226 void EasyUnlockServiceRegular::RunTurnOffFlow() {
227 if (turn_off_flow_status_ == PENDING)
228 return;
229 DCHECK(!cryptauth_client_);
231 SetTurnOffFlowStatus(PENDING);
233 scoped_ptr<proximity_auth::CryptAuthClientFactory> factory =
234 proximity_auth_client()->CreateCryptAuthClientFactory();
235 cryptauth_client_ = factory->CreateInstance();
237 cryptauth::ToggleEasyUnlockRequest request;
238 request.set_enable(false);
239 request.set_apply_to_all(true);
240 cryptauth_client_->ToggleEasyUnlock(
241 request,
242 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete,
243 weak_ptr_factory_.GetWeakPtr()),
244 base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed,
245 weak_ptr_factory_.GetWeakPtr()));
248 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
249 cryptauth_client_.reset();
250 SetTurnOffFlowStatus(IDLE);
253 EasyUnlockService::TurnOffFlowStatus
254 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
255 return turn_off_flow_status_;
258 std::string EasyUnlockServiceRegular::GetChallenge() const {
259 return std::string();
262 std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
263 return std::string();
266 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
267 const std::string& user_id,
268 bool success) const {
269 NOTREACHED();
272 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
273 const std::string& user_id) const {
274 NOTREACHED();
277 void EasyUnlockServiceRegular::StartAutoPairing(
278 const AutoPairingResultCallback& callback) {
279 if (!auto_pairing_callback_.is_null()) {
280 LOG(ERROR)
281 << "Start auto pairing when there is another auto pairing requested.";
282 callback.Run(false, std::string());
283 return;
286 auto_pairing_callback_ = callback;
288 scoped_ptr<base::ListValue> args(new base::ListValue());
289 scoped_ptr<extensions::Event> event(new extensions::Event(
290 extensions::events::EASY_UNLOCK_PRIVATE_ON_START_AUTO_PAIRING,
291 extensions::api::easy_unlock_private::OnStartAutoPairing::kEventName,
292 args.Pass()));
293 extensions::EventRouter::Get(profile())->DispatchEventWithLazyListener(
294 extension_misc::kEasyUnlockAppId, event.Pass());
297 void EasyUnlockServiceRegular::SetAutoPairingResult(
298 bool success,
299 const std::string& error) {
300 DCHECK(!auto_pairing_callback_.is_null());
302 auto_pairing_callback_.Run(success, error);
303 auto_pairing_callback_.Reset();
306 void EasyUnlockServiceRegular::InitializeInternal() {
307 proximity_auth::ScreenlockBridge::Get()->AddObserver(this);
308 registrar_.Init(profile()->GetPrefs());
309 registrar_.Add(
310 prefs::kEasyUnlockAllowed,
311 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
312 base::Unretained(this)));
313 registrar_.Add(prefs::kEasyUnlockProximityRequired,
314 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
315 base::Unretained(this)));
317 #if defined(OS_CHROMEOS)
318 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
319 proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery))
320 InitializeCryptAuth();
321 #endif
323 OnPrefsChanged();
326 void EasyUnlockServiceRegular::ShutdownInternal() {
327 #if defined(OS_CHROMEOS)
328 short_lived_user_context_.reset();
329 #endif
331 turn_off_flow_status_ = EasyUnlockService::IDLE;
332 registrar_.RemoveAll();
333 proximity_auth::ScreenlockBridge::Get()->RemoveObserver(this);
336 bool EasyUnlockServiceRegular::IsAllowedInternal() const {
337 #if defined(OS_CHROMEOS)
338 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
339 if (!user_manager->IsLoggedInAsUserWithGaiaAccount())
340 return false;
342 // TODO(tengs): Ephemeral accounts generate a new enrollment every time they
343 // are added, so disable Smart Lock to reduce enrollments on server. However,
344 // ephemeral accounts can be locked, so we should revisit this use case.
345 if (user_manager->IsCurrentUserNonCryptohomeDataEphemeral())
346 return false;
348 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
349 return false;
351 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
352 return false;
354 return true;
355 #else
356 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
357 return false;
358 #endif
361 void EasyUnlockServiceRegular::OnWillFinalizeUnlock(bool success) {
362 will_unlock_using_easy_unlock_ = success;
365 void EasyUnlockServiceRegular::OnSuspendDone() {
366 lock_screen_last_shown_timestamp_ = base::TimeTicks::Now();
369 void EasyUnlockServiceRegular::OnRefreshTokenAvailable(
370 const std::string& account_id) {
371 if (account_id == proximity_auth_client()->GetAccountId()) {
372 OAuth2TokenService* token_service =
373 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
374 token_service->RemoveObserver(this);
375 #if defined(OS_CHROMEOS)
376 InitializeCryptAuth();
377 #endif
381 void EasyUnlockServiceRegular::OnScreenDidLock(
382 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
383 will_unlock_using_easy_unlock_ = false;
384 lock_screen_last_shown_timestamp_ = base::TimeTicks::Now();
387 void EasyUnlockServiceRegular::OnScreenDidUnlock(
388 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
389 // Notifications of signin screen unlock events can also reach this code path;
390 // disregard them.
391 if (screen_type != proximity_auth::ScreenlockBridge::LockHandler::LOCK_SCREEN)
392 return;
394 // Only record metrics for users who have enabled the feature.
395 if (IsEnabled()) {
396 EasyUnlockAuthEvent event =
397 will_unlock_using_easy_unlock_
398 ? EASY_UNLOCK_SUCCESS
399 : GetPasswordAuthEvent();
400 RecordEasyUnlockScreenUnlockEvent(event);
402 if (will_unlock_using_easy_unlock_) {
403 RecordEasyUnlockScreenUnlockDuration(
404 base::TimeTicks::Now() - lock_screen_last_shown_timestamp_);
408 will_unlock_using_easy_unlock_ = false;
411 void EasyUnlockServiceRegular::OnFocusedUserChanged(
412 const std::string& user_id) {
413 // Nothing to do.
416 void EasyUnlockServiceRegular::OnPrefsChanged() {
417 SyncProfilePrefsToLocalState();
418 UpdateAppState();
421 void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
422 turn_off_flow_status_ = status;
423 NotifyTurnOffOperationStatusChanged();
426 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete(
427 const cryptauth::ToggleEasyUnlockResponse& response) {
428 cryptauth_client_.reset();
430 SetRemoteDevices(base::ListValue());
431 SetTurnOffFlowStatus(IDLE);
432 ReloadAppAndLockScreen();
435 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed(
436 const std::string& error_message) {
437 LOG(WARNING) << "Failed to turn off Smart Lock: " << error_message;
438 SetTurnOffFlowStatus(FAIL);
441 void EasyUnlockServiceRegular::SyncProfilePrefsToLocalState() {
442 PrefService* local_state =
443 g_browser_process ? g_browser_process->local_state() : NULL;
444 PrefService* profile_prefs = profile()->GetPrefs();
445 if (!local_state || !profile_prefs)
446 return;
448 // Create the dictionary of Easy Unlock preferences for the current user. The
449 // items in the dictionary are the same profile prefs used for Easy Unlock.
450 scoped_ptr<base::DictionaryValue> user_prefs_dict(
451 new base::DictionaryValue());
452 user_prefs_dict->SetBooleanWithoutPathExpansion(
453 prefs::kEasyUnlockProximityRequired,
454 profile_prefs->GetBoolean(prefs::kEasyUnlockProximityRequired));
456 DictionaryPrefUpdate update(local_state,
457 prefs::kEasyUnlockLocalStateUserPrefs);
458 std::string user_email = GetUserEmail();
459 update->SetWithoutPathExpansion(user_email, user_prefs_dict.Pass());
462 cryptauth::GcmDeviceInfo EasyUnlockServiceRegular::GetGcmDeviceInfo() {
463 cryptauth::GcmDeviceInfo device_info;
464 device_info.set_long_device_id(EasyUnlockService::GetDeviceId());
465 device_info.set_device_type(cryptauth::CHROME);
466 device_info.set_device_software_version(version_info::GetVersionNumber());
467 google::protobuf::int64 software_version_code =
468 proximity_auth::HashStringToInt64(version_info::GetLastChange());
469 device_info.set_device_software_version_code(software_version_code);
470 device_info.set_locale(
471 translate::TranslateDownloadManager::GetInstance()->application_locale());
473 #if defined(OS_CHROMEOS)
474 device_info.set_device_model(base::SysInfo::GetLsbReleaseBoard());
475 device_info.set_device_os_version(base::GetLinuxDistro());
476 // The Chrome OS version tracks the Chrome version, so fill in the same value
477 // as |device_software_version_code|.
478 device_info.set_device_os_version_code(software_version_code);
480 // There may not be a Shell instance in tests.
481 if (!ash::Shell::HasInstance())
482 return device_info;
484 ash::DisplayManager* display_manager =
485 ash::Shell::GetInstance()->display_manager();
486 int64 primary_display_id = display_manager->GetPrimaryDisplayCandidate().id();
487 ash::DisplayInfo display_info =
488 display_manager->GetDisplayInfo(primary_display_id);
489 gfx::Rect bounds = display_info.bounds_in_native();
491 // TODO(tengs): This is a heuristic to deterimine the DPI of the display, as
492 // there is no convenient way of getting this information right now.
493 const double dpi = display_info.device_scale_factor() > 1.0f ? 239.0f : 96.0f;
494 double width_in_inches = (bounds.width() - bounds.x()) / dpi;
495 double height_in_inches = (bounds.height() - bounds.y()) / dpi;
496 double diagonal_in_inches = sqrt(width_in_inches * width_in_inches +
497 height_in_inches * height_in_inches);
499 // Note: The unit of this measument is in milli-inches.
500 device_info.set_device_display_diagonal_mils(diagonal_in_inches * 1000.0);
501 #else
502 // TODO(tengs): Fill in device information for other platforms.
503 #endif
504 return device_info;
507 #if defined(OS_CHROMEOS)
508 void EasyUnlockServiceRegular::InitializeCryptAuth() {
509 OAuth2TokenService* token_service =
510 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
511 if (!token_service->RefreshTokenIsAvailable(
512 proximity_auth_client()->GetAccountId())) {
513 PA_LOG(INFO) << "Refresh token not yet available.";
514 token_service->AddObserver(this);
515 return;
518 PA_LOG(INFO) << "Initializing CryptAuth managers.";
519 // Initialize GCM manager.
520 gcm_manager_.reset(new proximity_auth::CryptAuthGCMManagerImpl(
521 gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver(),
522 proximity_auth_client()->GetPrefService()));
523 gcm_manager_->StartListening();
525 // Initialize enrollment manager.
526 cryptauth::GcmDeviceInfo device_info;
527 enrollment_manager_.reset(new proximity_auth::CryptAuthEnrollmentManager(
528 make_scoped_ptr(new base::DefaultClock()),
529 make_scoped_ptr(new proximity_auth::CryptAuthEnrollerFactoryImpl(
530 proximity_auth_client())),
531 proximity_auth_client()->CreateSecureMessageDelegate(),
532 GetGcmDeviceInfo(), gcm_manager_.get(),
533 proximity_auth_client()->GetPrefService()));
534 enrollment_manager_->Start();
536 // Initialize device manager.
537 device_manager_.reset(new proximity_auth::CryptAuthDeviceManager(
538 make_scoped_ptr(new base::DefaultClock()),
539 proximity_auth_client()->CreateCryptAuthClientFactory(),
540 gcm_manager_.get(), proximity_auth_client()->GetPrefService()));
541 device_manager_->Start();
543 #endif