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