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/common/net/gaia/authentication_fetcher_oauth.cc

Issue 6894027: Initial refactoring complete Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fixed some tests that were broken by previous refactoring Created 9 years, 7 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 (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/common/net/gaia/authentication_fetcher_oauth.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/string_split.h"
12 #include "base/string_util.h"
13 #include "chrome/common/net/gaia/authentication_consumer_oauth.h"
14 #include "chrome/common/net/gaia/gaia_constants.h"
15 #include "chrome/common/net/gaia/google_service_auth_error.h"
16 #include "chrome/common/net/http_return.h"
17 #include "net/base/load_flags.h"
18 #include "net/url_request/url_request_context_getter.h"
19 #include "net/url_request/url_request_status.h"
20 #include "third_party/libjingle/source/talk/base/urlencode.h"
21
22 // TODO(chron): Add sourceless version of this formatter.
23 // static
24 const char AuthenticationFetcherOAuth::kAuthenticationFormat[] =
25 "Email=%s&"
26 "Passwd=%s&"
27 "PersistentCookie=%s&"
28 "accountType=%s&"
29 "source=%s&"
30 "service=%s";
31 // static
32 const char AuthenticationFetcherOAuth::kAuthenticationCaptchaFormat[] =
33 "Email=%s&"
34 "Passwd=%s&"
35 "PersistentCookie=%s&"
36 "accountType=%s&"
37 "source=%s&"
38 "service=%s&"
39 "logintoken=%s&"
40 "logincaptcha=%s";
41 // static
42 const char AuthenticationFetcherOAuth::kIssueAuthTokenFormat[] =
43 "SID=%s&"
44 "LSID=%s&"
45 "service=%s&"
46 "Session=%s";
47 // static
48 const char AuthenticationFetcherOAuth::kGetUserInfoFormat[] =
49 "LSID=%s";
50
51 // static
52 const char AuthenticationFetcherOAuth::kAccountDeletedError[] =
53 "AccountDeleted";
54 // static
55 const char AuthenticationFetcherOAuth::kAccountDisabledError[] =
56 "AccountDisabled";
57 // static
58 const char AuthenticationFetcherOAuth::kBadAuthenticationError[] =
59 "BadAuthentication";
60 // static
61 const char AuthenticationFetcherOAuth::kCaptchaError[] = "CaptchaRequired";
62 // static
63 const char AuthenticationFetcherOAuth::kServiceUnavailableError[] =
64 "ServiceUnavailable";
65 // static
66 const char AuthenticationFetcherOAuth::kErrorParam[] = "Error";
67 // static
68 const char AuthenticationFetcherOAuth::kErrorUrlParam[] = "Url";
69 // static
70 const char AuthenticationFetcherOAuth::kCaptchaUrlParam[] = "CaptchaUrl";
71 // static
72 const char AuthenticationFetcherOAuth::kCaptchaTokenParam[] = "CaptchaToken";
73 // static
74 const char AuthenticationFetcherOAuth::kCaptchaUrlPrefix[] =
75 "http://www.google.com/accounts/";
76
77 // static
78 const char AuthenticationFetcherOAuth::kCookiePersistence[] = "true";
79 // static
80 // TODO(johnnyg): When hosted accounts are supported by sync,
81 // we can always use "HOSTED_OR_GOOGLE"
82 const char AuthenticationFetcherOAuth::kAccountTypeHostedOrGoogle[] =
83 "HOSTED_OR_GOOGLE";
84 const char AuthenticationFetcherOAuth::kAccountTypeGoogle[] =
85 "GOOGLE";
86
87 // static
88 const char AuthenticationFetcherOAuth::kSecondFactor[] =
89 "Info=InvalidSecondFactor";
90
91 // TODO(chron): These urls are also in auth_response_handler.h.
92 // The URLs for different calls in the Google Accounts programmatic login API.
93 const char AuthenticationFetcherOAuth::kAuthenticationUrl[] =
94 "https://www.google.com/accounts/ClientLogin";
95 const char AuthenticationFetcherOAuth::kIssueAuthTokenUrl[] =
96 "https://www.google.com/accounts/IssueAuthToken";
97 const char AuthenticationFetcherOAuth::kGetUserInfoUrl[] =
98 "https://www.google.com/accounts/GetUserInfo";
99
100 AuthenticationFetcherOAuth::AuthenticationFetcherOAuth(
101 AuthenticationConsumerOAuth* consumer,
102 const std::string& source,
103 net::URLRequestContextGetter* getter)
104 : AuthenticationFetcher(consumer, source, getter) {}
105
106 AuthenticationFetcherOAuth::~AuthenticationFetcherOAuth() {}
107
108 // static
109 URLFetcher* AuthenticationFetcherOAuth::CreateAuthenticationFetcherOAuth(
110 net::URLRequestContextGetter* getter,
111 const std::string& body,
112 const GURL& gaia_gurl,
113 URLFetcher::Delegate* delegate) {
114
115 URLFetcher* to_return =
116 URLFetcher::Create(0,
117 gaia_gurl,
118 URLFetcher::POST,
119 delegate);
120 to_return->set_request_context(getter);
121 to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
122 to_return->set_upload_data("application/x-www-form-urlencoded", body);
123 return to_return;
124 }
125
126 // static
127 std::string AuthenticationFetcherOAuth::MakeAuthenticationBody(
128 const std::string& username,
129 const std::string& password,
130 const std::string& source,
131 const char* service,
132 const std::string& login_token,
133 const std::string& login_captcha,
134 HostedAccountsSetting allow_hosted_accounts) {
135 std::string encoded_username = UrlEncodeString(username);
136 std::string encoded_password = UrlEncodeString(password);
137 std::string encoded_login_token = UrlEncodeString(login_token);
138 std::string encoded_login_captcha = UrlEncodeString(login_captcha);
139
140 const char* account_type = allow_hosted_accounts == HostedAccountsAllowed ?
141 kAccountTypeHostedOrGoogle :
142 kAccountTypeGoogle;
143
144 if (login_token.empty() || login_captcha.empty()) {
145 return base::StringPrintf(kAuthenticationFormat,
146 encoded_username.c_str(),
147 encoded_password.c_str(),
148 kCookiePersistence,
149 account_type,
150 source.c_str(),
151 service);
152 }
153
154 return base::StringPrintf(kAuthenticationCaptchaFormat,
155 encoded_username.c_str(),
156 encoded_password.c_str(),
157 kCookiePersistence,
158 account_type,
159 source.c_str(),
160 service,
161 encoded_login_token.c_str(),
162 encoded_login_captcha.c_str());
163
164 }
165
166 // static
167 std::string AuthenticationFetcherOAuth::MakeIssueAuthTokenBody(
168 const AuthenticationConsumer::AuthenticationResult& credentials,
169 const char* const service) {
170 const AuthenticationConsumerOAuth::AuthenticationResult& cred =
171 static_cast<const AuthenticationConsumerOAuth::AuthenticationResult&>(
172 credentials);
173 std::string encoded_sid = UrlEncodeString(cred.sid);
174 std::string encoded_lsid = UrlEncodeString(cred.lsid);
175
176 // All tokens should be session tokens except the gaia auth token.
177 bool session = true;
178 if (!strcmp(service, GaiaConstants::kGaiaService))
179 session = false;
180
181 return base::StringPrintf(kIssueAuthTokenFormat,
182 encoded_sid.c_str(),
183 encoded_lsid.c_str(),
184 service,
185 session ? "true" : "false");
186 }
187
188 // static
189 std::string AuthenticationFetcherOAuth::MakeGetUserInfoBody(
190 const std::string& lsid) {
191 std::string encoded_lsid = UrlEncodeString(lsid);
192 return base::StringPrintf(kGetUserInfoFormat, encoded_lsid.c_str());
193 }
194
195 // Helper method that extracts tokens from a successful reply.
196 // static
197 void AuthenticationFetcherOAuth::ParseAuthenticationResponse(
198 const std::string& data,
199 std::string* sid,
200 std::string* lsid,
201 std::string* token) {
202 using std::vector;
203 using std::pair;
204 using std::string;
205
206 vector<pair<string, string> > tokens;
207 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
208 for (vector<pair<string, string> >::iterator i = tokens.begin();
209 i != tokens.end(); ++i) {
210 if (i->first == "SID") {
211 sid->assign(i->second);
212 } else if (i->first == "LSID") {
213 lsid->assign(i->second);
214 } else if (i->first == "Auth") {
215 token->assign(i->second);
216 }
217 }
218 }
219
220 // static
221 void AuthenticationFetcherOAuth::ParseAuthenticationFailure(
222 const std::string& data,
223 std::string* error,
224 std::string* error_url,
225 std::string* captcha_url,
226 std::string* captcha_token) {
227 using std::vector;
228 using std::pair;
229 using std::string;
230
231 vector<pair<string, string> > tokens;
232 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
233 for (vector<pair<string, string> >::iterator i = tokens.begin();
234 i != tokens.end(); ++i) {
235 if (i->first == kErrorParam) {
236 error->assign(i->second);
237 } else if (i->first == kErrorUrlParam) {
238 error_url->assign(i->second);
239 } else if (i->first == kCaptchaUrlParam) {
240 captcha_url->assign(i->second);
241 } else if (i->first == kCaptchaTokenParam) {
242 captcha_token->assign(i->second);
243 }
244 }
245 }
246
247 void AuthenticationFetcherOAuth::StartAuthentication(
248 const std::string& username,
249 const std::string& password,
250 const char* const service,
251 const std::string& login_token,
252 const std::string& login_captcha,
253 HostedAccountsSetting allow_hosted_accounts) {
254
255 DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
256
257 // This class is thread agnostic, so be sure to call this only on the
258 // same thread each time.
259 VLOG(1) << "Starting new Authentication fetch for:" << username;
260
261 // Must outlive fetcher_.
262 request_body_ = MakeAuthenticationBody(username,
263 password,
264 source_,
265 service,
266 login_token,
267 login_captcha,
268 allow_hosted_accounts);
269 fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
270 request_body_,
271 oauth_gurl_,
272 this));
273 SetPending();
274 fetcher_->Start();
275 }
276
277 void AuthenticationFetcherOAuth::StartIssueAuthToken(
278 const AuthenticationConsumer::AuthenticationResult& credentials,
279 const char* const service) {
280
281 DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
282
283 VLOG(1) << "Starting IssueAuthToken for: " << service;
284 requested_service_ = service;
285
286 request_body_ = MakeIssueAuthTokenBody(credentials, service);
287
288 fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
289 request_body_,
290 issue_auth_token_gurl_,
291 this));
292 SetPending();
293 fetcher_->Start();
294 }
295
296 void AuthenticationFetcherOAuth::StartGetUserInfo(const std::string& lsid,
297 const std::string& info_key) {
298 DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
299
300 VLOG(1) << "Starting GetUserInfo for lsid=" << lsid;
301 request_body_ = MakeGetUserInfoBody(lsid);
302 fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
303 request_body_,
304 get_user_info_gurl_,
305 this));
306 SetPending();
307 requested_info_key_ = info_key;
308 fetcher_->Start();
309 }
310
311 // static
312 GoogleServiceAuthError AuthenticationFetcherOAuth::GenerateAuthError(
313 const std::string& data,
314 const net::URLRequestStatus& status) {
315
316 if (!status.is_success()) {
317 if (status.status() == net::URLRequestStatus::CANCELED) {
318 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
319 } else {
320 LOG(WARNING) << "Could not reach Google Accounts servers: errno "
321 << status.os_error();
322 return GoogleServiceAuthError::FromConnectionError(status.os_error());
323 }
324 } else {
325 if (IsSecondFactorSuccess(data)) {
326 return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
327 }
328
329 std::string error;
330 std::string url;
331 std::string captcha_url;
332 std::string captcha_token;
333 ParseAuthenticationFailure(
334 data, &error, &url, &captcha_url, &captcha_token);
335 LOG(WARNING) << "Authentication failed with " << error;
336
337 if (error == kCaptchaError) {
338 GURL image_url(kCaptchaUrlPrefix + captcha_url);
339 GURL unlock_url(url);
340 return GoogleServiceAuthError::FromCaptchaChallenge(
341 captcha_token, image_url, unlock_url);
342 }
343 if (error == kAccountDeletedError)
344 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
345 if (error == kAccountDisabledError)
346 return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
347 if (error == kBadAuthenticationError) {
348 return GoogleServiceAuthError(
349 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
350 }
351 if (error == kServiceUnavailableError) {
352 return GoogleServiceAuthError(
353 GoogleServiceAuthError::SERVICE_UNAVAILABLE);
354 }
355
356 LOG(WARNING) << "Incomprehensible response from Google Accounts servers.";
357 return GoogleServiceAuthError(
358 GoogleServiceAuthError::SERVICE_UNAVAILABLE);
359 }
360
361 NOTREACHED();
362 return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
363 }
364
365 void AuthenticationFetcherOAuth::OnAuthenticationFetched(
366 const std::string& data,
367 const net::URLRequestStatus& status,
368 int response_code) {
369 if (status.is_success() && response_code == RC_REQUEST_OK) {
370 VLOG(1) << "Authentication successful!";
371 std::string sid;
372 std::string lsid;
373 std::string token;
374 ParseAuthenticationResponse(data, &sid, &lsid, &token);
375 consumer_->OnAuthenticationSuccess(
376 AuthenticationConsumerOAuth::AuthenticationResult(
377 sid, lsid, token, data));
378 } else {
379 consumer_->OnAuthenticationFailure(GenerateAuthError(data, status));
380 }
381 }
382
383 void AuthenticationFetcherOAuth::OnIssueAuthTokenFetched(
384 const std::string& data,
385 const net::URLRequestStatus& status,
386 int response_code) {
387 if (status.is_success() && response_code == RC_REQUEST_OK) {
388 // Only the bare token is returned in the body of this Gaia call
389 // without any padding.
390 consumer_->OnIssueTokenSuccess(requested_service_, data);
391 } else {
392 consumer_->OnIssueTokenFailure(requested_service_,
393 GenerateAuthError(data, status));
394 }
395 }
396
397 void AuthenticationFetcherOAuth::OnGetUserInfoFetched(
398 const std::string& data,
399 const net::URLRequestStatus& status,
400 int response_code) {
401 using std::vector;
402 using std::string;
403 using std::pair;
404
405 if (status.is_success() && response_code == RC_REQUEST_OK) {
406 vector<pair<string, string> > tokens;
407 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
408 for (vector<pair<string, string> >::iterator i = tokens.begin();
409 i != tokens.end(); ++i) {
410 if (i->first == requested_info_key_) {
411 consumer_->OnGetUserInfoSuccess(i->first, i->second);
412 return;
413 }
414 }
415 consumer_->OnGetUserInfoKeyNotFound(requested_info_key_);
416 } else {
417 consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status));
418 }
419 }
420
421 void AuthenticationFetcherOAuth::OnURLFetchComplete(const URLFetcher* source,
422 const GURL& url,
423 const net::URLRequestStatus& status,
424 int response_code,
425 const ResponseCookies& cookies,
426 const std::string& data) {
427 ClearPending();
428 if (url == oauth_gurl_) {
429 OnAuthenticationFetched(data, status, response_code);
430 } else if (url == issue_auth_token_gurl_) {
431 OnIssueAuthTokenFetched(data, status, response_code);
432 } else if (url == get_user_info_gurl_) {
433 OnGetUserInfoFetched(data, status, response_code);
434 } else {
435 NOTREACHED();
436 }
437 }
438
439 // static
440 bool AuthenticationFetcherOAuth::IsSecondFactorSuccess(
441 const std::string& alleged_error) {
442 return alleged_error.find(kSecondFactor) !=
443 std::string::npos;
444 }
OLDNEW
« no previous file with comments | « chrome/common/net/gaia/authentication_fetcher_oauth.h ('k') | chrome/common/net/gaia/gaia_auth_consumer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698