• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/signin/signin_manager.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/command_line.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/profiles/profile_io_data.h"
19 #include "chrome/browser/signin/about_signin_internals.h"
20 #include "chrome/browser/signin/about_signin_internals_factory.h"
21 #include "chrome/browser/signin/local_auth.h"
22 #include "chrome/browser/signin/profile_oauth2_token_service.h"
23 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
24 #include "chrome/browser/signin/signin_account_id_helper.h"
25 #include "chrome/browser/signin/signin_global_error.h"
26 #include "chrome/browser/signin/signin_internals_util.h"
27 #include "chrome/browser/signin/signin_manager_cookie_helper.h"
28 #include "chrome/browser/signin/signin_manager_delegate.h"
29 #include "chrome/browser/signin/signin_manager_factory.h"
30 #include "chrome/browser/ui/global_error/global_error_service.h"
31 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "chrome/common/pref_names.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "google_apis/gaia/gaia_auth_fetcher.h"
38 #include "google_apis/gaia/gaia_auth_util.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "google_apis/gaia/gaia_urls.h"
41 #include "net/base/escape.h"
42 #include "net/url_request/url_request_context.h"
43 #include "third_party/icu/source/i18n/unicode/regex.h"
44 
45 using namespace signin_internals_util;
46 
47 using content::BrowserThread;
48 
49 namespace {
50 
51 const char kGetInfoDisplayEmailKey[] = "displayEmail";
52 const char kGetInfoEmailKey[] = "email";
53 
54 const int kInvalidProcessId = -1;
55 
56 const char kChromiumSyncService[] = "service=chromiumsync";
57 
58 }  // namespace
59 
60 // Under the covers, we use a dummy chrome-extension ID to serve the purposes
61 // outlined in the .h file comment for this string.
62 const char* SigninManager::kChromeSigninEffectiveSite =
63     "chrome-extension://acfccoigjajmmgbhpfbjnpckhjjegnih";
64 
65 // static
IsWebBasedSigninFlowURL(const GURL & url)66 bool SigninManager::IsWebBasedSigninFlowURL(const GURL& url) {
67   GURL effective(kChromeSigninEffectiveSite);
68   if (url.SchemeIs(effective.scheme().c_str()) &&
69       url.host() == effective.host()) {
70     return true;
71   }
72 
73   GURL service_login(GaiaUrls::GetInstance()->service_login_url());
74   if (url.GetOrigin() != service_login.GetOrigin())
75     return false;
76 
77   // Any login UI URLs with signin=chromiumsync should be considered a web
78   // URL (relies on GAIA keeping the "service=chromiumsync" query string
79   // fragment present even when embedding inside a "continue" parameter).
80   return net::UnescapeURLComponent(
81       url.query(), net::UnescapeRule::URL_SPECIAL_CHARS)
82           .find(kChromiumSyncService) != std::string::npos;
83 }
84 
SigninManager(scoped_ptr<SigninManagerDelegate> delegate)85 SigninManager::SigninManager(scoped_ptr<SigninManagerDelegate> delegate)
86     : prohibit_signout_(false),
87       had_two_factor_error_(false),
88       type_(SIGNIN_TYPE_NONE),
89       weak_pointer_factory_(this),
90       signin_process_id_(kInvalidProcessId),
91       delegate_(delegate.Pass()) {
92 }
93 
SetSigninProcess(int process_id)94 void SigninManager::SetSigninProcess(int process_id) {
95   if (process_id == signin_process_id_)
96     return;
97   DLOG_IF(WARNING, signin_process_id_ != kInvalidProcessId) <<
98       "Replacing in-use signin process.";
99   signin_process_id_ = process_id;
100   const content::RenderProcessHost* process =
101       content::RenderProcessHost::FromID(process_id);
102   DCHECK(process);
103   registrar_.Add(this,
104                  content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
105                  content::Source<content::RenderProcessHost>(process));
106 }
107 
ClearSigninProcess()108 void SigninManager::ClearSigninProcess() {
109   signin_process_id_ = kInvalidProcessId;
110 }
111 
IsSigninProcess(int process_id) const112 bool SigninManager::IsSigninProcess(int process_id) const {
113   return process_id == signin_process_id_;
114 }
115 
HasSigninProcess() const116 bool SigninManager::HasSigninProcess() const {
117   return signin_process_id_ != kInvalidProcessId;
118 }
119 
~SigninManager()120 SigninManager::~SigninManager() {
121 }
122 
InitTokenService()123 void SigninManager::InitTokenService() {
124   ProfileOAuth2TokenService* token_service =
125       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
126   if (token_service && !GetAuthenticatedUsername().empty())
127     token_service->LoadCredentials();
128 }
129 
SigninTypeToString(SigninManager::SigninType type)130 std::string SigninManager::SigninTypeToString(
131     SigninManager::SigninType type) {
132   switch (type) {
133     case SIGNIN_TYPE_NONE:
134       return "No Signin";
135     case SIGNIN_TYPE_WITH_CREDENTIALS:
136       return "Signin with credentials";
137     case SIGNIN_TYPE_WITH_OAUTH_CODE:
138       return "Signin with oauth code";
139   }
140 
141   NOTREACHED();
142   return std::string();
143 }
144 
PrepareForSignin(SigninType type,const std::string & username,const std::string & password)145 bool SigninManager::PrepareForSignin(SigninType type,
146                                      const std::string& username,
147                                      const std::string& password) {
148   DCHECK(possibly_invalid_username_.empty() ||
149          possibly_invalid_username_ == username);
150   DCHECK(!username.empty());
151 
152   if (!IsAllowedUsername(username)) {
153     // Account is not allowed by admin policy.
154     HandleAuthError(GoogleServiceAuthError(
155         GoogleServiceAuthError::ACCOUNT_DISABLED), true);
156     return false;
157   }
158 
159   // This attempt is either 1) the user trying to establish initial sync, or
160   // 2) trying to refresh credentials for an existing username.  If it is 2, we
161   // need to try again, but take care to leave state around tracking that the
162   // user has successfully signed in once before with this username, so that on
163   // restart we don't think sync setup has never completed.
164   ClearTransientSigninData();
165   type_ = type;
166   possibly_invalid_username_.assign(username);
167   password_.assign(password);
168 
169   client_login_.reset(new GaiaAuthFetcher(this,
170                                           GaiaConstants::kChromeSource,
171                                           profile_->GetRequestContext()));
172   NotifyDiagnosticsObservers(SIGNIN_TYPE, SigninTypeToString(type));
173   return true;
174 }
175 
StartSignInWithCredentials(const std::string & session_index,const std::string & username,const std::string & password,const OAuthTokenFetchedCallback & callback)176 void SigninManager::StartSignInWithCredentials(
177     const std::string& session_index,
178     const std::string& username,
179     const std::string& password,
180     const OAuthTokenFetchedCallback& callback) {
181   DCHECK(GetAuthenticatedUsername().empty() ||
182          gaia::AreEmailsSame(username, GetAuthenticatedUsername()));
183 
184   if (!PrepareForSignin(SIGNIN_TYPE_WITH_CREDENTIALS, username, password))
185     return;
186 
187   // Store our callback.
188   DCHECK(oauth_token_fetched_callback_.is_null());
189   oauth_token_fetched_callback_ = callback;
190 
191   if (password.empty()) {
192     // Chrome must verify the GAIA cookies first if auto sign-in is triggered
193     // with no password provided. This is to protect Chrome against forged
194     // GAIA cookies from a super-domain.
195     VerifyGaiaCookiesBeforeSignIn(session_index);
196   } else {
197     // This function starts with the current state of the web session's cookie
198     // jar and mints a new ClientLogin-style SID/LSID pair.  This involves going
199     // through the follow process or requests to GAIA and LSO:
200     //
201     // - call /o/oauth2/programmatic_auth with the returned token to get oauth2
202     //   access and refresh tokens
203     // - call /accounts/OAuthLogin with the oauth2 access token and get SID/LSID
204     //   pair for use by the token service
205     //
206     // The resulting SID/LSID can then be used just as if
207     // client_login_->StartClientLogin() had completed successfully.
208     client_login_->StartCookieForOAuthLoginTokenExchange(session_index);
209   }
210 }
211 
StartSignInWithOAuthCode(const std::string & username,const std::string & password,const std::string & oauth_code,const OAuthTokenFetchedCallback & callback)212 void SigninManager::StartSignInWithOAuthCode(
213     const std::string& username,
214     const std::string& password,
215     const std::string& oauth_code,
216     const OAuthTokenFetchedCallback& callback) {
217   DCHECK(GetAuthenticatedUsername().empty() ||
218          gaia::AreEmailsSame(username, GetAuthenticatedUsername()));
219 
220   if (!PrepareForSignin(SIGNIN_TYPE_WITH_OAUTH_CODE, username, password))
221     return;
222 
223   DCHECK(oauth_token_fetched_callback_.is_null());
224   oauth_token_fetched_callback_ = callback;
225 
226   client_login_->StartAuthCodeForOAuth2TokenExchange(oauth_code);
227 }
228 
VerifyGaiaCookiesBeforeSignIn(const std::string & session_index)229 void SigninManager::VerifyGaiaCookiesBeforeSignIn(
230     const std::string& session_index) {
231   scoped_refptr<SigninManagerCookieHelper> cookie_helper(
232       new SigninManagerCookieHelper(profile_->GetRequestContext()));
233   cookie_helper->StartFetchingGaiaCookiesOnUIThread(
234       base::Bind(&SigninManager::OnGaiaCookiesFetched,
235                  weak_pointer_factory_.GetWeakPtr(), session_index));
236 }
237 
OnGaiaCookiesFetched(const std::string session_index,const net::CookieList & cookie_list)238 void SigninManager::OnGaiaCookiesFetched(
239     const std::string session_index, const net::CookieList& cookie_list) {
240   net::CookieList::const_iterator it;
241   bool success = false;
242   for (it = cookie_list.begin(); it != cookie_list.end(); ++it) {
243     // Make sure the LSID cookie is set on the GAIA host, instead of a super-
244     // domain.
245     if (it->Name() == "LSID") {
246       if (it->IsHostCookie() && it->IsHttpOnly() && it->IsSecure()) {
247         // Found a valid LSID cookie. Continue loop to make sure we don't have
248         // invalid LSID cookies on any super-domain.
249         success = true;
250       } else {
251         success = false;
252         break;
253       }
254     }
255   }
256 
257   if (success) {
258     client_login_->StartCookieForOAuthLoginTokenExchange(session_index);
259   } else {
260     HandleAuthError(GoogleServiceAuthError(
261         GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), true);
262   }
263 }
264 
CopyCredentialsFrom(const SigninManager & source)265 void SigninManager::CopyCredentialsFrom(const SigninManager& source) {
266   DCHECK_NE(this, &source);
267   possibly_invalid_username_ = source.possibly_invalid_username_;
268   last_result_ = source.last_result_;
269   temp_oauth_login_tokens_ = source.temp_oauth_login_tokens_;
270 }
271 
ClearTransientSigninData()272 void SigninManager::ClearTransientSigninData() {
273   DCHECK(IsInitialized());
274 
275   client_login_.reset();
276   last_result_ = ClientLoginResult();
277   possibly_invalid_username_.clear();
278   password_.clear();
279   had_two_factor_error_ = false;
280   type_ = SIGNIN_TYPE_NONE;
281   temp_oauth_login_tokens_ = ClientOAuthResult();
282   oauth_token_fetched_callback_.Reset();
283 }
284 
HandleAuthError(const GoogleServiceAuthError & error,bool clear_transient_data)285 void SigninManager::HandleAuthError(const GoogleServiceAuthError& error,
286                                     bool clear_transient_data) {
287   // In some cases, the user should not be signed out.  For example, the failure
288   // may be due to a captcha or OTP challenge.  In these cases, the transient
289   // data must be kept to properly handle the follow up. This routine clears
290   // the data before sending out the notification so the SigninManager is no
291   // longer in the AuthInProgress state when the notification goes out.
292   if (clear_transient_data)
293     ClearTransientSigninData();
294 
295   content::NotificationService::current()->Notify(
296       chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
297       content::Source<Profile>(profile_),
298       content::Details<const GoogleServiceAuthError>(&error));
299 }
300 
SignOut()301 void SigninManager::SignOut() {
302   DCHECK(IsInitialized());
303 
304   if (GetAuthenticatedUsername().empty()) {
305     if (AuthInProgress()) {
306       // If the user is in the process of signing in, then treat a call to
307       // SignOut as a cancellation request.
308       GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
309       HandleAuthError(error, true);
310     } else {
311       // Clean up our transient data and exit if we aren't signed in.
312       // This avoids a perf regression from clearing out the TokenDB if
313       // SignOut() is invoked on startup to clean up any incomplete previous
314       // signin attempts.
315       ClearTransientSigninData();
316     }
317     return;
318   }
319 
320   if (prohibit_signout_) {
321     DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited";
322     return;
323   }
324 
325   ClearTransientSigninData();
326 
327   GoogleServiceSignoutDetails details(GetAuthenticatedUsername());
328   clear_authenticated_username();
329   profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername);
330 
331   // Erase (now) stale information from AboutSigninInternals.
332   NotifyDiagnosticsObservers(USERNAME, "");
333 
334   content::NotificationService::current()->Notify(
335       chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
336       content::Source<Profile>(profile_),
337       content::Details<const GoogleServiceSignoutDetails>(&details));
338   ProfileOAuth2TokenService* token_service =
339       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
340   token_service->RevokeAllCredentials();
341 }
342 
Initialize(Profile * profile,PrefService * local_state)343 void SigninManager::Initialize(Profile* profile, PrefService* local_state) {
344   SigninManagerBase::Initialize(profile, local_state);
345 
346   InitTokenService();
347 
348   // local_state can be null during unit tests.
349   if (local_state) {
350     local_state_pref_registrar_.Init(local_state);
351     local_state_pref_registrar_.Add(
352         prefs::kGoogleServicesUsernamePattern,
353         base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged,
354                    weak_pointer_factory_.GetWeakPtr()));
355   }
356   signin_allowed_.Init(prefs::kSigninAllowed, profile_->GetPrefs(),
357       base::Bind(&SigninManager::OnSigninAllowedPrefChanged,
358                  base::Unretained(this)));
359 
360   std::string user = profile_->GetPrefs()->GetString(
361       prefs::kGoogleServicesUsername);
362   if ((!user.empty() && !IsAllowedUsername(user)) || !IsSigninAllowed()) {
363     // User is signed in, but the username is invalid - the administrator must
364     // have changed the policy since the last signin, so sign out the user.
365     SignOut();
366   }
367 
368   account_id_helper_.reset(new SigninAccountIdHelper(profile));
369 }
370 
Shutdown()371 void SigninManager::Shutdown() {
372   local_state_pref_registrar_.RemoveAll();
373   account_id_helper_.reset();
374   SigninManagerBase::Shutdown();
375 }
376 
OnGoogleServicesUsernamePatternChanged()377 void SigninManager::OnGoogleServicesUsernamePatternChanged() {
378   if (!GetAuthenticatedUsername().empty() &&
379       !IsAllowedUsername(GetAuthenticatedUsername())) {
380     // Signed in user is invalid according to the current policy so sign
381     // the user out.
382     SignOut();
383   }
384 }
385 
IsSigninAllowed() const386 bool SigninManager::IsSigninAllowed() const {
387   return signin_allowed_.GetValue();
388 }
389 
390 // static
IsSigninAllowedOnIOThread(ProfileIOData * io_data)391 bool SigninManager::IsSigninAllowedOnIOThread(ProfileIOData* io_data) {
392   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
393   return io_data->signin_allowed()->GetValue();
394 }
395 
OnSigninAllowedPrefChanged()396 void SigninManager::OnSigninAllowedPrefChanged() {
397   if (!IsSigninAllowed())
398     SignOut();
399 }
400 
401 // static
IsUsernameAllowedByPolicy(const std::string & username,const std::string & policy)402 bool SigninManager::IsUsernameAllowedByPolicy(const std::string& username,
403                                               const std::string& policy) {
404   if (policy.empty())
405     return true;
406 
407   // Patterns like "*@foo.com" are not accepted by our regex engine (since they
408   // are not valid regular expressions - they should instead be ".*@foo.com").
409   // For convenience, detect these patterns and insert a "." character at the
410   // front.
411   base::string16 pattern = UTF8ToUTF16(policy);
412   if (pattern[0] == L'*')
413     pattern.insert(pattern.begin(), L'.');
414 
415   // See if the username matches the policy-provided pattern.
416   UErrorCode status = U_ZERO_ERROR;
417   const icu::UnicodeString icu_pattern(pattern.data(), pattern.length());
418   icu::RegexMatcher matcher(icu_pattern, UREGEX_CASE_INSENSITIVE, status);
419   if (!U_SUCCESS(status)) {
420     LOG(ERROR) << "Invalid login regex: " << pattern << ", status: " << status;
421     // If an invalid pattern is provided, then prohibit *all* logins (better to
422     // break signin than to quietly allow users to sign in).
423     return false;
424   }
425   base::string16 username16 = UTF8ToUTF16(username);
426   icu::UnicodeString icu_input(username16.data(), username16.length());
427   matcher.reset(icu_input);
428   status = U_ZERO_ERROR;
429   UBool match = matcher.matches(status);
430   DCHECK(U_SUCCESS(status));
431   return !!match;  // !! == convert from UBool to bool.
432 }
433 
IsAllowedUsername(const std::string & username) const434 bool SigninManager::IsAllowedUsername(const std::string& username) const {
435   const PrefService* local_state = local_state_pref_registrar_.prefs();
436   if (!local_state)
437     return true; // In a unit test with no local state - all names are allowed.
438 
439   std::string pattern = local_state->GetString(
440       prefs::kGoogleServicesUsernamePattern);
441   return IsUsernameAllowedByPolicy(username, pattern);
442 }
443 
AuthInProgress() const444 bool SigninManager::AuthInProgress() const {
445   return !possibly_invalid_username_.empty();
446 }
447 
GetUsernameForAuthInProgress() const448 const std::string& SigninManager::GetUsernameForAuthInProgress() const {
449   return possibly_invalid_username_;
450 }
451 
OnGetUserInfoKeyNotFound(const std::string & key)452 void SigninManager::OnGetUserInfoKeyNotFound(const std::string& key) {
453   DCHECK(key == kGetInfoDisplayEmailKey || key == kGetInfoEmailKey);
454   LOG(ERROR) << "Account is not associated with a valid email address. "
455              << "Login failed.";
456   OnClientLoginFailure(GoogleServiceAuthError(
457       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
458 }
459 
DisableOneClickSignIn(Profile * profile)460 void SigninManager::DisableOneClickSignIn(Profile* profile) {
461   PrefService* pref_service = profile->GetPrefs();
462   pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false);
463 }
464 
OnClientLoginSuccess(const ClientLoginResult & result)465 void SigninManager::OnClientLoginSuccess(const ClientLoginResult& result) {
466   last_result_ = result;
467   // Update signin_internals_
468   NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, "Successful");
469   // Make a request for the canonical email address and services.
470   client_login_->StartGetUserInfo(result.lsid);
471 }
472 
OnClientLoginFailure(const GoogleServiceAuthError & error)473 void SigninManager::OnClientLoginFailure(const GoogleServiceAuthError& error) {
474   // If we got a bad ASP, prompt for an ASP again by forcing another TWO_FACTOR
475   // error.  This function does not call HandleAuthError() because dealing
476   // with TWO_FACTOR errors needs special handling: we don't want to clear the
477   // transient signin data in such error cases.
478   bool invalid_gaia = error.state() ==
479       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS;
480 
481   GoogleServiceAuthError current_error =
482       (invalid_gaia && had_two_factor_error_) ?
483       GoogleServiceAuthError(GoogleServiceAuthError::TWO_FACTOR) : error;
484 
485   if (current_error.state() == GoogleServiceAuthError::TWO_FACTOR)
486     had_two_factor_error_ = true;
487 
488   NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, error.ToString());
489   HandleAuthError(current_error, !had_two_factor_error_);
490 }
491 
OnClientOAuthSuccess(const ClientOAuthResult & result)492 void SigninManager::OnClientOAuthSuccess(const ClientOAuthResult& result) {
493   DVLOG(1) << "SigninManager::OnClientOAuthSuccess access_token="
494            << result.access_token;
495 
496   NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, "Successful");
497 
498   switch (type_) {
499     case SIGNIN_TYPE_WITH_CREDENTIALS:
500     case SIGNIN_TYPE_WITH_OAUTH_CODE:
501       temp_oauth_login_tokens_ = result;
502       client_login_->StartOAuthLogin(result.access_token,
503                                      GaiaConstants::kGaiaService);
504       break;
505     default:
506       NOTREACHED();
507       break;
508   }
509 }
510 
OnClientOAuthFailure(const GoogleServiceAuthError & error)511 void SigninManager::OnClientOAuthFailure(const GoogleServiceAuthError& error) {
512   bool clear_transient_data = true;
513   NotifyDiagnosticsObservers(OAUTH_LOGIN_STATUS, error.ToString());
514   LOG(WARNING) << "SigninManager::OnClientOAuthFailure";
515   HandleAuthError(error, clear_transient_data);
516 }
517 
OnGetUserInfoSuccess(const UserInfoMap & data)518 void SigninManager::OnGetUserInfoSuccess(const UserInfoMap& data) {
519   NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, "Successful");
520 
521   UserInfoMap::const_iterator email_iter = data.find(kGetInfoEmailKey);
522   UserInfoMap::const_iterator display_email_iter =
523       data.find(kGetInfoDisplayEmailKey);
524   if (email_iter == data.end()) {
525     OnGetUserInfoKeyNotFound(kGetInfoEmailKey);
526     return;
527   }
528   if (display_email_iter == data.end()) {
529     OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey);
530     return;
531   }
532   DCHECK(email_iter->first == kGetInfoEmailKey);
533   DCHECK(display_email_iter->first == kGetInfoDisplayEmailKey);
534 
535   // When signing in with credentials, the possibly invalid name is the Gaia
536   // display name. If the name returned by GetUserInfo does not match what is
537   // expected, return an error.
538   if (type_ == SIGNIN_TYPE_WITH_CREDENTIALS &&
539       !gaia::AreEmailsSame(display_email_iter->second,
540                            possibly_invalid_username_)) {
541     OnGetUserInfoKeyNotFound(kGetInfoDisplayEmailKey);
542     return;
543   }
544 
545   possibly_invalid_username_ = email_iter->second;
546 
547   if (!oauth_token_fetched_callback_.is_null() &&
548       !temp_oauth_login_tokens_.refresh_token.empty()) {
549     oauth_token_fetched_callback_.Run(temp_oauth_login_tokens_.refresh_token);
550   } else {
551     // No oauth token or callback, so just complete our pending signin.
552     CompletePendingSignin();
553   }
554 }
555 
CompletePendingSignin()556 void SigninManager::CompletePendingSignin() {
557   DCHECK(!possibly_invalid_username_.empty());
558   OnSignedIn(possibly_invalid_username_);
559 
560   DCHECK(!temp_oauth_login_tokens_.refresh_token.empty());
561   DCHECK(!GetAuthenticatedUsername().empty());
562   ProfileOAuth2TokenService* token_service =
563     ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
564   token_service->UpdateCredentials(GetAuthenticatedUsername(),
565                                    temp_oauth_login_tokens_.refresh_token);
566   temp_oauth_login_tokens_ = ClientOAuthResult();
567 }
568 
OnExternalSigninCompleted(const std::string & username)569 void SigninManager::OnExternalSigninCompleted(const std::string& username) {
570   OnSignedIn(username);
571 }
572 
OnSignedIn(const std::string & username)573 void SigninManager::OnSignedIn(const std::string& username) {
574   SetAuthenticatedUsername(username);
575   possibly_invalid_username_.clear();
576   profile_->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
577                                   GetAuthenticatedUsername());
578 
579   GoogleServiceSigninSuccessDetails details(GetAuthenticatedUsername(),
580                                             password_);
581   content::NotificationService::current()->Notify(
582       chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
583       content::Source<Profile>(profile_),
584       content::Details<const GoogleServiceSigninSuccessDetails>(&details));
585 
586 #if !defined(OS_ANDROID)
587   // Don't store password hash except for users of new profile features.
588   if (CommandLine::ForCurrentProcess()->HasSwitch(
589           switches::kNewProfileManagement)) {
590     chrome::SetLocalAuthCredentials(profile_, password_);
591   }
592 #endif
593 
594   password_.clear();  // Don't need it anymore.
595   DisableOneClickSignIn(profile_);  // Don't ever offer again.
596 }
597 
OnGetUserInfoFailure(const GoogleServiceAuthError & error)598 void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) {
599   LOG(ERROR) << "Unable to retreive the canonical email address. Login failed.";
600   NotifyDiagnosticsObservers(GET_USER_INFO_STATUS, error.ToString());
601   // REVIEW: why does this call OnClientLoginFailure?
602   OnClientLoginFailure(error);
603 }
604 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)605 void SigninManager::Observe(int type,
606                             const content::NotificationSource& source,
607                             const content::NotificationDetails& details) {
608   DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type);
609 
610   // It's possible we're listening to a "stale" renderer because it was
611   // replaced with a new process by process-per-site. In either case,
612   // stop listening to it, but only reset signin_process_id_ tracking
613   // if this was from the current signin process.
614   registrar_.Remove(this,
615                     content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
616                     source);
617   if (signin_process_id_ ==
618       content::Source<content::RenderProcessHost>(source)->GetID()) {
619     signin_process_id_ = kInvalidProcessId;
620   }
621 }
622 
ProhibitSignout(bool prohibit_signout)623 void SigninManager::ProhibitSignout(bool prohibit_signout) {
624   prohibit_signout_ = prohibit_signout;
625 }
626 
IsSignoutProhibited() const627 bool SigninManager::IsSignoutProhibited() const {
628   return prohibit_signout_;
629 }
630