| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/signin/signin_manager.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/profiles/profile_io_data.h" |
| #include "chrome/browser/signin/about_signin_internals.h" |
| #include "chrome/browser/signin/about_signin_internals_factory.h" |
| #include "chrome/browser/signin/local_auth.h" |
| #include "chrome/browser/signin/signin_global_error.h" |
| #include "chrome/browser/signin/signin_internals_util.h" |
| #include "chrome/browser/signin/signin_manager_cookie_helper.h" |
| #include "chrome/browser/signin/signin_manager_delegate.h" |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/signin/token_service.h" |
| #include "chrome/browser/signin/token_service_factory.h" |
| #include "chrome/browser/ui/global_error/global_error_service.h" |
| #include "chrome/browser/ui/global_error/global_error_service_factory.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "google_apis/gaia/gaia_auth_fetcher.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| #include "google_apis/gaia/gaia_constants.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "net/base/escape.h" |
| #include "net/url_request/url_request_context.h" |
| #include "third_party/icu/source/i18n/unicode/regex.h" |
| |
| using namespace signin_internals_util; |
| |
| using content::BrowserThread; |
| |
| namespace { |
| |
| const char kGetInfoDisplayEmailKey[] = "displayEmail"; |
| const char kGetInfoEmailKey[] = "email"; |
| |
| const int kInvalidProcessId = -1; |
| |
| const char kChromiumSyncService[] = "service=chromiumsync"; |
| |
| } // namespace |
| |
| // Under the covers, we use a dummy chrome-extension ID to serve the purposes |
| // outlined in the .h file comment for this string. |
| const char* SigninManager::kChromeSigninEffectiveSite = |
| "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih"; |
| |
| // static |
| bool SigninManager::IsWebBasedSigninFlowURL(const GURL& url) { |
| GURL effective(kChromeSigninEffectiveSite); |
| if (url.SchemeIs(effective.scheme().c_str()) && |
| url.host() == effective.host()) { |
| return true; |
| } |
| |
| GURL service_login(GaiaUrls::GetInstance()->service_login_url()); |
| if (url.GetOrigin() != service_login.GetOrigin()) |
| return false; |
| |
| // Any login UI URLs with signin=chromiumsync should be considered a web |
| // URL (relies on GAIA keeping the "service=chromiumsync" query string |
| // fragment present even when embedding inside a "continue" parameter). |
| return net::UnescapeURLComponent( |
| url.query(), net::UnescapeRule::URL_SPECIAL_CHARS) |
| .find(kChromiumSyncService) != std::string::npos; |
| } |
| |
| SigninManager::SigninManager(scoped_ptr<SigninManagerDelegate> delegate) |
| : prohibit_signout_(false), |
| had_two_factor_error_(false), |
| type_(SIGNIN_TYPE_NONE), |
| weak_pointer_factory_(this), |
| signin_process_id_(kInvalidProcessId), |
| delegate_(delegate.Pass()) { |
| } |
| |
| void SigninManager::SetSigninProcess(int process_id) { |
| if (process_id == signin_process_id_) |
| return; |
| DLOG_IF(WARNING, signin_process_id_ != kInvalidProcessId) << |
| "Replacing in-use signin process."; |
| signin_process_id_ = process_id; |
| const content::RenderProcessHost* process = |
| content::RenderProcessHost::FromID(process_id); |
| DCHECK(process); |
| registrar_.Add(this, |
| content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| content::Source<content::RenderProcessHost>(process)); |
| } |
| |
| void SigninManager::ClearSigninProcess() { |
| signin_process_id_ = kInvalidProcessId; |
| } |
| |
| bool SigninManager::IsSigninProcess(int process_id) const { |
| return process_id == signin_process_id_; |
| } |
| |
| bool SigninManager::HasSigninProcess() const { |
| return signin_process_id_ != kInvalidProcessId; |
| } |
| |
| SigninManager::~SigninManager() { |
| } |
| |
| void SigninManager::InitTokenService() { |
| SigninManagerBase::InitTokenService(); |
| TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| if (token_service && !GetAuthenticatedUsername().empty()) |
| token_service->LoadTokensFromDB(); |
| } |
| |
| std::string SigninManager::SigninTypeToString( |
| SigninManager::SigninType type) { |
| switch (type) { |
| case SIGNIN_TYPE_NONE: |
| return "No Signin"; |
| case SIGNIN_TYPE_WITH_CREDENTIALS: |
| return "Signin with credentials"; |
| case SIGNIN_TYPE_WITH_OAUTH_CODE: |
| return "Signin with oauth code"; |
| } |
| |
| NOTREACHED(); |
| return std::string(); |
| } |
| |
| bool SigninManager::PrepareForSignin(SigninType type, |
| const std::string& username, |
| const std::string& password) { |
| DCHECK(possibly_invalid_username_.empty() || |
| possibly_invalid_username_ == username); |
| DCHECK(!username.empty()); |
| |
| if (!IsAllowedUsername(username)) { |
| // Account is not allowed by admin policy. |
| HandleAuthError(GoogleServiceAuthError( |
| GoogleServiceAuthError::ACCOUNT_DISABLED), true); |
| return false; |
| } |
| |
| // This attempt is either 1) the user trying to establish initial sync, or |
| // 2) trying to refresh credentials for an existing username. If it is 2, we |
| // need to try again, but take care to leave state around tracking that the |
| // user has successfully signed in once before with this username, so that on |
| // restart we don't think sync setup has never completed. |
| RevokeOAuthLoginToken(); |
| ClearTransientSigninData(); |
| type_ = type; |
| possibly_invalid_username_.assign(username); |
| password_.assign(password); |
| |
| client_login_.reset(new GaiaAuthFetcher(this, |
| GaiaConstants::kChromeSource, |
| profile_->GetRequestContext())); |
| NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type)); |
| return true; |
| } |
| |
| void SigninManager::StartSignInWithCredentials( |
| const std::string& session_index, |
| const std::string& username, |
| const std::string& password, |
| const OAuthTokenFetchedCallback& callback) { |
| DCHECK(GetAuthenticatedUsername().empty() || |
| gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| |
| if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password)) |
| return; |
| |
| // Store our callback. |
| DCHECK(oauth_token_fetched_callback_.is_null()); |
| oauth_token_fetched_callback_ = callback; |
| |
| if (password.empty()) { |
| // Chrome must verify the GAIA cookies first if auto sign-in is triggered |
| // with no password provided. This is to protect Chrome against forged |
| // GAIA cookies from a super-domain. |
| VerifyGaiaCookiesBeforeSignIn(session_index); |
| } else { |
| // This function starts with the current state of the web session's cookie |
| // jar and mints a new ClientLogin-style SID/LSID pair. This involves going |
| // through the follow process or requests to GAIA and LSO: |
| // |
| // - call /o/oauth2/programmatic_auth with the returned token to get oauth2 |
| // access and refresh tokens |
| // - call /accounts/OAuthLogin with the oauth2 access token and get SID/LSID |
| // pair for use by the token service |
| // |
| // The resulting SID/LSID can then be used just as if |
| // client_login_->StartClientLogin() had completed successfully. |
| client_login_->StartCookieForOAuthLoginTokenExchange(session_index); |
| } |
| } |
| |
| void SigninManager::StartSignInWithOAuthCode( |
| const std::string& username, |
| const std::string& password, |
| const std::string& oauth_code, |
| const OAuthTokenFetchedCallback& callback) { |
| DCHECK(GetAuthenticatedUsername().empty() || |
| gaia::AreEmailsSame(username, GetAuthenticatedUsername())); |
| |
| if (!PrepareForSignin(SIGNIN_TYPE_WITH_OAUTH_CODE, username, password)) |
| return; |
| |
| DCHECK(oauth_token_fetched_callback_.is_null()); |
| oauth_token_fetched_callback_ = callback; |
| |
| client_login_->StartAuthCodeForOAuth2TokenExchange(oauth_code); |
| } |
| |
| void SigninManager::VerifyGaiaCookiesBeforeSignIn( |
| const std::string& session_index) { |
| scoped_refptr<SigninManagerCookieHelper> cookie_helper( |
| new SigninManagerCookieHelper(profile_->GetRequestContext())); |
| cookie_helper->StartFetchingGaiaCookiesOnUIThread( |
| base::Bind(&SigninManager::OnGaiaCookiesFetched, |
| weak_pointer_factory_.GetWeakPtr(), session_index)); |
| } |
| |
| void SigninManager::OnGaiaCookiesFetched( |
| const std::string session_index, const net::CookieList& cookie_list) { |
| net::CookieList::const_iterator it; |
| bool success = false; |
| for (it = cookie_list.begin(); it != cookie_list.end(); ++it) { |
| // Make sure the LSID cookie is set on the GAIA host, instead of a super- |
| // domain. |
| if (it->Name() == "LSID") { |
| if (it->IsHostCookie() && it->IsHttpOnly() && it->IsSecure()) { |
| // Found a valid LSID cookie. Continue loop to make sure we don't have |
| // invalid LSID cookies on any super-domain. |
| success = true; |
| } else { |
| success = false; |
| break; |
| } |
| } |
| } |
| |
| if (success) { |
| client_login_->StartCookieForOAuthLoginTokenExchange(session_index); |
| } else { |
| HandleAuthError(GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true); |
| } |
| } |
| |
| void SigninManager::CopyCredentialsFrom(const SigninManager& source) { |
| DCHECK_NE(this, &source); |
| possibly_invalid_username_ = source.possibly_invalid_username_; |
| last_result_ = source.last_result_; |
| temp_oauth_login_tokens_ = source.temp_oauth_login_tokens_; |
| } |
| |
| void SigninManager::ClearTransientSigninData() { |
| DCHECK(IsInitialized()); |
| |
| client_login_.reset(); |
| last_result_ = ClientLoginResult(); |
| possibly_invalid_username_.clear(); |
| password_.clear(); |
| had_two_factor_error_ = false; |
| type_ = SIGNIN_TYPE_NONE; |
| temp_oauth_login_tokens_ = ClientOAuthResult(); |
| oauth_token_fetched_callback_.Reset(); |
| } |
| |
| void SigninManager::HandleAuthError(const GoogleServiceAuthError& error, |
| bool clear_transient_data) { |
| // In some cases, the user should not be signed out. For example, the failure |
| // may be due to a captcha or OTP challenge. In these cases, the transient |
| // data must be kept to properly handle the follow up. This routine clears |
| // the data before sending out the notification so the SigninManager is no |
| // longer in the AuthInProgress state when the notification goes out. |
| if (clear_transient_data) |
| ClearTransientSigninData(); |
| |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, |
| content::Source<Profile>(profile_), |
| content::Details<const GoogleServiceAuthError>(&error)); |
| } |
| |
| void SigninManager::SignOut() { |
| DCHECK(IsInitialized()); |
| |
| if (GetAuthenticatedUsername().empty()) { |
| if (AuthInProgress()) { |
| // If the user is in the process of signing in, then treat a call to |
| // SignOut as a cancellation request. |
| GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED); |
| HandleAuthError(error, true); |
| } else { |
| // Clean up our transient data and exit if we aren't signed in. |
| // This avoids a perf regression from clearing out the TokenDB if |
| // SignOut() is invoked on startup to clean up any incomplete previous |
| // signin attempts. |
| ClearTransientSigninData(); |
| } |
| return; |
| } |
| |
| if (prohibit_signout_) { |
| DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited"; |
| return; |
| } |
| |
| ClearTransientSigninData(); |
| RevokeOAuthLoginToken(); |
| |
| GoogleServiceSignoutDetails details(GetAuthenticatedUsername()); |
| clear_authenticated_username(); |
| profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername); |
| |
| // Erase (now) stale information from AboutSigninInternals. |
| NotifyDiagnosticsObservers(USERNAME, ""); |
| |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, |
| content::Source<Profile>(profile_), |
| content::Details<const GoogleServiceSignoutDetails>(&details)); |
| TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| token_service->ResetCredentialsInMemory(); |
| token_service->EraseTokensFromDB(); |
| } |
| |
| void SigninManager::Initialize(Profile* profile, PrefService* local_state) { |
| SigninManagerBase::Initialize(profile, local_state); |
| |
| // local_state can be null during unit tests. |
| if (local_state) { |
| local_state_pref_registrar_.Init(local_state); |
| local_state_pref_registrar_.Add( |
| prefs::kGoogleServicesUsernamePattern, |
| base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged, |
| weak_pointer_factory_.GetWeakPtr())); |
| } |
| signin_allowed_.Init(prefs::kSigninAllowed, profile_->GetPrefs(), |
| base::Bind(&SigninManager::OnSigninAllowedPrefChanged, |
| base::Unretained(this))); |
| |
| std::string user = profile_->GetPrefs()->GetString( |
| prefs::kGoogleServicesUsername); |
| if ((!user.empty() && !IsAllowedUsername(user)) || !IsSigninAllowed()) { |
| // User is signed in, but the username is invalid - the administrator must |
| // have changed the policy since the last signin, so sign out the user. |
| SignOut(); |
| } |
| } |
| |
| void SigninManager::Shutdown() { |
| local_state_pref_registrar_.RemoveAll(); |
| SigninManagerBase::Shutdown(); |
| } |
| |
| void SigninManager::OnGoogleServicesUsernamePatternChanged() { |
| if (!GetAuthenticatedUsername().empty() && |
| !IsAllowedUsername(GetAuthenticatedUsername())) { |
| // Signed in user is invalid according to the current policy so sign |
| // the user out. |
| SignOut(); |
| } |
| } |
| |
| bool SigninManager::IsSigninAllowed() const { |
| return signin_allowed_.GetValue(); |
| } |
| |
| // static |
| bool SigninManager::IsSigninAllowedOnIOThread(ProfileIOData* io_data) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| return io_data->signin_allowed()->GetValue(); |
| } |
| |
| void SigninManager::OnSigninAllowedPrefChanged() { |
| if (!IsSigninAllowed()) |
| SignOut(); |
| } |
| |
| // static |
| bool SigninManager::IsUsernameAllowedByPolicy(const std::string& username, |
| const std::string& policy) { |
| if (policy.empty()) |
| return true; |
| |
| // Patterns like "*@foo.com" are not accepted by our regex engine (since they |
| // are not valid regular expressions - they should instead be ".*@foo.com"). |
| // For convenience, detect these patterns and insert a "." character at the |
| // front. |
| string16 pattern = UTF8ToUTF16(policy); |
| if (pattern[0] == L'*') |
| pattern.insert(pattern.begin(), L'.'); |
| |
| // See if the username matches the policy-provided pattern. |
| UErrorCode status = U_ZERO_ERROR; |
| const icu::UnicodeString icu_pattern(pattern.data(), pattern.length()); |
| icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status); |
| if (!U_SUCCESS(status)) { |
| LOG(ERROR) << "Invalid login regex: " << pattern << ", status: " << status; |
| // If an invalid pattern is provided, then prohibit *all* logins (better to |
| // break signin than to quietly allow users to sign in). |
| return false; |
| } |
| string16 username16 = UTF8ToUTF16(username); |
| icu::UnicodeString icu_input(username16.data(), username16.length()); |
| matcher.reset(icu_input); |
| status = U_ZERO_ERROR; |
| UBool match = matcher.matches(status); |
| DCHECK(U_SUCCESS(status)); |
| return !!match; // !! == convert from UBool to bool. |
| } |
| |
| bool SigninManager::IsAllowedUsername(const std::string& username) const { |
| const PrefService* local_state = local_state_pref_registrar_.prefs(); |
| if (!local_state) |
| return true; // In a unit test with no local state - all names are allowed. |
| |
| std::string pattern = local_state->GetString( |
| prefs::kGoogleServicesUsernamePattern); |
| return IsUsernameAllowedByPolicy(username, pattern); |
| } |
| |
| void SigninManager::RevokeOAuthLoginToken() { |
| TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| if (token_service->HasOAuthLoginToken()) { |
| revoke_token_fetcher_.reset( |
| new GaiaAuthFetcher(this, |
| GaiaConstants::kChromeSource, |
| profile_->GetRequestContext())); |
| revoke_token_fetcher_->StartRevokeOAuth2Token( |
| token_service->GetOAuth2LoginRefreshToken()); |
| } |
| } |
| |
| void SigninManager::OnOAuth2RevokeTokenCompleted() { |
| revoke_token_fetcher_.reset(NULL); |
| } |
| |
| bool SigninManager::AuthInProgress() const { |
| return !possibly_invalid_username_.empty(); |
| } |
| |
| const std::string& SigninManager::GetUsernameForAuthInProgress() const { |
| return possibly_invalid_username_; |
| } |
| |
| void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { |
| DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey); |
| LOG(ERROR) << "Account is not associated with a valid email address. " |
| << "Login failed."; |
| OnClientLoginFailure(GoogleServiceAuthError( |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); |
| } |
| |
| void SigninManager::DisableOneClickSignIn(Profile* profile) { |
| PrefService* pref_service = profile->GetPrefs(); |
| pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false); |
| } |
| |
| void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { |
| last_result_ = result; |
| // Update signin_internals_ |
| NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, "Successful"); |
| // Make a request for the canonical email address and services. |
| client_login_->StartGetUserInfo(result.lsid); |
| } |
| |
| void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { |
| // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR |
| // error. This function does not call HandleAuthError() because dealing |
| // with TWO_FACTOR errors needs special handling: we don't want to clear the |
| // transient signin data in such error cases. |
| bool invalid_gaia = error.state() == |
| GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; |
| |
| GoogleServiceAuthError current_error = |
| (invalid_gaia && had_two_factor_error_) ? |
| GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR) : error; |
| |
| if (current_error.state() == GoogleServiceAuthError::TWO_FACTOR) |
| had_two_factor_error_ = true; |
| |
| NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, error.ToString()); |
| HandleAuthError(current_error, !had_two_factor_error_); |
| } |
| |
| void SigninManager::OnClientOAuthSuccess(const ClientOAuthResult& result) { |
| DVLOG(1) << "SigninManager::OnClientOAuthSuccess access_token=" |
| << result.access_token; |
| |
| NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, "Successful"); |
| |
| switch (type_) { |
| case SIGNIN_TYPE_WITH_CREDENTIALS: |
| case SIGNIN_TYPE_WITH_OAUTH_CODE: |
| temp_oauth_login_tokens_ = result; |
| client_login_->StartOAuthLogin(result.access_token, |
| GaiaConstants::kGaiaService); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void SigninManager::OnClientOAuthFailure(const GoogleServiceAuthError& error) { |
| bool clear_transient_data = true; |
| NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, error.ToString()); |
| LOG(WARNING) << "SigninManager::OnClientOAuthFailure"; |
| HandleAuthError(error, clear_transient_data); |
| } |
| |
| void SigninManager::OnGetUserInfoSuccess(const UserInfoMap& data) { |
| NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, "Successful"); |
| |
| UserInfoMap::const_iterator email_iter = data.find(kGetInfoEmailKey); |
| UserInfoMap::const_iterator display_email_iter = |
| data.find(kGetInfoDisplayEmailKey); |
| if (email_iter == data.end()) { |
| OnGetUserInfoKeyNotFound(kGetInfoEmailKey); |
| return; |
| } |
| if (display_email_iter == data.end()) { |
| OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); |
| return; |
| } |
| DCHECK(email_iter->first == kGetInfoEmailKey); |
| DCHECK(display_email_iter->first == kGetInfoDisplayEmailKey); |
| |
| // When signing in with credentials, the possibly invalid name is the Gaia |
| // display name. If the name returned by GetUserInfo does not match what is |
| // expected, return an error. |
| if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS && |
| !gaia::AreEmailsSame(display_email_iter->second, |
| possibly_invalid_username_)) { |
| OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey); |
| return; |
| } |
| |
| possibly_invalid_username_ = email_iter->second; |
| |
| if (!oauth_token_fetched_callback_.is_null() && |
| !temp_oauth_login_tokens_.refresh_token.empty()) { |
| oauth_token_fetched_callback_.Run(temp_oauth_login_tokens_.refresh_token); |
| } else { |
| // No oauth token or callback, so just complete our pending signin. |
| CompletePendingSignin(); |
| } |
| } |
| |
| void SigninManager::CompletePendingSignin() { |
| DCHECK(!possibly_invalid_username_.empty()); |
| OnSignedIn(possibly_invalid_username_); |
| |
| TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
| token_service->UpdateCredentials(last_result_); |
| DCHECK(token_service->AreCredentialsValid()); |
| token_service->StartFetchingTokens(); |
| |
| // If we have oauth2 tokens, tell token service about them so it does not |
| // need to fetch them again. Its important that the authenticated name has |
| // already been set before sending the oauth2 token to the token service. |
| // Some token service listeners will query the authenticated name when they |
| // receive the token available notification. |
| if (!temp_oauth_login_tokens_.refresh_token.empty()) { |
| DCHECK(!GetAuthenticatedUsername().empty()); |
| token_service->UpdateCredentialsWithOAuth2(temp_oauth_login_tokens_); |
| temp_oauth_login_tokens_ = ClientOAuthResult(); |
| } |
| } |
| |
| void SigninManager::OnExternalSigninCompleted(const std::string& username) { |
| OnSignedIn(username); |
| } |
| |
| void SigninManager::OnSignedIn(const std::string& username) { |
| SetAuthenticatedUsername(username); |
| possibly_invalid_username_.clear(); |
| profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, |
| GetAuthenticatedUsername()); |
| |
| GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(), |
| password_); |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, |
| content::Source<Profile>(profile_), |
| content::Details<const GoogleServiceSigninSuccessDetails>(&details)); |
| |
| // Don't store password hash except for users of new profile features. |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kNewProfileManagement)) { |
| std::string auth_username = GetAuthenticatedUsername(); |
| chrome::SetLocalAuthCredentials(profile_, auth_username, password_); |
| } |
| password_.clear(); // Don't need it anymore. |
| DisableOneClickSignIn(profile_); // Don't ever offer again. |
| |
| if (type_ == SIGNIN_TYPE_WITH_OAUTH_CODE && |
| !temp_oauth_login_tokens_.access_token.empty()) |
| // Cookie jar may not be set up properly, need to first get an uber token |
| // and then merge sessions with the token. |
| client_login_->StartTokenFetchForUberAuthExchange( |
| temp_oauth_login_tokens_.access_token); |
| } |
| |
| void SigninManager::OnUberAuthTokenSuccess(const std::string& token) { |
| DVLOG(1) << "SigninManager::OnUberAuthTokenSuccess"; |
| NotifyDiagnosticsObservers(UBER_TOKEN_STATUS, "Successful"); |
| client_login_->StartMergeSession(token); |
| } |
| |
| void SigninManager::OnMergeSessionSuccess(const std::string& data) { |
| DVLOG(1) << "SigninManager::OnMergeSessionSuccess"; |
| NotifyDiagnosticsObservers(MERGE_SESSION_STATUS, "Successful"); |
| } |
| |
| void SigninManager::OnMergeSessionFailure(const GoogleServiceAuthError& error) { |
| LOG(ERROR) << "Unable to mereg sessions. Login failed."; |
| NotifyDiagnosticsObservers(MERGE_SESSION_STATUS, error.ToString()); |
| } |
| |
| void SigninManager::OnUberAuthTokenFailure( |
| const GoogleServiceAuthError& error) { |
| LOG(ERROR) << "Unable to retreive the uber token. Login failed."; |
| NotifyDiagnosticsObservers(UBER_TOKEN_STATUS, error.ToString()); |
| } |
| |
| void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { |
| LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; |
| NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, error.ToString()); |
| // REVIEW: why does this call OnClientLoginFailure? |
| OnClientLoginFailure(error); |
| } |
| |
| void SigninManager::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type); |
| |
| // It's possible we're listening to a "stale" renderer because it was |
| // replaced with a new process by process-per-site. In either case, |
| // stop listening to it, but only reset signin_process_id_ tracking |
| // if this was from the current signin process. |
| registrar_.Remove(this, |
| content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| source); |
| if (signin_process_id_ == |
| content::Source<content::RenderProcessHost>(source)->GetID()) { |
| signin_process_id_ = kInvalidProcessId; |
| } |
| } |
| |
| void SigninManager::ProhibitSignout(bool prohibit_signout) { |
| prohibit_signout_ = prohibit_signout; |
| } |
| |
| bool SigninManager::IsSignoutProhibited() const { |
| return prohibit_signout_; |
| } |