| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/chromeos/login/oauth_login_manager.h" |
| 6 |
| 7 #include "base/command_line.h" |
| 8 #include "base/metrics/histogram.h" |
| 9 #include "base/string_util.h" |
| 10 #include "chrome/browser/browser_process.h" |
| 11 #include "chrome/browser/chromeos/login/user_manager.h" |
| 12 #include "chrome/browser/policy/browser_policy_connector.h" |
| 13 #include "chrome/browser/prefs/pref_service.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/signin/token_service.h" |
| 16 #include "chrome/browser/signin/token_service_factory.h" |
| 17 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "chrome/common/chrome_switches.h" |
| 19 #include "chrome/common/pref_names.h" |
| 20 #include "content/public/browser/notification_service.h" |
| 21 #include "google_apis/gaia/gaia_auth_fetcher.h" |
| 22 #include "google_apis/gaia/gaia_constants.h" |
| 23 #include "net/url_request/url_request_context_getter.h" |
| 24 |
| 25 using content::BrowserThread; |
| 26 |
| 27 namespace chromeos { |
| 28 |
| 29 // OAuthLoginManager. |
| 30 |
| 31 // static. |
| 32 OAuthLoginManager* OAuthLoginManager::Create( |
| 33 OAuthLoginManager::Delegate* delegate) { |
| 34 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kForceOAuth2)) |
| 35 return new OAuth2LoginManager(delegate); |
| 36 |
| 37 return new OAuth1LoginManager(delegate); |
| 38 } |
| 39 |
| 40 void OAuthLoginManager::CompleteAuthentication() { |
| 41 delegate_->OnCompletedAuthentication(user_profile_); |
| 42 TokenService* token_service = |
| 43 TokenServiceFactory::GetForProfile(user_profile_); |
| 44 if (token_service->AreCredentialsValid()) |
| 45 token_service->StartFetchingTokens(); |
| 46 } |
| 47 |
| 48 OAuthLoginManager::OAuthLoginManager(Delegate* delegate) |
| 49 : delegate_(delegate), |
| 50 user_profile_(NULL), |
| 51 restore_from_auth_cookies_(false), |
| 52 state_(SESSION_RESTORE_NOT_STARTED) { |
| 53 } |
| 54 |
| 55 // OAuth2LoginManager. |
| 56 |
| 57 OAuth2LoginManager::OAuth2LoginManager(OAuthLoginManager::Delegate* delegate) |
| 58 : OAuthLoginManager(delegate), |
| 59 loading_reported_(false) { |
| 60 } |
| 61 |
| 62 void OAuth2LoginManager::RestoreSession( |
| 63 Profile* user_profile, |
| 64 net::URLRequestContextGetter* auth_request_context, |
| 65 bool restore_from_auth_cookies) { |
| 66 // TODO(zelidrag): Remove eventualy the next line in some future milestone. |
| 67 RemoveLegacyTokens(); |
| 68 |
| 69 user_profile_ = user_profile; |
| 70 auth_request_context_ = auth_request_context; |
| 71 state_ = OAuthLoginManager::SESSION_RESTORE_IN_PROGRESS; |
| 72 |
| 73 // Reuse the access token fetched by the OAuth2PolicyFetcher, if it was |
| 74 // used to fetch policies before Profile creation. |
| 75 if (oauth2_policy_fetcher_.get() && |
| 76 oauth2_policy_fetcher_->has_oauth2_tokens()) { |
| 77 VLOG(1) << "Resuming profile creation after fetching policy token"; |
| 78 refresh_token_ = oauth2_policy_fetcher_->oauth2_tokens().refresh_token; |
| 79 restore_from_auth_cookies = false; |
| 80 } |
| 81 restore_from_auth_cookies_ = restore_from_auth_cookies; |
| 82 ContinueSessionRestore(); |
| 83 } |
| 84 |
| 85 void OAuth2LoginManager::ContinueSessionRestore() { |
| 86 if (restore_from_auth_cookies_) { |
| 87 FetchOAuth2Tokens(); |
| 88 return; |
| 89 } |
| 90 |
| 91 // Did we already fetch the refresh token (either policy or db)? |
| 92 if (!refresh_token_.empty()) { |
| 93 // TODO(zelidrag): Figure out where to stick that refresh_token_ into. |
| 94 // We probalby need bit more than that. |
| 95 } |
| 96 LoadAndVerifyOAuth2Tokens(); |
| 97 } |
| 98 |
| 99 |
| 100 void OAuth2LoginManager::RestorePolicyTokens( |
| 101 net::URLRequestContextGetter* auth_request_context) { |
| 102 oauth2_policy_fetcher_.reset( |
| 103 new OAuth2PolicyFetcher(auth_request_context, |
| 104 g_browser_process->system_request_context())); |
| 105 oauth2_policy_fetcher_->Start(); |
| 106 } |
| 107 |
| 108 void OAuth2LoginManager::Stop() { |
| 109 oauth2_token_fetcher_.reset(); |
| 110 login_verifier_.reset(); |
| 111 } |
| 112 |
| 113 TokenService* OAuth2LoginManager::SetupTokenService() { |
| 114 DCHECK(registrar_.IsEmpty()); |
| 115 TokenService* token_service = |
| 116 TokenServiceFactory::GetForProfile(user_profile_); |
| 117 registrar_.Add(this, |
| 118 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED, |
| 119 content::Source<TokenService>(token_service)); |
| 120 registrar_.Add(this, |
| 121 chrome::NOTIFICATION_TOKEN_AVAILABLE, |
| 122 content::Source<TokenService>(token_service)); |
| 123 registrar_.Add(this, |
| 124 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED, |
| 125 content::Source<TokenService>(token_service)); |
| 126 return token_service; |
| 127 } |
| 128 |
| 129 void OAuth2LoginManager::RemoveLegacyTokens() { |
| 130 PrefServiceSyncable* prefs = user_profile_->GetPrefs(); |
| 131 prefs->RegisterStringPref(prefs::kOAuth1Token, |
| 132 "", |
| 133 PrefServiceSyncable::UNSYNCABLE_PREF); |
| 134 prefs->RegisterStringPref(prefs::kOAuth1Secret, |
| 135 "", |
| 136 PrefServiceSyncable::UNSYNCABLE_PREF); |
| 137 prefs->ClearPref(prefs::kOAuth1Token); |
| 138 prefs->ClearPref(prefs::kOAuth1Secret); |
| 139 prefs->UnregisterPreference(prefs::kOAuth1Token); |
| 140 prefs->UnregisterPreference(prefs::kOAuth1Secret); |
| 141 } |
| 142 |
| 143 void OAuth2LoginManager::LoadAndVerifyOAuth2Tokens() { |
| 144 // If we have no cookies, try to load saved OAuth2 token from TokenService. |
| 145 TokenService* token_service = SetupTokenService(); |
| 146 token_service->Initialize(GaiaConstants::kChromeSource, user_profile_); |
| 147 token_service->LoadTokensFromDB(); |
| 148 } |
| 149 |
| 150 void OAuth2LoginManager::FetchOAuth2Tokens() { |
| 151 DCHECK(auth_request_context_.get()); |
| 152 // If we have authenticated cookie jar, get OAuth1 token first, then fetch |
| 153 // SID/LSID cookies through OAuthLogin call. |
| 154 oauth2_token_fetcher_.reset( |
| 155 new OAuth2TokenFetcher(this, auth_request_context_)); |
| 156 oauth2_token_fetcher_->Start(); |
| 157 } |
| 158 |
| 159 void OAuth2LoginManager::OnOAuth2TokenAvailable( |
| 160 const GaiaAuthConsumer::ClientLoginResult& gaia_credentials, |
| 161 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) { |
| 162 TokenService* token_service = SetupTokenService(); |
| 163 token_service->UpdateCredentialsWithOAuth2(oauth2_tokens); |
| 164 token_service->UpdateCredentials(gaia_credentials); |
| 165 CompleteAuthentication(); |
| 166 } |
| 167 |
| 168 void OAuth2LoginManager::OnOAuth2TokenFetchFailed() { |
| 169 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 170 UserManager::Get()->SaveUserOAuthStatus( |
| 171 UserManager::Get()->GetLoggedInUser()->email(), |
| 172 User::OAUTH2_TOKEN_STATUS_INVALID); |
| 173 } |
| 174 |
| 175 void OAuth2LoginManager::Observe( |
| 176 int type, |
| 177 const content::NotificationSource& source, |
| 178 const content::NotificationDetails& details) OVERRIDE { |
| 179 TokenService* token_service = |
| 180 TokenServiceFactory::GetForProfile(user_profile_); |
| 181 switch (type) { |
| 182 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { |
| 183 refresh_token_ = token_service->GetOAuth2LoginRefreshToken(); |
| 184 ReportOAuth2TokensLoaded(); |
| 185 // Have we started restoring GAIA auth cookies yet? |
| 186 if (!refresh_token_.empty() && !login_verifier_.get()) |
| 187 RestoreSessionCookies(); |
| 188 |
| 189 break; |
| 190 } |
| 191 case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: { |
| 192 // TODO(zelidrag): Figure out how to recover from transient errors with |
| 193 // TokenService class - similar to what we do in RetryOnError() here. |
| 194 TokenService::TokenAvailableDetails* token_details = |
| 195 content::Details<TokenService::TokenAvailableDetails>( |
| 196 details).ptr(); |
| 197 if (token_details->service() == |
| 198 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { |
| 199 UserManager::Get()->SaveUserOAuthStatus( |
| 200 UserManager::Get()->GetLoggedInUser()->email(), |
| 201 User::OAUTH2_TOKEN_STATUS_INVALID); |
| 202 } |
| 203 break; |
| 204 } |
| 205 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
| 206 TokenService::TokenAvailableDetails* token_details = |
| 207 content::Details<TokenService::TokenAvailableDetails>( |
| 208 details).ptr(); |
| 209 if (token_details->service() == |
| 210 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { |
| 211 DCHECK(!login_verifier_.get()); |
| 212 refresh_token_ = token_details->token(); |
| 213 RestoreSessionCookies(); |
| 214 } |
| 215 |
| 216 break; |
| 217 } |
| 218 default: |
| 219 NOTREACHED(); |
| 220 break; |
| 221 } |
| 222 } |
| 223 |
| 224 void OAuth2LoginManager::RestoreSessionCookies() { |
| 225 VLOG(1) << "Fetched refresh token!"; |
| 226 DCHECK(!refresh_token_.empty()); |
| 227 if (!login_verifier_.get()) { |
| 228 login_verifier_.reset( |
| 229 new OAuth2LoginVerifier(this, |
| 230 g_browser_process->system_request_context(), |
| 231 user_profile_->GetRequestContext())); |
| 232 } |
| 233 login_verifier_->VerifyRefreshToken(refresh_token_); |
| 234 FetchPolicyTokens(); |
| 235 } |
| 236 |
| 237 void OAuth2LoginManager::FetchPolicyTokens() { |
| 238 DCHECK(!refresh_token_.empty()); |
| 239 if (!oauth2_policy_fetcher_.get() || oauth2_policy_fetcher_->failed()) { |
| 240 // Trigger OAuth2 token fetch for user policy. |
| 241 oauth2_policy_fetcher_.reset( |
| 242 new OAuth2PolicyFetcher(g_browser_process->system_request_context(), |
| 243 refresh_token_)); |
| 244 oauth2_policy_fetcher_->Start(); |
| 245 } |
| 246 } |
| 247 |
| 248 void OAuth2LoginManager::OnOAuth2LoginVerifierSuccess( |
| 249 const std::string& sid, |
| 250 const std::string& lsid, |
| 251 const std::string& auth) { |
| 252 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 253 UserManager::Get()->SaveUserOAuthStatus( |
| 254 UserManager::Get()->GetLoggedInUser()->email(), |
| 255 User::OAUTH2_TOKEN_STATUS_VALID); |
| 256 } |
| 257 |
| 258 void OAuth2LoginManager::OnOAuth2LoginVerifierFailure() { |
| 259 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 260 UserManager::Get()->SaveUserOAuthStatus( |
| 261 UserManager::Get()->GetLoggedInUser()->email(), |
| 262 User::OAUTH2_TOKEN_STATUS_INVALID); |
| 263 } |
| 264 |
| 265 void OAuth2LoginManager::ReportOAuth2TokensLoaded() { |
| 266 VLOG(1) << "Got OAuth2 refresh token!"; |
| 267 DCHECK(!loading_reported_); |
| 268 loading_reported_ = true; |
| 269 if (refresh_token_.empty()) { |
| 270 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 271 UserManager::Get()->SaveUserOAuthStatus( |
| 272 UserManager::Get()->GetLoggedInUser()->email(), |
| 273 User::OAUTH2_TOKEN_STATUS_INVALID); |
| 274 } |
| 275 } |
| 276 |
| 277 // OAuth1LoginManager. |
| 278 // TODO(zelidrag): Nuke this one once we switch everything to OAuth2. |
| 279 |
| 280 OAuth1LoginManager::OAuth1LoginManager( |
| 281 OAuthLoginManager::Delegate* delegate) |
| 282 : OAuthLoginManager(delegate) { |
| 283 } |
| 284 |
| 285 void OAuth1LoginManager::RestoreSession( |
| 286 Profile* user_profile, |
| 287 net::URLRequestContextGetter* auth_request_context, |
| 288 bool restore_from_auth_cookies) { |
| 289 user_profile_ = user_profile; |
| 290 auth_request_context_ = auth_request_context; |
| 291 state_ = OAuthLoginManager::SESSION_RESTORE_IN_PROGRESS; |
| 292 |
| 293 // Reuse the access token fetched by the PolicyOAuthFetcher, if it was |
| 294 // used to fetch policies before Profile creation. |
| 295 if (policy_oauth_fetcher_.get() && |
| 296 !policy_oauth_fetcher_->oauth1_token().empty()) { |
| 297 VLOG(1) << "Resuming profile creation after fetching policy token"; |
| 298 oauth1_token_ = policy_oauth_fetcher_->oauth1_token(); |
| 299 oauth1_secret_ = policy_oauth_fetcher_->oauth1_secret(); |
| 300 StoreOAuth1Tokens(); |
| 301 restore_from_auth_cookies = false; |
| 302 } |
| 303 restore_from_auth_cookies_ = restore_from_auth_cookies; |
| 304 ContinueSessionRestore(); |
| 305 } |
| 306 |
| 307 void OAuth1LoginManager::ContinueSessionRestore() { |
| 308 // Have we even started session restore? |
| 309 if (!user_profile_) |
| 310 return; |
| 311 |
| 312 if (restore_from_auth_cookies_) { |
| 313 DCHECK(auth_request_context_.get()); |
| 314 // If we don't have it, fetch OAuth1 access token. |
| 315 // Once we get that, we will kick off individual requests for OAuth2 |
| 316 // tokens for all our services. |
| 317 // Use off-the-record profile that was used for this step. It should |
| 318 // already contain all needed cookies that will let us skip GAIA's user |
| 319 // authentication UI. |
| 320 oauth1_token_fetcher_.reset( |
| 321 new OAuth1TokenFetcher(this, auth_request_context_)); |
| 322 oauth1_token_fetcher_->Start(); |
| 323 } else if (ReadOAuth1Tokens()) { |
| 324 // Verify OAuth access token when we find it in the profile and always if |
| 325 // if we don't have cookies. |
| 326 // TODO(xiyuan): Change back to use authenticator to verify token when |
| 327 // we support Gaia in lock screen. |
| 328 VerifyOAuth1AccessToken(); |
| 329 } else { |
| 330 UserManager::Get()->SaveUserOAuthStatus( |
| 331 UserManager::Get()->GetLoggedInUser()->email(), |
| 332 User::OAUTH1_TOKEN_STATUS_INVALID); |
| 333 } |
| 334 } |
| 335 |
| 336 void OAuth1LoginManager::RestorePolicyTokens( |
| 337 net::URLRequestContextGetter* auth_request_context) { |
| 338 DCHECK(!policy_oauth_fetcher_.get()); |
| 339 policy_oauth_fetcher_.reset( |
| 340 new PolicyOAuthFetcher(auth_request_context)); |
| 341 policy_oauth_fetcher_->Start(); |
| 342 } |
| 343 |
| 344 void OAuth1LoginManager::Stop() { |
| 345 oauth1_token_fetcher_.reset(); |
| 346 oauth1_login_verifier_.reset(); |
| 347 state_ = OAuthLoginManager::SESSION_RESTORE_NOT_STARTED; |
| 348 } |
| 349 |
| 350 void OAuth1LoginManager::VerifyOAuth1AccessToken() { |
| 351 // Kick off verification of OAuth1 access token (via OAuthLogin), this should |
| 352 // let us fetch credentials that will be used to initialize sync engine. |
| 353 FetchCredentialsWithOAuth1(); |
| 354 delegate_->OnFoundStoredTokens(); |
| 355 FetchPolicyTokens(); |
| 356 } |
| 357 |
| 358 void OAuth1LoginManager::FetchPolicyTokens() { |
| 359 if (!policy_oauth_fetcher_.get() || policy_oauth_fetcher_->failed()) { |
| 360 // Trigger oauth token fetch for user policy. |
| 361 policy_oauth_fetcher_.reset( |
| 362 new PolicyOAuthFetcher(g_browser_process->system_request_context(), |
| 363 oauth1_token_, |
| 364 oauth1_secret_)); |
| 365 policy_oauth_fetcher_->Start(); |
| 366 } |
| 367 } |
| 368 |
| 369 void OAuth1LoginManager::FetchCredentialsWithOAuth1() { |
| 370 oauth1_login_verifier_.reset( |
| 371 new OAuth1LoginVerifier(this, |
| 372 user_profile_->GetRequestContext(), |
| 373 oauth1_token_, |
| 374 oauth1_secret_, |
| 375 UserManager::Get()->GetLoggedInUser()->email())); |
| 376 oauth1_login_verifier_->StartOAuthVerification(); |
| 377 } |
| 378 |
| 379 void OAuth1LoginManager::OnOAuth1AccessTokenAvailable( |
| 380 const std::string& token, |
| 381 const std::string& secret) { |
| 382 oauth1_token_ = token; |
| 383 oauth1_secret_ = secret; |
| 384 StoreOAuth1Tokens(); |
| 385 // Verify OAuth1 token by doing OAuthLogin and fetching credentials. If we |
| 386 // have just transfered auth cookies out of authenticated cookie jar, there |
| 387 // is no need to try to mint them from OAuth token again. |
| 388 VerifyOAuth1AccessToken(); |
| 389 } |
| 390 |
| 391 void OAuth1LoginManager::OnOAuth1AccessTokenFetchFailed() { |
| 392 // TODO(kochi): Show failure notification UI here? |
| 393 LOG(ERROR) << "Failed to fetch OAuth1 access token."; |
| 394 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 395 g_browser_process->browser_policy_connector()->RegisterForUserPolicy( |
| 396 EmptyString()); |
| 397 } |
| 398 |
| 399 void OAuth1LoginManager::OnOAuth1VerificationSucceeded( |
| 400 const std::string& user_name, const std::string& sid, |
| 401 const std::string& lsid, const std::string& auth) { |
| 402 // Kick off sync engine. |
| 403 GaiaAuthConsumer::ClientLoginResult credentials(sid, lsid, auth, |
| 404 std::string()); |
| 405 TokenService* token_service = |
| 406 TokenServiceFactory::GetForProfile(user_profile_); |
| 407 token_service->UpdateCredentials(credentials); |
| 408 CompleteAuthentication(); |
| 409 } |
| 410 |
| 411 void OAuth1LoginManager::OnOAuth1VerificationFailed( |
| 412 const std::string& user_name) { |
| 413 state_ = OAuthLoginManager::SESSION_RESTORE_DONE; |
| 414 UserManager::Get()->SaveUserOAuthStatus(user_name, |
| 415 User::OAUTH1_TOKEN_STATUS_INVALID); |
| 416 } |
| 417 |
| 418 bool OAuth1LoginManager::ReadOAuth1Tokens() { |
| 419 // Skip reading oauth token if user does not have a valid status. |
| 420 if (UserManager::Get()->IsUserLoggedIn() && |
| 421 UserManager::Get()->GetLoggedInUser()->oauth_token_status() != |
| 422 User::OAUTH1_TOKEN_STATUS_VALID) { |
| 423 return false; |
| 424 } |
| 425 |
| 426 PrefService* pref_service = user_profile_->GetPrefs(); |
| 427 std::string encoded_token = pref_service->GetString(prefs::kOAuth1Token); |
| 428 std::string encoded_secret = pref_service->GetString(prefs::kOAuth1Secret); |
| 429 if (!encoded_token.length() || !encoded_secret.length()) |
| 430 return false; |
| 431 |
| 432 std::string decoded_token = |
| 433 CrosLibrary::Get()->GetCertLibrary()->DecryptToken(encoded_token); |
| 434 std::string decoded_secret = |
| 435 CrosLibrary::Get()->GetCertLibrary()->DecryptToken(encoded_secret); |
| 436 |
| 437 if (!decoded_token.length() || !decoded_secret.length()) |
| 438 return false; |
| 439 |
| 440 oauth1_token_ = decoded_token; |
| 441 oauth1_secret_ = decoded_secret; |
| 442 return true; |
| 443 } |
| 444 |
| 445 void OAuth1LoginManager::StoreOAuth1Tokens() { |
| 446 DCHECK(!oauth1_token_.empty()); |
| 447 DCHECK(!oauth1_secret_.empty()); |
| 448 // First store OAuth1 token + service for the current user profile... |
| 449 std::string encrypted_token = |
| 450 CrosLibrary::Get()->GetCertLibrary()->EncryptToken(oauth1_token_); |
| 451 std::string encrypted_secret = |
| 452 CrosLibrary::Get()->GetCertLibrary()->EncryptToken(oauth1_secret_); |
| 453 |
| 454 PrefService* pref_service = user_profile_->GetPrefs(); |
| 455 User* user = UserManager::Get()->GetLoggedInUser(); |
| 456 if (!encrypted_token.empty() && !encrypted_secret.empty()) { |
| 457 pref_service->SetString(prefs::kOAuth1Token, encrypted_token); |
| 458 pref_service->SetString(prefs::kOAuth1Secret, encrypted_secret); |
| 459 |
| 460 // ...then record the presence of valid OAuth token for this account in |
| 461 // local state as well. |
| 462 UserManager::Get()->SaveUserOAuthStatus( |
| 463 user->email(), User::OAUTH1_TOKEN_STATUS_VALID); |
| 464 } else { |
| 465 LOG(WARNING) << "Failed to get OAuth1 token/secret encrypted."; |
| 466 // Set the OAuth status invalid so that the user will go through full |
| 467 // GAIA login next time. |
| 468 UserManager::Get()->SaveUserOAuthStatus( |
| 469 user->email(), User::OAUTH1_TOKEN_STATUS_INVALID); |
| 470 } |
| 471 } |
| 472 |
| 473 } // namespace chromeos |
| OLD | NEW |