[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service_signin_chromeos.cc
blobad3536f856e0c06e985c3d3a5f3ae6af37c9bdf6
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_signin_chromeos.h"
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/sys_info.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
16 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
17 #include "chrome/browser/signin/easy_unlock_app_manager.h"
18 #include "chrome/browser/signin/easy_unlock_metrics.h"
19 #include "chrome/browser/signin/proximity_auth_facade.h"
20 #include "chromeos/login/auth/user_context.h"
21 #include "chromeos/tpm/tpm_token_loader.h"
23 namespace {
25 // The maximum allowed backoff interval when waiting for cryptohome to start.
26 uint32 kMaxCryptohomeBackoffIntervalMs = 10000u;
28 // If the data load fails, the initial interval after which the load will be
29 // retried. Further intervals will exponentially increas by factor 2.
30 uint32 kInitialCryptohomeBackoffIntervalMs = 200u;
32 // Calculates the backoff interval that should be used next.
33 // |backoff| The last backoff interval used.
34 uint32 GetNextBackoffInterval(uint32 backoff) {
35 if (backoff == 0u)
36 return kInitialCryptohomeBackoffIntervalMs;
37 return backoff * 2;
40 void LoadDataForUser(
41 const std::string& user_id,
42 uint32 backoff_ms,
43 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback);
45 // Callback passed to |LoadDataForUser()|.
46 // If |LoadDataForUser| function succeeded, it invokes |callback| with the
47 // results.
48 // If |LoadDataForUser| failed and further retries are allowed, schedules new
49 // |LoadDataForUser| call with some backoff. If no further retires are allowed,
50 // it invokes |callback| with the |LoadDataForUser| results.
51 void RetryDataLoadOnError(
52 const std::string& user_id,
53 uint32 backoff_ms,
54 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback,
55 bool success,
56 const chromeos::EasyUnlockDeviceKeyDataList& data_list) {
57 if (success) {
58 callback.Run(success, data_list);
59 return;
62 uint32 next_backoff_ms = GetNextBackoffInterval(backoff_ms);
63 if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) {
64 callback.Run(false, data_list);
65 return;
68 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
69 FROM_HERE,
70 base::Bind(&LoadDataForUser, user_id, next_backoff_ms, callback),
71 base::TimeDelta::FromMilliseconds(next_backoff_ms));
74 // Loads device data list associated with the user's Easy unlock keys.
75 void LoadDataForUser(
76 const std::string& user_id,
77 uint32 backoff_ms,
78 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback) {
79 chromeos::EasyUnlockKeyManager* key_manager =
80 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
81 DCHECK(key_manager);
83 key_manager->GetDeviceDataList(
84 chromeos::UserContext(user_id),
85 base::Bind(&RetryDataLoadOnError, user_id, backoff_ms, callback));
88 } // namespace
90 EasyUnlockServiceSignin::UserData::UserData()
91 : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) {
94 EasyUnlockServiceSignin::UserData::~UserData() {}
96 EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile)
97 : EasyUnlockService(profile),
98 allow_cryptohome_backoff_(true),
99 service_active_(false),
100 user_pod_last_focused_timestamp_(base::TimeTicks::Now()),
101 weak_ptr_factory_(this) {
104 EasyUnlockServiceSignin::~EasyUnlockServiceSignin() {
107 void EasyUnlockServiceSignin::SetCurrentUser(const std::string& user_id) {
108 OnFocusedUserChanged(user_id);
111 EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const {
112 return EasyUnlockService::TYPE_SIGNIN;
115 std::string EasyUnlockServiceSignin::GetUserEmail() const {
116 return user_id_;
119 void EasyUnlockServiceSignin::LaunchSetup() {
120 NOTREACHED();
123 const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const {
124 return NULL;
127 void EasyUnlockServiceSignin::SetPermitAccess(
128 const base::DictionaryValue& permit) {
129 NOTREACHED();
132 void EasyUnlockServiceSignin::ClearPermitAccess() {
133 NOTREACHED();
136 const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const {
137 const UserData* data = FindLoadedDataForCurrentUser();
138 if (!data)
139 return NULL;
140 return &data->remote_devices_value;
143 void EasyUnlockServiceSignin::SetRemoteDevices(
144 const base::ListValue& devices) {
145 NOTREACHED();
148 void EasyUnlockServiceSignin::RunTurnOffFlow() {
149 NOTREACHED();
152 void EasyUnlockServiceSignin::ResetTurnOffFlow() {
153 NOTREACHED();
156 EasyUnlockService::TurnOffFlowStatus
157 EasyUnlockServiceSignin::GetTurnOffFlowStatus() const {
158 return EasyUnlockService::IDLE;
161 std::string EasyUnlockServiceSignin::GetChallenge() const {
162 const UserData* data = FindLoadedDataForCurrentUser();
163 // TODO(xiyuan): Use correct remote device instead of hard coded first one.
164 uint32 device_index = 0;
165 if (!data || data->devices.size() <= device_index)
166 return std::string();
167 return data->devices[device_index].challenge;
170 std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
171 const UserData* data = FindLoadedDataForCurrentUser();
172 // TODO(xiyuan): Use correct remote device instead of hard coded first one.
173 uint32 device_index = 0;
174 if (!data || data->devices.size() <= device_index)
175 return std::string();
176 return data->devices[device_index].wrapped_secret;
179 void EasyUnlockServiceSignin::RecordEasySignInOutcome(
180 const std::string& user_id,
181 bool success) const {
182 DCHECK_EQ(GetUserEmail(), user_id);
184 RecordEasyUnlockSigninEvent(
185 success ? EASY_UNLOCK_SUCCESS : EASY_UNLOCK_FAILURE);
186 if (success) {
187 RecordEasyUnlockSigninDuration(
188 base::TimeTicks::Now() - user_pod_last_focused_timestamp_);
190 DVLOG(1) << "Easy sign-in " << (success ? "success" : "failure");
193 void EasyUnlockServiceSignin::RecordPasswordLoginEvent(
194 const std::string& user_id) const {
195 // This happens during tests, where a user could log in without the user pod
196 // being focused.
197 if (GetUserEmail() != user_id)
198 return;
200 if (!IsEnabled())
201 return;
203 EasyUnlockAuthEvent event = GetPasswordAuthEvent();
204 RecordEasyUnlockSigninEvent(event);
205 DVLOG(1) << "Easy Sign-in password login event, event=" << event;
208 void EasyUnlockServiceSignin::StartAutoPairing(
209 const AutoPairingResultCallback& callback) {
210 NOTREACHED();
213 void EasyUnlockServiceSignin::SetAutoPairingResult(
214 bool success,
215 const std::string& error) {
216 NOTREACHED();
219 void EasyUnlockServiceSignin::InitializeInternal() {
220 if (chromeos::LoginState::Get()->IsUserLoggedIn())
221 return;
223 service_active_ = true;
225 chromeos::LoginState::Get()->AddObserver(this);
226 proximity_auth::ScreenlockBridge* screenlock_bridge =
227 GetScreenlockBridgeInstance();
228 screenlock_bridge->AddObserver(this);
229 if (!screenlock_bridge->focused_user_id().empty())
230 OnFocusedUserChanged(screenlock_bridge->focused_user_id());
233 void EasyUnlockServiceSignin::ShutdownInternal() {
234 if (!service_active_)
235 return;
236 service_active_ = false;
238 weak_ptr_factory_.InvalidateWeakPtrs();
239 GetScreenlockBridgeInstance()->RemoveObserver(this);
240 chromeos::LoginState::Get()->RemoveObserver(this);
241 STLDeleteContainerPairSecondPointers(user_data_.begin(), user_data_.end());
242 user_data_.clear();
245 bool EasyUnlockServiceSignin::IsAllowedInternal() const {
246 return service_active_ &&
247 !user_id_.empty() &&
248 !chromeos::LoginState::Get()->IsUserLoggedIn();
251 void EasyUnlockServiceSignin::OnWillFinalizeUnlock(bool success) {
252 // This code path should only be exercised for the lock screen, not for the
253 // sign-in screen.
254 NOTREACHED();
257 void EasyUnlockServiceSignin::OnSuspendDone() {
258 // Ignored.
261 void EasyUnlockServiceSignin::OnScreenDidLock(
262 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
263 // In production code, the screen type should always be the signin screen; but
264 // in tests, the screen type might be different.
265 if (screen_type !=
266 proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
267 return;
269 // Update initial UI is when the account picker on login screen is ready.
270 ShowInitialUserState();
271 user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
274 void EasyUnlockServiceSignin::OnScreenDidUnlock(
275 proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
276 // In production code, the screen type should always be the signin screen; but
277 // in tests, the screen type might be different.
278 if (screen_type !=
279 proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
280 return;
282 DisableAppWithoutResettingScreenlockState();
284 Shutdown();
287 void EasyUnlockServiceSignin::OnFocusedUserChanged(const std::string& user_id) {
288 if (user_id_ == user_id)
289 return;
291 // Setting or clearing the user_id may changed |IsAllowed| value, so in these
292 // cases update the app state. Otherwise, it's enough to notify the app the
293 // user data has been updated.
294 bool should_update_app_state = user_id_.empty() != user_id.empty();
295 user_id_ = user_id;
296 user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
298 ResetScreenlockState();
299 ShowInitialUserState();
301 if (should_update_app_state) {
302 UpdateAppState();
303 } else {
304 NotifyUserUpdated();
307 LoadCurrentUserDataIfNeeded();
309 // Start loading TPM system token.
310 // The system token will be needed to sign a nonce using TPM private key
311 // during the sign-in protocol.
312 EasyUnlockScreenlockStateHandler::HardlockState hardlock_state;
313 if (GetPersistedHardlockState(&hardlock_state) &&
314 hardlock_state != EasyUnlockScreenlockStateHandler::NO_PAIRING) {
315 chromeos::TPMTokenLoader::Get()->EnsureStarted();
319 void EasyUnlockServiceSignin::LoggedInStateChanged() {
320 if (!chromeos::LoginState::Get()->IsUserLoggedIn())
321 return;
322 DisableAppWithoutResettingScreenlockState();
325 void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() {
326 // TODO(xiyuan): Revisit this when adding tests.
327 if (!base::SysInfo::IsRunningOnChromeOS())
328 return;
330 if (user_id_.empty() || !service_active_)
331 return;
333 std::map<std::string, UserData*>::iterator it = user_data_.find(user_id_);
334 if (it == user_data_.end())
335 user_data_.insert(std::make_pair(user_id_, new UserData()));
337 UserData* data = user_data_[user_id_];
339 if (data->state != USER_DATA_STATE_INITIAL)
340 return;
341 data->state = USER_DATA_STATE_LOADING;
343 LoadDataForUser(
344 user_id_,
345 allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs,
346 base::Bind(&EasyUnlockServiceSignin::OnUserDataLoaded,
347 weak_ptr_factory_.GetWeakPtr(),
348 user_id_));
351 void EasyUnlockServiceSignin::OnUserDataLoaded(
352 const std::string& user_id,
353 bool success,
354 const chromeos::EasyUnlockDeviceKeyDataList& devices) {
355 allow_cryptohome_backoff_ = false;
357 UserData* data = user_data_[user_id];
358 data->state = USER_DATA_STATE_LOADED;
359 if (success) {
360 data->devices = devices;
361 chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
362 user_id, devices, &data->remote_devices_value);
364 // User could have a NO_HARDLOCK state but has no remote devices if
365 // previous user session shuts down before
366 // CheckCryptohomeKeysAndMaybeHardlock finishes. Set NO_PAIRING state
367 // and update UI to remove the confusing spinner in this case.
368 EasyUnlockScreenlockStateHandler::HardlockState hardlock_state;
369 if (devices.empty() &&
370 GetPersistedHardlockState(&hardlock_state) &&
371 hardlock_state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) {
372 SetHardlockStateForUser(user_id,
373 EasyUnlockScreenlockStateHandler::NO_PAIRING);
377 // If the fetched data belongs to the currently focused user, notify the app
378 // that it has to refresh it's user data.
379 if (user_id == user_id_)
380 NotifyUserUpdated();
383 const EasyUnlockServiceSignin::UserData*
384 EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const {
385 if (user_id_.empty())
386 return NULL;
388 std::map<std::string, UserData*>::const_iterator it =
389 user_data_.find(user_id_);
390 if (it == user_data_.end())
391 return NULL;
392 if (it->second->state != USER_DATA_STATE_LOADED)
393 return NULL;
394 return it->second;