#include "chrome/browser/chromeos/net/network_portal_detector.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
// OAuth token request max retry count.
const int kMaxRequestAttemptCount = 5;
+
// OAuth token request retry delay in milliseconds.
const int kRequestRestartDelay = 3000;
+// Post merge session verification delay.
+#ifndef NDEBUG
+const int kPostResoreVerificationDelay = 1000;
+#else
+const int kPostResoreVerificationDelay = 1000*60*3;
+#endif
+
bool IsConnectionOrServiceError(const GoogleServiceAuthError& error) {
return error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
OAuth2LoginVerifier::OAuth2LoginVerifier(
OAuth2LoginVerifier::Delegate* delegate,
net::URLRequestContextGetter* system_request_context,
- net::URLRequestContextGetter* user_request_context)
- : delegate_(delegate),
+ net::URLRequestContextGetter* user_request_context,
+ const std::string& oauthlogin_access_token)
+ : OAuth2TokenService::Consumer("cros_login_verifier"),
+ delegate_(delegate),
system_request_context_(system_request_context),
user_request_context_(user_request_context),
+ access_token_(oauthlogin_access_token),
retry_count_(0) {
DCHECK(delegate);
}
OAuth2LoginVerifier::~OAuth2LoginVerifier() {
}
+void OAuth2LoginVerifier::VerifyUserCookies(Profile* profile) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyUserCookies,
+ AsWeakPtr(),
+ profile))) {
+ return;
+ }
+
+ StartAuthCookiesVerification();
+}
+
void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- // Delay the verification if the network is not connected or on a captive
- // portal.
- const NetworkState* default_network =
- NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
- NetworkPortalDetector* detector = NetworkPortalDetector::Get();
- if (!default_network ||
- default_network->connection_state() == shill::kStatePortal ||
- (detector && detector->GetCaptivePortalState(default_network).status !=
- NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
- // 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::VerifyProfileTokens, AsWeakPtr(), profile),
- base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
+ if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyProfileTokens,
+ AsWeakPtr(),
+ profile))) {
return;
}
- access_token_.clear();
gaia_token_.clear();
- StartFetchingOAuthLoginAccessToken(profile);
+ if (access_token_.empty()) {
+ // Fetch /OAuthLogin scoped access token.
+ StartFetchingOAuthLoginAccessToken(profile);
+ } else {
+ // If OAuthLogin-scoped access token already exists (if it's generated
+ // together with freshly minted refresh token), then fetch GAIA uber token.
+ StartOAuthLoginForUberToken();
+ }
}
void OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken(Profile* profile) {
scopes.insert(GaiaUrls::GetInstance()->oauth1_login_scope());
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+ SigninManagerBase* signin_manager =
+ SigninManagerFactory::GetForProfile(profile);
login_token_request_ = token_service->StartRequestWithContext(
- token_service->GetPrimaryAccountId(),
+ signin_manager->GetAuthenticatedAccountId(),
system_request_context_.get(),
scopes,
this);
void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
// No service will fetch us uber auth token.
- gaia_system_fetcher_.reset(
+ gaia_fetcher_.reset(
new GaiaAuthFetcher(this,
std::string(GaiaConstants::kChromeOSSource),
- system_request_context_.get()));
- gaia_system_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
+ user_request_context_.get()));
+ gaia_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
}
void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
const std::string& uber_token) {
- LOG(INFO) << "OAuthLogin(uber_token) successful!";
+ VLOG(1) << "OAuthLogin(uber_token) successful!";
retry_count_ = 0;
gaia_token_ = uber_token;
StartMergeSession();
const GoogleServiceAuthError& error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
LOG(WARNING) << "OAuthLogin(uber_token) failed,"
- << " error: " << error.state();
+ << " error: " << error.state();
RetryOnError("OAuthLoginUberToken", error,
base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForUberToken,
AsWeakPtr()),
- base::Bind(&Delegate::OnOAuthLoginFailure,
+ base::Bind(&Delegate::OnSessionMergeFailure,
base::Unretained(delegate_)));
}
-void OAuth2LoginVerifier::StartOAuthLoginForGaiaCredentials() {
- // No service will fetch us uber auth token.
- gaia_system_fetcher_.reset(
- new GaiaAuthFetcher(this,
- std::string(GaiaConstants::kChromeOSSource),
- system_request_context_.get()));
- gaia_system_fetcher_->StartOAuthLogin(access_token_, EmptyString());
-}
-
-void OAuth2LoginVerifier::OnClientLoginSuccess(
- const ClientLoginResult& gaia_credentials) {
- LOG(INFO) << "OAuthLogin(SID+LSID) successful!";
- retry_count_ = 0;
- delegate_->OnOAuthLoginSuccess(gaia_credentials);
-}
-
-void OAuth2LoginVerifier::OnClientLoginFailure(
- const GoogleServiceAuthError& error) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- LOG(WARNING) << "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_.reset(
void OAuth2LoginVerifier::OnMergeSessionSuccess(const std::string& data) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- LOG(INFO) << "MergeSession successful.";
+ VLOG(1) << "MergeSession successful.";
delegate_->OnSessionMergeSuccess();
- // Get GAIA credentials needed to kick off TokenService and friends.
- StartOAuthLoginForGaiaCredentials();
+ // Schedule post-merge verification to analyze how many LSID/SID overruns
+ // were created by the session restore.
+ SchedulePostMergeVerification();
+}
+
+void OAuth2LoginVerifier::SchedulePostMergeVerification() {
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &OAuth2LoginVerifier::StartAuthCookiesVerification, AsWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kPostResoreVerificationDelay));
+}
+
+void OAuth2LoginVerifier::StartAuthCookiesVerification() {
+ gaia_fetcher_.reset(
+ new GaiaAuthFetcher(this,
+ std::string(GaiaConstants::kChromeOSSource),
+ user_request_context_.get()));
+ gaia_fetcher_->StartListAccounts();
}
void OAuth2LoginVerifier::OnMergeSessionFailure(
const GoogleServiceAuthError& error) {
- LOG(WARNING) << "Failed MergeSession request,"
- << " error: " << error.state();
+ LOG(WARNING) << "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(
DCHECK_EQ(login_token_request_.get(), request);
login_token_request_.reset();
- LOG(INFO) << "Got OAuth2 access token!";
+ VLOG(1) << "Got OAuth2 access token!";
retry_count_ = 0;
access_token_ = access_token;
StartOAuthLoginForUberToken();
login_token_request_.reset();
LOG(WARNING) << "Failed to get OAuth2 access token, "
- << " error: " << error.state();
+ << " error: " << error.state();
UMA_HISTOGRAM_ENUMERATION(
base::StringPrintf("OAuth2Login.%sFailure", "GetOAuth2AccessToken"),
error.state(),
GoogleServiceAuthError::NUM_STATES);
- delegate_->OnOAuthLoginFailure(IsConnectionOrServiceError(error));
+ delegate_->OnSessionMergeFailure(IsConnectionOrServiceError(error));
+}
+
+void OAuth2LoginVerifier::OnListAccountsSuccess(
+ const std::string& data) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ VLOG(1) << "ListAccounts successful.";
+ delegate_->OnListAccountsSuccess(data);
+}
+
+void OAuth2LoginVerifier::OnListAccountsFailure(
+ const GoogleServiceAuthError& error) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ LOG(WARNING) << "Failed to get list of session accounts, "
+ << " error: " << error.state();
+ RetryOnError(
+ "ListAccounts",
+ error,
+ base::Bind(&OAuth2LoginVerifier::StartAuthCookiesVerification,
+ AsWeakPtr()),
+ base::Bind(&Delegate::OnListAccountsFailure,
+ base::Unretained(delegate_)));
}
void OAuth2LoginVerifier::RetryOnError(const char* operation_id,
}
LOG(WARNING) << "Unrecoverable error or retry count max reached for "
- << operation_id;
+ << operation_id;
UMA_HISTOGRAM_ENUMERATION(
base::StringPrintf("OAuth2Login.%sFailure", operation_id),
error.state(),
error_handler.Run(IsConnectionOrServiceError(error));
}
+bool OAuth2LoginVerifier::DelayNetworkCall(const base::Closure& callback) {
+ // Delay the verification if the network is not connected or on a captive
+ // portal.
+ const NetworkState* default_network =
+ NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
+ NetworkPortalDetector* detector = NetworkPortalDetector::Get();
+ if (!default_network ||
+ default_network->connection_state() == shill::kStatePortal ||
+ (detector && detector->GetCaptivePortalState(default_network).status !=
+ NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
+ // If network is offline, defer the token fetching until online.
+ LOG(WARNING) << "Network is offline. Deferring call.";
+ BrowserThread::PostDelayedTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ callback,
+ base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
+ return true;
+ }
+
+ return false;
+}
+
} // namespace chromeos