Home | History | Annotate | Download | only in sync
      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