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

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

Powered by Google App Engine
This is Rietveld 408576698