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

Side by Side Diff: chrome/browser/managed_mode/managed_user_token_fetcher.cc

Issue 15977002: Add ManagedUserTokenFetcher to fetch scoped-down tokens. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/managed_mode/managed_user_token_fetcher.h"
6
7 #include "base/callback.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/string16.h"
11 #include "base/stringprintf.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/signin/oauth2_token_service.h"
15 #include "google_apis/gaia/gaia_oauth_client.h"
16 #include "google_apis/gaia/gaia_urls.h"
17 #include "google_apis/gaia/google_service_auth_error.h"
18 #include "google_apis/gaia/oauth2_api_call_flow.h"
19 #include "net/base/escape.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/net_errors.h"
22 #include "net/http/http_status_code.h"
23 #include "net/url_request/url_fetcher.h"
24 #include "net/url_request/url_request_status.h"
25
26 using base::Time;
27 using gaia::GaiaOAuthClient;
28 using net::URLFetcher;
29 using net::URLFetcherDelegate;
30 using net::URLRequestContextGetter;
31
32 namespace {
33
34 const int kNumRetries = 1;
35
36 static const char kChromeSyncManagedScope[] =
37 "https://www.googleapis.com/auth/chromesync_playpen";
Andrew T Wilson (Slow) 2013/05/27 13:52:15 You may want to move this into GaiaUrls - at the v
Bernhard Bauer 2013/05/27 14:42:13 This is a scope, not an actual URL that we resolve
38
39 static const char kIssueTokenBodyFormat[] =
40 "client_id=%s"
41 "&scope=&%s"
42 "&response_type=code"
43 "&profile_id=%s"
44 "&profile_name=%s"
45 "&device_name=%s";
46
47 static const char kAuthorizationHeaderFormat[] =
48 "Authorization: Bearer %s";
49
50 static const char kCodeKey[] = "code";
51
52 class ManagedUserTokenFetcherImpl : public ManagedUserTokenFetcher,
53 public OAuth2TokenService::Consumer,
54 public URLFetcherDelegate,
55 public GaiaOAuthClient::Delegate {
56 public:
57 ManagedUserTokenFetcherImpl(OAuth2TokenService* oauth2_token_service,
58 URLRequestContextGetter* context);
59 virtual ~ManagedUserTokenFetcherImpl();
60
61 // ManagedUserTokenFetcher implementation:
62 virtual void Start(const std::string& managed_user_id,
63 const string16& name,
64 const std::string& device_name,
65 const TokenCallback& callback) OVERRIDE;
66
67 protected:
68 // OAuth2TokenService::Consumer implementation:
69 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
70 const std::string& access_token,
71 const Time& expiration_time) OVERRIDE;
72 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
73 const GoogleServiceAuthError& error) OVERRIDE;
74
75 // net::URLFetcherDelegate implementation.
76 virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE;
77
78 // GaiaOAuthClient::Delegate implementation:
Andrew T Wilson (Slow) 2013/05/27 13:52:15 Incorrect indent on this comment.
Bernhard Bauer 2013/05/27 14:42:13 Done.
79 virtual void OnGetTokensResponse(const std::string& refresh_token,
80 const std::string& access_token,
81 int expires_in_seconds) OVERRIDE;
82 virtual void OnRefreshTokenResponse(const std::string& access_token,
83 int expires_in_seconds) OVERRIDE;
84 virtual void OnOAuthError() OVERRIDE;
85 virtual void OnNetworkError(int response_code) OVERRIDE;
86
87 private:
88 void StartInternal();
Andrew T Wilson (Slow) 2013/05/27 13:52:15 Maybe a better name for this is worthwhile? What p
Bernhard Bauer 2013/05/27 14:42:13 Renamed to StartFetching() and added a comment.
89
90 void DispatchNetworkError(int error_code);
91 void DispatchGoogleServiceAuthError(GoogleServiceAuthError::State foo);
92
93 OAuth2TokenService* oauth2_token_service_;
94 URLRequestContextGetter* context_;
95
96 std::string device_name_;
97 std::string managed_user_id_;
98 string16 name_;
99 TokenCallback callback_;
100
101 scoped_ptr<OAuth2TokenService::Request> access_token_request_;
102 std::string access_token_;
103 scoped_ptr<URLFetcher> url_fetcher_;
104 scoped_ptr<GaiaOAuthClient> gaia_oauth_client_;
105 };
106
107 ManagedUserTokenFetcherImpl::ManagedUserTokenFetcherImpl(
108 OAuth2TokenService* oauth2_token_service,
109 URLRequestContextGetter* context)
110 : oauth2_token_service_(oauth2_token_service),
111 context_(context) {}
112
113 ManagedUserTokenFetcherImpl::~ManagedUserTokenFetcherImpl() {}
114
115 void ManagedUserTokenFetcherImpl::Start(
116 const std::string& managed_user_id,
117 const string16& name,
118 const std::string& device_name,
119 const TokenCallback& callback) {
120 DCHECK(callback_.is_null());
121 managed_user_id_ = managed_user_id;
122 name_ = name;
123 device_name_ = device_name;
124 callback_ = callback;
125 StartInternal();
126 }
127
128 void ManagedUserTokenFetcherImpl::StartInternal() {
129 access_token_request_ = oauth2_token_service_->StartRequest(
130 OAuth2TokenService::ScopeSet(), this);
Andrew T Wilson (Slow) 2013/05/27 13:52:15 What is this doing? You aren't passing any scopes
Bernhard Bauer 2013/05/27 14:42:13 See OAuth2AccessTokenFetcher::Start(): If the set
Andrew T Wilson (Slow) 2013/05/27 16:41:24 Yes, but OAuth2TokenService doesn't advertise that
131 }
132
133 void ManagedUserTokenFetcherImpl::OnGetTokenSuccess(
134 const OAuth2TokenService::Request* request,
135 const std::string& access_token,
136 const Time& expiration_time) {
137 DCHECK_EQ(access_token_request_.get(), request);
138 access_token_ = access_token;
139
140 GURL url(GaiaUrls::GetInstance()->oauth2_issue_token_url());
141 // GaiaOAuthClient uses id 0, so we use 1 to distinguish the requests in
142 // unit tests.
143 int id = 1;
144
145 url_fetcher_.reset(URLFetcher::Create(id, url, URLFetcher::POST, this));
146
147 url_fetcher_->SetRequestContext(context_);
148 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
149 net::LOAD_DO_NOT_SAVE_COOKIES);
150 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kNumRetries);
151 url_fetcher_->AddExtraRequestHeader(
152 base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
153
154 std::string body = base::StringPrintf(
155 kIssueTokenBodyFormat,
156 net::EscapeUrlEncodedData(
157 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
158 net::EscapeUrlEncodedData(kChromeSyncManagedScope, true).c_str(),
159 net::EscapeUrlEncodedData(managed_user_id_, true).c_str(),
160 net::EscapeUrlEncodedData(UTF16ToUTF8(name_), true).c_str(),
161 net::EscapeUrlEncodedData(device_name_, true).c_str());
162 url_fetcher_->SetUploadData("application/x-www-form-urlencoded", body);
Andrew T Wilson (Slow) 2013/05/27 13:52:15 This is the piece I don't understand. You are call
Bernhard Bauer 2013/05/27 14:42:13 Yes, the first time is for a regular access token
163
164 url_fetcher_->Start();
165 }
166
167 void ManagedUserTokenFetcherImpl::OnGetTokenFailure(
168 const OAuth2TokenService::Request* request,
169 const GoogleServiceAuthError& error) {
170 DCHECK_EQ(access_token_request_.get(), request);
171 callback_.Run(error, std::string());
172 callback_.Reset();
173 }
174
175 void ManagedUserTokenFetcherImpl::OnURLFetchComplete(
176 const URLFetcher* source) {
177 const net::URLRequestStatus& status = source->GetStatus();
178 if (!status.is_success()) {
179 DispatchNetworkError(status.error());
180 return;
181 }
182
183 int response_code = source->GetResponseCode();
184 if (response_code == net::HTTP_UNAUTHORIZED) {
185 oauth2_token_service_->InvalidateToken(OAuth2TokenService::ScopeSet(),
186 access_token_);
187 StartInternal();
188 return;
189 }
190
191 if (response_code != net::HTTP_OK) {
192 // TODO(bauerb): We should return the HTTP response code somehow.
193 LOG(WARNING) << "HTTP error " << response_code;
194 DispatchGoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED);
195 return;
196 }
197
198 std::string response_body;
199 source->GetResponseAsString(&response_body);
200 scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
201 DictionaryValue* dict = NULL;
202 if (!value.get() || !value->GetAsDictionary(&dict)) {
203 DispatchNetworkError(net::ERR_INVALID_RESPONSE);
204 return;
205 }
206 std::string auth_code;
207 if (!dict->GetString(kCodeKey, &auth_code)) {
208 DispatchNetworkError(net::ERR_INVALID_RESPONSE);
209 return;
210 }
211
212 gaia::OAuthClientInfo client_info;
213 GaiaUrls* urls = GaiaUrls::GetInstance();
214 client_info.client_id = urls->oauth2_chrome_client_id();
215 client_info.client_secret = urls->oauth2_chrome_client_secret();
216 gaia_oauth_client_.reset(
217 new gaia::GaiaOAuthClient(GaiaUrls::GetInstance()->oauth2_token_url(),
218 context_));
219 gaia_oauth_client_->GetTokensFromAuthCode(client_info, auth_code, kNumRetries,
220 this);
221 }
222
223 void ManagedUserTokenFetcherImpl::OnGetTokensResponse(
224 const std::string& refresh_token,
225 const std::string& access_token,
226 int expires_in_seconds) {
227 // TODO(bauerb): It would be nice if we could pass the access token as well,
228 // so we don't need to fetch another one immediately.
229 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
230 callback_.Run(error, refresh_token);
231 callback_.Reset();
232 }
233
234 void ManagedUserTokenFetcherImpl::OnRefreshTokenResponse(
235 const std::string& access_token,
236 int expires_in_seconds) {
237 NOTREACHED();
238 }
239
240 void ManagedUserTokenFetcherImpl::OnOAuthError() {
241 DispatchGoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED);
242 }
243
244 void ManagedUserTokenFetcherImpl::OnNetworkError(int response_code) {
245 // TODO(bauerb): We should return the HTTP response code somehow.
246 LOG(WARNING) << "HTTP error " << response_code;
247 DispatchGoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED);
248 }
249
250 void ManagedUserTokenFetcherImpl::DispatchNetworkError(int error_code) {
251 callback_.Run(GoogleServiceAuthError::FromConnectionError(error_code),
252 std::string());
253 callback_.Reset();
254 }
255
256 void ManagedUserTokenFetcherImpl::DispatchGoogleServiceAuthError(
257 GoogleServiceAuthError::State state) {
258 GoogleServiceAuthError error(state);
259 callback_.Run(error, std::string());
Andrew T Wilson (Slow) 2013/05/27 13:52:15 Does it make sense to refactor all these callback_
Bernhard Bauer 2013/05/27 14:42:13 Honestly, I don't know. I have three cases where I
260 callback_.Reset();
261 }
262
263 } // namespace
264
265 // static
266 scoped_ptr<ManagedUserTokenFetcher> ManagedUserTokenFetcher::Create(
267 OAuth2TokenService* oauth2_token_service,
268 URLRequestContextGetter* context) {
269 scoped_ptr<ManagedUserTokenFetcher> fetcher(
270 new ManagedUserTokenFetcherImpl(oauth2_token_service, context));
271 return fetcher.Pass();
272 }
273
274 ManagedUserTokenFetcher::~ManagedUserTokenFetcher() {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698