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