Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: chrome/browser/chromeos/settings/device_oauth2_token_service.cc

Issue 17109006: Device robot refresh token integrity validation. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: addressed atwilson's review comments Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/chromeos/settings/device_oauth2_token_service.h" 5 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
6 6
7 #include <string>
8 #include <vector>
9
7 #include "base/prefs/pref_registry_simple.h" 10 #include "base/prefs/pref_registry_simple.h"
8 #include "base/prefs/pref_service.h" 11 #include "base/prefs/pref_service.h"
12 #include "base/values.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
15 #include "chrome/browser/policy/browser_policy_connector.h"
16 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
9 #include "chrome/common/pref_names.h" 17 #include "chrome/common/pref_names.h"
10 #include "chromeos/cryptohome/cryptohome_library.h" 18 #include "chromeos/cryptohome/cryptohome_library.h"
11 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
20 #include "google_apis/gaia/gaia_urls.h"
21 #include "google_apis/gaia/google_service_auth_error.h"
12 22
13 namespace chromeos { 23 namespace chromeos {
14 24
25 // A wrapper for the consumer passed to StartRequest, which doesn't call
26 // through to the target Consumer unless the refresh token validation is
27 // complete.
28 class DeviceOAuth2TokenService::ValidatingConsumer
29 : public OAuth2TokenService::Consumer,
30 public gaia::GaiaOAuthClient::Delegate {
31 public:
32 explicit ValidatingConsumer(DeviceOAuth2TokenService* token_service,
33 Consumer* consumer);
34 virtual ~ValidatingConsumer();
35
36 void StartValidation();
37
38 // OAuth2TokenService::Consumer
39 virtual void OnGetTokenSuccess(
40 const Request* request,
41 const std::string& access_token,
42 const base::Time& expiration_time) OVERRIDE;
43 virtual void OnGetTokenFailure(
44 const Request* request,
45 const GoogleServiceAuthError& error) OVERRIDE;
46
47 // gaia::GaiaOAuthClient::Delegate implementation.
48 virtual void OnRefreshTokenResponse(const std::string& access_token,
49 int expires_in_seconds) OVERRIDE;
50 virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info)
51 OVERRIDE;
52 virtual void OnOAuthError() OVERRIDE;
53 virtual void OnNetworkError(int response_code) OVERRIDE;
54
55 private:
56 void RefreshTokenIsValid(bool is_valid);
57 void InformConsumer();
58
59 DeviceOAuth2TokenService* token_service_;
60 Consumer* consumer_;
61 scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
62
63 // We don't know which will complete first: the validation or the token
64 // minting. So, we need to cache the results so the final callback can
65 // take action.
66
67 // RefreshTokenValidationConsumer results
68 bool token_validation_done_;
69 bool token_is_valid_;
70
71 // OAuth2TokenService::Consumer results
72 const Request* request_;
73 std::string access_token_;
74 base::Time expiration_time_;
75 scoped_ptr<GoogleServiceAuthError> error_;
76 };
77
78 DeviceOAuth2TokenService::ValidatingConsumer::ValidatingConsumer(
79 DeviceOAuth2TokenService* token_service,
80 Consumer* consumer)
81 : token_service_(token_service),
82 consumer_(consumer),
83 token_validation_done_(false),
84 token_is_valid_(false),
85 request_(NULL) {
86 }
87
88 DeviceOAuth2TokenService::ValidatingConsumer::~ValidatingConsumer() {
89 }
90
91 void DeviceOAuth2TokenService::ValidatingConsumer::StartValidation() {
92 DCHECK(!gaia_oauth_client_);
93 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
94 g_browser_process->system_request_context()));
95
96 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
97 gaia::OAuthClientInfo client_info;
98 client_info.client_id = gaia_urls->oauth2_chrome_client_id();
99 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
100
101 gaia_oauth_client_->RefreshToken(
102 client_info,
103 token_service_->GetRefreshToken(),
104 std::vector<std::string>(1, gaia_urls->oauth2_token_info_url()),
105 token_service_->max_refresh_token_validation_retries_,
106 this);
107 }
108
109 void DeviceOAuth2TokenService::ValidatingConsumer::OnRefreshTokenResponse(
110 const std::string& access_token,
111 int expires_in_seconds) {
112 gaia_oauth_client_->GetTokenInfo(
113 access_token,
114 token_service_->max_refresh_token_validation_retries_,
115 this);
116 }
117
118 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenInfoResponse(
119 scoped_ptr<DictionaryValue> token_info) {
120 std::string gaia_robot_id;
121 token_info->GetString("issued_to", &gaia_robot_id);
122
123 std::string policy_robot_id = token_service_->GetRobotAccountId();
124
125 if (policy_robot_id == gaia_robot_id) {
126 RefreshTokenIsValid(true);
127 } else {
128 if (gaia_robot_id.empty()) {
129 LOG(WARNING) << "Device service account owner in policy is empty.";
130 } else {
131 LOG(INFO) << "Device service account owner in policy does not match "
132 << "refresh token.";
133 }
134 RefreshTokenIsValid(false);
135 }
136 }
137
138 void DeviceOAuth2TokenService::ValidatingConsumer::OnOAuthError() {
139 RefreshTokenIsValid(false);
140 }
141
142 void DeviceOAuth2TokenService::ValidatingConsumer::OnNetworkError(
143 int response_code) {
144 RefreshTokenIsValid(false);
145 }
146
147 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenSuccess(
148 const Request* request,
149 const std::string& access_token,
150 const base::Time& expiration_time) {
151 request_ = request;
152 access_token_ = access_token;
153 expiration_time_ = expiration_time;
154 if (token_validation_done_)
155 InformConsumer();
156 }
157
158 void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenFailure(
159 const Request* request,
160 const GoogleServiceAuthError& error) {
161 request_ = request;
162 error_.reset(new GoogleServiceAuthError(error.state()));
163 if (token_validation_done_)
164 InformConsumer();
165 }
166
167 void DeviceOAuth2TokenService::ValidatingConsumer::RefreshTokenIsValid(
168 bool is_valid) {
169 token_validation_done_ = true;
170 token_is_valid_ = is_valid;
171 // If we have a request pointer, then the minting is complete.
172 if (request_)
173 InformConsumer();
174 }
175
176 void DeviceOAuth2TokenService::ValidatingConsumer::InformConsumer() {
177 DCHECK(request_);
178 DCHECK(token_validation_done_);
179 if (!token_is_valid_) {
180 consumer_->OnGetTokenFailure(request_, GoogleServiceAuthError(
181 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
182 } else if (error_) {
183 consumer_->OnGetTokenFailure(request_, *error_.get());
184 } else {
185 consumer_->OnGetTokenSuccess(request_, access_token_, expiration_time_);
186 }
187 token_service_->OnValidationComplete(this, token_is_valid_);
188 }
189
15 DeviceOAuth2TokenService::DeviceOAuth2TokenService( 190 DeviceOAuth2TokenService::DeviceOAuth2TokenService(
16 net::URLRequestContextGetter* getter, 191 net::URLRequestContextGetter* getter,
17 PrefService* local_state) 192 PrefService* local_state)
18 : OAuth2TokenService(getter), 193 : OAuth2TokenService(getter),
194 refresh_token_is_valid_(false),
195 max_refresh_token_validation_retries_(3),
196 pending_validators_(new std::set<ValidatingConsumer*>()),
19 local_state_(local_state) { 197 local_state_(local_state) {
20 } 198 }
21 199
22 DeviceOAuth2TokenService::~DeviceOAuth2TokenService() { 200 DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
201 STLDeleteElements(pending_validators_.get());
202 }
203
204 // TODO(davidroche): if the caller deletes the returned Request while
205 // the fetches are in-flight, the OAuth2TokenService class won't call
206 // back into the ValidatingConsumer and we'll end up with stale values
207 // in pending_validators_ until this object is deleted. Probably not a
208 // big deal, but it should be resolved by returning a Request that this
209 // object owns.
Mattias Nissler (ping if slow) 2013/06/20 18:58:30 The other problem now is that you start validation
David Roche 2013/06/20 20:13:59 Only until the validation is successful, after whi
210 scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
211 const OAuth2TokenService::ScopeSet& scopes,
212 OAuth2TokenService::Consumer* consumer) {
213 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
214
215 if (refresh_token_is_valid_) {
216 return OAuth2TokenService::StartRequest(scopes, consumer).Pass();
217 } else {
218 ValidatingConsumer* validating_consumer = new ValidatingConsumer(this,
219 consumer);
220 pending_validators_->insert(validating_consumer);
221
222 validating_consumer->StartValidation();
223 return OAuth2TokenService::StartRequest(scopes, validating_consumer).Pass();
224 }
225 }
226
227 void DeviceOAuth2TokenService::OnValidationComplete(
228 ValidatingConsumer* validator,
229 bool refresh_token_is_valid) {
230 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
231 refresh_token_is_valid_ = refresh_token_is_valid;
232 std::set<ValidatingConsumer*>::iterator iter = pending_validators_->find(
233 validator);
234 if (iter != pending_validators_->end())
235 pending_validators_->erase(iter);
236 else
237 LOG(ERROR) << "OnValidationComplete called for unknown validator";
23 } 238 }
24 239
25 // static 240 // static
26 void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) { 241 void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
27 registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken, 242 registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
28 std::string()); 243 std::string());
29 } 244 }
30 245
31 void DeviceOAuth2TokenService::SetAndSaveRefreshToken( 246 void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
32 const std::string& refresh_token) { 247 const std::string& refresh_token) {
33 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 248 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
34 std::string encrypted_refresh_token = 249 std::string encrypted_refresh_token =
35 CryptohomeLibrary::Get()->EncryptWithSystemSalt(refresh_token); 250 CryptohomeLibrary::Get()->EncryptWithSystemSalt(refresh_token);
36 251
37 local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken, 252 local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
38 encrypted_refresh_token); 253 encrypted_refresh_token);
39 } 254 }
40 255
41 std::string DeviceOAuth2TokenService::GetRefreshToken() { 256 std::string DeviceOAuth2TokenService::GetRefreshToken() {
42 if (refresh_token_.empty()) { 257 if (refresh_token_.empty()) {
43 std::string encrypted_refresh_token = 258 std::string encrypted_refresh_token =
44 local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken); 259 local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);
45 260
46 refresh_token_ = CryptohomeLibrary::Get()->DecryptWithSystemSalt( 261 refresh_token_ = CryptohomeLibrary::Get()->DecryptWithSystemSalt(
47 encrypted_refresh_token); 262 encrypted_refresh_token);
48 } 263 }
49 return refresh_token_; 264 return refresh_token_;
50 } 265 }
51 266
267 std::string DeviceOAuth2TokenService::GetRobotAccountId() {
268 policy::BrowserPolicyConnector* connector =
269 g_browser_process->browser_policy_connector();
270 if (connector)
271 return connector->GetDeviceCloudPolicyManager()->GetRobotAccountId();
272 return std::string();
273 }
274
52 } // namespace chromeos 275 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698