Home | History | Annotate | Download | only in signin
      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