Upstream version 11.39.250.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / signin / easy_unlock_service_regular.cc
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.
4
5 #include "chrome/browser/signin/easy_unlock_service_regular.h"
6
7 #include "base/bind.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"
23
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"
32 #endif
33
34 namespace {
35
36 // Key name of the local device permit record dictonary in kEasyUnlockPairing.
37 const char kKeyPermitAccess[] = "permitAccess";
38
39 // Key name of the remote device list in kEasyUnlockPairing.
40 const char kKeyDevices[] = "devices";
41
42 // Key name of the phone public key in a device dictionary.
43 const char kKeyPhoneId[] = "permitRecord.id";
44
45 }  // namespace
46
47 EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile)
48     : EasyUnlockService(profile),
49       turn_off_flow_status_(EasyUnlockService::IDLE),
50       weak_ptr_factory_(this) {
51 }
52
53 EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
54 }
55
56 EasyUnlockService::Type EasyUnlockServiceRegular::GetType() const {
57   return EasyUnlockService::TYPE_REGULAR;
58 }
59
60 std::string EasyUnlockServiceRegular::GetUserEmail() const {
61   return ScreenlockBridge::GetAuthenticatedUserEmail(profile());
62 }
63
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()) {
71     OpenSetupApp();
72   } else {
73     bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext(
74         base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth,
75                    weak_ptr_factory_.GetWeakPtr()));
76     if (!reauth_success)
77       OpenSetupApp();
78   }
79 #else
80   OpenSetupApp();
81 #endif
82 }
83
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()));
91
92   OpenSetupApp();
93 }
94
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.
99   if (success) {
100     SetHardlockStateForUser(GetUserEmail(),
101                             EasyUnlockScreenlockStateHandler::NO_HARDLOCK);
102   }
103
104   // Even if the keys refresh suceeded, we still fetch the cryptohome keys as a
105   // sanity check.
106   CheckCryptohomeKeysAndMaybeHardlock();
107 }
108 #endif
109
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);
115
116   OpenApplication(AppLaunchParams(
117       profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW));
118 }
119
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;
124   if (pairing_dict &&
125       pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict))
126     return permit_dict;
127
128   return NULL;
129 }
130
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());
136 }
137
138 void EasyUnlockServiceRegular::ClearPermitAccess() {
139   DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
140                                       prefs::kEasyUnlockPairing);
141   pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
142 }
143
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))
149     return devices;
150
151   return NULL;
152 }
153
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());
159
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() &&
164       !devices.empty()) {
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();
171
172     key_manager->RefreshKeys(
173         *user_context, devices,
174         base::Bind(&EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices,
175                    weak_ptr_factory_.GetWeakPtr()));
176   } else {
177     CheckCryptohomeKeysAndMaybeHardlock();
178   }
179 #else
180   CheckCryptohomeKeysAndMaybeHardlock();
181 #endif
182 }
183
184 void EasyUnlockServiceRegular::ClearRemoteDevices() {
185   DictionaryPrefUpdate pairing_update(profile()->GetPrefs(),
186                                       prefs::kEasyUnlockPairing);
187   pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
188   CheckCryptohomeKeysAndMaybeHardlock();
189 }
190
191 void EasyUnlockServiceRegular::RunTurnOffFlow() {
192   if (turn_off_flow_status_ == PENDING)
193     return;
194
195   SetTurnOffFlowStatus(PENDING);
196
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) ||
207       !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);
211     return;
212   }
213
214   turn_off_flow_.reset(new EasyUnlockToggleFlow(
215       profile(),
216       phone_public_key,
217       false,
218       base::Bind(&EasyUnlockServiceRegular::OnTurnOffFlowFinished,
219                  base::Unretained(this))));
220   turn_off_flow_->Start();
221 }
222
223 void EasyUnlockServiceRegular::ResetTurnOffFlow() {
224   turn_off_flow_.reset();
225   SetTurnOffFlowStatus(IDLE);
226 }
227
228 EasyUnlockService::TurnOffFlowStatus
229     EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
230   return turn_off_flow_status_;
231 }
232
233 std::string EasyUnlockServiceRegular::GetChallenge() const {
234   return std::string();
235 }
236
237 std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
238   return std::string();
239 }
240
241 void EasyUnlockServiceRegular::RecordEasySignInOutcome(
242     const std::string& user_id,
243     bool success) const {
244   NOTREACHED();
245 }
246
247 void EasyUnlockServiceRegular::RecordPasswordLoginEvent(
248     const std::string& user_id) const {
249   NOTREACHED();
250 }
251
252 void EasyUnlockServiceRegular::InitializeInternal() {
253   registrar_.Init(profile()->GetPrefs());
254   registrar_.Add(
255       prefs::kEasyUnlockAllowed,
256       base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
257                  base::Unretained(this)));
258   OnPrefsChanged();
259 }
260
261 void EasyUnlockServiceRegular::ShutdownInternal() {
262 #if defined(OS_CHROMEOS)
263   short_lived_user_context_.reset();
264 #endif
265
266   turn_off_flow_.reset();
267   turn_off_flow_status_ = EasyUnlockService::IDLE;
268   registrar_.RemoveAll();
269 }
270
271 bool EasyUnlockServiceRegular::IsAllowedInternal() {
272 #if defined(OS_CHROMEOS)
273   if (!user_manager::UserManager::Get()->IsLoggedInAsRegularUser())
274     return false;
275
276   if (!chromeos::ProfileHelper::IsPrimaryProfile(profile()))
277     return false;
278
279   if (!profile()->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
280     return false;
281
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";
286   }
287
288   return true;
289 #else
290   // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
291   return false;
292 #endif
293 }
294
295 void EasyUnlockServiceRegular::OnPrefsChanged() {
296   UpdateAppState();
297 }
298
299 void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
300   turn_off_flow_status_ = status;
301   NotifyTurnOffOperationStatusChanged();
302 }
303
304 void EasyUnlockServiceRegular::OnTurnOffFlowFinished(bool success) {
305   turn_off_flow_.reset();
306
307   if (!success) {
308     SetTurnOffFlowStatus(FAIL);
309     return;
310   }
311
312   ClearRemoteDevices();
313   SetTurnOffFlowStatus(IDLE);
314   ReloadApp();
315 }