Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / signin / signin_manager.cc
blobc10c7c4d8f9d13b43585916726d7e330799d8900
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"
7 #include <string>
8 #include <vector>
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;
51 namespace {
53 const char kGetInfoDisplayEmailKey[] = "displayEmail";
54 const char kGetInfoEmailKey[] = "email";
56 const char kChromiumSyncService[] = "service=chromiumsync";
58 } // namespace
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";
65 // static
66 bool SigninManager::IsWebBasedSigninFlowURL(const GURL& url) {
67 GURL effective(kChromeSigninEffectiveSite);
68 if (url.SchemeIs(effective.scheme().c_str()) &&
69 url.host() == effective.host()) {
70 return true;
73 GURL service_login(GaiaUrls::GetInstance()->service_login_url());
74 if (url.GetOrigin() != service_login.GetOrigin())
75 return false;
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_)
96 return;
97 DLOG_IF(WARNING,
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);
102 DCHECK(host);
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();
135 ++i) {
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) {
149 switch (type) {
150 case SIGNIN_TYPE_NONE:
151 return "No Signin";
152 case SIGNIN_TYPE_WITH_CREDENTIALS:
153 return "Signin with credentials";
154 case SIGNIN_TYPE_WITH_OAUTH_CODE:
155 return "Signin with oauth code";
158 NOTREACHED();
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);
173 return false;
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();
182 type_ = type;
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));
190 return true;
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))
202 return;
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);
213 } else {
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))
238 return;
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-
261 // domain.
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.
266 success = true;
267 } else {
268 success = false;
269 break;
274 if (success) {
275 client_login_->StartCookieForOAuthLoginTokenExchange(session_index);
276 } else {
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();
295 password_.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);
327 } else {
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
331 // signin attempts.
332 ClearTransientSigninData();
334 return;
337 if (prohibit_signout_) {
338 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited";
339 return;
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);
363 InitTokenService();
365 // local_state can be null during unit tests.
366 if (local_state) {
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.
382 SignOut();
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
401 // the user out.
402 SignOut();
406 bool SigninManager::IsSigninAllowed() const {
407 return signin_allowed_.GetValue();
410 // static
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())
418 SignOut();
421 // static
422 bool SigninManager::IsUsernameAllowedByPolicy(const std::string& username,
423 const std::string& policy) {
424 if (policy.empty())
425 return true;
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
430 // front.
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).
443 return false;
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();
456 if (!local_state)
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. "
475 << "Login failed.";
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");
518 switch (type_) {
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);
524 break;
525 default:
526 NOTREACHED();
527 break;
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);
546 return;
548 if (display_email_iter == data.end()) {
549 OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey);
550 return;
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);
562 return;
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);
570 } else {
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(),
612 password_);
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_);
622 #endif
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
639 // process.
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_;