1 // Copyright (c) 2013 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.
5 #include "chrome/browser/chromeos/login/oauth2_login_manager.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_util.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/login/user_manager.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chromeos/chromeos_switches.h"
21 #include "components/signin/core/browser/profile_oauth2_token_service.h"
22 #include "components/signin/core/browser/signin_manager.h"
23 #include "google_apis/gaia/gaia_auth_util.h"
24 #include "google_apis/gaia/gaia_constants.h"
25 #include "google_apis/gaia/gaia_urls.h"
26 #include "net/url_request/url_request_context_getter.h"
32 static const char kServiceScopeGetUserInfo[] =
33 "https://www.googleapis.com/auth/userinfo.email";
34 static const int kMaxRetries = 5;
38 OAuth2LoginManager::OAuth2LoginManager(Profile* user_profile)
39 : user_profile_(user_profile),
40 restore_strategy_(RESTORE_FROM_COOKIE_JAR),
41 state_(SESSION_RESTORE_NOT_STARTED) {
42 GetTokenService()->AddObserver(this);
43 if (CommandLine::ForCurrentProcess()->
44 HasSwitch(chromeos::switches::kOobeSkipPostLogin)) {
45 // For telemetry we should mark session restore completed to avoid
46 // warnings from MergeSessionThrottle.
47 SetSessionRestoreState(SESSION_RESTORE_DONE);
51 OAuth2LoginManager::~OAuth2LoginManager() {
54 void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) {
55 observer_list_.AddObserver(observer);
58 void OAuth2LoginManager::RemoveObserver(
59 OAuth2LoginManager::Observer* observer) {
60 observer_list_.RemoveObserver(observer);
63 void OAuth2LoginManager::RestoreSession(
64 net::URLRequestContextGetter* auth_request_context,
65 SessionRestoreStrategy restore_strategy,
66 const std::string& oauth2_refresh_token,
67 const std::string& auth_code) {
68 DCHECK(user_profile_);
69 auth_request_context_ = auth_request_context;
70 restore_strategy_ = restore_strategy;
71 refresh_token_ = oauth2_refresh_token;
72 oauthlogin_access_token_ = std::string();
73 auth_code_ = auth_code;
74 session_restore_start_ = base::Time::Now();
75 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_PREPARING);
76 ContinueSessionRestore();
79 void OAuth2LoginManager::ContinueSessionRestore() {
80 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR ||
81 restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
86 // Save passed OAuth2 refresh token.
87 if (restore_strategy_ == RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN) {
88 DCHECK(!refresh_token_.empty());
89 restore_strategy_ = RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
94 DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN);
95 RestoreSessionFromSavedTokens();
98 void OAuth2LoginManager::RestoreSessionFromSavedTokens() {
99 ProfileOAuth2TokenService* token_service = GetTokenService();
100 const std::string& primary_account_id = GetPrimaryAccountId();
101 if (token_service->RefreshTokenIsAvailable(primary_account_id)) {
102 LOG(WARNING) << "OAuth2 refresh token is already loaded.";
103 VerifySessionCookies();
105 LOG(WARNING) << "Loading OAuth2 refresh token from database.";
107 // Flag user with unknown token status in case there are no saved tokens
108 // and OnRefreshTokenAvailable is not called. Flagging it here would
109 // cause user to go through Gaia in next login to obtain a new refresh
111 UserManager::Get()->SaveUserOAuthStatus(primary_account_id,
112 User::OAUTH_TOKEN_STATUS_UNKNOWN);
114 token_service->LoadCredentials(primary_account_id);
118 void OAuth2LoginManager::Stop() {
119 oauth2_token_fetcher_.reset();
120 login_verifier_.reset();
123 bool OAuth2LoginManager::ShouldBlockTabLoading() {
124 return state_ == SESSION_RESTORE_PREPARING ||
125 state_ == SESSION_RESTORE_IN_PROGRESS;
128 void OAuth2LoginManager::OnRefreshTokenAvailable(
129 const std::string& account_id) {
130 LOG(WARNING) << "OnRefreshTokenAvailable";
132 if (state_ == SESSION_RESTORE_NOT_STARTED)
135 // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make
136 // sure to restore session cookies in the context of the correct account_id.
138 // Do not validate tokens for supervised users, as they don't actually have
140 if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
141 LOG(WARNING) << "Logged in as managed user, skip token validation.";
144 // Only restore session cookies for the primary account in the profile.
145 if (GetPrimaryAccountId() == account_id) {
146 // Token is loaded. Undo the flagging before token loading.
147 UserManager::Get()->SaveUserOAuthStatus(account_id,
148 User::OAUTH2_TOKEN_STATUS_VALID);
149 VerifySessionCookies();
153 ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() {
154 return ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_);
157 const std::string& OAuth2LoginManager::GetPrimaryAccountId() {
158 SigninManagerBase* signin_manager =
159 SigninManagerFactory::GetForProfile(user_profile_);
160 return signin_manager->GetAuthenticatedAccountId();
163 void OAuth2LoginManager::StoreOAuth2Token() {
164 const std::string& primary_account_id = GetPrimaryAccountId();
165 if (primary_account_id.empty()) {
166 GetAccountIdOfRefreshToken(refresh_token_);
170 OnGetUserEmailResponse(primary_account_id);
173 void OAuth2LoginManager::GetAccountIdOfRefreshToken(
174 const std::string& refresh_token) {
175 gaia::OAuthClientInfo client_info;
176 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
177 client_info.client_id = gaia_urls->oauth2_chrome_client_id();
178 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
180 account_id_fetcher_.reset(new gaia::GaiaOAuthClient(
181 auth_request_context_.get()));
182 account_id_fetcher_->RefreshToken(client_info, refresh_token,
183 std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries,
187 void OAuth2LoginManager::OnRefreshTokenResponse(
188 const std::string& access_token,
189 int expires_in_seconds) {
190 account_id_fetcher_->GetUserEmail(access_token, kMaxRetries, this);
193 void OAuth2LoginManager::OnGetUserEmailResponse(
194 const std::string& user_email) {
195 DCHECK(!refresh_token_.empty());
196 account_id_fetcher_.reset();
197 std::string canonicalized = gaia::CanonicalizeEmail(user_email);
198 GetTokenService()->UpdateCredentials(canonicalized, refresh_token_);
200 FOR_EACH_OBSERVER(Observer, observer_list_,
201 OnNewRefreshTokenAvaiable(user_profile_));
204 void OAuth2LoginManager::OnOAuthError() {
205 account_id_fetcher_.reset();
206 LOG(ERROR) << "Account id fetch failed!";
207 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
210 void OAuth2LoginManager::OnNetworkError(int response_code) {
211 account_id_fetcher_.reset();
212 LOG(ERROR) << "Account id fetch failed! response_code=" << response_code;
213 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
216 void OAuth2LoginManager::FetchOAuth2Tokens() {
217 DCHECK(auth_request_context_.get());
218 // If we have authenticated cookie jar, get OAuth1 token first, then fetch
219 // SID/LSID cookies through OAuthLogin call.
220 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR) {
221 oauth2_token_fetcher_.reset(
222 new OAuth2TokenFetcher(this, auth_request_context_.get()));
223 oauth2_token_fetcher_->StartExchangeFromCookies();
224 } else if (restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
225 DCHECK(!auth_code_.empty());
226 oauth2_token_fetcher_.reset(
227 new OAuth2TokenFetcher(this,
228 g_browser_process->system_request_context()));
229 oauth2_token_fetcher_->StartExchangeFromAuthCode(auth_code_);
232 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
236 void OAuth2LoginManager::OnOAuth2TokensAvailable(
237 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
238 VLOG(1) << "OAuth2 tokens fetched";
239 DCHECK(refresh_token_.empty());
240 refresh_token_.assign(oauth2_tokens.refresh_token);
241 oauthlogin_access_token_ = oauth2_tokens.access_token;
245 void OAuth2LoginManager::OnOAuth2TokensFetchFailed() {
246 LOG(ERROR) << "OAuth2 tokens fetch failed!";
247 RecordSessionRestoreOutcome(SESSION_RESTORE_TOKEN_FETCH_FAILED,
248 SESSION_RESTORE_FAILED);
251 void OAuth2LoginManager::VerifySessionCookies() {
252 DCHECK(!login_verifier_.get());
253 login_verifier_.reset(
254 new OAuth2LoginVerifier(this,
255 g_browser_process->system_request_context(),
256 user_profile_->GetRequestContext(),
257 oauthlogin_access_token_));
259 if (restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) {
260 login_verifier_->VerifyUserCookies(user_profile_);
264 RestoreSessionCookies();
267 void OAuth2LoginManager::RestoreSessionCookies() {
268 SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS);
269 login_verifier_->VerifyProfileTokens(user_profile_);
272 void OAuth2LoginManager::Shutdown() {
273 GetTokenService()->RemoveObserver(this);
274 login_verifier_.reset();
275 oauth2_token_fetcher_.reset();
278 void OAuth2LoginManager::OnSessionMergeSuccess() {
279 VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded.";
280 RecordSessionRestoreOutcome(SESSION_RESTORE_SUCCESS,
281 SESSION_RESTORE_DONE);
284 void OAuth2LoginManager::OnSessionMergeFailure(bool connection_error) {
285 LOG(ERROR) << "OAuth2 refresh and GAIA token verification failed!"
286 << " connection_error: " << connection_error;
287 RecordSessionRestoreOutcome(SESSION_RESTORE_MERGE_SESSION_FAILED,
289 SESSION_RESTORE_CONNECTION_FAILED :
290 SESSION_RESTORE_FAILED);
293 void OAuth2LoginManager::OnListAccountsSuccess(const std::string& data) {
294 MergeVerificationOutcome outcome = POST_MERGE_SUCCESS;
295 // Let's analyze which accounts we see logged in here:
296 std::vector<std::pair<std::string, bool> > accounts;
297 gaia::ParseListAccountsData(data, &accounts);
298 std::string user_email = gaia::CanonicalizeEmail(GetPrimaryAccountId());
299 if (!accounts.empty()) {
302 for (std::vector<std::pair<std::string, bool> >::const_iterator iter =
304 iter != accounts.end(); ++iter) {
305 if (gaia::CanonicalizeEmail(iter->first) == user_email) {
314 outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT;
316 outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT;
319 outcome = POST_MERGE_NO_ACCOUNTS;
322 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
323 RecordCookiesCheckOutcome(is_pre_merge, outcome);
324 // If the primary account is missing during the initial cookie freshness
325 // check, try to restore GAIA session cookies form the OAuth2 tokens.
327 if (outcome != POST_MERGE_SUCCESS &&
328 outcome != POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT) {
329 RestoreSessionCookies();
331 // We are done with this account, it's GAIA cookies are legit.
332 RecordSessionRestoreOutcome(SESSION_RESTORE_NOT_NEEDED,
333 SESSION_RESTORE_DONE);
338 void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) {
339 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
340 RecordCookiesCheckOutcome(
342 connection_error ? POST_MERGE_CONNECTION_FAILED :
343 POST_MERGE_VERIFICATION_FAILED);
345 if (!connection_error) {
346 // If we failed to get account list, our cookies might be stale so we
347 // need to attempt to restore them.
348 RestoreSessionCookies();
350 RecordSessionRestoreOutcome(SESSION_RESTORE_LISTACCOUNTS_FAILED,
351 SESSION_RESTORE_CONNECTION_FAILED);
356 void OAuth2LoginManager::RecordSessionRestoreOutcome(
357 SessionRestoreOutcome outcome,
358 OAuth2LoginManager::SessionRestoreState state) {
359 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
361 SESSION_RESTORE_COUNT);
362 SetSessionRestoreState(state);
366 void OAuth2LoginManager::RecordCookiesCheckOutcome(
368 MergeVerificationOutcome outcome) {
370 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PreMergeVerification",
374 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification",
380 void OAuth2LoginManager::SetSessionRestoreState(
381 OAuth2LoginManager::SessionRestoreState state) {
386 if (state == OAuth2LoginManager::SESSION_RESTORE_FAILED) {
387 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToFailure",
388 base::Time::Now() - session_restore_start_);
389 } else if (state == OAuth2LoginManager::SESSION_RESTORE_DONE) {
390 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToSuccess",
391 base::Time::Now() - session_restore_start_);
394 FOR_EACH_OBSERVER(Observer, observer_list_,
395 OnSessionRestoreStateChanged(user_profile_, state_));
398 void OAuth2LoginManager::SetSessionRestoreStartForTesting(
399 const base::Time& time) {
400 session_restore_start_ = time;
403 } // namespace chromeos