blob: c01583925a18efb22e732ce5907ea47d7961a17a [file] [log] [blame]
// Copyright 2014 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.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SIGNIN_OAUTH2_LOGIN_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SIGNIN_OAUTH2_LOGIN_MANAGER_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/login/signin/oauth2_login_verifier.h"
#include "chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/oauth2_token_service.h"
class GoogleServiceAuthError;
class Profile;
class ProfileOAuth2TokenService;
namespace network {
class SharedURLLoaderFactory;
}
namespace chromeos {
// This class is responsible for restoring authenticated web sessions out of
// OAuth2 refresh tokens or pre-authenticated cookie jar.
class OAuth2LoginManager : public KeyedService,
public OAuth2LoginVerifier::Delegate,
public OAuth2TokenFetcher::Delegate,
public OAuth2TokenService::Observer {
public:
// Session restore states.
enum SessionRestoreState {
// Session restore is not started.
SESSION_RESTORE_NOT_STARTED = 0,
// Session restore is being prepared.
SESSION_RESTORE_PREPARING = 1,
// Session restore is in progress. We are currently issuing calls to verify
// stored OAuth tokens and populate cookie jar with GAIA credentials.
SESSION_RESTORE_IN_PROGRESS = 2,
// Session restore is completed.
SESSION_RESTORE_DONE = 3,
// Session restore failed.
SESSION_RESTORE_FAILED = 4,
// Session restore failed due to connection or service errors.
SESSION_RESTORE_CONNECTION_FAILED = 5,
};
// Session restore strategy.
enum SessionRestoreStrategy {
// Generate OAuth2 refresh token from authentication profile's cookie jar.
// Restore session from generated OAuth2 refresh token.
RESTORE_FROM_COOKIE_JAR,
// Restore session from saved OAuth2 refresh token from TokenServices.
RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN,
// Restore session from OAuth2 refresh token passed via command line.
RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN,
};
class Observer {
public:
virtual ~Observer() {}
// Raised when merge session state changes.
virtual void OnSessionRestoreStateChanged(Profile* user_profile,
SessionRestoreState state) {}
// Raised when a new OAuth2 refresh token is available.
virtual void OnNewRefreshTokenAvaiable(Profile* user_profile) {}
// Raised when session's GAIA credentials (SID+LSID) are available to
// other signed in services.
virtual void OnSessionAuthenticated(Profile* user_profile) {}
};
explicit OAuth2LoginManager(Profile* user_profile);
~OAuth2LoginManager() override;
void AddObserver(OAuth2LoginManager::Observer* observer);
void RemoveObserver(OAuth2LoginManager::Observer* observer);
// Restores and verifies OAuth tokens following specified |restore_strategy|.
// For |restore_strategy| RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN, parameter
// |oauth2_refresh_token| needs to have a non-empty value.
// For |restore_strategy| RESTORE_FROM_COOKIE_JAR.
void RestoreSession(
scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
SessionRestoreStrategy restore_strategy,
const std::string& oauth2_refresh_token,
const std::string& oauth2_access_token);
// Continues session restore after transient network errors.
void ContinueSessionRestore();
// Start restoring session from saved OAuth2 refresh token.
void RestoreSessionFromSavedTokens();
// Stops all background authentication requests.
void Stop();
// Returns session restore state.
SessionRestoreState state() { return state_; }
const base::Time& session_restore_start() { return session_restore_start_; }
bool SessionRestoreIsRunning() const;
// Returns true if the tab loading should block until session restore
// finishes.
bool ShouldBlockTabLoading() const;
private:
friend class MergeSessionNavigationThrottleTest;
friend class OAuth2Test;
// Session restore outcomes (for UMA).
enum SessionRestoreOutcome {
SESSION_RESTORE_UNDEFINED = 0,
SESSION_RESTORE_SUCCESS = 1,
SESSION_RESTORE_TOKEN_FETCH_FAILED = 2,
SESSION_RESTORE_NO_REFRESH_TOKEN_FAILED = 3,
SESSION_RESTORE_OAUTHLOGIN_FAILED = 4,
SESSION_RESTORE_MERGE_SESSION_FAILED = 5,
SESSION_RESTORE_LISTACCOUNTS_FAILED = 6,
SESSION_RESTORE_NOT_NEEDED = 7,
SESSION_RESTORE_COUNT = 8,
};
// Outcomes of post-merge session verification.
// This enum is used for an UMA histogram, and hence new items should only be
// appended at the end.
enum MergeVerificationOutcome {
POST_MERGE_UNDEFINED = 0,
POST_MERGE_SUCCESS = 1,
POST_MERGE_NO_ACCOUNTS = 2,
POST_MERGE_MISSING_PRIMARY_ACCOUNT = 3,
POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT = 4,
POST_MERGE_VERIFICATION_FAILED = 5,
POST_MERGE_CONNECTION_FAILED = 6,
POST_MERGE_COUNT = 7,
};
// KeyedService implementation.
void Shutdown() override;
// OAuth2LoginVerifier::Delegate overrides.
void OnSessionMergeSuccess() override;
void OnSessionMergeFailure(bool connection_error) override;
void OnListAccountsSuccess(
const std::vector<gaia::ListedAccount>& accounts) override;
void OnListAccountsFailure(bool connection_error) override;
// OAuth2TokenFetcher::Delegate overrides.
void OnOAuth2TokensAvailable(
const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) override;
void OnOAuth2TokensFetchFailed() override;
// OAuth2TokenService::Observer implementation:
void OnRefreshTokenAvailable(const std::string& user_email) override;
// Signals delegate that authentication is completed, kicks off token fetching
// process.
void CompleteAuthentication();
// Retrieves ProfileOAuth2TokenService for |user_profile_|.
ProfileOAuth2TokenService* GetTokenService();
// Retrieves the primary account for |user_profile_|.
std::string GetPrimaryAccountId();
// Records |refresh_token_| to token service. The associated account id is
// assumed to be the primary account id of the user profile. If the primary
// account id is not present, GetAccountInfoOfRefreshToken will be called to
// retrieve the associated account info.
void StoreOAuth2Token();
// Update the token service and inform listeners of a new refresh token.
void UpdateCredentials(const std::string& account_id);
// Notify that the refresh tokens are loaded and ready to use.
void FireRefreshTokensLoaded();
// Attempts to fetch OAuth2 tokens by using pre-authenticated cookie jar from
// provided |auth_profile|.
void FetchOAuth2Tokens();
// Reports when all tokens are loaded.
void ReportOAuth2TokensLoaded();
// Checks if primary account sessions cookies are stale and restores them
// if needed.
void VerifySessionCookies();
// Issue GAIA cookie recovery (MergeSession) from |refresh_token_|.
void RestoreSessionCookies();
// Checks GAIA error and figures out whether the request should be
// re-attempted.
bool RetryOnError(const GoogleServiceAuthError& error);
// Changes |state_|, if needed fires observers (OnSessionRestoreStateChanged).
void SetSessionRestoreState(SessionRestoreState state);
// Testing helper.
void SetSessionRestoreStartForTesting(const base::Time& time);
// Records |outcome| of session restore process and sets new |state|.
void RecordSessionRestoreOutcome(SessionRestoreOutcome outcome,
SessionRestoreState state);
// Records |outcome| of merge verification check. |is_pre_merge| specifies
// if this is pre or post merge session verification.
static void RecordCookiesCheckOutcome(bool is_pre_merge,
MergeVerificationOutcome outcome);
// Keeps the track if we have already reported OAuth2 token being loaded
// by OAuth2TokenService.
Profile* user_profile_;
scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory_;
SessionRestoreStrategy restore_strategy_;
SessionRestoreState state_;
// Whether there is pending TokenService::LoadCredentials call.
bool pending_token_service_load_ = false;
std::unique_ptr<OAuth2TokenFetcher> oauth2_token_fetcher_;
std::unique_ptr<OAuth2LoginVerifier> login_verifier_;
// OAuth2 refresh token.
std::string refresh_token_;
// OAuthLogin scoped access token.
std::string oauthlogin_access_token_;
// Session restore start time.
base::Time session_restore_start_;
// List of observers to notify when token availability changes.
// Makes sure list is empty on destruction.
// TODO(zelidrag|gspencer): Figure out how to get rid of ProfileHelper so we
// can change the line below to base::ObserverList<Observer, true>.
base::ObserverList<Observer, false> observer_list_;
DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManager);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SIGNIN_OAUTH2_LOGIN_MANAGER_H_