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

Unified Diff: chrome/browser/chromeos/login/oauth2_login_verifier.cc

Issue 11649055: OAuth2 sign-in flow for ChromeOS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: clang fix Created 7 years, 11 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
Index: chrome/browser/chromeos/login/oauth2_login_verifier.cc
diff --git a/chrome/browser/chromeos/login/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
new file mode 100644
index 0000000000000000000000000000000000000000..453ba2370179bc15e43f390cd0882217b8ee164d
--- /dev/null
+++ b/chrome/browser/chromeos/login/oauth2_login_verifier.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2013 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/browser/chromeos/login/oauth2_login_verifier.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+#include "base/time.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/network_library.h"
+#include "content/public/browser/browser_thread.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// OAuth token request max retry count.
+const int kMaxRequestAttemptCount = 5;
+// OAuth token request retry delay in milliseconds.
+const int kRequestRestartDelay = 3000;
+
+} // namespace
+
+namespace chromeos {
+
+OAuth2LoginVerifier::OAuth2LoginVerifier(
+ OAuth2LoginVerifier::Delegate* delegate,
+ net::URLRequestContextGetter* system_request_context,
+ net::URLRequestContextGetter* user_request_context)
+ : delegate_(delegate),
+ ALLOW_THIS_IN_INITIALIZER_LIST(token_fetcher_(
+ this, system_request_context)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(gaia_system_fetcher_(
+ this, std::string(GaiaConstants::kChromeOSSource),
+ system_request_context)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(gaia_fetcher_(
+ this, std::string(GaiaConstants::kChromeOSSource),
+ user_request_context)),
+ retry_count_(0) {
+ DCHECK(delegate);
+}
+
+OAuth2LoginVerifier::~OAuth2LoginVerifier() {
+}
+
+void OAuth2LoginVerifier::VerifyTokens(const std::string& oauth2_refresh_token,
+ const std::string& gaia_token) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (CrosLibrary::Get()->libcros_loaded()) {
+ // Delay the verification if the network is not connected or on a captive
+ // portal.
+ const Network* network =
+ CrosLibrary::Get()->GetNetworkLibrary()->active_network();
+ if (!network || !network->connected() || network->restricted_pool()) {
+ // If network is offline, defer the token fetching until online.
+ VLOG(1) << "Network is offline. Deferring OAuth2 access token fetch.";
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&OAuth2LoginVerifier::VerifyTokens,
+ AsWeakPtr(),
+ oauth2_refresh_token,
+ gaia_token),
+ base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
+ return;
+ }
+ }
+
+ access_token_.clear();
+ refresh_token_ = oauth2_refresh_token;
+ gaia_token_ = gaia_token;
+ if (gaia_token_.empty()) {
+ // If we have no token for GAIA service and can't merge the session
+ // immediately, attempt to perform OAuthLogin and reconstruct all service
+ // tokens.
+ RestoreSessionFromOAuth2RefreshToken();
+ } else {
+ // If GAIA token is present, we can attempt to shortcut the process straight
+ // to /MergeSession call.
+ RestoreSessionFromGaiaToken();
+ }
+}
+
+
+void OAuth2LoginVerifier::RestoreSessionFromOAuth2RefreshToken() {
+ type_ = RESTORE_FROM_OAUTH2_REFRESH_TOKEN;
+ StartFetchingOAuthLoginAccessToken();
+}
+
+void OAuth2LoginVerifier::RestoreSessionFromGaiaToken() {
+ type_ = RESTORE_FROM_GAIA_TOKEN;
+ StartMergeSession();
+}
+
+void OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken() {
+ access_token_.clear();
+ gaia_token_.clear();
+ std::vector<std::string> scopes;
+ scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope());
+ token_fetcher_.Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
+ GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
+ refresh_token_,
+ scopes);
+}
+
+void OAuth2LoginVerifier::OnGetTokenSuccess(
+ const std::string& access_token, const base::Time& expiration_time) {
+ LOG(INFO) << "Got OAuth2 access token!";
+ retry_count_ = 0;
+ access_token_ = access_token;
+ StartOAuthLoginForUberToken();
+}
+
+void OAuth2LoginVerifier::OnGetTokenFailure(
+ const GoogleServiceAuthError& error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ LOG(ERROR) << "Failed to get OAuth2 access token, "
+ << " error: " << error.state();
+ RetryOnError(
+ "GetOAuth2AccessToken", error,
+ base::Bind(&OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken,
+ AsWeakPtr()),
+ base::Bind(&Delegate::OnOAuthLoginFailure,
+ base::Unretained(delegate_)));
+}
+
+void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
+ // No service will fetch us uber auth token.
+ gaia_system_fetcher_.StartTokenFetchForUberAuthExchange(access_token_);
+}
+
+
+void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
+ const std::string& uber_token) {
+ LOG(INFO) << "OAuthLogin(uber_token) successful!";
+ retry_count_ = 0;
+ gaia_token_ = uber_token;
+ StartMergeSession();
+}
+
+void OAuth2LoginVerifier::OnUberAuthTokenFailure(
+ const GoogleServiceAuthError& error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ LOG(ERROR) << "OAuthLogin(uber_token) failed,"
+ << " error: " << error.state();
+ RetryOnError("OAuthLoginUberToken", error,
+ base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForUberToken,
+ AsWeakPtr()),
+ base::Bind(&Delegate::OnOAuthLoginFailure,
+ base::Unretained(delegate_)));
+}
+
+void OAuth2LoginVerifier::StartOAuthLoginForGaiaCredentials() {
+ // No service will fetch us uber auth token.
+ gaia_system_fetcher_.StartOAuthLogin(access_token_, EmptyString());
+}
+
+void OAuth2LoginVerifier::OnClientLoginSuccess(
+ const ClientLoginResult& gaia_credentials) {
+ LOG(INFO) << "OAuthLogin(SID+LSID) successful!";
+ retry_count_ = 0;
+ gaia_credentials_ = gaia_credentials;
+ delegate_->OnOAuthLoginSuccess(gaia_credentials_);
+}
+
+void OAuth2LoginVerifier::OnClientLoginFailure(
+ const GoogleServiceAuthError& error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ LOG(ERROR) << "OAuthLogin(SID+LSID failed),"
+ << " error: " << error.state();
+ RetryOnError(
+ "OAuthLoginGaiaCred", error,
+ base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForGaiaCredentials,
+ AsWeakPtr()),
+ base::Bind(&Delegate::OnOAuthLoginFailure,
+ base::Unretained(delegate_)));
+}
+
+void OAuth2LoginVerifier::StartMergeSession() {
+ DCHECK(!gaia_token_.empty());
+ gaia_fetcher_.StartMergeSession(gaia_token_);
+}
+
+void OAuth2LoginVerifier::OnMergeSessionSuccess(const std::string& data) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ LOG(INFO) << "MergeSession successful.";
+ UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionOrigin", type_, 2);
+ delegate_->OnSessionMergeSuccess();
+ // Get GAIA credentials needed to kick off TokenService and friends.
+ StartOAuthLoginForGaiaCredentials();
+}
+
+void OAuth2LoginVerifier::OnMergeSessionFailure(
+ const GoogleServiceAuthError& error) {
+ LOG(ERROR) << "Failed MergeSession request,"
+ << " error: " << error.state();
+ // If MergeSession from GAIA service token fails, retry the session restore
+ // from OAuth2 refresh token. If that failed too, signal the delegate.
+ RetryOnError(
+ (type_ == RESTORE_FROM_GAIA_TOKEN) ?
+ "MergeSessionGAIA" : "MergeSessionOAuth2",
+ error,
+ base::Bind(&OAuth2LoginVerifier::StartMergeSession,
+ AsWeakPtr()),
+ (type_ == RESTORE_FROM_GAIA_TOKEN) ?
+ base::Bind(&OAuth2LoginVerifier::RestoreSessionFromOAuth2RefreshToken,
+ AsWeakPtr()) :
+ base::Bind(&Delegate::OnSessionMergeFailure,
+ base::Unretained(delegate_)));
+}
+
+void OAuth2LoginVerifier::RetryOnError(const char* operation_id,
+ const GoogleServiceAuthError& error,
+ const base::Closure& task_to_retry,
+ const base::Closure& error_handler) {
+ if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
+ error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
+ error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
+ retry_count_ < kMaxRequestAttemptCount) {
+ retry_count_++;
+ UMA_HISTOGRAM_ENUMERATION(
+ base::StringPrintf("OAuth2Login.%sWithRetry", operation_id),
+ error.state(),
+ GoogleServiceAuthError::NUM_STATES);
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI, FROM_HERE, task_to_retry,
+ base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
+ return;
+ }
+
+ LOG(ERROR) << "Unrecoverable error or retry count max reached for "
+ << operation_id;
+ UMA_HISTOGRAM_ENUMERATION(
+ base::StringPrintf("OAuth2Login.%sFailureCause", operation_id),
+ error.state(),
+ GoogleServiceAuthError::NUM_STATES);
+ error_handler.Run();
+}
+
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698