| Index: chrome/browser/chromeos/login/login_utils.cc
|
| diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
|
| index 0f5bcb62af78cb402b3cb18ba96ab4af70a25402..5ff1f25498de96f94dfd0e4939f14d4400169e6d 100644
|
| --- a/chrome/browser/chromeos/login/login_utils.cc
|
| +++ b/chrome/browser/chromeos/login/login_utils.cc
|
| @@ -95,10 +95,15 @@ namespace chromeos {
|
|
|
| namespace {
|
|
|
| -// OAuth token verification retry count.
|
| +// OAuth token verification max retry count.
|
| const int kMaxOAuthTokenVerificationAttemptCount = 5;
|
| -// OAuth token verification retry delay.
|
| -const int kOAuthVerificationRestartDelay = 10000; // ms
|
| +// OAuth token verification retry delay in milliseconds.
|
| +const int kOAuthVerificationRestartDelay = 10000;
|
| +
|
| +// OAuth token request max retry count.
|
| +const int kMaxOAuth1TokenRequestAttemptCount = 5;
|
| +// OAuth token request retry delay in milliseconds.
|
| +const int kOAuth1TokenRequestRestartDelay = 3000;
|
|
|
| // Affixes for Auth token received from ClientLogin request.
|
| const char kAuthPrefix[] = "Auth=";
|
| @@ -186,6 +191,7 @@ void TransferDefaultAuthCacheOnIOThread(
|
|
|
| // Verifies OAuth1 access token by performing OAuthLogin. Fetches user cookies
|
| // on successful OAuth authentication.
|
| +// TODO(kochi): Split this class into another file after M20 merge.
|
| class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>,
|
| public GaiaOAuthConsumer,
|
| public GaiaAuthConsumer {
|
| @@ -335,7 +341,7 @@ class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>,
|
| delegate_->OnOAuthVerificationFailed(username_);
|
| }
|
|
|
| - void OnCookueFetchFailed(const GoogleServiceAuthError& error) {
|
| + void OnCookieFetchFailed(const GoogleServiceAuthError& error) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| if (!RetryOnError(error))
|
| delegate_->OnUserCookiesFetchFailed(username_);
|
| @@ -351,7 +357,7 @@ class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>,
|
| const GoogleServiceAuthError& error) OVERRIDE {
|
| DVLOG(1) << "Failed IssueAuthToken request,"
|
| << " error.state=" << error.state();
|
| - OnCookueFetchFailed(error);
|
| + OnCookieFetchFailed(error);
|
| }
|
|
|
| virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE {
|
| @@ -365,7 +371,7 @@ class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>,
|
| const GoogleServiceAuthError& error) OVERRIDE {
|
| DVLOG(1) << "Failed MergeSession request,"
|
| << " error.state=" << error.state();
|
| - OnCookueFetchFailed(error);
|
| + OnCookieFetchFailed(error);
|
| }
|
|
|
| OAuthLoginVerifier::Delegate* delegate_;
|
| @@ -388,6 +394,7 @@ class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>,
|
| // send a (possibly empty) token to the BrowserPolicyConnector, which will then
|
| // let the policy subsystem proceed and resume Profile creation.
|
| // Sending the token even when no Profile is pending is also OK.
|
| +// TODO(kochi): Split this class into another file after M20 merge.
|
| class PolicyOAuthFetcher : public GaiaOAuthConsumer {
|
| public:
|
| // Fetches the device management service's oauth token using |oauth1_token|
|
| @@ -536,9 +543,118 @@ class JobRestartRequest
|
| base::OneShotTimer<JobRestartRequest> timer_;
|
| };
|
|
|
| +// Given the authenticated credentials from the cookie jar, try to exchange
|
| +// fetch OAuth1 token and secret. Automatically retries until max retry count is
|
| +// reached.
|
| +// TODO(kochi): Split this class into another file after M20 merge.
|
| +class OAuth1TokenFetcher
|
| + : public base::SupportsWeakPtr<OAuth1TokenFetcher>,
|
| + public GaiaOAuthConsumer {
|
| + public:
|
| + class Delegate {
|
| + public:
|
| + virtual ~Delegate() {}
|
| + virtual void OnOAuth1AccessTokenAvailable(const std::string& token,
|
| + const std::string& secret) = 0;
|
| + virtual void OnOAuth1AccessTokenFetchFailed() = 0;
|
| + };
|
| +
|
| + OAuth1TokenFetcher(OAuth1TokenFetcher::Delegate* delegate,
|
| + Profile* auth_profile)
|
| + : delegate_(delegate),
|
| + auth_profile_(auth_profile),
|
| + oauth_fetcher_(this,
|
| + auth_profile_->GetRequestContext(),
|
| + auth_profile_,
|
| + kServiceScopeChromeOS),
|
| + retry_count_(0) {
|
| + DCHECK(delegate);
|
| + }
|
| + virtual ~OAuth1TokenFetcher() {}
|
| +
|
| + void Start() {
|
| + 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 OAuth1 token fetch.";
|
| + BrowserThread::PostDelayedTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&OAuth1TokenFetcher::Start, AsWeakPtr()),
|
| + base::TimeDelta::FromMilliseconds(kOAuth1TokenRequestRestartDelay));
|
| + return;
|
| + }
|
| + }
|
| + oauth_fetcher_.SetAutoFetchLimit(GaiaOAuthFetcher::OAUTH1_ALL_ACCESS_TOKEN);
|
| + oauth_fetcher_.StartGetOAuthTokenRequest();
|
| + }
|
| +
|
| + private:
|
| + // Decides how to proceed on GAIA response and other errors. If the error
|
| + // looks temporary, retries token fetching until max retry count is reached.
|
| + // If retry count runs out, or error condition is unrecoverable, returns
|
| + // false.
|
| + bool RetryOnError(const GoogleServiceAuthError& error) {
|
| + if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
|
| + error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
|
| + error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
|
| + retry_count_++ < kMaxOAuth1TokenRequestAttemptCount) {
|
| + BrowserThread::PostDelayedTask(
|
| + BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&OAuth1TokenFetcher::Start, AsWeakPtr()),
|
| + base::TimeDelta::FromMilliseconds(kOAuth1TokenRequestRestartDelay));
|
| + return true;
|
| + }
|
| + LOG(WARNING) << "Unrecoverable error or retry count max reached.";
|
| + return false;
|
| + }
|
| +
|
| + // GaiaOAuthConsumer implementation:
|
| + virtual void OnGetOAuthTokenSuccess(const std::string& oauth_token) OVERRIDE {
|
| + VLOG(1) << "Got OAuth request token!";
|
| + }
|
| +
|
| + virtual void OnGetOAuthTokenFailure(
|
| + const GoogleServiceAuthError& error) OVERRIDE {
|
| + LOG(WARNING) << "Failed to get OAuth1 request token, error: "
|
| + << error.state();
|
| + if (!RetryOnError(error))
|
| + delegate_->OnOAuth1AccessTokenFetchFailed();
|
| + }
|
| +
|
| + virtual void OnOAuthGetAccessTokenSuccess(
|
| + const std::string& token,
|
| + const std::string& secret) OVERRIDE {
|
| + VLOG(1) << "Got OAuth v1 token!";
|
| + retry_count_ = 0;
|
| + delegate_->OnOAuth1AccessTokenAvailable(token, secret);
|
| + }
|
| +
|
| + virtual void OnOAuthGetAccessTokenFailure(
|
| + const GoogleServiceAuthError& error) OVERRIDE {
|
| + LOG(WARNING) << "Failed fetching OAuth1 access token, error: "
|
| + << error.state();
|
| + if (!RetryOnError(error))
|
| + delegate_->OnOAuth1AccessTokenFetchFailed();
|
| + }
|
| +
|
| + OAuth1TokenFetcher::Delegate* delegate_;
|
| + Profile* auth_profile_;
|
| + GaiaOAuthFetcher oauth_fetcher_;
|
| +
|
| + // The retry counter. Increment this only when failure happened.
|
| + int retry_count_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(OAuth1TokenFetcher);
|
| +};
|
| +
|
| class LoginUtilsImpl
|
| : public LoginUtils,
|
| - public GaiaOAuthConsumer,
|
| + public OAuth1TokenFetcher::Delegate,
|
| public OAuthLoginVerifier::Delegate,
|
| public net::NetworkChangeNotifier::ConnectionTypeObserver,
|
| public base::SupportsWeakPtr<LoginUtilsImpl> {
|
| @@ -585,14 +701,10 @@ class LoginUtilsImpl
|
| Profile* new_profile) OVERRIDE;
|
| virtual void StopBackgroundFetchers() OVERRIDE;
|
|
|
| - // GaiaOAuthConsumer overrides.
|
| - virtual void OnGetOAuthTokenSuccess(const std::string& oauth_token) OVERRIDE;
|
| - virtual void OnGetOAuthTokenFailure(
|
| - const GoogleServiceAuthError& error) OVERRIDE;
|
| - virtual void OnOAuthGetAccessTokenSuccess(const std::string& token,
|
| - const std::string& secret) OVERRIDE;
|
| - virtual void OnOAuthGetAccessTokenFailure(
|
| - const GoogleServiceAuthError& error) OVERRIDE;
|
| + // OAuth1TokenFetcher::Delegate overrides.
|
| + void OnOAuth1AccessTokenAvailable(const std::string& token,
|
| + const std::string& secret) OVERRIDE;
|
| + void OnOAuth1AccessTokenFetchFailed() OVERRIDE;
|
|
|
| // OAuthLoginVerifier::Delegate overrides.
|
| virtual void OnOAuthVerificationSucceeded(const std::string& user_name,
|
| @@ -605,10 +717,6 @@ class LoginUtilsImpl
|
| virtual void OnConnectionTypeChanged(
|
| net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
|
|
|
| - // Given the authenticated credentials from the cookie jar, try to exchange
|
| - // fetch OAuth request, v1 and v2 tokens.
|
| - void FetchOAuth1AccessToken(Profile* auth_profile);
|
| -
|
| protected:
|
| virtual std::string GetOffTheRecordCommandLine(
|
| const GURL& start_url,
|
| @@ -663,8 +771,8 @@ class LoginUtilsImpl
|
| bool has_cookies_;
|
| // Has to be scoped_refptr, see comment for CreateAuthenticator(...).
|
| scoped_refptr<Authenticator> authenticator_;
|
| - scoped_ptr<GaiaOAuthFetcher> oauth_fetcher_;
|
| scoped_ptr<PolicyOAuthFetcher> policy_oauth_fetcher_;
|
| + scoped_ptr<OAuth1TokenFetcher> oauth1_token_fetcher_;
|
| scoped_ptr<OAuthLoginVerifier> oauth_login_verifier_;
|
|
|
| // Delegate to be fired when the profile will be prepared.
|
| @@ -886,12 +994,17 @@ void LoginUtilsImpl::OnProfileCreated(
|
| VerifyOAuth1AccessToken(user_profile, oauth1_token, oauth1_secret);
|
| } else {
|
| // If we don't have it, fetch OAuth1 access token.
|
| + // Once we get that, we will kick off individual requests for OAuth2
|
| + // tokens for all our services.
|
| // Use off-the-record profile that was used for this step. It should
|
| // already contain all needed cookies that will let us skip GAIA's user
|
| // authentication UI.
|
| //
|
| // TODO(rickcam) We should use an isolated App here.
|
| - FetchOAuth1AccessToken(authenticator_->authentication_profile());
|
| + oauth1_token_fetcher_.reset(
|
| + new OAuth1TokenFetcher(this,
|
| + authenticator_->authentication_profile()));
|
| + oauth1_token_fetcher_->Start();
|
| }
|
| }
|
|
|
| @@ -927,18 +1040,6 @@ void LoginUtilsImpl::OnProfileCreated(
|
| delegate_->OnProfilePrepared(user_profile);
|
| }
|
|
|
| -void LoginUtilsImpl::FetchOAuth1AccessToken(Profile* auth_profile) {
|
| - oauth_fetcher_.reset(new GaiaOAuthFetcher(this,
|
| - auth_profile->GetRequestContext(),
|
| - auth_profile,
|
| - kServiceScopeChromeOS));
|
| - // Let's first get the Oauth request token and OAuth1 token+secret.
|
| - // Once we get that, we will kick off individual requests for OAuth2 tokens
|
| - // for all our services.
|
| - oauth_fetcher_->SetAutoFetchLimit(GaiaOAuthFetcher::OAUTH1_ALL_ACCESS_TOKEN);
|
| - oauth_fetcher_->StartGetOAuthTokenRequest();
|
| -}
|
| -
|
| void LoginUtilsImpl::StartTokenServices(Profile* user_profile) {
|
| std::string oauth1_token;
|
| std::string oauth1_secret;
|
| @@ -1270,39 +1371,11 @@ void LoginUtilsImpl::TransferDefaultAuthCache(Profile* default_profile,
|
| }
|
|
|
| void LoginUtilsImpl::StopBackgroundFetchers() {
|
| - oauth_fetcher_.reset();
|
| policy_oauth_fetcher_.reset();
|
| + oauth1_token_fetcher_.reset();
|
| oauth_login_verifier_.reset();
|
| }
|
|
|
| -void LoginUtilsImpl::OnGetOAuthTokenSuccess(const std::string& oauth_token) {
|
| - VLOG(1) << "Got OAuth request token!";
|
| -}
|
| -
|
| -void LoginUtilsImpl::OnGetOAuthTokenFailure(
|
| - const GoogleServiceAuthError& error) {
|
| - // TODO(zelidrag): Pop up sync setup UI here?
|
| - LOG(WARNING) << "Failed fetching OAuth request token, error: "
|
| - << error.state();
|
| -}
|
| -
|
| -void LoginUtilsImpl::OnOAuthGetAccessTokenSuccess(const std::string& token,
|
| - const std::string& secret) {
|
| - VLOG(1) << "Got OAuth v1 token!";
|
| - Profile* user_profile = ProfileManager::GetDefaultProfile();
|
| - StoreOAuth1AccessToken(user_profile, token, secret);
|
| -
|
| - // Verify OAuth1 token by doing OAuthLogin and fetching credentials.
|
| - VerifyOAuth1AccessToken(user_profile, token, secret);
|
| -}
|
| -
|
| -void LoginUtilsImpl::OnOAuthGetAccessTokenFailure(
|
| - const GoogleServiceAuthError& error) {
|
| - // TODO(zelidrag): Pop up sync setup UI here?
|
| - LOG(WARNING) << "Failed fetching OAuth request token, error: "
|
| - << error.state();
|
| -}
|
| -
|
| void LoginUtilsImpl::FetchSecondaryTokens(Profile* offrecord_profile,
|
| const std::string& token,
|
| const std::string& secret) {
|
| @@ -1417,6 +1490,20 @@ void LoginUtilsImpl::OnOAuthVerificationFailed(const std::string& user_name) {
|
| User::OAUTH_TOKEN_STATUS_INVALID);
|
| }
|
|
|
| +void LoginUtilsImpl::OnOAuth1AccessTokenAvailable(const std::string& token,
|
| + const std::string& secret) {
|
| + Profile* user_profile = ProfileManager::GetDefaultProfile();
|
| + StoreOAuth1AccessToken(user_profile, token, secret);
|
| +
|
| + // Verify OAuth1 token by doing OAuthLogin and fetching credentials.
|
| + VerifyOAuth1AccessToken(user_profile, token, secret);
|
| +}
|
| +
|
| +void LoginUtilsImpl::OnOAuth1AccessTokenFetchFailed() {
|
| + // TODO(kochi): Show failure notification UI here?
|
| + LOG(ERROR) << "Failed to fetch OAuth1 access token.";
|
| +}
|
| +
|
| void LoginUtilsImpl::OnOAuthVerificationSucceeded(
|
| const std::string& user_name, const std::string& sid,
|
| const std::string& lsid, const std::string& auth) {
|
| @@ -1434,7 +1521,7 @@ void LoginUtilsImpl::OnConnectionTypeChanged(
|
| if (oauth_login_verifier_.get() &&
|
| !oauth_login_verifier_->is_done()) {
|
| // If we come online for the first time after successful offline login,
|
| - // we need to kick of OAuth token verification process again.
|
| + // we need to kick off OAuth token verification process again.
|
| oauth_login_verifier_->ContinueVerification();
|
| } else if (should_restore_auth_session_) {
|
| should_restore_auth_session_ = false;
|
|
|