ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / chromeos / login / signin / oauth2_login_manager.cc
blob15bda188f4ba569154996099928c29d8d67aa4c5
1 // Copyright 2014 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/signin/oauth2_login_manager.h"
7 #include <utility>
8 #include <vector>
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/profiles/profile.h"
16 #include "chrome/browser/signin/account_tracker_service_factory.h"
17 #include "chrome/browser/signin/chrome_signin_client_factory.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "components/signin/core/browser/account_tracker_service.h"
23 #include "components/signin/core/browser/profile_oauth2_token_service.h"
24 #include "components/signin/core/browser/signin_client.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/user_manager/user_manager.h"
27 #include "google_apis/gaia/gaia_auth_util.h"
28 #include "google_apis/gaia/gaia_constants.h"
29 #include "google_apis/gaia/gaia_urls.h"
30 #include "net/url_request/url_request_context_getter.h"
32 namespace chromeos {
34 namespace {
36 static const char kServiceScopeGetUserInfo[] =
37 "https://www.googleapis.com/auth/userinfo.email";
38 static const int kMaxRetries = 5;
40 } // namespace
42 OAuth2LoginManager::OAuth2LoginManager(Profile* user_profile)
43 : user_profile_(user_profile),
44 restore_strategy_(RESTORE_FROM_COOKIE_JAR),
45 state_(SESSION_RESTORE_NOT_STARTED) {
46 GetTokenService()->AddObserver(this);
48 // For telemetry, we mark session restore completed to avoid warnings from
49 // MergeSessionThrottle.
50 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
51 chromeos::switches::kDisableGaiaServices)) {
52 SetSessionRestoreState(SESSION_RESTORE_DONE);
56 OAuth2LoginManager::~OAuth2LoginManager() {
59 void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) {
60 observer_list_.AddObserver(observer);
63 void OAuth2LoginManager::RemoveObserver(
64 OAuth2LoginManager::Observer* observer) {
65 observer_list_.RemoveObserver(observer);
68 void OAuth2LoginManager::RestoreSession(
69 net::URLRequestContextGetter* auth_request_context,
70 SessionRestoreStrategy restore_strategy,
71 const std::string& oauth2_refresh_token,
72 const std::string& auth_code) {
73 DCHECK(user_profile_);
74 auth_request_context_ = auth_request_context;
75 restore_strategy_ = restore_strategy;
76 refresh_token_ = oauth2_refresh_token;
77 oauthlogin_access_token_ = std::string();
78 auth_code_ = auth_code;
79 session_restore_start_ = base::Time::Now();
80 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_PREPARING);
81 ContinueSessionRestore();
84 void OAuth2LoginManager::ContinueSessionRestore() {
85 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR ||
86 restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
87 FetchOAuth2Tokens();
88 return;
91 // Save passed OAuth2 refresh token.
92 if (restore_strategy_ == RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN) {
93 DCHECK(!refresh_token_.empty());
94 restore_strategy_ = RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
95 StoreOAuth2Token();
96 return;
99 DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN);
100 RestoreSessionFromSavedTokens();
103 void OAuth2LoginManager::RestoreSessionFromSavedTokens() {
104 ProfileOAuth2TokenService* token_service = GetTokenService();
105 const std::string& primary_account_id = GetPrimaryAccountId();
106 if (token_service->RefreshTokenIsAvailable(primary_account_id)) {
107 VLOG(1) << "OAuth2 refresh token is already loaded.";
108 VerifySessionCookies();
109 } else {
110 VLOG(1) << "Loading OAuth2 refresh token from database.";
112 // Flag user with unknown token status in case there are no saved tokens
113 // and OnRefreshTokenAvailable is not called. Flagging it here would
114 // cause user to go through Gaia in next login to obtain a new refresh
115 // token.
116 user_manager::UserManager::Get()->SaveUserOAuthStatus(
117 primary_account_id, user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN);
119 token_service->LoadCredentials(primary_account_id);
123 void OAuth2LoginManager::Stop() {
124 oauth2_token_fetcher_.reset();
125 login_verifier_.reset();
128 bool OAuth2LoginManager::ShouldBlockTabLoading() {
129 return state_ == SESSION_RESTORE_PREPARING ||
130 state_ == SESSION_RESTORE_IN_PROGRESS;
133 void OAuth2LoginManager::OnRefreshTokenAvailable(
134 const std::string& account_id) {
135 VLOG(1) << "OnRefreshTokenAvailable";
137 if (state_ == SESSION_RESTORE_NOT_STARTED)
138 return;
140 // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make
141 // sure to restore session cookies in the context of the correct account_id.
143 // Do not validate tokens for supervised users, as they don't actually have
144 // oauth2 token.
145 if (user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) {
146 VLOG(1) << "Logged in as supervised user, skip token validation.";
147 return;
149 // Only restore session cookies for the primary account in the profile.
150 if (GetPrimaryAccountId() == account_id) {
151 // Token is loaded. Undo the flagging before token loading.
152 user_manager::UserManager::Get()->SaveUserOAuthStatus(
153 account_id, user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
154 VerifySessionCookies();
158 ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() {
159 return ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_);
162 const std::string& OAuth2LoginManager::GetPrimaryAccountId() {
163 SigninManagerBase* signin_manager =
164 SigninManagerFactory::GetForProfile(user_profile_);
165 return signin_manager->GetAuthenticatedAccountId();
168 void OAuth2LoginManager::StoreOAuth2Token() {
169 const std::string& primary_account_id = GetPrimaryAccountId();
170 if (primary_account_id.empty()) {
171 GetAccountInfoOfRefreshToken(refresh_token_);
172 return;
175 UpdateCredentials(primary_account_id);
178 void OAuth2LoginManager::GetAccountInfoOfRefreshToken(
179 const std::string& refresh_token) {
180 gaia::OAuthClientInfo client_info;
181 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
182 client_info.client_id = gaia_urls->oauth2_chrome_client_id();
183 client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
185 account_info_fetcher_.reset(new gaia::GaiaOAuthClient(
186 auth_request_context_.get()));
187 account_info_fetcher_->RefreshToken(client_info, refresh_token,
188 std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries,
189 this);
192 void OAuth2LoginManager::UpdateCredentials(const std::string& account_id) {
193 DCHECK(!account_id.empty());
194 DCHECK(!refresh_token_.empty());
195 // |account_id| is assumed to be already canonicalized if it's an email.
196 GetTokenService()->UpdateCredentials(account_id, refresh_token_);
198 FOR_EACH_OBSERVER(Observer, observer_list_,
199 OnNewRefreshTokenAvaiable(user_profile_));
202 void OAuth2LoginManager::OnRefreshTokenResponse(
203 const std::string& access_token,
204 int expires_in_seconds) {
205 account_info_fetcher_->GetUserInfo(access_token, kMaxRetries, this);
208 void OAuth2LoginManager::OnGetUserInfoResponse(
209 scoped_ptr<base::DictionaryValue> user_info) {
210 account_info_fetcher_.reset();
212 std::string gaia_id;
213 std::string email;
214 user_info->GetString("id", &gaia_id);
215 user_info->GetString("email", &email);
217 AccountTrackerService* account_tracker =
218 AccountTrackerServiceFactory::GetForProfile(user_profile_);
219 account_tracker->SeedAccountInfo(gaia_id, email);
220 UpdateCredentials(account_tracker->PickAccountIdForAccount(gaia_id, email));
223 void OAuth2LoginManager::OnOAuthError() {
224 account_info_fetcher_.reset();
225 LOG(ERROR) << "Account info fetch failed!";
226 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
229 void OAuth2LoginManager::OnNetworkError(int response_code) {
230 account_info_fetcher_.reset();
231 LOG(ERROR) << "Account info fetch failed! response_code=" << response_code;
232 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
235 void OAuth2LoginManager::FetchOAuth2Tokens() {
236 DCHECK(auth_request_context_.get());
237 // If we have authenticated cookie jar, get OAuth1 token first, then fetch
238 // SID/LSID cookies through OAuthLogin call.
239 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR) {
240 SigninClient* signin_client =
241 ChromeSigninClientFactory::GetForProfile(user_profile_);
242 std::string signin_scoped_device_id =
243 signin_client->GetSigninScopedDeviceId();
245 oauth2_token_fetcher_.reset(
246 new OAuth2TokenFetcher(this, auth_request_context_.get()));
247 oauth2_token_fetcher_->StartExchangeFromCookies(std::string(),
248 signin_scoped_device_id);
249 } else if (restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
250 DCHECK(!auth_code_.empty());
251 oauth2_token_fetcher_.reset(
252 new OAuth2TokenFetcher(this,
253 g_browser_process->system_request_context()));
254 oauth2_token_fetcher_->StartExchangeFromAuthCode(auth_code_);
255 } else {
256 NOTREACHED();
257 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
261 void OAuth2LoginManager::OnOAuth2TokensAvailable(
262 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
263 VLOG(1) << "OAuth2 tokens fetched";
264 DCHECK(refresh_token_.empty());
265 refresh_token_.assign(oauth2_tokens.refresh_token);
266 oauthlogin_access_token_ = oauth2_tokens.access_token;
267 StoreOAuth2Token();
270 void OAuth2LoginManager::OnOAuth2TokensFetchFailed() {
271 LOG(ERROR) << "OAuth2 tokens fetch failed!";
272 RecordSessionRestoreOutcome(SESSION_RESTORE_TOKEN_FETCH_FAILED,
273 SESSION_RESTORE_FAILED);
276 void OAuth2LoginManager::VerifySessionCookies() {
277 DCHECK(!login_verifier_.get());
278 login_verifier_.reset(
279 new OAuth2LoginVerifier(this,
280 g_browser_process->system_request_context(),
281 user_profile_->GetRequestContext(),
282 oauthlogin_access_token_));
284 if (restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) {
285 login_verifier_->VerifyUserCookies(user_profile_);
286 return;
289 RestoreSessionCookies();
292 void OAuth2LoginManager::RestoreSessionCookies() {
293 SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS);
294 login_verifier_->VerifyProfileTokens(user_profile_);
297 void OAuth2LoginManager::Shutdown() {
298 GetTokenService()->RemoveObserver(this);
299 login_verifier_.reset();
300 oauth2_token_fetcher_.reset();
303 void OAuth2LoginManager::OnSessionMergeSuccess() {
304 VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded.";
305 RecordSessionRestoreOutcome(SESSION_RESTORE_SUCCESS,
306 SESSION_RESTORE_DONE);
309 void OAuth2LoginManager::OnSessionMergeFailure(bool connection_error) {
310 LOG(ERROR) << "OAuth2 refresh and GAIA token verification failed!"
311 << " connection_error: " << connection_error;
312 RecordSessionRestoreOutcome(SESSION_RESTORE_MERGE_SESSION_FAILED,
313 connection_error ?
314 SESSION_RESTORE_CONNECTION_FAILED :
315 SESSION_RESTORE_FAILED);
318 void OAuth2LoginManager::OnListAccountsSuccess(const std::string& data) {
319 MergeVerificationOutcome outcome = POST_MERGE_SUCCESS;
320 // Let's analyze which accounts we see logged in here:
321 std::vector<std::pair<std::string, bool> > accounts;
322 gaia::ParseListAccountsData(data, &accounts);
323 std::string user_email = gaia::CanonicalizeEmail(GetPrimaryAccountId());
324 if (!accounts.empty()) {
325 bool found = false;
326 bool first = true;
327 for (std::vector<std::pair<std::string, bool> >::const_iterator iter =
328 accounts.begin();
329 iter != accounts.end(); ++iter) {
330 if (gaia::CanonicalizeEmail(iter->first) == user_email) {
331 found = iter->second;
332 break;
335 first = false;
338 if (!found)
339 outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT;
340 else if (!first)
341 outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT;
343 } else {
344 outcome = POST_MERGE_NO_ACCOUNTS;
347 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
348 RecordCookiesCheckOutcome(is_pre_merge, outcome);
349 // If the primary account is missing during the initial cookie freshness
350 // check, try to restore GAIA session cookies form the OAuth2 tokens.
351 if (is_pre_merge) {
352 if (outcome != POST_MERGE_SUCCESS &&
353 outcome != POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT) {
354 RestoreSessionCookies();
355 } else {
356 // We are done with this account, it's GAIA cookies are legit.
357 RecordSessionRestoreOutcome(SESSION_RESTORE_NOT_NEEDED,
358 SESSION_RESTORE_DONE);
363 void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) {
364 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
365 RecordCookiesCheckOutcome(
366 is_pre_merge,
367 connection_error ? POST_MERGE_CONNECTION_FAILED :
368 POST_MERGE_VERIFICATION_FAILED);
369 if (is_pre_merge) {
370 if (!connection_error) {
371 // If we failed to get account list, our cookies might be stale so we
372 // need to attempt to restore them.
373 RestoreSessionCookies();
374 } else {
375 RecordSessionRestoreOutcome(SESSION_RESTORE_LISTACCOUNTS_FAILED,
376 SESSION_RESTORE_CONNECTION_FAILED);
381 void OAuth2LoginManager::RecordSessionRestoreOutcome(
382 SessionRestoreOutcome outcome,
383 OAuth2LoginManager::SessionRestoreState state) {
384 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
385 outcome,
386 SESSION_RESTORE_COUNT);
387 SetSessionRestoreState(state);
390 // static
391 void OAuth2LoginManager::RecordCookiesCheckOutcome(
392 bool is_pre_merge,
393 MergeVerificationOutcome outcome) {
394 if (is_pre_merge) {
395 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PreMergeVerification",
396 outcome,
397 POST_MERGE_COUNT);
398 } else {
399 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification",
400 outcome,
401 POST_MERGE_COUNT);
405 void OAuth2LoginManager::SetSessionRestoreState(
406 OAuth2LoginManager::SessionRestoreState state) {
407 if (state_ == state)
408 return;
410 state_ = state;
411 if (state == OAuth2LoginManager::SESSION_RESTORE_FAILED) {
412 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToFailure",
413 base::Time::Now() - session_restore_start_);
414 } else if (state == OAuth2LoginManager::SESSION_RESTORE_DONE) {
415 UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToSuccess",
416 base::Time::Now() - session_restore_start_);
419 FOR_EACH_OBSERVER(Observer, observer_list_,
420 OnSessionRestoreStateChanged(user_profile_, state_));
423 void OAuth2LoginManager::SetSessionRestoreStartForTesting(
424 const base::Time& time) {
425 session_restore_start_ = time;
428 } // namespace chromeos