Index: chrome/browser/chromeos/login/login_utils.cc |
=================================================================== |
--- chrome/browser/chromeos/login/login_utils.cc (revision 110566) |
+++ chrome/browser/chromeos/login/login_utils.cc (working copy) |
@@ -77,6 +77,11 @@ |
namespace { |
+// OAuth token verification retry count. |
+const int kMaxOAuthTokenVerificationAttemptCount = 5; |
+// OAuth token verification retry delay. |
+const int kOAuthVerificationRestartDelay = 10000; // ms |
+ |
// Affixes for Auth token received from ClientLogin request. |
const char kAuthPrefix[] = "Auth="; |
const char kAuthSuffix[] = "\n"; |
@@ -100,29 +105,6 @@ |
"https://www.googleapis.com/auth/chromeosdevicemanagement"; |
} // namespace |
-// Task for fetching tokens from UI thread. |
-class StartSyncOnUIThreadTask : public Task { |
- public: |
- explicit StartSyncOnUIThreadTask( |
- const GaiaAuthConsumer::ClientLoginResult& credentials) |
- : credentials_(credentials) {} |
- virtual ~StartSyncOnUIThreadTask() {} |
- |
- // Task override. |
- virtual void Run() OVERRIDE { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- LoginUtils::Get()->FetchCookies(ProfileManager::GetDefaultProfile(), |
- credentials_); |
- LoginUtils::Get()->StartSync(ProfileManager::GetDefaultProfile(), |
- credentials_); |
- } |
- |
- private: |
- GaiaAuthConsumer::ClientLoginResult credentials_; |
- |
- DISALLOW_COPY_AND_ASSIGN(StartSyncOnUIThreadTask); |
-}; |
- |
// Transfers initial set of Profile cookies from the default profile. |
class TransferDefaultCookiesOnIOThreadTask : public Task { |
public: |
@@ -190,24 +172,52 @@ |
DISALLOW_COPY_AND_ASSIGN(TransferDefaultAuthCacheOnIOThreadTask); |
}; |
-// Verifies OAuth1 access token by performing OAuthLogin. |
-class OAuthLoginVerifier : public GaiaOAuthConsumer { |
+// Verifies OAuth1 access token by performing OAuthLogin. Fetches user cookies |
+// on successful OAuth authentication. |
+class OAuthLoginVerifier : public base::SupportsWeakPtr<OAuthLoginVerifier>, |
+ public GaiaOAuthConsumer, |
+ public GaiaAuthConsumer { |
public: |
- OAuthLoginVerifier(Profile* user_profile, |
+ class Delegate { |
+ public: |
+ virtual ~Delegate() {} |
+ virtual void OnOAuthVerificationSucceeded(const std::string& user_name, |
+ const std::string& sid, |
+ const std::string& lsid, |
+ const std::string& auth) {} |
+ virtual void OnOAuthVerificationFailed(const std::string& user_name) {} |
+ virtual void OnUserCookiesFetchSucceeded(const std::string& user_name) {} |
+ virtual void OnUserCookiesFetchFailed(const std::string& user_name) {} |
+ }; |
+ |
+ OAuthLoginVerifier(OAuthLoginVerifier::Delegate* delegate, |
+ Profile* user_profile, |
const std::string& oauth1_token, |
const std::string& oauth1_secret, |
const std::string& username) |
- : oauth_fetcher_(this, |
+ : delegate_(delegate), |
+ oauth_fetcher_(this, |
user_profile->GetOffTheRecordProfile()->GetRequestContext(), |
user_profile->GetOffTheRecordProfile(), |
kServiceScopeChromeOS), |
+ gaia_fetcher_(this, |
+ std::string(GaiaConstants::kChromeOSSource), |
+ user_profile->GetRequestContext()), |
oauth1_token_(oauth1_token), |
oauth1_secret_(oauth1_secret), |
- username_(username) { |
+ username_(username), |
+ user_profile_(user_profile), |
+ verification_count_(0), |
+ step_(VERIFICATION_STEP_UNVERIFIED) { |
} |
virtual ~OAuthLoginVerifier() {} |
- void Start() { |
+ bool is_done() { |
+ return step_ == VERIFICATION_STEP_FAILED || |
+ step_ == VERIFICATION_STEP_COOKIES_FETCHED; |
+ } |
+ |
+ void StartOAuthVerification() { |
if (oauth1_token_.empty() || oauth1_secret_.empty()) { |
// Empty OAuth1 access token or secret probably means that we are |
// dealing with a legacy ChromeOS account. This should be treated as |
@@ -222,56 +232,104 @@ |
} |
} |
- // GaiaOAuthConsumer implementation: |
- virtual void OnOAuthLoginSuccess(const std::string& sid, |
- const std::string& lsid, |
- const std::string& auth) OVERRIDE { |
- GaiaAuthConsumer::ClientLoginResult credentials( |
- sid, lsid, auth, std::string()); |
- UserManager::Get()->set_offline_login(false); |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- new StartSyncOnUIThreadTask(credentials)); |
- } |
+ void ContinueVerification() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ // Check if we have finished with this one already. |
+ if (is_done()) |
+ return; |
- virtual void OnOAuthLoginFailure( |
- const GoogleServiceAuthError& error) OVERRIDE { |
- LOG(WARNING) << "Failed to verify OAuth1 access tokens, error: " |
- << error.state(); |
+ if (user_profile_ != ProfileManager::GetDefaultProfile()) |
+ return; |
- // Mark this account's OAuth token state as invalid if the failure is not |
- // caused by network error. |
- if (error.state() != GoogleServiceAuthError::CONNECTION_FAILED) { |
- UserManager::Get()->SaveUserOAuthStatus(username_, |
- User::OAUTH_TOKEN_STATUS_INVALID); |
+ // Check if we currently trying to fetch something. |
+ if (oauth_fetcher_.HasPendingFetch() || gaia_fetcher_.HasPendingFetch()) |
+ return; |
+ |
+ if (CrosLibrary::Get()->EnsureLoaded()) { |
+ // 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()) { |
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, |
+ base::Bind(&OAuthLoginVerifier::ContinueVerification, AsWeakPtr()), |
+ kOAuthVerificationRestartDelay); |
Nikita (slow)
2011/11/22 09:14:39
verification_count_ is increased below this block.
Nikita (slow)
2011/11/22 09:21:56
Reading it differently, I think that initial idea
|
+ return; |
+ } |
+ } |
+ |
+ verification_count_++; |
+ if (step_ == VERIFICATION_STEP_UNVERIFIED) { |
+ DVLOG(1) << "Retrying to verify OAuth1 access tokens."; |
+ StartOAuthVerification(); |
} else { |
- UserManager::Get()->set_offline_login(true); |
+ DVLOG(1) << "Retrying to fetch user cookies."; |
+ StartCookiesRetreival(); |
} |
} |
private: |
- GaiaOAuthFetcher oauth_fetcher_; |
- std::string oauth1_token_; |
- std::string oauth1_secret_; |
- std::string username_; |
+ typedef enum { |
+ VERIFICATION_STEP_UNVERIFIED, |
+ VERIFICATION_STEP_OAUTH_VERIFIED, |
+ VERIFICATION_STEP_COOKIES_FETCHED, |
+ VERIFICATION_STEP_FAILED, |
+ } VerificationStep; |
- DISALLOW_COPY_AND_ASSIGN(OAuthLoginVerifier); |
-}; |
+ // Kicks off GAIA session cookie retreival process. |
+ void StartCookiesRetreival() { |
+ DCHECK(!sid_.empty()); |
+ DCHECK(!lsid_.empty()); |
+ gaia_fetcher_.StartIssueAuthToken(sid_, lsid_, GaiaConstants::kGaiaService); |
+ } |
-// Verifies OAuth1 access token by performing OAuthLogin. |
-class UserSessionCookieFetcher : public GaiaAuthConsumer { |
- public: |
- explicit UserSessionCookieFetcher(Profile* user_profile) |
- : gaia_fetcher_(this, |
- std::string(GaiaConstants::kChromeOSSource), |
- user_profile->GetRequestContext()) { |
+ // Decides how to proceed on GAIA response and other errors. It can schedule |
+ // to rerun the verification process if detects transient network or service |
+ // errors. |
+ bool RetryOnError(const GoogleServiceAuthError& error) { |
+ // If we can't connect to GAIA due to network or service related reasons, |
+ // we should attempt OAuth token verification again. |
+ if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED || |
+ error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) { |
+ if (verification_count_ < kMaxOAuthTokenVerificationAttemptCount) { |
+ BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, |
+ base::Bind(&OAuthLoginVerifier::ContinueVerification, AsWeakPtr()), |
+ kOAuthVerificationRestartDelay); |
+ return true; |
+ } |
+ } |
+ step_ = VERIFICATION_STEP_FAILED; |
+ return false; |
} |
- virtual ~UserSessionCookieFetcher() {} |
- void Start(const GaiaAuthConsumer::ClientLoginResult& credentials) { |
- gaia_fetcher_.StartIssueAuthToken(credentials.sid, credentials.lsid, |
- GaiaConstants::kGaiaService); |
+ // GaiaOAuthConsumer implementation: |
+ virtual void OnOAuthLoginSuccess(const std::string& sid, |
+ const std::string& lsid, |
+ const std::string& auth) OVERRIDE { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ step_ = VERIFICATION_STEP_OAUTH_VERIFIED; |
+ verification_count_ = 0; |
+ sid_ = sid; |
+ lsid_ = lsid; |
+ delegate_->OnOAuthVerificationSucceeded(username_, sid, lsid, auth); |
+ StartCookiesRetreival(); |
} |
+ virtual void OnOAuthLoginFailure( |
+ const GoogleServiceAuthError& error) OVERRIDE { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ LOG(WARNING) << "Failed to verify OAuth1 access tokens," |
+ << " error.state=" << error.state(); |
+ if (!RetryOnError(error)) |
+ delegate_->OnOAuthVerificationFailed(username_); |
+ } |
+ |
+ void OnCookueFetchFailed(const GoogleServiceAuthError& error) { |
Nikita (slow)
2011/11/22 09:14:39
nit: fix spelling OnCookieFetchFailed
|
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!RetryOnError(error)) |
+ delegate_->OnUserCookiesFetchFailed(username_); |
+ } |
+ |
// GaiaAuthConsumer overrides. |
virtual void OnIssueAuthTokenSuccess(const std::string& service, |
const std::string& auth_token) OVERRIDE { |
@@ -280,34 +338,38 @@ |
virtual void OnIssueAuthTokenFailure(const std::string& service, |
const GoogleServiceAuthError& error) OVERRIDE { |
- LOG(WARNING) << "Failed IssueAuthToken request, error: " << error.state(); |
- HandlerGaiaAuthError(error); |
- delete this; |
+ DVLOG(1) << "Failed IssueAuthToken request," |
+ << " error.state=" << error.state(); |
+ OnCookueFetchFailed(error); |
} |
virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE { |
- VLOG(1) << "MergeSession successful."; |
- delete this; |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ DVLOG(1) << "MergeSession successful."; |
+ step_ = VERIFICATION_STEP_COOKIES_FETCHED; |
+ delegate_->OnUserCookiesFetchSucceeded(username_); |
} |
virtual void OnMergeSessionFailure( |
const GoogleServiceAuthError& error) OVERRIDE { |
- LOG(WARNING) << "Failed MergeSession request, error: " << error.state(); |
- HandlerGaiaAuthError(error); |
- delete this; |
+ DVLOG(1) << "Failed MergeSession request," |
+ << " error.state=" << error.state(); |
+ OnCookueFetchFailed(error); |
} |
- private: |
- void HandlerGaiaAuthError(const GoogleServiceAuthError& error) { |
- // Mark this account's login state as offline if we encountered a network |
- // error. That will make us verify user OAuth token and try to fetch session |
- // cookies again once we detect that the machine comes online. |
- if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) |
- UserManager::Get()->set_offline_login(true); |
- } |
+ OAuthLoginVerifier::Delegate* delegate_; |
+ GaiaOAuthFetcher oauth_fetcher_; |
+ GaiaAuthFetcher gaia_fetcher_; |
+ std::string oauth1_token_; |
+ std::string oauth1_secret_; |
+ std::string sid_; |
+ std::string lsid_; |
+ std::string username_; |
+ Profile* user_profile_; |
+ int verification_count_; |
+ VerificationStep step_; |
- GaiaAuthFetcher gaia_fetcher_; |
- DISALLOW_COPY_AND_ASSIGN(UserSessionCookieFetcher); |
+ DISALLOW_COPY_AND_ASSIGN(OAuthLoginVerifier); |
}; |
// Fetches the oauth token for the device management service. Since Profile |
@@ -466,6 +528,7 @@ |
class LoginUtilsImpl : public LoginUtils, |
public ProfileManagerObserver, |
public GaiaOAuthConsumer, |
+ public OAuthLoginVerifier::Delegate, |
public net::NetworkChangeNotifier::OnlineStateObserver { |
public: |
LoginUtilsImpl() |
@@ -491,7 +554,7 @@ |
bool using_oauth, |
bool has_cookies, |
LoginUtils::Delegate* delegate) OVERRIDE; |
- virtual void DelegateDeleted(Delegate* delegate) OVERRIDE; |
+ virtual void DelegateDeleted(LoginUtils::Delegate* delegate) OVERRIDE; |
virtual void CompleteOffTheRecordLogin(const GURL& start_url) OVERRIDE; |
virtual void SetFirstLoginPrefs(PrefService* prefs) OVERRIDE; |
virtual scoped_refptr<Authenticator> CreateAuthenticator( |
@@ -499,9 +562,6 @@ |
virtual void PrewarmAuthentication() OVERRIDE; |
virtual void RestoreAuthenticationSession(const std::string& user_name, |
Profile* profile) OVERRIDE; |
- virtual void FetchCookies( |
- Profile* profile, |
- const GaiaAuthConsumer::ClientLoginResult& credentials) OVERRIDE; |
virtual void StartTokenServices(Profile* user_profile) OVERRIDE; |
virtual void StartSync( |
Profile* profile, |
@@ -526,6 +586,13 @@ |
virtual void OnOAuthGetAccessTokenFailure( |
const GoogleServiceAuthError& error) OVERRIDE; |
+ // OAuthLoginVerifier::Delegate overrides. |
+ virtual void OnOAuthVerificationSucceeded(const std::string& user_name, |
+ const std::string& sid, |
+ const std::string& lsid, |
+ const std::string& auth) OVERRIDE; |
+ virtual void OnOAuthVerificationFailed(const std::string& user_name) OVERRIDE; |
+ |
// net::NetworkChangeNotifier::OnlineStateObserver overrides. |
virtual void OnOnlineStateChanged(bool online) OVERRIDE; |
@@ -697,7 +764,7 @@ |
ProfileManager::CreateDefaultProfileAsync(this); |
} |
-void LoginUtilsImpl::DelegateDeleted(Delegate* delegate) { |
+void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) { |
if (delegate_ == delegate) |
delegate_ = NULL; |
} |
@@ -718,21 +785,6 @@ |
return; |
} |
- // Initialize the user-policy backend. |
- if (!using_oauth_) { |
- g_browser_process->browser_policy_connector()-> |
- SetUserPolicyTokenService(user_profile->GetTokenService()); |
- } |
- |
- // We suck. This is a hack since we do not have the enterprise feature |
- // done yet to pull down policies from the domain admin. We'll take this |
- // out when we get that done properly. |
- // TODO(xiyuan): Remove this once enterprise feature is ready. |
- if (EndsWith(username_, "@google.com", true)) { |
- PrefService* pref_service = user_profile->GetPrefs(); |
- pref_service->SetBoolean(prefs::kEnableScreenLock, true); |
- } |
- |
BootTimesLoader* btl = BootTimesLoader::Get(); |
btl->AddLoginTimeMarker("UserProfileGotten", false); |
@@ -778,32 +830,8 @@ |
// TODO(rickcam) We should use an isolated App here. |
FetchOAuth1AccessToken(authenticator_->authentication_profile()); |
} |
- } else { |
- // Since we're doing parallel authentication, only new user sign in |
- // would perform online auth before calling PrepareProfile. |
- // For existing users there's usually a pending online auth request. |
- // Cookies will be fetched after it's is succeeded. |
- if (!pending_requests_) { |
- FetchCookies(user_profile, credentials_); |
- } |
} |
- if (!using_oauth_) { |
- // We don't need authenticator instance anymore in LoginUtils. |
- // Release it so that ScreenLocker would create a separate instance. |
- // Note that for GAIA WebUI login authenticator instance is reset in |
- // OnOAuthGetAccessTokenSuccess(...). |
- authenticator_ = NULL; |
- } |
- |
- // Supply credentials for sync and others to use. Load tokens from disk. |
- if (!using_oauth_) { |
- // For existing users there's usually a pending online auth request. |
- // Tokens will be fetched after it's is succeeded. |
- if (!pending_requests_) |
- StartSync(user_profile, credentials_); |
- } |
- |
// Own TPM device if, for any reason, it has not been done in EULA |
// wizard screen. |
if (system::runtime_environment::IsRunningOnChromeOS()) { |
@@ -846,23 +874,6 @@ |
oauth_fetcher_->StartGetOAuthTokenRequest(); |
} |
-void LoginUtilsImpl::FetchCookies(Profile* user_profile, |
- const GaiaAuthConsumer::ClientLoginResult& credentials) { |
- if (!using_oauth_) { |
- // Take the credentials passed in and try to exchange them for |
- // full-fledged Google authentication cookies. This is |
- // best-effort; it's possible that we'll fail due to network |
- // troubles or some such. |
- // CookieFetcher will delete itself once done. |
- CookieFetcher* cf = new CookieFetcher(user_profile); |
- cf->AttemptFetch(credentials.data); |
- } else { |
- UserSessionCookieFetcher* cf = |
- new UserSessionCookieFetcher(user_profile); |
- cf->Start(credentials); |
- } |
-} |
- |
void LoginUtilsImpl::StartTokenServices(Profile* user_profile) { |
std::string oauth1_token; |
std::string oauth1_secret; |
@@ -1245,11 +1256,12 @@ |
void LoginUtilsImpl::FetchCredentials(Profile* user_profile, |
const std::string& token, |
const std::string& secret) { |
- oauth_login_verifier_.reset(new OAuthLoginVerifier(user_profile, |
+ oauth_login_verifier_.reset(new OAuthLoginVerifier(this, |
+ user_profile, |
token, |
secret, |
username_)); |
- oauth_login_verifier_->Start(); |
+ oauth_login_verifier_->StartOAuthVerification(); |
} |
@@ -1276,12 +1288,28 @@ |
authenticator_ = NULL; |
} |
+void LoginUtilsImpl::OnOAuthVerificationFailed(const std::string& user_name) { |
+ UserManager::Get()->SaveUserOAuthStatus(user_name, |
+ User::OAUTH_TOKEN_STATUS_INVALID); |
+} |
+ |
+void LoginUtilsImpl::OnOAuthVerificationSucceeded( |
+ const std::string& user_name, const std::string& sid, |
+ const std::string& lsid, const std::string& auth) { |
+ // Kick off sync engine. |
+ GaiaAuthConsumer::ClientLoginResult credentials(sid, lsid, auth, |
+ std::string()); |
+ StartSync(ProfileManager::GetDefaultProfile(), credentials); |
+} |
+ |
+ |
void LoginUtilsImpl::OnOnlineStateChanged(bool online) { |
// If we come online for the first time after successful offline login, |
// we need to kick of OAuth token verification process again. |
- if (UserManager::Get()->user_is_logged_in() && |
- UserManager::Get()->offline_login() && online) { |
- KickStartAuthentication(ProfileManager::GetDefaultProfile()); |
+ if (online && UserManager::Get()->user_is_logged_in() && |
+ oauth_login_verifier_.get() && |
+ !oauth_login_verifier_->is_done()) { |
+ oauth_login_verifier_->ContinueVerification(); |
} |
} |