1 // Copyright (c) 2011 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/sync/signin_manager.h" 6 7 #include "base/string_util.h" 8 #include "chrome/browser/net/gaia/token_service.h" 9 #include "chrome/browser/prefs/pref_service.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/common/net/gaia/gaia_constants.h" 12 #include "chrome/common/pref_names.h" 13 #include "content/common/notification_service.h" 14 15 const char kGetInfoEmailKey[] = "email"; 16 17 SigninManager::SigninManager() 18 : profile_(NULL), had_two_factor_error_(false) {} 19 20 SigninManager::~SigninManager() {} 21 22 // static 23 void SigninManager::RegisterUserPrefs(PrefService* user_prefs) { 24 user_prefs->RegisterStringPref(prefs::kGoogleServicesUsername, ""); 25 } 26 27 void SigninManager::Initialize(Profile* profile) { 28 profile_ = profile; 29 username_ = profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername); 30 profile_->GetTokenService()->Initialize( 31 GaiaConstants::kChromeSource, profile_); 32 if (!username_.empty()) { 33 profile_->GetTokenService()->LoadTokensFromDB(); 34 } 35 } 36 37 // If a username already exists, the user is logged in. 38 const std::string& SigninManager::GetUsername() { 39 return username_; 40 } 41 42 void SigninManager::SetUsername(const std::string& username) { 43 username_ = username; 44 } 45 46 // Users must always sign out before they sign in again. 47 void SigninManager::StartSignIn(const std::string& username, 48 const std::string& password, 49 const std::string& login_token, 50 const std::string& login_captcha) { 51 DCHECK(username_.empty()); 52 #if !defined(OS_CHROMEOS) 53 // The Sign out should clear the token service credentials. 54 // Note: In CHROMEOS we might have valid credentials but still need to 55 // set up 2-factor authentication. 56 DCHECK(!profile_->GetTokenService()->AreCredentialsValid()); 57 #endif 58 username_.assign(username); 59 password_.assign(password); 60 61 client_login_.reset(new GaiaAuthFetcher(this, 62 GaiaConstants::kChromeSource, 63 profile_->GetRequestContext())); 64 client_login_->StartClientLogin(username, 65 password, 66 "", 67 login_token, 68 login_captcha, 69 GaiaAuthFetcher::HostedAccountsNotAllowed); 70 } 71 72 void SigninManager::ProvideSecondFactorAccessCode( 73 const std::string& access_code) { 74 DCHECK(!username_.empty() && !password_.empty() && 75 last_result_.data.empty()); 76 77 client_login_.reset(new GaiaAuthFetcher(this, 78 GaiaConstants::kChromeSource, 79 profile_->GetRequestContext())); 80 client_login_->StartClientLogin(username_, 81 access_code, 82 "", 83 std::string(), 84 std::string(), 85 GaiaAuthFetcher::HostedAccountsNotAllowed); 86 } 87 88 void SigninManager::SignOut() { 89 if (!profile_) 90 return; 91 92 client_login_.reset(); 93 last_result_ = ClientLoginResult(); 94 username_.clear(); 95 password_.clear(); 96 had_two_factor_error_ = false; 97 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_); 98 profile_->GetPrefs()->ScheduleSavePersistentPrefs(); 99 profile_->GetTokenService()->ResetCredentialsInMemory(); 100 profile_->GetTokenService()->EraseTokensFromDB(); 101 } 102 103 void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) { 104 last_result_ = result; 105 // Make a request for the canonical email address. 106 client_login_->StartGetUserInfo(result.lsid, kGetInfoEmailKey); 107 } 108 109 void SigninManager::OnGetUserInfoSuccess(const std::string& key, 110 const std::string& value) { 111 DCHECK(key == kGetInfoEmailKey); 112 113 username_ = value; 114 profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_); 115 profile_->GetPrefs()->ScheduleSavePersistentPrefs(); 116 117 GoogleServiceSigninSuccessDetails details(username_, password_); 118 NotificationService::current()->Notify( 119 NotificationType::GOOGLE_SIGNIN_SUCCESSFUL, 120 Source<Profile>(profile_), 121 Details<const GoogleServiceSigninSuccessDetails>(&details)); 122 123 password_.clear(); // Don't need it anymore. 124 125 profile_->GetTokenService()->UpdateCredentials(last_result_); 126 DCHECK(profile_->GetTokenService()->AreCredentialsValid()); 127 profile_->GetTokenService()->StartFetchingTokens(); 128 } 129 130 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) { 131 DCHECK(key == kGetInfoEmailKey); 132 LOG(ERROR) << "Account is not associated with a valid email address. " 133 << "Login failed."; 134 OnClientLoginFailure(GoogleServiceAuthError( 135 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); 136 } 137 138 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { 139 LOG(ERROR) << "Unable to retreive the canonical email address. Login failed."; 140 OnClientLoginFailure(error); 141 } 142 143 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) { 144 NotificationService::current()->Notify( 145 NotificationType::GOOGLE_SIGNIN_FAILED, 146 Source<Profile>(profile_), 147 Details<const GoogleServiceAuthError>(&error)); 148 149 // We don't sign-out if the password was valid and we're just dealing with 150 // a second factor error, and we don't sign out if we're dealing with 151 // an invalid access code (again, because the password was valid). 152 bool invalid_gaia = error.state() == 153 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS; 154 if (error.state() == GoogleServiceAuthError::TWO_FACTOR || 155 (had_two_factor_error_ && invalid_gaia)) { 156 had_two_factor_error_ = true; 157 return; 158 } 159 160 SignOut(); 161 } 162