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/metrics/field_trial.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/values.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/signin/easy_unlock_toggle_flow.h"
16 #include "chrome/browser/signin/screenlock_bridge.h"
17 #include "chrome/browser/ui/extensions/application_launch.h"
18 #include "chrome/common/extensions/extension_constants.h"
19 #include "chrome/common/pref_names.h"
20 #include "components/pref_registry/pref_registry_syncable.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "extensions/browser/extension_system.h"
24 #if defined(OS_CHROMEOS)
25 #include "apps/app_lifetime_monitor_factory.h"
26 #include "base/thread_task_runner_handle.h"
27 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
28 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h"
29 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
30 #include "chrome/browser/chromeos/profiles/profile_helper.h"
31 #include "components/user_manager/user_manager.h"
36 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
37 const char kKeyPermitAccess[] = "permitAccess";
39 // Key name of the remote device list in kEasyUnlockPairing.
40 const char kKeyDevices[] = "devices";
42 // Key name of the phone public key in a device dictionary.
43 const char kKeyPhoneId[] = "permitRecord.id";
47 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile)
48 : EasyUnlockService(profile),
49 turn_off_flow_status_(EasyUnlockService::IDLE),
50 weak_ptr_factory_(this) {
53 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
56 EasyUnlockService::Type EasyUnlockServiceRegular::GetType() const {
57 return EasyUnlockService::TYPE_REGULAR;
60 std::string EasyUnlockServiceRegular::GetUserEmail() const {
61 return ScreenlockBridge::GetAuthenticatedUserEmail(profile());
64 void EasyUnlockServiceRegular::LaunchSetup() {
65 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
66 #if defined(OS_CHROMEOS)
67 // 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()) {
73 bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext(
74 base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth,
75 weak_ptr_factory_.GetWeakPtr()));
84 #if defined(OS_CHROMEOS)
85 void 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()));
95 void 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.
100 SetHardlockStateForUser(GetUserEmail(),
101 EasyUnlockScreenlockStateHandler::NO_HARDLOCK);
104 // Even if the keys refresh suceeded, we still fetch the cryptohome keys as a
106 CheckCryptohomeKeysAndMaybeHardlock();
110 void EasyUnlockServiceRegular::OpenSetupApp() {
111 ExtensionService* service =
112 extensions::ExtensionSystem::Get(profile())->extension_service();
113 const extensions::Extension* extension =
114 service->GetExtensionById(extension_misc::kEasyUnlockAppId, false);
116 OpenApplication(AppLaunchParams(
117 profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW));
120 const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const {
121 const base::DictionaryValue* pairing_dict =
122 profile()->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
123 const base::DictionaryValue* permit_dict = NULL;
125 pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict))
131 void EasyUnlockServiceRegular::SetPermitAccess(
132 const base::DictionaryValue& permit) {
133 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
134 prefs::kEasyUnlockPairing);
135 pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy());
138 void EasyUnlockServiceRegular::ClearPermitAccess() {
139 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
140 prefs::kEasyUnlockPairing);
141 pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
144 const 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))
154 void EasyUnlockServiceRegular::SetRemoteDevices(
155 const base::ListValue& devices) {
156 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
157 prefs::kEasyUnlockPairing);
158 pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy());
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() &&
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();
172 key_manager->RefreshKeys(
173 *user_context, devices,
174 base::Bind(&EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices,
175 weak_ptr_factory_.GetWeakPtr()));
177 CheckCryptohomeKeysAndMaybeHardlock();
180 CheckCryptohomeKeysAndMaybeHardlock();
184 void EasyUnlockServiceRegular::ClearRemoteDevices() {
185 DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
186 prefs::kEasyUnlockPairing);
187 pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
188 CheckCryptohomeKeysAndMaybeHardlock();
191 void EasyUnlockServiceRegular::RunTurnOffFlow() {
192 if (turn_off_flow_status_ == PENDING)
195 SetTurnOffFlowStatus(PENDING);
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) ||
208 !first_device->GetString(kKeyPhoneId, &phone_public_key)) {
209 LOG(WARNING) << "Bad easy unlock pairing data, wiping out local data";
210 OnTurnOffFlowFinished(true);
214 turn_off_flow_.reset(new EasyUnlockToggleFlow(
218 base::Bind(&EasyUnlockServiceRegular::OnTurnOffFlowFinished,
219 base::Unretained(this))));
220 turn_off_flow_->Start();
223 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
224 turn_off_flow_.reset();
225 SetTurnOffFlowStatus(IDLE);
228 EasyUnlockService::TurnOffFlowStatus
229 EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
230 return turn_off_flow_status_;
233 std::string EasyUnlockServiceRegular::GetChallenge() const {
234 return std::string();
237 std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
238 return std::string();
241 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
242 const std::string& user_id,
243 bool success) const {
247 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
248 const std::string& user_id) const {
252 void EasyUnlockServiceRegular::InitializeInternal() {
253 registrar_.Init(profile()->GetPrefs());
255 prefs::kEasyUnlockAllowed,
256 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
257 base::Unretained(this)));
261 void EasyUnlockServiceRegular::ShutdownInternal() {
262 #if defined(OS_CHROMEOS)
263 short_lived_user_context_.reset();
266 turn_off_flow_.reset();
267 turn_off_flow_status_ = EasyUnlockService::IDLE;
268 registrar_.RemoveAll();
271 bool EasyUnlockServiceRegular::IsAllowedInternal() {
272 #if defined(OS_CHROMEOS)
273 if (!user_manager::UserManager::Get()->IsLoggedInAsRegularUser())
276 if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
279 if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
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";
290 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
295 void EasyUnlockServiceRegular::OnPrefsChanged() {
299 void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
300 turn_off_flow_status_ = status;
301 NotifyTurnOffOperationStatusChanged();
304 void EasyUnlockServiceRegular::OnTurnOffFlowFinished(bool success) {
305 turn_off_flow_.reset();
308 SetTurnOffFlowStatus(FAIL);
312 ClearRemoteDevices();
313 SetTurnOffFlowStatus(IDLE);