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.
5 #include "chrome/browser/signin/signin_manager.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/profiles/profile_io_data.h"
18 #include "chrome/browser/signin/about_signin_internals.h"
19 #include "chrome/browser/signin/about_signin_internals_factory.h"
20 #include "chrome/browser/signin/local_auth.h"
21 #include "chrome/browser/signin/profile_oauth2_token_service.h"
22 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
23 #include "chrome/browser/signin/signin_account_id_helper.h"
24 #include "chrome/browser/signin/signin_global_error.h"
25 #include "chrome/browser/signin/signin_internals_util.h"
26 #include "chrome/browser/signin/signin_manager_cookie_helper.h"
27 #include "chrome/browser/signin/signin_manager_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/pref_names.h"
31 #include "chrome/common/profile_management_switches.h"
32 #include "components/signin/core/signin_manager_delegate.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/common/child_process_host.h"
37 #include "google_apis/gaia/gaia_auth_fetcher.h"
38 #include "google_apis/gaia/gaia_auth_util.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "google_apis/gaia/gaia_urls.h"
41 #include "net/base/escape.h"
42 #include "net/url_request/url_request_context.h"
43 #include "third_party/icu/source/i18n/unicode/regex.h"
45 using namespace signin_internals_util
;
47 using content::BrowserThread
;
48 using content::ChildProcessHost
;
49 using content::RenderProcessHost
;
53 const char kGetInfoDisplayEmailKey
[] = "displayEmail";
54 const char kGetInfoEmailKey
[] = "email";
56 const char kChromiumSyncService
[] = "service=chromiumsync";
60 // Under the covers, we use a dummy chrome-extension ID to serve the purposes
61 // outlined in the .h file comment for this string.
62 const char* SigninManager::kChromeSigninEffectiveSite
=
63 "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih";
66 bool SigninManager::IsWebBasedSigninFlowURL(const GURL
& url
) {
67 GURL
effective(kChromeSigninEffectiveSite
);
68 if (url
.SchemeIs(effective
.scheme().c_str()) &&
69 url
.host() == effective
.host()) {
73 GURL
service_login(GaiaUrls::GetInstance()->service_login_url());
74 if (url
.GetOrigin() != service_login
.GetOrigin())
77 // Any login UI URLs with signin=chromiumsync should be considered a web
78 // URL (relies on GAIA keeping the "service=chromiumsync" query string
79 // fragment present even when embedding inside a "continue" parameter).
80 return net::UnescapeURLComponent(
81 url
.query(), net::UnescapeRule::URL_SPECIAL_CHARS
)
82 .find(kChromiumSyncService
) != std::string::npos
;
85 SigninManager::SigninManager(scoped_ptr
<SigninManagerDelegate
> delegate
)
86 : prohibit_signout_(false),
87 had_two_factor_error_(false),
88 type_(SIGNIN_TYPE_NONE
),
89 weak_pointer_factory_(this),
90 signin_host_id_(ChildProcessHost::kInvalidUniqueID
),
91 delegate_(delegate
.Pass()) {
94 void SigninManager::SetSigninProcess(int process_id
) {
95 if (process_id
== signin_host_id_
)
98 signin_host_id_
!= ChildProcessHost::kInvalidUniqueID
)
99 << "Replacing in-use signin process.";
100 signin_host_id_
= process_id
;
101 RenderProcessHost
* host
= RenderProcessHost::FromID(process_id
);
103 host
->AddObserver(this);
104 signin_hosts_observed_
.insert(host
);
107 void SigninManager::ClearSigninProcess() {
108 signin_host_id_
= ChildProcessHost::kInvalidUniqueID
;
111 bool SigninManager::IsSigninProcess(int process_id
) const {
112 return process_id
== signin_host_id_
;
115 bool SigninManager::HasSigninProcess() const {
116 return signin_host_id_
!= ChildProcessHost::kInvalidUniqueID
;
119 void SigninManager::AddMergeSessionObserver(
120 GoogleAutoLoginHelper::Observer
* observer
) {
121 if (merge_session_helper_
)
122 merge_session_helper_
->AddObserver(observer
);
125 void SigninManager::RemoveMergeSessionObserver(
126 GoogleAutoLoginHelper::Observer
* observer
) {
127 if (merge_session_helper_
)
128 merge_session_helper_
->RemoveObserver(observer
);
131 SigninManager::~SigninManager() {
132 std::set
<RenderProcessHost
*>::iterator i
;
133 for (i
= signin_hosts_observed_
.begin();
134 i
!= signin_hosts_observed_
.end();
136 (*i
)->RemoveObserver(this);
140 void SigninManager::InitTokenService() {
141 ProfileOAuth2TokenService
* token_service
=
142 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
);
143 if (token_service
&& !GetAuthenticatedUsername().empty())
144 token_service
->LoadCredentials();
147 std::string
SigninManager::SigninTypeToString(
148 SigninManager::SigninType type
) {
150 case SIGNIN_TYPE_NONE
:
152 case SIGNIN_TYPE_WITH_CREDENTIALS
:
153 return "Signin with credentials";
154 case SIGNIN_TYPE_WITH_OAUTH_CODE
:
155 return "Signin with oauth code";
159 return std::string();
162 bool SigninManager::PrepareForSignin(SigninType type
,
163 const std::string
& username
,
164 const std::string
& password
) {
165 DCHECK(possibly_invalid_username_
.empty() ||
166 possibly_invalid_username_
== username
);
167 DCHECK(!username
.empty());
169 if (!IsAllowedUsername(username
)) {
170 // Account is not allowed by admin policy.
171 HandleAuthError(GoogleServiceAuthError(
172 GoogleServiceAuthError::ACCOUNT_DISABLED
), true);
176 // This attempt is either 1) the user trying to establish initial sync, or
177 // 2) trying to refresh credentials for an existing username. If it is 2, we
178 // need to try again, but take care to leave state around tracking that the
179 // user has successfully signed in once before with this username, so that on
180 // restart we don't think sync setup has never completed.
181 ClearTransientSigninData();
183 possibly_invalid_username_
.assign(username
);
184 password_
.assign(password
);
186 client_login_
.reset(new GaiaAuthFetcher(this,
187 GaiaConstants::kChromeSource
,
188 profile_
->GetRequestContext()));
189 NotifyDiagnosticsObservers(SIGNIN_TYPE
, SigninTypeToString(type
));
193 void SigninManager::StartSignInWithCredentials(
194 const std::string
& session_index
,
195 const std::string
& username
,
196 const std::string
& password
,
197 const OAuthTokenFetchedCallback
& callback
) {
198 DCHECK(GetAuthenticatedUsername().empty() ||
199 gaia::AreEmailsSame(username
, GetAuthenticatedUsername()));
201 if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS
, username
, password
))
204 // Store our callback.
205 DCHECK(oauth_token_fetched_callback_
.is_null());
206 oauth_token_fetched_callback_
= callback
;
208 if (password
.empty()) {
209 // Chrome must verify the GAIA cookies first if auto sign-in is triggered
210 // with no password provided. This is to protect Chrome against forged
211 // GAIA cookies from a super-domain.
212 VerifyGaiaCookiesBeforeSignIn(session_index
);
214 // This function starts with the current state of the web session's cookie
215 // jar and mints a new ClientLogin-style SID/LSID pair. This involves going
216 // through the follow process or requests to GAIA and LSO:
218 // - call /o/oauth2/programmatic_auth with the returned token to get oauth2
219 // access and refresh tokens
220 // - call /accounts/OAuthLogin with the oauth2 access token and get SID/LSID
221 // pair for use by the token service
223 // The resulting SID/LSID can then be used just as if
224 // client_login_->StartClientLogin() had completed successfully.
225 client_login_
->StartCookieForOAuthLoginTokenExchange(session_index
);
229 void SigninManager::StartSignInWithOAuthCode(
230 const std::string
& username
,
231 const std::string
& password
,
232 const std::string
& oauth_code
,
233 const OAuthTokenFetchedCallback
& callback
) {
234 DCHECK(GetAuthenticatedUsername().empty() ||
235 gaia::AreEmailsSame(username
, GetAuthenticatedUsername()));
237 if (!PrepareForSignin(SIGNIN_TYPE_WITH_OAUTH_CODE
, username
, password
))
240 DCHECK(oauth_token_fetched_callback_
.is_null());
241 oauth_token_fetched_callback_
= callback
;
243 client_login_
->StartAuthCodeForOAuth2TokenExchange(oauth_code
);
246 void SigninManager::VerifyGaiaCookiesBeforeSignIn(
247 const std::string
& session_index
) {
248 scoped_refptr
<SigninManagerCookieHelper
> cookie_helper(
249 new SigninManagerCookieHelper(profile_
->GetRequestContext()));
250 cookie_helper
->StartFetchingGaiaCookiesOnUIThread(
251 base::Bind(&SigninManager::OnGaiaCookiesFetched
,
252 weak_pointer_factory_
.GetWeakPtr(), session_index
));
255 void SigninManager::OnGaiaCookiesFetched(
256 const std::string session_index
, const net::CookieList
& cookie_list
) {
257 net::CookieList::const_iterator it
;
258 bool success
= false;
259 for (it
= cookie_list
.begin(); it
!= cookie_list
.end(); ++it
) {
260 // Make sure the LSID cookie is set on the GAIA host, instead of a super-
262 if (it
->Name() == "LSID") {
263 if (it
->IsHostCookie() && it
->IsHttpOnly() && it
->IsSecure()) {
264 // Found a valid LSID cookie. Continue loop to make sure we don't have
265 // invalid LSID cookies on any super-domain.
275 client_login_
->StartCookieForOAuthLoginTokenExchange(session_index
);
277 HandleAuthError(GoogleServiceAuthError(
278 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
), true);
282 void SigninManager::CopyCredentialsFrom(const SigninManager
& source
) {
283 DCHECK_NE(this, &source
);
284 possibly_invalid_username_
= source
.possibly_invalid_username_
;
285 last_result_
= source
.last_result_
;
286 temp_oauth_login_tokens_
= source
.temp_oauth_login_tokens_
;
289 void SigninManager::ClearTransientSigninData() {
290 DCHECK(IsInitialized());
292 client_login_
.reset();
293 last_result_
= ClientLoginResult();
294 possibly_invalid_username_
.clear();
296 had_two_factor_error_
= false;
297 type_
= SIGNIN_TYPE_NONE
;
298 temp_oauth_login_tokens_
= ClientOAuthResult();
299 oauth_token_fetched_callback_
.Reset();
302 void SigninManager::HandleAuthError(const GoogleServiceAuthError
& error
,
303 bool clear_transient_data
) {
304 // In some cases, the user should not be signed out. For example, the failure
305 // may be due to a captcha or OTP challenge. In these cases, the transient
306 // data must be kept to properly handle the follow up. This routine clears
307 // the data before sending out the notification so the SigninManager is no
308 // longer in the AuthInProgress state when the notification goes out.
309 if (clear_transient_data
)
310 ClearTransientSigninData();
312 content::NotificationService::current()->Notify(
313 chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED
,
314 content::Source
<Profile
>(profile_
),
315 content::Details
<const GoogleServiceAuthError
>(&error
));
318 void SigninManager::SignOut() {
319 DCHECK(IsInitialized());
321 if (GetAuthenticatedUsername().empty()) {
322 if (AuthInProgress()) {
323 // If the user is in the process of signing in, then treat a call to
324 // SignOut as a cancellation request.
325 GoogleServiceAuthError
error(GoogleServiceAuthError::REQUEST_CANCELED
);
326 HandleAuthError(error
, true);
328 // Clean up our transient data and exit if we aren't signed in.
329 // This avoids a perf regression from clearing out the TokenDB if
330 // SignOut() is invoked on startup to clean up any incomplete previous
332 ClearTransientSigninData();
337 if (prohibit_signout_
) {
338 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited";
342 ClearTransientSigninData();
344 GoogleServiceSignoutDetails
details(GetAuthenticatedUsername());
345 clear_authenticated_username();
346 profile_
->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername
);
348 // Erase (now) stale information from AboutSigninInternals.
349 NotifyDiagnosticsObservers(USERNAME
, "");
351 content::NotificationService::current()->Notify(
352 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT
,
353 content::Source
<Profile
>(profile_
),
354 content::Details
<const GoogleServiceSignoutDetails
>(&details
));
355 ProfileOAuth2TokenService
* token_service
=
356 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
);
357 token_service
->RevokeAllCredentials();
360 void SigninManager::Initialize(Profile
* profile
, PrefService
* local_state
) {
361 SigninManagerBase::Initialize(profile
, local_state
);
365 // local_state can be null during unit tests.
367 local_state_pref_registrar_
.Init(local_state
);
368 local_state_pref_registrar_
.Add(
369 prefs::kGoogleServicesUsernamePattern
,
370 base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged
,
371 weak_pointer_factory_
.GetWeakPtr()));
373 signin_allowed_
.Init(prefs::kSigninAllowed
, profile_
->GetPrefs(),
374 base::Bind(&SigninManager::OnSigninAllowedPrefChanged
,
375 base::Unretained(this)));
377 std::string user
= profile_
->GetPrefs()->GetString(
378 prefs::kGoogleServicesUsername
);
379 if ((!user
.empty() && !IsAllowedUsername(user
)) || !IsSigninAllowed()) {
380 // User is signed in, but the username is invalid - the administrator must
381 // have changed the policy since the last signin, so sign out the user.
385 account_id_helper_
.reset(new SigninAccountIdHelper(profile
));
388 void SigninManager::Shutdown() {
389 if (merge_session_helper_
)
390 merge_session_helper_
->CancelAll();
392 local_state_pref_registrar_
.RemoveAll();
393 account_id_helper_
.reset();
394 SigninManagerBase::Shutdown();
397 void SigninManager::OnGoogleServicesUsernamePatternChanged() {
398 if (!GetAuthenticatedUsername().empty() &&
399 !IsAllowedUsername(GetAuthenticatedUsername())) {
400 // Signed in user is invalid according to the current policy so sign
406 bool SigninManager::IsSigninAllowed() const {
407 return signin_allowed_
.GetValue();
411 bool SigninManager::IsSigninAllowedOnIOThread(ProfileIOData
* io_data
) {
412 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO
));
413 return io_data
->signin_allowed()->GetValue();
416 void SigninManager::OnSigninAllowedPrefChanged() {
417 if (!IsSigninAllowed())
422 bool SigninManager::IsUsernameAllowedByPolicy(const std::string
& username
,
423 const std::string
& policy
) {
427 // Patterns like "*@foo.com" are not accepted by our regex engine (since they
428 // are not valid regular expressions - they should instead be ".*@foo.com").
429 // For convenience, detect these patterns and insert a "." character at the
431 base::string16 pattern
= base::UTF8ToUTF16(policy
);
432 if (pattern
[0] == L
'*')
433 pattern
.insert(pattern
.begin(), L
'.');
435 // See if the username matches the policy-provided pattern.
436 UErrorCode status
= U_ZERO_ERROR
;
437 const icu::UnicodeString
icu_pattern(pattern
.data(), pattern
.length());
438 icu::RegexMatcher
matcher(icu_pattern
, UREGEX_CASE_INSENSITIVE
, status
);
439 if (!U_SUCCESS(status
)) {
440 LOG(ERROR
) << "Invalid login regex: " << pattern
<< ", status: " << status
;
441 // If an invalid pattern is provided, then prohibit *all* logins (better to
442 // break signin than to quietly allow users to sign in).
445 base::string16 username16
= base::UTF8ToUTF16(username
);
446 icu::UnicodeString
icu_input(username16
.data(), username16
.length());
447 matcher
.reset(icu_input
);
448 status
= U_ZERO_ERROR
;
449 UBool match
= matcher
.matches(status
);
450 DCHECK(U_SUCCESS(status
));
451 return !!match
; // !! == convert from UBool to bool.
454 bool SigninManager::IsAllowedUsername(const std::string
& username
) const {
455 const PrefService
* local_state
= local_state_pref_registrar_
.prefs();
457 return true; // In a unit test with no local state - all names are allowed.
459 std::string pattern
= local_state
->GetString(
460 prefs::kGoogleServicesUsernamePattern
);
461 return IsUsernameAllowedByPolicy(username
, pattern
);
464 bool SigninManager::AuthInProgress() const {
465 return !possibly_invalid_username_
.empty();
468 const std::string
& SigninManager::GetUsernameForAuthInProgress() const {
469 return possibly_invalid_username_
;
472 void SigninManager::OnGetUserInfoKeyNotFound(const std::string
& key
) {
473 DCHECK(key
== kGetInfoDisplayEmailKey
|| key
== kGetInfoEmailKey
);
474 LOG(ERROR
) << "Account is not associated with a valid email address. "
476 OnClientLoginFailure(GoogleServiceAuthError(
477 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
));
480 void SigninManager::DisableOneClickSignIn(Profile
* profile
) {
481 PrefService
* pref_service
= profile
->GetPrefs();
482 pref_service
->SetBoolean(prefs::kReverseAutologinEnabled
, false);
485 void SigninManager::OnClientLoginSuccess(const ClientLoginResult
& result
) {
486 last_result_
= result
;
487 // Update signin_internals_
488 NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS
, "Successful");
489 // Make a request for the canonical email address and services.
490 client_login_
->StartGetUserInfo(result
.lsid
);
493 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError
& error
) {
494 // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR
495 // error. This function does not call HandleAuthError() because dealing
496 // with TWO_FACTOR errors needs special handling: we don't want to clear the
497 // transient signin data in such error cases.
498 bool invalid_gaia
= error
.state() ==
499 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
;
501 GoogleServiceAuthError current_error
=
502 (invalid_gaia
&& had_two_factor_error_
) ?
503 GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR
) : error
;
505 if (current_error
.state() == GoogleServiceAuthError::TWO_FACTOR
)
506 had_two_factor_error_
= true;
508 NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS
, error
.ToString());
509 HandleAuthError(current_error
, !had_two_factor_error_
);
512 void SigninManager::OnClientOAuthSuccess(const ClientOAuthResult
& result
) {
513 DVLOG(1) << "SigninManager::OnClientOAuthSuccess access_token="
514 << result
.access_token
;
516 NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS
, "Successful");
519 case SIGNIN_TYPE_WITH_CREDENTIALS
:
520 case SIGNIN_TYPE_WITH_OAUTH_CODE
:
521 temp_oauth_login_tokens_
= result
;
522 client_login_
->StartOAuthLogin(result
.access_token
,
523 GaiaConstants::kGaiaService
);
531 void SigninManager::OnClientOAuthFailure(const GoogleServiceAuthError
& error
) {
532 bool clear_transient_data
= true;
533 NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS
, error
.ToString());
534 LOG(WARNING
) << "SigninManager::OnClientOAuthFailure";
535 HandleAuthError(error
, clear_transient_data
);
538 void SigninManager::OnGetUserInfoSuccess(const UserInfoMap
& data
) {
539 NotifyDiagnosticsObservers(GET_USER_INFO_STATUS
, "Successful");
541 UserInfoMap::const_iterator email_iter
= data
.find(kGetInfoEmailKey
);
542 UserInfoMap::const_iterator display_email_iter
=
543 data
.find(kGetInfoDisplayEmailKey
);
544 if (email_iter
== data
.end()) {
545 OnGetUserInfoKeyNotFound(kGetInfoEmailKey
);
548 if (display_email_iter
== data
.end()) {
549 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey
);
552 DCHECK(email_iter
->first
== kGetInfoEmailKey
);
553 DCHECK(display_email_iter
->first
== kGetInfoDisplayEmailKey
);
555 // When signing in with credentials, the possibly invalid name is the Gaia
556 // display name. If the name returned by GetUserInfo does not match what is
557 // expected, return an error.
558 if (type_
== SIGNIN_TYPE_WITH_CREDENTIALS
&&
559 !gaia::AreEmailsSame(display_email_iter
->second
,
560 possibly_invalid_username_
)) {
561 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey
);
565 possibly_invalid_username_
= email_iter
->second
;
567 if (!oauth_token_fetched_callback_
.is_null() &&
568 !temp_oauth_login_tokens_
.refresh_token
.empty()) {
569 oauth_token_fetched_callback_
.Run(temp_oauth_login_tokens_
.refresh_token
);
571 // No oauth token or callback, so just complete our pending signin.
572 CompletePendingSignin();
576 void SigninManager::CompletePendingSignin() {
577 DCHECK(!possibly_invalid_username_
.empty());
578 OnSignedIn(possibly_invalid_username_
);
580 // If inline sign in is enabled, but new profile management is not, perform a
581 // merge session now to push the user's credentials into the cookie jar.
582 bool do_merge_session_in_signin_manager
=
583 !switches::IsEnableWebBasedSignin() &&
584 !switches::IsNewProfileManagement();
586 if (do_merge_session_in_signin_manager
)
587 merge_session_helper_
.reset(new GoogleAutoLoginHelper(profile_
, NULL
));
589 DCHECK(!temp_oauth_login_tokens_
.refresh_token
.empty());
590 DCHECK(!GetAuthenticatedUsername().empty());
591 ProfileOAuth2TokenService
* token_service
=
592 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
);
593 token_service
->UpdateCredentials(GetAuthenticatedUsername(),
594 temp_oauth_login_tokens_
.refresh_token
);
595 temp_oauth_login_tokens_
= ClientOAuthResult();
597 if (do_merge_session_in_signin_manager
)
598 merge_session_helper_
->LogIn(GetAuthenticatedUsername());
601 void SigninManager::OnExternalSigninCompleted(const std::string
& username
) {
602 OnSignedIn(username
);
605 void SigninManager::OnSignedIn(const std::string
& username
) {
606 SetAuthenticatedUsername(username
);
607 possibly_invalid_username_
.clear();
608 profile_
->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
609 GetAuthenticatedUsername());
611 GoogleServiceSigninSuccessDetails
details(GetAuthenticatedUsername(),
613 content::NotificationService::current()->Notify(
614 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL
,
615 content::Source
<Profile
>(profile_
),
616 content::Details
<const GoogleServiceSigninSuccessDetails
>(&details
));
618 #if !defined(OS_ANDROID)
619 // Don't store password hash except for users of new profile features.
620 if (switches::IsNewProfileManagement())
621 chrome::SetLocalAuthCredentials(profile_
, password_
);
624 password_
.clear(); // Don't need it anymore.
625 DisableOneClickSignIn(profile_
); // Don't ever offer again.
628 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError
& error
) {
629 LOG(ERROR
) << "Unable to retreive the canonical email address. Login failed.";
630 NotifyDiagnosticsObservers(GET_USER_INFO_STATUS
, error
.ToString());
631 // REVIEW: why does this call OnClientLoginFailure?
632 OnClientLoginFailure(error
);
635 void SigninManager::RenderProcessHostDestroyed(RenderProcessHost
* host
) {
636 // It's possible we're listening to a "stale" renderer because it was replaced
637 // with a new process by process-per-site. In either case, stop observing it,
638 // but only reset signin_host_id_ tracking if this was from the current signin
640 signin_hosts_observed_
.erase(host
);
641 if (signin_host_id_
== host
->GetID())
642 signin_host_id_
= ChildProcessHost::kInvalidUniqueID
;
645 void SigninManager::ProhibitSignout(bool prohibit_signout
) {
646 prohibit_signout_
= prohibit_signout
;
649 bool SigninManager::IsSignoutProhibited() const {
650 return prohibit_signout_
;