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

Unified 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, 8 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/common/net/gaia/authentication_fetcher_oauth.cc
diff --git a/chrome/common/net/gaia/authentication_fetcher_oauth.cc b/chrome/common/net/gaia/authentication_fetcher_oauth.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f4ad49cf45bc3aca9cf06c65b29d5d8c219500c0
--- /dev/null
+++ b/chrome/common/net/gaia/authentication_fetcher_oauth.cc
@@ -0,0 +1,444 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/net/gaia/authentication_fetcher_oauth.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "chrome/common/net/gaia/authentication_consumer_oauth.h"
+#include "chrome/common/net/gaia/gaia_constants.h"
+#include "chrome/common/net/gaia/google_service_auth_error.h"
+#include "chrome/common/net/http_return.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_status.h"
+#include "third_party/libjingle/source/talk/base/urlencode.h"
+
+// TODO(chron): Add sourceless version of this formatter.
+// static
+const char AuthenticationFetcherOAuth::kAuthenticationFormat[] =
+ "Email=%s&"
+ "Passwd=%s&"
+ "PersistentCookie=%s&"
+ "accountType=%s&"
+ "source=%s&"
+ "service=%s";
+// static
+const char AuthenticationFetcherOAuth::kAuthenticationCaptchaFormat[] =
+ "Email=%s&"
+ "Passwd=%s&"
+ "PersistentCookie=%s&"
+ "accountType=%s&"
+ "source=%s&"
+ "service=%s&"
+ "logintoken=%s&"
+ "logincaptcha=%s";
+// static
+const char AuthenticationFetcherOAuth::kIssueAuthTokenFormat[] =
+ "SID=%s&"
+ "LSID=%s&"
+ "service=%s&"
+ "Session=%s";
+// static
+const char AuthenticationFetcherOAuth::kGetUserInfoFormat[] =
+ "LSID=%s";
+
+// static
+const char AuthenticationFetcherOAuth::kAccountDeletedError[] =
+ "AccountDeleted";
+// static
+const char AuthenticationFetcherOAuth::kAccountDisabledError[] =
+ "AccountDisabled";
+// static
+const char AuthenticationFetcherOAuth::kBadAuthenticationError[] =
+ "BadAuthentication";
+// static
+const char AuthenticationFetcherOAuth::kCaptchaError[] = "CaptchaRequired";
+// static
+const char AuthenticationFetcherOAuth::kServiceUnavailableError[] =
+ "ServiceUnavailable";
+// static
+const char AuthenticationFetcherOAuth::kErrorParam[] = "Error";
+// static
+const char AuthenticationFetcherOAuth::kErrorUrlParam[] = "Url";
+// static
+const char AuthenticationFetcherOAuth::kCaptchaUrlParam[] = "CaptchaUrl";
+// static
+const char AuthenticationFetcherOAuth::kCaptchaTokenParam[] = "CaptchaToken";
+// static
+const char AuthenticationFetcherOAuth::kCaptchaUrlPrefix[] =
+ "http://www.google.com/accounts/";
+
+// static
+const char AuthenticationFetcherOAuth::kCookiePersistence[] = "true";
+// static
+// TODO(johnnyg): When hosted accounts are supported by sync,
+// we can always use "HOSTED_OR_GOOGLE"
+const char AuthenticationFetcherOAuth::kAccountTypeHostedOrGoogle[] =
+ "HOSTED_OR_GOOGLE";
+const char AuthenticationFetcherOAuth::kAccountTypeGoogle[] =
+ "GOOGLE";
+
+// static
+const char AuthenticationFetcherOAuth::kSecondFactor[] =
+ "Info=InvalidSecondFactor";
+
+// TODO(chron): These urls are also in auth_response_handler.h.
+// The URLs for different calls in the Google Accounts programmatic login API.
+const char AuthenticationFetcherOAuth::kAuthenticationUrl[] =
+ "https://www.google.com/accounts/ClientLogin";
+const char AuthenticationFetcherOAuth::kIssueAuthTokenUrl[] =
+ "https://www.google.com/accounts/IssueAuthToken";
+const char AuthenticationFetcherOAuth::kGetUserInfoUrl[] =
+ "https://www.google.com/accounts/GetUserInfo";
+
+AuthenticationFetcherOAuth::AuthenticationFetcherOAuth(
+ AuthenticationConsumerOAuth* consumer,
+ const std::string& source,
+ net::URLRequestContextGetter* getter)
+ : AuthenticationFetcher(consumer, source, getter) {}
+
+AuthenticationFetcherOAuth::~AuthenticationFetcherOAuth() {}
+
+// static
+URLFetcher* AuthenticationFetcherOAuth::CreateAuthenticationFetcherOAuth(
+ net::URLRequestContextGetter* getter,
+ const std::string& body,
+ const GURL& gaia_gurl,
+ URLFetcher::Delegate* delegate) {
+
+ URLFetcher* to_return =
+ URLFetcher::Create(0,
+ gaia_gurl,
+ URLFetcher::POST,
+ delegate);
+ to_return->set_request_context(getter);
+ to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES);
+ to_return->set_upload_data("application/x-www-form-urlencoded", body);
+ return to_return;
+}
+
+// static
+std::string AuthenticationFetcherOAuth::MakeAuthenticationBody(
+ const std::string& username,
+ const std::string& password,
+ const std::string& source,
+ const char* service,
+ const std::string& login_token,
+ const std::string& login_captcha,
+ HostedAccountsSetting allow_hosted_accounts) {
+ std::string encoded_username = UrlEncodeString(username);
+ std::string encoded_password = UrlEncodeString(password);
+ std::string encoded_login_token = UrlEncodeString(login_token);
+ std::string encoded_login_captcha = UrlEncodeString(login_captcha);
+
+ const char* account_type = allow_hosted_accounts == HostedAccountsAllowed ?
+ kAccountTypeHostedOrGoogle :
+ kAccountTypeGoogle;
+
+ if (login_token.empty() || login_captcha.empty()) {
+ return base::StringPrintf(kAuthenticationFormat,
+ encoded_username.c_str(),
+ encoded_password.c_str(),
+ kCookiePersistence,
+ account_type,
+ source.c_str(),
+ service);
+ }
+
+ return base::StringPrintf(kAuthenticationCaptchaFormat,
+ encoded_username.c_str(),
+ encoded_password.c_str(),
+ kCookiePersistence,
+ account_type,
+ source.c_str(),
+ service,
+ encoded_login_token.c_str(),
+ encoded_login_captcha.c_str());
+
+}
+
+// static
+std::string AuthenticationFetcherOAuth::MakeIssueAuthTokenBody(
+ const AuthenticationConsumer::AuthenticationResult& credentials,
+ const char* const service) {
+ const AuthenticationConsumerOAuth::AuthenticationResult& cred =
+ static_cast<const AuthenticationConsumerOAuth::AuthenticationResult&>(
+ credentials);
+ std::string encoded_sid = UrlEncodeString(cred.sid);
+ std::string encoded_lsid = UrlEncodeString(cred.lsid);
+
+ // All tokens should be session tokens except the gaia auth token.
+ bool session = true;
+ if (!strcmp(service, GaiaConstants::kGaiaService))
+ session = false;
+
+ return base::StringPrintf(kIssueAuthTokenFormat,
+ encoded_sid.c_str(),
+ encoded_lsid.c_str(),
+ service,
+ session ? "true" : "false");
+}
+
+// static
+std::string AuthenticationFetcherOAuth::MakeGetUserInfoBody(
+ const std::string& lsid) {
+ std::string encoded_lsid = UrlEncodeString(lsid);
+ return base::StringPrintf(kGetUserInfoFormat, encoded_lsid.c_str());
+}
+
+// Helper method that extracts tokens from a successful reply.
+// static
+void AuthenticationFetcherOAuth::ParseAuthenticationResponse(
+ const std::string& data,
+ std::string* sid,
+ std::string* lsid,
+ std::string* token) {
+ using std::vector;
+ using std::pair;
+ using std::string;
+
+ vector<pair<string, string> > tokens;
+ base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
+ for (vector<pair<string, string> >::iterator i = tokens.begin();
+ i != tokens.end(); ++i) {
+ if (i->first == "SID") {
+ sid->assign(i->second);
+ } else if (i->first == "LSID") {
+ lsid->assign(i->second);
+ } else if (i->first == "Auth") {
+ token->assign(i->second);
+ }
+ }
+}
+
+// static
+void AuthenticationFetcherOAuth::ParseAuthenticationFailure(
+ const std::string& data,
+ std::string* error,
+ std::string* error_url,
+ std::string* captcha_url,
+ std::string* captcha_token) {
+ using std::vector;
+ using std::pair;
+ using std::string;
+
+ vector<pair<string, string> > tokens;
+ base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
+ for (vector<pair<string, string> >::iterator i = tokens.begin();
+ i != tokens.end(); ++i) {
+ if (i->first == kErrorParam) {
+ error->assign(i->second);
+ } else if (i->first == kErrorUrlParam) {
+ error_url->assign(i->second);
+ } else if (i->first == kCaptchaUrlParam) {
+ captcha_url->assign(i->second);
+ } else if (i->first == kCaptchaTokenParam) {
+ captcha_token->assign(i->second);
+ }
+ }
+}
+
+void AuthenticationFetcherOAuth::StartAuthentication(
+ const std::string& username,
+ const std::string& password,
+ const char* const service,
+ const std::string& login_token,
+ const std::string& login_captcha,
+ HostedAccountsSetting allow_hosted_accounts) {
+
+ DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
+
+ // This class is thread agnostic, so be sure to call this only on the
+ // same thread each time.
+ VLOG(1) << "Starting new Authentication fetch for:" << username;
+
+ // Must outlive fetcher_.
+ request_body_ = MakeAuthenticationBody(username,
+ password,
+ source_,
+ service,
+ login_token,
+ login_captcha,
+ allow_hosted_accounts);
+ fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
+ request_body_,
+ oauth_gurl_,
+ this));
+ SetPending();
+ fetcher_->Start();
+}
+
+void AuthenticationFetcherOAuth::StartIssueAuthToken(
+ const AuthenticationConsumer::AuthenticationResult& credentials,
+ const char* const service) {
+
+ DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
+
+ VLOG(1) << "Starting IssueAuthToken for: " << service;
+ requested_service_ = service;
+
+ request_body_ = MakeIssueAuthTokenBody(credentials, service);
+
+ fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
+ request_body_,
+ issue_auth_token_gurl_,
+ this));
+ SetPending();
+ fetcher_->Start();
+}
+
+void AuthenticationFetcherOAuth::StartGetUserInfo(const std::string& lsid,
+ const std::string& info_key) {
+ DCHECK(!HasPendingFetch()) << "Tried to fetch two things at once!";
+
+ VLOG(1) << "Starting GetUserInfo for lsid=" << lsid;
+ request_body_ = MakeGetUserInfoBody(lsid);
+ fetcher_.reset(CreateAuthenticationFetcherOAuth(getter_,
+ request_body_,
+ get_user_info_gurl_,
+ this));
+ SetPending();
+ requested_info_key_ = info_key;
+ fetcher_->Start();
+}
+
+// static
+GoogleServiceAuthError AuthenticationFetcherOAuth::GenerateAuthError(
+ const std::string& data,
+ const net::URLRequestStatus& status) {
+
+ if (!status.is_success()) {
+ if (status.status() == net::URLRequestStatus::CANCELED) {
+ return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
+ } else {
+ LOG(WARNING) << "Could not reach Google Accounts servers: errno "
+ << status.os_error();
+ return GoogleServiceAuthError::FromConnectionError(status.os_error());
+ }
+ } else {
+ if (IsSecondFactorSuccess(data)) {
+ return GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR);
+ }
+
+ std::string error;
+ std::string url;
+ std::string captcha_url;
+ std::string captcha_token;
+ ParseAuthenticationFailure(
+ data, &error, &url, &captcha_url, &captcha_token);
+ LOG(WARNING) << "Authentication failed with " << error;
+
+ if (error == kCaptchaError) {
+ GURL image_url(kCaptchaUrlPrefix + captcha_url);
+ GURL unlock_url(url);
+ return GoogleServiceAuthError::FromCaptchaChallenge(
+ captcha_token, image_url, unlock_url);
+ }
+ if (error == kAccountDeletedError)
+ return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
+ if (error == kAccountDisabledError)
+ return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
+ if (error == kBadAuthenticationError) {
+ return GoogleServiceAuthError(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ }
+ if (error == kServiceUnavailableError) {
+ return GoogleServiceAuthError(
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+ }
+
+ LOG(WARNING) << "Incomprehensible response from Google Accounts servers.";
+ return GoogleServiceAuthError(
+ GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+ }
+
+ NOTREACHED();
+ return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+}
+
+void AuthenticationFetcherOAuth::OnAuthenticationFetched(
+ const std::string& data,
+ const net::URLRequestStatus& status,
+ int response_code) {
+ if (status.is_success() && response_code == RC_REQUEST_OK) {
+ VLOG(1) << "Authentication successful!";
+ std::string sid;
+ std::string lsid;
+ std::string token;
+ ParseAuthenticationResponse(data, &sid, &lsid, &token);
+ consumer_->OnAuthenticationSuccess(
+ AuthenticationConsumerOAuth::AuthenticationResult(
+ sid, lsid, token, data));
+ } else {
+ consumer_->OnAuthenticationFailure(GenerateAuthError(data, status));
+ }
+}
+
+void AuthenticationFetcherOAuth::OnIssueAuthTokenFetched(
+ const std::string& data,
+ const net::URLRequestStatus& status,
+ int response_code) {
+ if (status.is_success() && response_code == RC_REQUEST_OK) {
+ // Only the bare token is returned in the body of this Gaia call
+ // without any padding.
+ consumer_->OnIssueTokenSuccess(requested_service_, data);
+ } else {
+ consumer_->OnIssueTokenFailure(requested_service_,
+ GenerateAuthError(data, status));
+ }
+}
+
+void AuthenticationFetcherOAuth::OnGetUserInfoFetched(
+ const std::string& data,
+ const net::URLRequestStatus& status,
+ int response_code) {
+ using std::vector;
+ using std::string;
+ using std::pair;
+
+ if (status.is_success() && response_code == RC_REQUEST_OK) {
+ vector<pair<string, string> > tokens;
+ base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
+ for (vector<pair<string, string> >::iterator i = tokens.begin();
+ i != tokens.end(); ++i) {
+ if (i->first == requested_info_key_) {
+ consumer_->OnGetUserInfoSuccess(i->first, i->second);
+ return;
+ }
+ }
+ consumer_->OnGetUserInfoKeyNotFound(requested_info_key_);
+ } else {
+ consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status));
+ }
+}
+
+void AuthenticationFetcherOAuth::OnURLFetchComplete(const URLFetcher* source,
+ const GURL& url,
+ const net::URLRequestStatus& status,
+ int response_code,
+ const ResponseCookies& cookies,
+ const std::string& data) {
+ ClearPending();
+ if (url == oauth_gurl_) {
+ OnAuthenticationFetched(data, status, response_code);
+ } else if (url == issue_auth_token_gurl_) {
+ OnIssueAuthTokenFetched(data, status, response_code);
+ } else if (url == get_user_info_gurl_) {
+ OnGetUserInfoFetched(data, status, response_code);
+ } else {
+ NOTREACHED();
+ }
+}
+
+// static
+bool AuthenticationFetcherOAuth::IsSecondFactorSuccess(
+ const std::string& alleged_error) {
+ return alleged_error.find(kSecondFactor) !=
+ std::string::npos;
+}
« 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