Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: chrome/browser/chromeos/login/oauth2_login_manager.cc

Issue 286933002: [cros login] Split login related classes into subfolders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix includes in new tests Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/chromeos/login/oauth2_login_manager.h"
6
7 #include <utility>
8 #include <vector>
9
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"
27
28 namespace chromeos {
29
30 namespace {
31
32 static const char kServiceScopeGetUserInfo[] =
33 "https://www.googleapis.com/auth/userinfo.email";
34 static const int kMaxRetries = 5;
35
36 } // namespace
37
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);
48 }
49 }
50
51 OAuth2LoginManager::~OAuth2LoginManager() {
52 }
53
54 void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) {
55 observer_list_.AddObserver(observer);
56 }
57
58 void OAuth2LoginManager::RemoveObserver(
59 OAuth2LoginManager::Observer* observer) {
60 observer_list_.RemoveObserver(observer);
61 }
62
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();
77 }
78
79 void OAuth2LoginManager::ContinueSessionRestore() {
80 if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR ||
81 restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
82 FetchOAuth2Tokens();
83 return;
84 }
85
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;
90 StoreOAuth2Token();
91 return;
92 }
93
94 DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN);
95 RestoreSessionFromSavedTokens();
96 }
97
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();
104 } else {
105 LOG(WARNING) << "Loading OAuth2 refresh token from database.";
106
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
110 // token.
111 UserManager::Get()->SaveUserOAuthStatus(primary_account_id,
112 User::OAUTH_TOKEN_STATUS_UNKNOWN);
113
114 token_service->LoadCredentials(primary_account_id);
115 }
116 }
117
118 void OAuth2LoginManager::Stop() {
119 oauth2_token_fetcher_.reset();
120 login_verifier_.reset();
121 }
122
123 bool OAuth2LoginManager::ShouldBlockTabLoading() {
124 return state_ == SESSION_RESTORE_PREPARING ||
125 state_ == SESSION_RESTORE_IN_PROGRESS;
126 }
127
128 void OAuth2LoginManager::OnRefreshTokenAvailable(
129 const std::string& account_id) {
130 LOG(WARNING) << "OnRefreshTokenAvailable";
131
132 if (state_ == SESSION_RESTORE_NOT_STARTED)
133 return;
134
135 // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make
136 // sure to restore session cookies in the context of the correct account_id.
137
138 // Do not validate tokens for supervised users, as they don't actually have
139 // oauth2 token.
140 if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
141 LOG(WARNING) << "Logged in as managed user, skip token validation.";
142 return;
143 }
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();
150 }
151 }
152
153 ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() {
154 return ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_);
155 }
156
157 const std::string& OAuth2LoginManager::GetPrimaryAccountId() {
158 SigninManagerBase* signin_manager =
159 SigninManagerFactory::GetForProfile(user_profile_);
160 return signin_manager->GetAuthenticatedAccountId();
161 }
162
163 void OAuth2LoginManager::StoreOAuth2Token() {
164 const std::string& primary_account_id = GetPrimaryAccountId();
165 if (primary_account_id.empty()) {
166 GetAccountIdOfRefreshToken(refresh_token_);
167 return;
168 }
169
170 OnGetUserEmailResponse(primary_account_id);
171 }
172
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();
179
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,
184 this);
185 }
186
187 void OAuth2LoginManager::OnRefreshTokenResponse(
188 const std::string& access_token,
189 int expires_in_seconds) {
190 account_id_fetcher_->GetUserEmail(access_token, kMaxRetries, this);
191 }
192
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_);
199
200 FOR_EACH_OBSERVER(Observer, observer_list_,
201 OnNewRefreshTokenAvaiable(user_profile_));
202 }
203
204 void OAuth2LoginManager::OnOAuthError() {
205 account_id_fetcher_.reset();
206 LOG(ERROR) << "Account id fetch failed!";
207 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
208 }
209
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);
214 }
215
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(std::string());
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_);
230 } else {
231 NOTREACHED();
232 SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
233 }
234 }
235
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;
242 StoreOAuth2Token();
243 }
244
245 void OAuth2LoginManager::OnOAuth2TokensFetchFailed() {
246 LOG(ERROR) << "OAuth2 tokens fetch failed!";
247 RecordSessionRestoreOutcome(SESSION_RESTORE_TOKEN_FETCH_FAILED,
248 SESSION_RESTORE_FAILED);
249 }
250
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_));
258
259 if (restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) {
260 login_verifier_->VerifyUserCookies(user_profile_);
261 return;
262 }
263
264 RestoreSessionCookies();
265 }
266
267 void OAuth2LoginManager::RestoreSessionCookies() {
268 SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS);
269 login_verifier_->VerifyProfileTokens(user_profile_);
270 }
271
272 void OAuth2LoginManager::Shutdown() {
273 GetTokenService()->RemoveObserver(this);
274 login_verifier_.reset();
275 oauth2_token_fetcher_.reset();
276 }
277
278 void OAuth2LoginManager::OnSessionMergeSuccess() {
279 VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded.";
280 RecordSessionRestoreOutcome(SESSION_RESTORE_SUCCESS,
281 SESSION_RESTORE_DONE);
282 }
283
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,
288 connection_error ?
289 SESSION_RESTORE_CONNECTION_FAILED :
290 SESSION_RESTORE_FAILED);
291 }
292
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()) {
300 bool found = false;
301 bool first = true;
302 for (std::vector<std::pair<std::string, bool> >::const_iterator iter =
303 accounts.begin();
304 iter != accounts.end(); ++iter) {
305 if (gaia::CanonicalizeEmail(iter->first) == user_email) {
306 found = true;
307 break;
308 }
309
310 first = false;
311 }
312
313 if (!found)
314 outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT;
315 else if (!first)
316 outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT;
317
318 } else {
319 outcome = POST_MERGE_NO_ACCOUNTS;
320 }
321
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.
326 if (is_pre_merge) {
327 if (outcome != POST_MERGE_SUCCESS &&
328 outcome != POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT) {
329 RestoreSessionCookies();
330 } else {
331 // We are done with this account, it's GAIA cookies are legit.
332 RecordSessionRestoreOutcome(SESSION_RESTORE_NOT_NEEDED,
333 SESSION_RESTORE_DONE);
334 }
335 }
336 }
337
338 void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) {
339 bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
340 RecordCookiesCheckOutcome(
341 is_pre_merge,
342 connection_error ? POST_MERGE_CONNECTION_FAILED :
343 POST_MERGE_VERIFICATION_FAILED);
344 if (is_pre_merge) {
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();
349 } else {
350 RecordSessionRestoreOutcome(SESSION_RESTORE_LISTACCOUNTS_FAILED,
351 SESSION_RESTORE_CONNECTION_FAILED);
352 }
353 }
354 }
355
356 void OAuth2LoginManager::RecordSessionRestoreOutcome(
357 SessionRestoreOutcome outcome,
358 OAuth2LoginManager::SessionRestoreState state) {
359 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
360 outcome,
361 SESSION_RESTORE_COUNT);
362 SetSessionRestoreState(state);
363 }
364
365 // static
366 void OAuth2LoginManager::RecordCookiesCheckOutcome(
367 bool is_pre_merge,
368 MergeVerificationOutcome outcome) {
369 if (is_pre_merge) {
370 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PreMergeVerification",
371 outcome,
372 POST_MERGE_COUNT);
373 } else {
374 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification",
375 outcome,
376 POST_MERGE_COUNT);
377 }
378 }
379
380 void OAuth2LoginManager::SetSessionRestoreState(
381 OAuth2LoginManager::SessionRestoreState state) {
382 if (state_ == state)
383 return;
384
385 state_ = 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_);
392 }
393
394 FOR_EACH_OBSERVER(Observer, observer_list_,
395 OnSessionRestoreStateChanged(user_profile_, state_));
396 }
397
398 void OAuth2LoginManager::SetSessionRestoreStartForTesting(
399 const base::Time& time) {
400 session_restore_start_ = time;
401 }
402
403 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/login/oauth2_login_manager.h ('k') | chrome/browser/chromeos/login/oauth2_login_manager_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698