// Copyright (c) 2011 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/sync/signin_manager.h" #include "base/string_util.h" #include "chrome/browser/net/gaia/token_service.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/pref_names.h" #include "content/common/notification_service.h" const char kGetInfoEmailKey[] = "email"; SigninManager::SigninManager() : profile_(NULL), had_two_factor_error_(false) {} SigninManager::~SigninManager() {} // static void SigninManager::RegisterUserPrefs(PrefService* user_prefs) { user_prefs->RegisterStringPref(prefs::kGoogleServicesUsername, ""); } void SigninManager::Initialize(Profile* profile) { profile_ = profile; username_ = profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername); profile_->GetTokenService()->Initialize( GaiaConstants::kChromeSource, profile_); if (!username_.empty()) { profile_->GetTokenService()->LoadTokensFromDB(); } } // If a username already exists, the user is logged in. const std::string& SigninManager::GetUsername() { return username_; } void SigninManager::SetUsername(const std::string& username) { username_ = username; } // Users must always sign out before they sign in again. void SigninManager::StartSignIn(const std::string& username, const std::string& password, const std::string& login_token, const std::string& login_captcha) { DCHECK(username_.empty()); #if !defined(OS_CHROMEOS) // The Sign out should clear the token service credentials. // Note: In CHROMEOS we might have valid credentials but still need to // set up 2-factor authentication. DCHECK(!profile_->GetTokenService()->AreCredentialsValid()); #endif username_.assign(username); password_.assign(password); client_login_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource, profile_->GetRequestContext())); client_login_->StartClientLogin(username, password, "", login_token, login_captcha, GaiaAuthFetcher::HostedAccountsNotAllowed); } void SigninManager::ProvideSecondFactorAccessCode( const std::string& access_code) { DCHECK(!username_.empty() && !password_.empty() && last_result_.data.empty()); client_login_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource, profile_->GetRequestContext())); client_login_->StartClientLogin(username_, access_code, "", std::string(), std::string(), GaiaAuthFetcher::HostedAccountsNotAllowed); } void SigninManager::SignOut() { if (!profile_) return; client_login_.reset(); last_result_ = ClientLoginResult(); username_.clear(); password_.clear(); had_two_factor_error_ = false; profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_); profile_->GetPrefs()->ScheduleSavePersistentPrefs(); profile_->GetTokenService()->ResetCredentialsInMemory(); profile_->GetTokenService()->EraseTokensFromDB(); } void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { last_result_ = result; // Make a request for the canonical email address. client_login_->StartGetUserInfo(result.lsid, kGetInfoEmailKey); } void SigninManager::OnGetUserInfoSuccess(const std::string& key, const std::string& value) { DCHECK(key == kGetInfoEmailKey); username_ = value; profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_); profile_->GetPrefs()->ScheduleSavePersistentPrefs(); GoogleServiceSigninSuccessDetails details(username_, password_); NotificationService::current()->Notify( NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, Source<Profile>(profile_), Details<const GoogleServiceSigninSuccessDetails>(&details)); password_.clear(); // Don't need it anymore. profile_->GetTokenService()->UpdateCredentials(last_result_); DCHECK(profile_->GetTokenService()->AreCredentialsValid()); profile_->GetTokenService()->StartFetchingTokens(); } void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { DCHECK(key == kGetInfoEmailKey); LOG(ERROR) << "Account is not associated with a valid email address. " << "Login failed."; OnClientLoginFailure(GoogleServiceAuthError( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); } void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; OnClientLoginFailure(error); } void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { NotificationService::current()->Notify( NotificationType::GOOGLE_SIGNIN_FAILED, Source<Profile>(profile_), Details<const GoogleServiceAuthError>(&error)); // We don't sign-out if the password was valid and we're just dealing with // a second factor error, and we don't sign out if we're dealing with // an invalid access code (again, because the password was valid). bool invalid_gaia = error.state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; if (error.state() == GoogleServiceAuthError::TWO_FACTOR || (had_two_factor_error_ && invalid_gaia)) { had_two_factor_error_ = true; return; } SignOut(); }