Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/signin/easy_unlock_service_signin_chromeos.h" | 5 #include "chrome/browser/signin/easy_unlock_service_signin_chromeos.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/location.h" | |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/values.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/thread_task_runner_handle.h" | |
| 13 #include "base/time/time.h" | |
| 11 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" | 14 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" |
| 12 #include "chrome/browser/chromeos/login/session/user_session_manager.h" | 15 #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
| 13 #include "chromeos/chromeos_switches.h" | 16 #include "chromeos/chromeos_switches.h" |
| 14 #include "chromeos/login/auth/user_context.h" | 17 #include "chromeos/login/auth/user_context.h" |
| 15 | 18 |
| 19 namespace { | |
| 20 | |
| 21 // The maximum allowed backoff interval when waiting for cryptohome to start. | |
| 22 size_t kMaxCryptohomeBackoffIntervalMs = 10000u; | |
|
xiyuan
2014/09/22 20:12:43
nit: size_t -> uint32
tbarzic
2014/09/22 20:22:27
Done.
| |
| 23 | |
| 24 // If the data load fails, the initial interval after which the load will be | |
| 25 // retried. Further intervals will exponentially increas by factor 2. | |
| 26 size_t kInitialCryptohomeBackoffIntervalMs = 200u; | |
| 27 | |
| 28 // Calculates the backoff interval that should be used next. | |
| 29 // |backoff| The last backoff interval used. | |
| 30 size_t GetNextBackoffInterval(size_t backoff) { | |
| 31 if (backoff == 0u) | |
| 32 return kInitialCryptohomeBackoffIntervalMs; | |
| 33 return backoff * 2; | |
| 34 } | |
| 35 | |
| 36 void LoadDataForUser( | |
| 37 const std::string& user_id, | |
| 38 size_t backoff_ms, | |
| 39 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback); | |
| 40 | |
| 41 // Callback passed to |LoadDataForUser()|. | |
| 42 // If |LoadDataForUser| function succeeded, it invokes |callback| with the | |
| 43 // results. | |
| 44 // If |LoadDataForUser| failed and further retries are allowed, schedules new | |
| 45 // |LoadDataForUser| call with some backoff. If no further retires are allowed, | |
| 46 // it invokes |callback| with the |LoadDataForUser| results. | |
| 47 void RetryDataLoadOnError( | |
| 48 const std::string& user_id, | |
| 49 size_t backoff_ms, | |
| 50 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback, | |
| 51 bool success, | |
| 52 const chromeos::EasyUnlockDeviceKeyDataList& data_list) { | |
| 53 if (success) { | |
| 54 callback.Run(success, data_list); | |
| 55 return; | |
| 56 } | |
| 57 | |
| 58 size_t next_backoff_ms = GetNextBackoffInterval(backoff_ms); | |
| 59 if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) { | |
| 60 callback.Run(false, data_list); | |
| 61 return; | |
| 62 } | |
| 63 | |
| 64 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 65 FROM_HERE, | |
| 66 base::Bind(&LoadDataForUser, user_id, next_backoff_ms, callback), | |
| 67 base::TimeDelta::FromMilliseconds(next_backoff_ms)); | |
| 68 } | |
| 69 | |
| 70 // Loads device data list associated with the user's Easy unlock keys. | |
| 71 void LoadDataForUser( | |
| 72 const std::string& user_id, | |
| 73 size_t backoff_ms, | |
| 74 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback) { | |
| 75 chromeos::EasyUnlockKeyManager* key_manager = | |
| 76 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); | |
| 77 DCHECK(key_manager); | |
| 78 | |
| 79 key_manager->GetDeviceDataList( | |
| 80 chromeos::UserContext(user_id), | |
| 81 base::Bind(&RetryDataLoadOnError, user_id, backoff_ms, callback)); | |
| 82 } | |
| 83 | |
| 84 } // namespace | |
| 85 | |
| 86 EasyUnlockServiceSignin::UserData::UserData() | |
| 87 : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) { | |
| 88 } | |
| 89 | |
| 90 EasyUnlockServiceSignin::UserData::~UserData() {} | |
| 91 | |
| 16 EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile) | 92 EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile) |
| 17 : EasyUnlockService(profile), | 93 : EasyUnlockService(profile), |
| 94 allow_cryptohome_backoff_(true), | |
| 18 weak_ptr_factory_(this) { | 95 weak_ptr_factory_(this) { |
| 19 } | 96 } |
| 20 | 97 |
| 21 EasyUnlockServiceSignin::~EasyUnlockServiceSignin() { | 98 EasyUnlockServiceSignin::~EasyUnlockServiceSignin() { |
| 22 } | 99 STLDeleteContainerPairSecondPointers(user_data_.begin(), user_data_.end()); |
| 23 | |
| 24 void EasyUnlockServiceSignin::SetAssociatedUser(const std::string& user_id) { | |
| 25 if (user_id_ == user_id) | |
| 26 return; | |
| 27 | |
| 28 user_id_ = user_id; | |
| 29 FetchCryptohomeKeys(); | |
| 30 } | 100 } |
| 31 | 101 |
| 32 EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const { | 102 EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const { |
| 33 return EasyUnlockService::TYPE_SIGNIN; | 103 return EasyUnlockService::TYPE_SIGNIN; |
| 34 } | 104 } |
| 35 | 105 |
| 36 std::string EasyUnlockServiceSignin::GetUserEmail() const { | 106 std::string EasyUnlockServiceSignin::GetUserEmail() const { |
| 37 return user_id_; | 107 return user_id_; |
| 38 } | 108 } |
| 39 | 109 |
| 40 void EasyUnlockServiceSignin::LaunchSetup() { | 110 void EasyUnlockServiceSignin::LaunchSetup() { |
| 41 NOTREACHED(); | 111 NOTREACHED(); |
| 42 } | 112 } |
| 43 | 113 |
| 44 const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const { | 114 const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const { |
| 45 // TODO(tbarzic): Implement this (http://crbug.com/401634). | |
| 46 return NULL; | 115 return NULL; |
| 47 } | 116 } |
| 48 | 117 |
| 49 void EasyUnlockServiceSignin::SetPermitAccess( | 118 void EasyUnlockServiceSignin::SetPermitAccess( |
| 50 const base::DictionaryValue& permit) { | 119 const base::DictionaryValue& permit) { |
| 51 NOTREACHED(); | 120 NOTREACHED(); |
| 52 } | 121 } |
| 53 | 122 |
| 54 void EasyUnlockServiceSignin::ClearPermitAccess() { | 123 void EasyUnlockServiceSignin::ClearPermitAccess() { |
| 55 NOTREACHED(); | 124 NOTREACHED(); |
| 56 } | 125 } |
| 57 | 126 |
| 58 const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const { | 127 const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const { |
| 59 return remote_devices_value_.get(); | 128 const UserData* data = FindLoadedDataForCurrentUser(); |
| 129 if (!data) | |
| 130 return NULL; | |
| 131 return &data->remote_devices_value; | |
| 60 } | 132 } |
| 61 | 133 |
| 62 void EasyUnlockServiceSignin::SetRemoteDevices( | 134 void EasyUnlockServiceSignin::SetRemoteDevices( |
| 63 const base::ListValue& devices) { | 135 const base::ListValue& devices) { |
| 64 NOTREACHED(); | 136 NOTREACHED(); |
| 65 } | 137 } |
| 66 | 138 |
| 67 void EasyUnlockServiceSignin::ClearRemoteDevices() { | 139 void EasyUnlockServiceSignin::ClearRemoteDevices() { |
| 68 NOTREACHED(); | 140 NOTREACHED(); |
| 69 } | 141 } |
| 70 | 142 |
| 71 void EasyUnlockServiceSignin::RunTurnOffFlow() { | 143 void EasyUnlockServiceSignin::RunTurnOffFlow() { |
| 72 NOTREACHED(); | 144 NOTREACHED(); |
| 73 } | 145 } |
| 74 | 146 |
| 75 void EasyUnlockServiceSignin::ResetTurnOffFlow() { | 147 void EasyUnlockServiceSignin::ResetTurnOffFlow() { |
| 76 NOTREACHED(); | 148 NOTREACHED(); |
| 77 } | 149 } |
| 78 | 150 |
| 79 EasyUnlockService::TurnOffFlowStatus | 151 EasyUnlockService::TurnOffFlowStatus |
| 80 EasyUnlockServiceSignin::GetTurnOffFlowStatus() const { | 152 EasyUnlockServiceSignin::GetTurnOffFlowStatus() const { |
| 81 return EasyUnlockService::IDLE; | 153 return EasyUnlockService::IDLE; |
| 82 } | 154 } |
| 83 | 155 |
| 84 std::string EasyUnlockServiceSignin::GetChallenge() const { | 156 std::string EasyUnlockServiceSignin::GetChallenge() const { |
| 157 const UserData* data = FindLoadedDataForCurrentUser(); | |
| 85 // TODO(xiyuan): Use correct remote device instead of hard coded first one. | 158 // TODO(xiyuan): Use correct remote device instead of hard coded first one. |
| 86 size_t device_index = 0; | 159 size_t device_index = 0; |
| 87 return device_index < remote_devices_.size() | 160 if (!data || data->devices.size() <= device_index) |
| 88 ? remote_devices_[device_index].challenge | 161 return std::string(); |
| 89 : std::string(); | 162 return data->devices[device_index].challenge; |
| 90 } | 163 } |
| 91 | 164 |
| 92 void EasyUnlockServiceSignin::InitializeInternal() { | 165 void EasyUnlockServiceSignin::InitializeInternal() { |
| 93 } | 166 } |
| 94 | 167 |
| 95 bool EasyUnlockServiceSignin::IsAllowedInternal() { | 168 bool EasyUnlockServiceSignin::IsAllowedInternal() { |
| 96 return !user_id_.empty() && !remote_devices_.empty() && | 169 return !user_id_.empty() && |
| 170 FindLoadedDataForCurrentUser() && | |
| 97 CommandLine::ForCurrentProcess()->HasSwitch( | 171 CommandLine::ForCurrentProcess()->HasSwitch( |
| 98 chromeos::switches::kEnableEasySignin); | 172 chromeos::switches::kEnableEasySignin); |
| 99 } | 173 } |
| 100 | 174 |
| 101 void EasyUnlockServiceSignin::FetchCryptohomeKeys() { | 175 void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() { |
| 102 remote_devices_.clear(); | 176 if (user_id_.empty() || |
| 103 remote_devices_value_.reset(); | 177 !CommandLine::ForCurrentProcess()->HasSwitch( |
| 104 if (user_id_.empty()) { | 178 chromeos::switches::kEnableEasySignin)) |
| 105 UpdateAppState(); | |
| 106 return; | 179 return; |
| 107 } | |
| 108 | 180 |
| 109 chromeos::EasyUnlockKeyManager* key_manager = | 181 std::map<std::string, UserData*>::iterator it = user_data_.find(user_id_); |
| 110 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); | 182 if (it == user_data_.end()) |
| 111 DCHECK(key_manager); | 183 user_data_.insert(std::make_pair(user_id_, new UserData())); |
| 112 key_manager->GetDeviceDataList( | 184 |
| 113 chromeos::UserContext(user_id_), | 185 UserData* data = user_data_[user_id_]; |
| 114 base::Bind(&EasyUnlockServiceSignin::OnCryptohomeKeysFetched, | 186 |
| 115 weak_ptr_factory_.GetWeakPtr())); | 187 if (data->state != USER_DATA_STATE_INITIAL) |
| 188 return; | |
| 189 data->state = USER_DATA_STATE_LOADING; | |
| 190 | |
| 191 LoadDataForUser( | |
| 192 user_id_, | |
| 193 allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs, | |
| 194 base::Bind(&EasyUnlockServiceSignin::OnUserDataLoaded, | |
| 195 weak_ptr_factory_.GetWeakPtr(), | |
| 196 user_id_)); | |
| 116 } | 197 } |
| 117 | 198 |
| 118 void EasyUnlockServiceSignin::OnCryptohomeKeysFetched( | 199 void EasyUnlockServiceSignin::OnUserDataLoaded( |
| 200 const std::string& user_id, | |
| 119 bool success, | 201 bool success, |
| 120 const chromeos::EasyUnlockDeviceKeyDataList& devices) { | 202 const chromeos::EasyUnlockDeviceKeyDataList& devices) { |
| 121 if (!success) { | 203 allow_cryptohome_backoff_ = false; |
| 122 LOG(WARNING) << "Easy unlock cryptohome keys not found for user " | 204 |
| 123 << user_id_; | 205 UserData* data = user_data_[user_id_]; |
| 124 return; | 206 data->state = USER_DATA_STATE_LOADED; |
| 207 if (success) { | |
| 208 data->devices = devices; | |
| 209 chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList( | |
| 210 user_id, devices, &data->remote_devices_value); | |
| 125 } | 211 } |
| 212 } | |
| 126 | 213 |
| 127 remote_devices_ = devices; | 214 const EasyUnlockServiceSignin::UserData* |
| 128 remote_devices_value_.reset(new base::ListValue); | 215 EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const { |
| 129 chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList( | 216 if (user_id_.empty()) |
| 130 user_id_, remote_devices_, remote_devices_value_.get()); | 217 return NULL; |
| 131 | 218 std::map<std::string, UserData*>::const_iterator it = |
| 132 UpdateAppState(); | 219 user_data_.find(user_id_); |
| 220 if (it == user_data_.end()) | |
| 221 return NULL; | |
| 222 if (it->second->state != USER_DATA_STATE_LOADED) | |
| 223 return NULL; | |
| 224 return it->second; | |
| 133 } | 225 } |
| OLD | NEW |