1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/sync/signin_manager.h"
6bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
7bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/string_util.h"
8bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/net/gaia/token_service.h"
9bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/prefs/pref_service.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
11bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/common/net/gaia/gaia_constants.h"
12bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/common/pref_names.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
14bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
15bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenconst char kGetInfoEmailKey[] = "email";
16bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
17731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSigninManager::SigninManager()
18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : profile_(NULL), had_two_factor_error_(false) {}
19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
20731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSigninManager::~SigninManager() {}
21731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
22bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// static
23bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::RegisterUserPrefs(PrefService* user_prefs) {
24bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  user_prefs->RegisterStringPref(prefs::kGoogleServicesUsername, "");
25bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
26bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
27bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::Initialize(Profile* profile) {
28bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_ = profile;
29bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  username_ = profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername);
30bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetTokenService()->Initialize(
31bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      GaiaConstants::kChromeSource, profile_);
32bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (!username_.empty()) {
33bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    profile_->GetTokenService()->LoadTokensFromDB();
34bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
35bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
36bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
37bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// If a username already exists, the user is logged in.
38bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenconst std::string& SigninManager::GetUsername() {
39bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return username_;
40bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
41bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
42bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::SetUsername(const std::string& username) {
43bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  username_ = username;
44bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
45bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
46bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Users must always sign out before they sign in again.
47bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::StartSignIn(const std::string& username,
48bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                const std::string& password,
49bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                const std::string& login_token,
50bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                const std::string& login_captcha) {
51bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(username_.empty());
52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if !defined(OS_CHROMEOS)
53bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // The Sign out should clear the token service credentials.
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Note: In CHROMEOS we might have valid credentials but still need to
55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // set up 2-factor authentication.
56bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(!profile_->GetTokenService()->AreCredentialsValid());
57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif
58bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  username_.assign(username);
59bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  password_.assign(password);
60bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  client_login_.reset(new GaiaAuthFetcher(this,
624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                          GaiaConstants::kChromeSource,
634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                          profile_->GetRequestContext()));
64bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  client_login_->StartClientLogin(username,
65bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                  password,
66bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                  "",
67bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                  login_token,
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  login_captcha,
694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  GaiaAuthFetcher::HostedAccountsNotAllowed);
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid SigninManager::ProvideSecondFactorAccessCode(
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& access_code) {
74731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(!username_.empty() && !password_.empty() &&
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      last_result_.data.empty());
76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  client_login_.reset(new GaiaAuthFetcher(this,
784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                          GaiaConstants::kChromeSource,
794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                          profile_->GetRequestContext()));
80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  client_login_->StartClientLogin(username_,
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  access_code,
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  "",
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  std::string(),
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  std::string(),
854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                  GaiaAuthFetcher::HostedAccountsNotAllowed);
86bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
87bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
88bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::SignOut() {
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!profile_)
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
92bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  client_login_.reset();
93bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  last_result_ = ClientLoginResult();
94bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  username_.clear();
95bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  password_.clear();
96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  had_two_factor_error_ = false;
97bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_);
98bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
99bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetTokenService()->ResetCredentialsInMemory();
100bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetTokenService()->EraseTokensFromDB();
101bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
102bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
103bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) {
104bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  last_result_ = result;
105bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // Make a request for the canonical email address.
106bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  client_login_->StartGetUserInfo(result.lsid, kGetInfoEmailKey);
107bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
108bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
109bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::OnGetUserInfoSuccess(const std::string& key,
110bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen                                         const std::string& value) {
111bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(key == kGetInfoEmailKey);
112bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
113bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  username_ = value;
114bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername, username_);
115bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
116bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
117bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  GoogleServiceSigninSuccessDetails details(username_, password_);
118bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  NotificationService::current()->Notify(
119bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      Source<Profile>(profile_),
121bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      Details<const GoogleServiceSigninSuccessDetails>(&details));
122bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
123bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  password_.clear();  // Don't need it anymore.
124bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
125bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetTokenService()->UpdateCredentials(last_result_);
126bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(profile_->GetTokenService()->AreCredentialsValid());
127bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  profile_->GetTokenService()->StartFetchingTokens();
128bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
129bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
130bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) {
131bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(key == kGetInfoEmailKey);
132bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  LOG(ERROR) << "Account is not associated with a valid email address. "
133bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen             << "Login failed.";
134bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  OnClientLoginFailure(GoogleServiceAuthError(
135bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
136bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
137bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
138bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) {
139bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  LOG(ERROR) << "Unable to retreive the canonical email address. Login failed.";
140bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  OnClientLoginFailure(error);
141bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
142bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
143bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenvoid SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) {
144bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  NotificationService::current()->Notify(
145bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      NotificationType::GOOGLE_SIGNIN_FAILED,
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      Source<Profile>(profile_),
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Details<const GoogleServiceAuthError>(&error));
148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
149731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // We don't sign-out if the password was valid and we're just dealing with
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // a second factor error, and we don't sign out if we're dealing with
151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // an invalid access code (again, because the password was valid).
152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool invalid_gaia = error.state() ==
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS;
154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (error.state() == GoogleServiceAuthError::TWO_FACTOR ||
155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      (had_two_factor_error_ && invalid_gaia)) {
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    had_two_factor_error_ = true;
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
160bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  SignOut();
161bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
162