1 // Copyright (c) 2012 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/signin/signin_manager.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/command_line.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "base/time/time.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/profiles/profile_io_data.h" 19 #include "chrome/browser/signin/about_signin_internals.h" 20 #include "chrome/browser/signin/about_signin_internals_factory.h" 21 #include "chrome/browser/signin/signin_global_error.h" 22 #include "chrome/browser/signin/signin_internals_util.h" 23 #include "chrome/browser/signin/signin_manager_cookie_helper.h" 24 #include "chrome/browser/signin/signin_manager_delegate.h" 25 #include "chrome/browser/signin/signin_manager_factory.h" 26 #include "chrome/browser/signin/token_service.h" 27 #include "chrome/browser/signin/token_service_factory.h" 28 #include "chrome/browser/ui/global_error/global_error_service.h" 29 #include "chrome/browser/ui/global_error/global_error_service_factory.h" 30 #include "chrome/common/chrome_switches.h" 31 #include "chrome/common/pref_names.h" 32 #include "content/public/browser/browser_thread.h" 33 #include "content/public/browser/notification_service.h" 34 #include "content/public/browser/render_process_host.h" 35 #include "google_apis/gaia/gaia_auth_fetcher.h" 36 #include "google_apis/gaia/gaia_auth_util.h" 37 #include "google_apis/gaia/gaia_constants.h" 38 #include "google_apis/gaia/gaia_urls.h" 39 #include "net/base/escape.h" 40 #include "net/url_request/url_request_context.h" 41 #include "third_party/icu/source/i18n/unicode/regex.h" 42 43 using namespace signin_internals_util; 44 45 using content::BrowserThread; 46 47 namespace { 48 49 const char kGetInfoDisplayEmailKey[] = "displayEmail"; 50 const char kGetInfoEmailKey[] = "email"; 51 52 const int kInvalidProcessId = -1; 53 54 const char kChromiumSyncService[] = "service=chromiumsync"; 55 56 } // namespace 57 58 // Under the covers, we use a dummy chrome-extension ID to serve the purposes 59 // outlined in the .h file comment for this string. 60 const char* SigninManager::kChromeSigninEffectiveSite = 61 "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih"; 62 63 // static 64 bool SigninManager::IsWebBasedSigninFlowURL(const GURL& url) { 65 GURL effective(kChromeSigninEffectiveSite); 66 if (url.SchemeIs(effective.scheme().c_str()) && 67 url.host() == effective.host()) { 68 return true; 69 } 70 71 GURL service_login(GaiaUrls::GetInstance()->service_login_url()); 72 if (url.GetOrigin() != service_login.GetOrigin()) 73 return false; 74 75 // Any login UI URLs with signin=chromiumsync should be considered a web 76 // URL (relies on GAIA keeping the "service=chromiumsync" query string 77 // fragment present even when embedding inside a "continue" parameter). 78 return net::UnescapeURLComponent( 79 url.query(), net::UnescapeRule::URL_SPECIAL_CHARS) 80 .find(kChromiumSyncService) != std::string::npos; 81 } 82 83 SigninManager::SigninManager(scoped_ptr<SigninManagerDelegate> delegate) 84 : prohibit_signout_(false), 85 had_two_factor_error_(false), 86 type_(SIGNIN_TYPE_NONE), 87 weak_pointer_factory_(this), 88 signin_process_id_(kInvalidProcessId), 89 delegate_(delegate.Pass()) { 90 } 91 92 void SigninManager::SetSigninProcess(int process_id) { 93 if (process_id == signin_process_id_) 94 return; 95 DLOG_IF(WARNING, signin_process_id_ != kInvalidProcessId) << 96 "Replacing in-use signin process."; 97 signin_process_id_ = process_id; 98 const content::RenderProcessHost* process = 99 content::RenderProcessHost::FromID(process_id); 100 DCHECK(process); 101 registrar_.Add(this, 102 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 103 content::Source<content::RenderProcessHost>(process)); 104 } 105 106 void SigninManager::ClearSigninProcess() { 107 signin_process_id_ = kInvalidProcessId; 108 } 109 110 bool SigninManager::IsSigninProcess(int process_id) const { 111 return process_id == signin_process_id_; 112 } 113 114 bool SigninManager::HasSigninProcess() const { 115 return signin_process_id_ != kInvalidProcessId; 116 } 117 118 SigninManager::~SigninManager() { 119 } 120 121 void SigninManager::InitTokenService() { 122 SigninManagerBase::InitTokenService(); 123 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 124 if (token_service && !GetAuthenticatedUsername().empty()) 125 token_service->LoadTokensFromDB(); 126 } 127 128 std::string SigninManager::SigninTypeToString( 129 SigninManager::SigninType type) { 130 switch (type) { 131 case SIGNIN_TYPE_NONE: 132 return "No Signin"; 133 case SIGNIN_TYPE_CLIENT_LOGIN: 134 return "Client Login"; 135 case SIGNIN_TYPE_WITH_CREDENTIALS: 136 return "Signin with credentials"; 137 } 138 139 NOTREACHED(); 140 return std::string(); 141 } 142 143 bool SigninManager::PrepareForSignin(SigninType type, 144 const std::string& username, 145 const std::string& password) { 146 DCHECK(possibly_invalid_username_.empty() || 147 possibly_invalid_username_ == username); 148 DCHECK(!username.empty()); 149 150 if (!IsAllowedUsername(username)) { 151 // Account is not allowed by admin policy. 152 HandleAuthError(GoogleServiceAuthError( 153 GoogleServiceAuthError::ACCOUNT_DISABLED), true); 154 return false; 155 } 156 157 // This attempt is either 1) the user trying to establish initial sync, or 158 // 2) trying to refresh credentials for an existing username. If it is 2, we 159 // need to try again, but take care to leave state around tracking that the 160 // user has successfully signed in once before with this username, so that on 161 // restart we don't think sync setup has never completed. 162 RevokeOAuthLoginToken(); 163 ClearTransientSigninData(); 164 type_ = type; 165 possibly_invalid_username_.assign(username); 166 password_.assign(password); 167 168 client_login_.reset(new GaiaAuthFetcher(this, 169 GaiaConstants::kChromeSource, 170 profile_->GetRequestContext())); 171 172 NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); 173 return true; 174 } 175 176 // Users must always sign out before they sign in again. 177 void SigninManager::StartSignIn(const std::string& username, 178 const std::string& password, 179 const std::string& login_token, 180 const std::string& login_captcha) { 181 DCHECK(GetAuthenticatedUsername().empty() || 182 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); 183 184 if (!PrepareForSignin(SIGNIN_TYPE_CLIENT_LOGIN, username, password)) 185 return; 186 187 client_login_->StartClientLogin(username, 188 password, 189 "", 190 login_token, 191 login_captcha, 192 GaiaAuthFetcher::HostedAccountsNotAllowed); 193 } 194 195 void SigninManager::ProvideSecondFactorAccessCode( 196 const std::string& access_code) { 197 DCHECK(!possibly_invalid_username_.empty() && !password_.empty() && 198 last_result_.data.empty()); 199 DCHECK(type_ == SIGNIN_TYPE_CLIENT_LOGIN); 200 201 client_login_.reset(new GaiaAuthFetcher(this, 202 GaiaConstants::kChromeSource, 203 profile_->GetRequestContext())); 204 client_login_->StartClientLogin(possibly_invalid_username_, 205 access_code, 206 "", 207 std::string(), 208 std::string(), 209 GaiaAuthFetcher::HostedAccountsNotAllowed); 210 } 211 212 void SigninManager::StartSignInWithCredentials( 213 const std::string& session_index, 214 const std::string& username, 215 const std::string& password, 216 const OAuthTokenFetchedCallback& callback) { 217 DCHECK(GetAuthenticatedUsername().empty() || 218 gaia::AreEmailsSame(username, GetAuthenticatedUsername())); 219 220 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) 221 return; 222 223 // Store our callback. 224 DCHECK(oauth_token_fetched_callback_.is_null()); 225 oauth_token_fetched_callback_ = callback; 226 227 if (password.empty()) { 228 // Chrome must verify the GAIA cookies first if auto sign-in is triggered 229 // with no password provided. This is to protect Chrome against forged 230 // GAIA cookies from a super-domain. 231 VerifyGaiaCookiesBeforeSignIn(session_index); 232 } else { 233 // This function starts with the current state of the web session's cookie 234 // jar and mints a new ClientLogin-style SID/LSID pair. This involves going 235 // through the follow process or requests to GAIA and LSO: 236 // 237 // - call /o/oauth2/programmatic_auth with the returned token to get oauth2 238 // access and refresh tokens 239 // - call /accounts/OAuthLogin with the oauth2 access token and get SID/LSID 240 // pair for use by the token service 241 // 242 // The resulting SID/LSID can then be used just as if 243 // client_login_->StartClientLogin() had completed successfully. 244 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); 245 } 246 } 247 248 void SigninManager::VerifyGaiaCookiesBeforeSignIn( 249 const std::string& session_index) { 250 scoped_refptr<SigninManagerCookieHelper> cookie_helper( 251 new SigninManagerCookieHelper(profile_->GetRequestContext())); 252 cookie_helper->StartFetchingGaiaCookiesOnUIThread( 253 base::Bind(&SigninManager::OnGaiaCookiesFetched, 254 weak_pointer_factory_.GetWeakPtr(), session_index)); 255 } 256 257 void SigninManager::OnGaiaCookiesFetched( 258 const std::string session_index, const net::CookieList& cookie_list) { 259 net::CookieList::const_iterator it; 260 bool success = false; 261 for (it = cookie_list.begin(); it != cookie_list.end(); ++it) { 262 // Make sure the LSID cookie is set on the GAIA host, instead of a super- 263 // domain. 264 if (it->Name() == "LSID") { 265 if (it->IsHostCookie() && it->IsHttpOnly() && it->IsSecure()) { 266 // Found a valid LSID cookie. Continue loop to make sure we don't have 267 // invalid LSID cookies on any super-domain. 268 success = true; 269 } else { 270 success = false; 271 break; 272 } 273 } 274 } 275 276 if (success) { 277 client_login_->StartCookieForOAuthLoginTokenExchange(session_index); 278 } else { 279 HandleAuthError(GoogleServiceAuthError( 280 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); 281 } 282 } 283 284 void SigninManager::CopyCredentialsFrom(const SigninManager& source) { 285 DCHECK_NE(this, &source); 286 possibly_invalid_username_ = source.possibly_invalid_username_; 287 last_result_ = source.last_result_; 288 temp_oauth_login_tokens_ = source.temp_oauth_login_tokens_; 289 } 290 291 void SigninManager::ClearTransientSigninData() { 292 DCHECK(IsInitialized()); 293 294 client_login_.reset(); 295 last_result_ = ClientLoginResult(); 296 possibly_invalid_username_.clear(); 297 password_.clear(); 298 had_two_factor_error_ = false; 299 type_ = SIGNIN_TYPE_NONE; 300 temp_oauth_login_tokens_ = ClientOAuthResult(); 301 oauth_token_fetched_callback_.Reset(); 302 } 303 304 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, 305 bool clear_transient_data) { 306 // In some cases, the user should not be signed out. For example, the failure 307 // may be due to a captcha or OTP challenge. In these cases, the transient 308 // data must be kept to properly handle the follow up. This routine clears 309 // the data before sending out the notification so the SigninManager is no 310 // longer in the AuthInProgress state when the notification goes out. 311 if (clear_transient_data) 312 ClearTransientSigninData(); 313 314 content::NotificationService::current()->Notify( 315 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, 316 content::Source<Profile>(profile_), 317 content::Details<const GoogleServiceAuthError>(&error)); 318 } 319 320 void SigninManager::SignOut() { 321 DCHECK(IsInitialized()); 322 323 if (GetAuthenticatedUsername().empty()) { 324 if (AuthInProgress()) { 325 // If the user is in the process of signing in, then treat a call to 326 // SignOut as a cancellation request. 327 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); 328 HandleAuthError(error, true); 329 } else { 330 // Clean up our transient data and exit if we aren't signed in. 331 // This avoids a perf regression from clearing out the TokenDB if 332 // SignOut() is invoked on startup to clean up any incomplete previous 333 // signin attempts. 334 ClearTransientSigninData(); 335 } 336 return; 337 } 338 339 if (prohibit_signout_) { 340 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; 341 return; 342 } 343 344 ClearTransientSigninData(); 345 RevokeOAuthLoginToken(); 346 347 GoogleServiceSignoutDetails details(GetAuthenticatedUsername()); 348 clear_authenticated_username(); 349 profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); 350 351 // Erase (now) stale information from AboutSigninInternals. 352 NotifyDiagnosticsObservers(USERNAME, ""); 353 NotifyDiagnosticsObservers(LSID, ""); 354 NotifyDiagnosticsObservers( 355 signin_internals_util::SID, ""); 356 357 content::NotificationService::current()->Notify( 358 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, 359 content::Source<Profile>(profile_), 360 content::Details<const GoogleServiceSignoutDetails>(&details)); 361 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 362 token_service->ResetCredentialsInMemory(); 363 token_service->EraseTokensFromDB(); 364 } 365 366 void SigninManager::Initialize(Profile* profile, PrefService* local_state) { 367 SigninManagerBase::Initialize(profile, local_state); 368 369 // local_state can be null during unit tests. 370 if (local_state) { 371 local_state_pref_registrar_.Init(local_state); 372 local_state_pref_registrar_.Add( 373 prefs::kGoogleServicesUsernamePattern, 374 base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged, 375 weak_pointer_factory_.GetWeakPtr())); 376 } 377 signin_allowed_.Init(prefs::kSigninAllowed, profile_->GetPrefs(), 378 base::Bind(&SigninManager::OnSigninAllowedPrefChanged, 379 base::Unretained(this))); 380 381 std::string user = profile_->GetPrefs()->GetString( 382 prefs::kGoogleServicesUsername); 383 if ((!user.empty() && !IsAllowedUsername(user)) || !IsSigninAllowed()) { 384 // User is signed in, but the username is invalid - the administrator must 385 // have changed the policy since the last signin, so sign out the user. 386 SignOut(); 387 } 388 } 389 390 void SigninManager::Shutdown() { 391 local_state_pref_registrar_.RemoveAll(); 392 SigninManagerBase::Shutdown(); 393 } 394 395 void SigninManager::OnGoogleServicesUsernamePatternChanged() { 396 if (!GetAuthenticatedUsername().empty() && 397 !IsAllowedUsername(GetAuthenticatedUsername())) { 398 // Signed in user is invalid according to the current policy so sign 399 // the user out. 400 SignOut(); 401 } 402 } 403 404 bool SigninManager::IsSigninAllowed() const { 405 return signin_allowed_.GetValue(); 406 } 407 408 // static 409 bool SigninManager::IsSigninAllowedOnIOThread(ProfileIOData* io_data) { 410 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 411 return io_data->signin_allowed()->GetValue(); 412 } 413 414 void SigninManager::OnSigninAllowedPrefChanged() { 415 if (!IsSigninAllowed()) 416 SignOut(); 417 } 418 419 // static 420 bool SigninManager::IsUsernameAllowedByPolicy(const std::string& username, 421 const std::string& policy) { 422 if (policy.empty()) 423 return true; 424 425 // Patterns like "*@foo.com" are not accepted by our regex engine (since they 426 // are not valid regular expressions - they should instead be ".*@foo.com"). 427 // For convenience, detect these patterns and insert a "." character at the 428 // front. 429 string16 pattern = UTF8ToUTF16(policy); 430 if (pattern[0] == L'*') 431 pattern.insert(pattern.begin(), L'.'); 432 433 // See if the username matches the policy-provided pattern. 434 UErrorCode status = U_ZERO_ERROR; 435 const icu::UnicodeString icu_pattern(pattern.data(), pattern.length()); 436 icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status); 437 if (!U_SUCCESS(status)) { 438 LOG(ERROR) << "Invalid login regex: " << pattern << ", status: " << status; 439 // If an invalid pattern is provided, then prohibit *all* logins (better to 440 // break signin than to quietly allow users to sign in). 441 return false; 442 } 443 string16 username16 = UTF8ToUTF16(username); 444 icu::UnicodeString icu_input(username16.data(), username16.length()); 445 matcher.reset(icu_input); 446 status = U_ZERO_ERROR; 447 UBool match = matcher.matches(status); 448 DCHECK(U_SUCCESS(status)); 449 return !!match; // !! == convert from UBool to bool. 450 } 451 452 bool SigninManager::IsAllowedUsername(const std::string& username) const { 453 const PrefService* local_state = local_state_pref_registrar_.prefs(); 454 if (!local_state) 455 return true; // In a unit test with no local state - all names are allowed. 456 457 std::string pattern = local_state->GetString( 458 prefs::kGoogleServicesUsernamePattern); 459 return IsUsernameAllowedByPolicy(username, pattern); 460 } 461 462 void SigninManager::RevokeOAuthLoginToken() { 463 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 464 if (token_service->HasOAuthLoginToken()) { 465 revoke_token_fetcher_.reset( 466 new GaiaAuthFetcher(this, 467 GaiaConstants::kChromeSource, 468 profile_->GetRequestContext())); 469 revoke_token_fetcher_->StartRevokeOAuth2Token( 470 token_service->GetOAuth2LoginRefreshToken()); 471 } 472 } 473 474 void SigninManager::OnOAuth2RevokeTokenCompleted() { 475 revoke_token_fetcher_.reset(NULL); 476 } 477 478 bool SigninManager::AuthInProgress() const { 479 return !possibly_invalid_username_.empty(); 480 } 481 482 const std::string& SigninManager::GetUsernameForAuthInProgress() const { 483 return possibly_invalid_username_; 484 } 485 486 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { 487 DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); 488 LOG(ERROR) << "Account is not associated with a valid email address. " 489 << "Login failed."; 490 OnClientLoginFailure(GoogleServiceAuthError( 491 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 492 } 493 494 void SigninManager::DisableOneClickSignIn(Profile* profile) { 495 PrefService* pref_service = profile->GetPrefs(); 496 pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false); 497 } 498 499 void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { 500 last_result_ = result; 501 // Update signin_internals_ 502 NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, "Successful"); 503 NotifyDiagnosticsObservers(LSID, result.lsid); 504 NotifyDiagnosticsObservers( 505 signin_internals_util::SID, result.sid); 506 // Make a request for the canonical email address and services. 507 client_login_->StartGetUserInfo(result.lsid); 508 } 509 510 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { 511 // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR 512 // error. This function does not call HandleAuthError() because dealing 513 // with TWO_FACTOR errors needs special handling: we don't want to clear the 514 // transient signin data in such error cases. 515 bool invalid_gaia = error.state() == 516 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; 517 518 GoogleServiceAuthError current_error = 519 (invalid_gaia && had_two_factor_error_) ? 520 GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR) : error; 521 522 if (current_error.state() == GoogleServiceAuthError::TWO_FACTOR) 523 had_two_factor_error_ = true; 524 525 NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, error.ToString()); 526 HandleAuthError(current_error, !had_two_factor_error_); 527 } 528 529 void SigninManager::OnClientOAuthSuccess(const ClientOAuthResult& result) { 530 DVLOG(1) << "SigninManager::OnClientOAuthSuccess access_token=" 531 << result.access_token; 532 533 NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, "Successful"); 534 535 switch (type_) { 536 case SIGNIN_TYPE_WITH_CREDENTIALS: 537 temp_oauth_login_tokens_ = result; 538 client_login_->StartOAuthLogin(result.access_token, 539 GaiaConstants::kGaiaService); 540 break; 541 default: 542 NOTREACHED(); 543 break; 544 } 545 } 546 547 void SigninManager::OnClientOAuthFailure(const GoogleServiceAuthError& error) { 548 bool clear_transient_data = true; 549 NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, error.ToString()); 550 LOG(WARNING) << "SigninManager::OnClientOAuthFailure"; 551 HandleAuthError(error, clear_transient_data); 552 } 553 554 void SigninManager::OnGetUserInfoSuccess(const UserInfoMap& data) { 555 NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, "Successful"); 556 557 UserInfoMap::const_iterator email_iter = data.find(kGetInfoEmailKey); 558 UserInfoMap::const_iterator display_email_iter = 559 data.find(kGetInfoDisplayEmailKey); 560 if (email_iter == data.end()) { 561 OnGetUserInfoKeyNotFound(kGetInfoEmailKey); 562 return; 563 } 564 if (display_email_iter == data.end()) { 565 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); 566 return; 567 } 568 DCHECK(email_iter->first == kGetInfoEmailKey); 569 DCHECK(display_email_iter->first == kGetInfoDisplayEmailKey); 570 571 // When signing in with credentials, the possibly invalid name is the Gaia 572 // display name. If the name returned by GetUserInfo does not match what is 573 // expected, return an error. 574 if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && 575 !gaia::AreEmailsSame(display_email_iter->second, 576 possibly_invalid_username_)) { 577 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); 578 return; 579 } 580 581 possibly_invalid_username_ = email_iter->second; 582 583 if (!oauth_token_fetched_callback_.is_null() && 584 !temp_oauth_login_tokens_.refresh_token.empty()) { 585 oauth_token_fetched_callback_.Run(temp_oauth_login_tokens_.refresh_token); 586 } else { 587 // No oauth token or callback, so just complete our pending signin. 588 CompletePendingSignin(); 589 } 590 } 591 592 void SigninManager::CompletePendingSignin() { 593 DCHECK(!possibly_invalid_username_.empty()); 594 OnSignedIn(possibly_invalid_username_); 595 596 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 597 token_service->UpdateCredentials(last_result_); 598 DCHECK(token_service->AreCredentialsValid()); 599 token_service->StartFetchingTokens(); 600 601 // If we have oauth2 tokens, tell token service about them so it does not 602 // need to fetch them again. 603 if (!temp_oauth_login_tokens_.refresh_token.empty()) { 604 token_service->UpdateCredentialsWithOAuth2(temp_oauth_login_tokens_); 605 temp_oauth_login_tokens_ = ClientOAuthResult(); 606 } 607 } 608 609 void SigninManager::OnExternalSigninCompleted(const std::string& username) { 610 OnSignedIn(username); 611 } 612 613 void SigninManager::OnSignedIn(const std::string& username) { 614 SetAuthenticatedUsername(username); 615 possibly_invalid_username_.clear(); 616 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 617 GetAuthenticatedUsername()); 618 619 GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(), 620 password_); 621 content::NotificationService::current()->Notify( 622 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 623 content::Source<Profile>(profile_), 624 content::Details<const GoogleServiceSigninSuccessDetails>(&details)); 625 626 password_.clear(); // Don't need it anymore. 627 DisableOneClickSignIn(profile_); // Don't ever offer again. 628 } 629 630 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { 631 LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; 632 NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, error.ToString()); 633 // REVIEW: why does this call OnClientLoginFailure? 634 OnClientLoginFailure(error); 635 } 636 637 void SigninManager::Observe(int type, 638 const content::NotificationSource& source, 639 const content::NotificationDetails& details) { 640 DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type); 641 642 // It's possible we're listening to a "stale" renderer because it was 643 // replaced with a new process by process-per-site. In either case, 644 // stop listening to it, but only reset signin_process_id_ tracking 645 // if this was from the current signin process. 646 registrar_.Remove(this, 647 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 648 source); 649 if (signin_process_id_ == 650 content::Source<content::RenderProcessHost>(source)->GetID()) { 651 signin_process_id_ = kInvalidProcessId; 652 } 653 } 654 655 void SigninManager::ProhibitSignout(bool prohibit_signout) { 656 prohibit_signout_ = prohibit_signout; 657 } 658 659 bool SigninManager::IsSignoutProhibited() const { 660 return prohibit_signout_; 661 } 662