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

Side by Side Diff: chrome/browser/net/gaia/oauth2_login_token_fetcher.cc

Issue 8603009: Add a fetcher class to fetch an OAuth2 login scope token from ClientLogin credentials. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month 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 (c) 2011 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/net/gaia/oauth2_login_token_fetcher.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/json/json_reader.h"
11 #include "base/string_split.h"
12 #include "base/string_util.h"
13 #include "base/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/common/net/gaia/gaia_urls.h"
16 #include "chrome/common/net/gaia/google_service_auth_error.h"
17 #include "chrome/common/net/http_return.h"
18 #include "net/base/escape.h"
19 #include "net/base/load_flags.h"
20 #include "net/url_request/url_request_context_getter.h"
21 #include "net/url_request/url_request_status.h"
22
23 using content::URLFetcher;
24 using content::URLFetcherDelegate;
25 using net::ResponseCookies;
26 using net::URLRequestContextGetter;
27 using net::URLRequestStatus;
28
29 namespace {
30 // To get OAtuh2 authorization code from "lso" service auth token.
31 static const char kAuthHeaderFormat[] = "Authorization: GoogleLogin auth=%s";
32 static const char kGetAuthCodeBodyFormat[] = "scope=%s&client_id=%s";
33 static const char kAuthCodeCookiePartSecure[] = "Secure";
34 static const char kAuthCodeCookiePartHttpOnly[] = "HttpOnly";
35 static const char kAuthCodeCookiePartCodePrefix[] = "oauth_code=";
36 static const int kAuthCodeCookiePartCodePrefixLength =
37 arraysize(kAuthCodeCookiePartCodePrefix) - 1;
38
39 // To get OAuth2 token pair from authorization code.
40 static const char kGetTokenPairBodyFormat[] =
41 "scope=%s&"
42 "grant_type=authorization_code&"
43 "client_id=%s&"
44 "client_secret=%s&"
45 "code=%s";
46 static const char kRefreshTokenKey[] = "refresh_token";
47 static const char kAccessTokenKey[] = "access_token";
48
49 static bool CookiePartsContains(const std::vector<std::string>& parts,
50 const char* part) {
51 return std::find(parts.begin(), parts.end(), part) != parts.end();
52 }
53
54 static bool ParseCookieToAuthCode(const std::string& cookie,
55 std::string* auth_code) {
56 std::vector<std::string> parts;
57 base::SplitString(cookie, ';', &parts);
58 // Per documentation, the cookie should have Secure and HttpOnly.
59 if (!CookiePartsContains(parts, kAuthCodeCookiePartSecure) ||
60 !CookiePartsContains(parts, kAuthCodeCookiePartHttpOnly)) {
61 return false;
62 }
63
64 std::vector<std::string>::const_iterator iter;
65 for (iter = parts.begin(); iter != parts.end(); ++iter) {
66 const std::string& part = *iter;
67 if (StartsWithASCII(part, kAuthCodeCookiePartCodePrefix, false)) {
68 auth_code->assign(part.substr(kAuthCodeCookiePartCodePrefixLength));
69 return true;
70 }
71 }
72 return false;
73 }
74
75 static bool GetStringFromDictionary(const DictionaryValue* dict,
76 const std::string& key,
77 std::string* value) {
78 Value* json_value;
79 if (!dict->Get(key, &json_value))
80 return false;
81 if (json_value->GetType() != base::Value::TYPE_STRING)
82 return false;
83
84 StringValue* json_str_value = static_cast<StringValue*>(json_value);
85 json_str_value->GetAsString(value);
86 return true;
87 }
88
89 static GoogleServiceAuthError CreateAuthError(URLRequestStatus status) {
90 CHECK(!status.is_success());
91 if (status.status() == URLRequestStatus::CANCELED) {
92 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
93 } else {
94 DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
95 << status.error();
96 return GoogleServiceAuthError::FromConnectionError(status.error());
97 }
98 }
99
100 static URLFetcher* CreateFetcher(URLRequestContextGetter* getter,
101 const GURL& url,
102 const std::string& body,
103 const std::string& headers,
104 URLFetcherDelegate* delegate) {
105 bool empty_body = body.empty();
106 URLFetcher* result = URLFetcher::Create(
107 0, url,
108 empty_body ? URLFetcher::GET : URLFetcher::POST,
109 delegate);
110
111 result->SetRequestContext(getter);
112 result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
113 net::LOAD_DO_NOT_SAVE_COOKIES);
114
115 if (!empty_body)
116 result->SetUploadData("application/x-www-form-urlencoded", body);
117 if (!headers.empty())
118 result->SetExtraRequestHeaders(headers);
119
120 return result;
121 }
122 } // namespace
123
124 OAuth2LoginTokenFetcher::OAuth2LoginTokenFetcher(
125 OAuth2LoginTokenConsumer* consumer,
126 URLRequestContextGetter* getter,
127 const std::string& source)
128 : consumer_(consumer),
129 getter_(getter),
130 source_(source),
131 state_(INITIAL) { }
132
133 OAuth2LoginTokenFetcher::~OAuth2LoginTokenFetcher() { }
134
135 void OAuth2LoginTokenFetcher::CancelRequest() {
136 fetcher_.reset();
137 }
138
139 void OAuth2LoginTokenFetcher::Start(const std::string& auth_token) {
140 auth_token_ = auth_token;
141 StartGetAuthCode();
142 }
143
144 void OAuth2LoginTokenFetcher::StartGetAuthCode() {
145 CHECK_EQ(INITIAL, state_);
146 state_ = GET_AUTH_CODE_STARTED;
147 fetcher_.reset(CreateFetcher(
148 getter_,
149 MakeGetAuthCodeUrl(),
150 MakeGetAuthCodeBody(),
151 MakeGetAuthCodeHeader(auth_token_),
152 this));
153 fetcher_->Start(); // OnUrlFetchComplete will be called.
154 }
155
156 void OAuth2LoginTokenFetcher::EndGetAuthCode(const URLFetcher* source) {
157 CHECK_EQ(GET_AUTH_CODE_STARTED, state_);
158 state_ = GET_AUTH_CODE_DONE;
159
160 URLRequestStatus status = source->GetStatus();
161 if (!status.is_success()) {
162 ReportFailure(CreateAuthError(status));
163 return;
164 }
165
166 if (source->GetResponseCode() != RC_REQUEST_OK) {
167 ReportFailure(GoogleServiceAuthError(
168 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
169 return;
170 }
171
172 // The request was successfully fetched and it returned OK.
173 // Parse out the auth code from cookies.
174 if (!ParseGetAuthCodeResponse(source, &auth_code_)) {
175 ReportFailure(GoogleServiceAuthError(
176 GoogleServiceAuthError::UNEXPECTED_RESPONSE));
177 return;
178 }
179
180 StartGetTokenPair();
181 }
182
183 void OAuth2LoginTokenFetcher::StartGetTokenPair() {
184 CHECK_EQ(GET_AUTH_CODE_DONE, state_);
185 state_ = GET_TOKEN_PAIR_STARTED;
186
187 fetcher_.reset(CreateFetcher(
188 getter_,
189 MakeGetTokenPairUrl(),
190 MakeGetTokenPairBody(auth_code_),
191 "",
192 this));
193 fetcher_->Start(); // OnUrlFetchComplete will be called.
194 }
195
196 void OAuth2LoginTokenFetcher::EndGetTokenPair(const URLFetcher* source) {
197 CHECK_EQ(GET_TOKEN_PAIR_STARTED, state_);
198 state_ = GET_TOKEN_PAIR_DONE;
199
200 URLRequestStatus status = source->GetStatus();
201 if (!status.is_success()) {
202 ReportFailure(CreateAuthError(status));
203 return;
204 }
205
206 if (source->GetResponseCode() != RC_REQUEST_OK) {
207 ReportFailure(GoogleServiceAuthError(
208 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
209 return;
210 }
211
212 std::string refresh_token;
213 std::string access_token;
214 if (!ParseGetTokenPairResponse(source, &refresh_token, &access_token)) {
215 ReportFailure(GoogleServiceAuthError(
216 GoogleServiceAuthError::UNEXPECTED_RESPONSE));
217 return;
218 }
219
220 ReportSuccess(refresh_token, access_token);
221 }
222
223 void OAuth2LoginTokenFetcher::ReportSuccess(const std::string& refresh_token,
224 const std::string& access_token) {
225 consumer_->OnGetTokenSuccess(refresh_token, access_token);
226 }
227
228 void OAuth2LoginTokenFetcher::ReportFailure(GoogleServiceAuthError error) {
229 state_ = ERROR_STATE;
230 consumer_->OnGetTokenFailure(error);
231 }
232
233 void OAuth2LoginTokenFetcher::OnURLFetchComplete(const URLFetcher* source) {
234 CHECK(source);
235 CHECK(state_ == GET_AUTH_CODE_STARTED || state_ == GET_TOKEN_PAIR_STARTED);
236 switch (state_) {
237 case GET_AUTH_CODE_STARTED:
238 EndGetAuthCode(source);
239 break;
240 case GET_TOKEN_PAIR_STARTED:
241 EndGetTokenPair(source);
242 break;
243 default:
244 CHECK(false) << "This should not happen.";
245 break;
246 }
247 }
248
249 // static
250 GURL OAuth2LoginTokenFetcher::MakeGetAuthCodeUrl() {
251 return GURL(GaiaUrls::GetInstance()->client_login_to_oauth2_url());
252 }
253
254 // static
255 std::string OAuth2LoginTokenFetcher::MakeGetAuthCodeHeader(
256 const std::string& auth_token) {
257 return StringPrintf(kAuthHeaderFormat, auth_token.c_str());
258 }
259
260 // static
261 std::string OAuth2LoginTokenFetcher::MakeGetAuthCodeBody() {
262 return StringPrintf(
263 kGetAuthCodeBodyFormat,
264 net::EscapeUrlEncodedData(
265 GaiaUrls::GetInstance()->oauth1_login_scope(), true).c_str(),
266 net::EscapeUrlEncodedData(
267 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str());
268 }
269
270 // static
271 bool OAuth2LoginTokenFetcher::ParseGetAuthCodeResponse(
272 const URLFetcher* source,
273 std::string* auth_code) {
274 CHECK(source);
275 CHECK(auth_code);
276 const ResponseCookies& cookies = source->GetCookies();
277 ResponseCookies::const_iterator iter;
278 for (iter = cookies.begin(); iter != cookies.end(); ++iter) {
279 if (ParseCookieToAuthCode(*iter, auth_code))
280 return true;
281 }
282 return false;
283 }
284
285 // static
286 GURL OAuth2LoginTokenFetcher::MakeGetTokenPairUrl() {
287 return GURL(GaiaUrls::GetInstance()->oauth2_token_url());
288 }
289
290 // static
291 std::string OAuth2LoginTokenFetcher::MakeGetTokenPairBody(
292 const std::string& auth_code) {
293 return StringPrintf(
294 kGetTokenPairBodyFormat,
295 net::EscapeUrlEncodedData(
296 GaiaUrls::GetInstance()->oauth1_login_scope(), true).c_str(),
297 net::EscapeUrlEncodedData(
298 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
299 net::EscapeUrlEncodedData(
300 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
301 true).c_str(),
302 net::EscapeUrlEncodedData(auth_code, true).c_str());
303 }
304
305 // static
306 bool OAuth2LoginTokenFetcher::ParseGetTokenPairResponse(
307 const URLFetcher* source,
308 std::string* refresh_token,
309 std::string* access_token) {
310 CHECK(source);
311 CHECK(refresh_token);
312 CHECK(access_token);
313 std::string data;
314 source->GetResponseAsString(&data);
315 base::JSONReader reader;
316 scoped_ptr<base::Value> value(reader.Read(data, false));
317 if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY)
318 return false;
319
320 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
321 std::string rt;
322 std::string at;
323 if (!GetStringFromDictionary(dict, kRefreshTokenKey, &rt) ||
324 !GetStringFromDictionary(dict, kAccessTokenKey, &at)) {
325 return false;
326 }
327
328 refresh_token->assign(rt);
329 access_token->assign(at);
330 return true;
331 }
OLDNEW
« no previous file with comments | « chrome/browser/net/gaia/oauth2_login_token_fetcher.h ('k') | chrome/browser/net/gaia/oauth2_login_token_fetcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698