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

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

Issue 11649055: OAuth2 sign-in flow for ChromeOS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: wired policy with OAuth2 path Created 7 years, 11 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/oauth_login_manager.h"
6
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/string_util.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chromeos/login/user_manager.h"
12 #include "chrome/browser/policy/browser_policy_connector.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/signin/token_service.h"
16 #include "chrome/browser/signin/token_service_factory.h"
17 #include "chrome/common/chrome_notification_types.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/pref_names.h"
20 #include "content/public/browser/notification_observer.h"
Joao da Silva 2013/01/11 16:45:07 Already in .h
zel 2013/01/11 19:51:16 Done.
21 #include "content/public/browser/notification_service.h"
22 #include "google_apis/gaia/gaia_auth_fetcher.h"
23 #include "google_apis/gaia/gaia_constants.h"
24 #include "net/url_request/url_request_context_getter.h"
25
26 using content::BrowserThread;
27
28 namespace {
29
30 // OAuth token verification max retry count.
31 const int kMaxCookieRecoveryAttemptCount = 5;
32 // OAuth token verification retry delay in milliseconds.
33 const int kCookieRecoveryRestartDelay = 10000;
Joao da Silva 2013/01/11 16:45:07 These 2 aren't used.
zel 2013/01/11 19:51:16 Done.
34
35 } // namespace
36
37
38 namespace chromeos {
39
40 // OAuthLoginManagerFactory.
41 OAuthLoginManager* OAuthLoginManagerFactory::Create(
42 OAuthLoginManager::Delegate* delegate) {
43 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kForceOAuth2))
44 return new OAuth2LoginManager(delegate);
45
46 return new OAuth1LoginManager(delegate);
47 }
48
49 // OAuthLoginManager.
50
51 void OAuthLoginManager::CompleteAuthentication() {
52 delegate_->OnCompletedAuthentication(user_profile_);
53 TokenService* token_service =
54 TokenServiceFactory::GetForProfile(user_profile_);
55 if (token_service->AreCredentialsValid())
56 token_service->StartFetchingTokens();
57 }
58
59 OAuthLoginManager::OAuthLoginManager(Delegate* delegate)
60 : delegate_(delegate),
61 user_profile_(NULL),
62 restore_from_auth_cookies_(false),
63 state_(SESSION_RESTORE_NOT_STARTED) {
64 }
65
66 // OAuth2LoginManager.
67
68 OAuth2LoginManager::OAuth2LoginManager(OAuthLoginManager::Delegate* delegate)
69 : OAuthLoginManager(delegate),
70 loading_reported_(false),
71 restore_attempt_count_(0) {
72 }
73
74 void OAuth2LoginManager::RestoreSession(
75 Profile* user_profile,
76 net::URLRequestContextGetter* auth_request_context,
77 bool restore_from_auth_cookies) {
78 // TODO(zelidrag): Remove eventualy the next line in some future milestone.
79 RemoveLegacyTokens();
80
81 user_profile_ = user_profile;
82 auth_request_context_ = auth_request_context;
83 state_ = OAuthLoginManager::SESSION_RESTORE_IN_PROGRESS;
84
85 // Reuse the access token fetched by the OAuth2PolicyFetcher, if it was
86 // used to fetch policies before Profile creation.
87 if (oauth2_policy_fetcher_.get() &&
88 oauth2_policy_fetcher_->has_oauth2_tokens()) {
89 VLOG(1) << "Resuming profile creation after fetching policy token";
90 refresh_token_ = oauth2_policy_fetcher_->oauth2_tokens().refresh_token;
91 restore_from_auth_cookies = false;
92 }
93 restore_from_auth_cookies_ = restore_from_auth_cookies;
94 ContinueSessionRestore();
95 }
96
97 void OAuth2LoginManager::ContinueSessionRestore() {
98 if (restore_from_auth_cookies_) {
99 FetchOAuth2Tokens();
100 return;
101 }
102
103 // Did we already fetch the refresh token (either policy or db)?
104 if (!refresh_token_.empty()) {
105 // TODO(zelidrag): Figure out where to stick that refresh_token_ into.
106 // We probalby need bit more than that.
107 }
108 LoadAndVerifyOAuth2Tokens();
109 }
110
111
112 void OAuth2LoginManager::RestorePolicyTokens(
113 net::URLRequestContextGetter* auth_request_context) {
114 oauth2_policy_fetcher_.reset(
115 new OAuth2PolicyFetcher(auth_request_context,
116 g_browser_process->system_request_context()));
117 oauth2_policy_fetcher_->Start();
118 }
119
120 void OAuth2LoginManager::Stop() {
121 oauth2_token_fetcher_.reset();
122 login_verifier_.reset();
123 }
124
125 TokenService* OAuth2LoginManager::SetupTokenService() {
126 DCHECK(registrar_.IsEmpty());
127 TokenService* token_service =
128 TokenServiceFactory::GetForProfile(user_profile_);
129 registrar_.Add(this,
130 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
131 content::Source<TokenService>(token_service));
132 registrar_.Add(this,
133 chrome::NOTIFICATION_TOKEN_AVAILABLE,
134 content::Source<TokenService>(token_service));
135 registrar_.Add(this,
136 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
137 content::Source<TokenService>(token_service));
138 return token_service;
139 }
140
141 void OAuth2LoginManager::RemoveLegacyTokens() {
142 PrefServiceSyncable* prefs = user_profile_->GetPrefs();
143 prefs->RegisterStringPref(prefs::kOAuth1Token,
144 "",
145 PrefServiceSyncable::UNSYNCABLE_PREF);
146 prefs->RegisterStringPref(prefs::kOAuth1Secret,
147 "",
148 PrefServiceSyncable::UNSYNCABLE_PREF);
149 prefs->ClearPref(prefs::kOAuth1Token);
150 prefs->ClearPref(prefs::kOAuth1Secret);
151 prefs->UnregisterPreference(prefs::kOAuth1Token);
152 prefs->UnregisterPreference(prefs::kOAuth1Secret);
153 }
154
155 void OAuth2LoginManager::LoadAndVerifyOAuth2Tokens() {
156 // If we have no cookies, try to load saved OAuth2 token from TokenService.
157 TokenService* token_service = SetupTokenService();
158 token_service->Initialize(GaiaConstants::kChromeSource, user_profile_);
159 token_service->LoadTokensFromDB();
160 }
161
162 void OAuth2LoginManager::FetchOAuth2Tokens() {
163 DCHECK(auth_request_context_.get());
164 // If we have authenticated cookie jar, get OAuth1 token first, then fetch
165 // SID/LSID cookies through OAuthLogin call.
166 oauth2_token_fetcher_.reset(
167 new OAuth2TokenFetcher(this, auth_request_context_));
168 oauth2_token_fetcher_->Start();
169 }
170
171 void OAuth2LoginManager::OnOAuth2TokenAvailable(
172 const GaiaAuthConsumer::ClientLoginResult& gaia_credentials,
173 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
174 TokenService* token_service = SetupTokenService();
175 token_service->UpdateCredentialsWithOAuth2(oauth2_tokens);
176 token_service->UpdateCredentials(gaia_credentials);
177 CompleteAuthentication();
178 }
179
180 void OAuth2LoginManager::OnOAuth2TokenFetchFailed() {
181 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
182 UserManager::Get()->SaveUserOAuthStatus(
183 UserManager::Get()->GetLoggedInUser()->email(),
184 User::OAUTH2_TOKEN_STATUS_INVALID);
185 }
186
187 void OAuth2LoginManager::Observe(
188 int type,
189 const content::NotificationSource& source,
190 const content::NotificationDetails& details) OVERRIDE {
191 TokenService* token_service =
192 TokenServiceFactory::GetForProfile(user_profile_);
193 switch (type) {
194 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
195 refresh_token_ = token_service->GetOAuth2LoginRefreshToken();
196 ReportOAuth2TokensLoaded();
197 // Have we started restoring GAIA auth cookies yet?
198 if (!refresh_token_.empty() && !login_verifier_.get())
199 RestoreSessionCookies();
200
201 break;
202 }
203 case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: {
204 // TODO(zelidrag): Figure out how to recover from transient errors with
205 // TokenService class - similar to what we do in RetryOnError() here.
206 TokenService::TokenAvailableDetails* token_details =
207 content::Details<TokenService::TokenAvailableDetails>(
208 details).ptr();
209 if (token_details->service() ==
210 GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
211 UserManager::Get()->SaveUserOAuthStatus(
212 UserManager::Get()->GetLoggedInUser()->email(),
213 User::OAUTH2_TOKEN_STATUS_INVALID);
214 }
215 break;
216 }
217 case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
218 TokenService::TokenAvailableDetails* token_details =
219 content::Details<TokenService::TokenAvailableDetails>(
220 details).ptr();
221 if (token_details->service() ==
222 GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
223 DCHECK(!login_verifier_.get());
224 refresh_token_ = token_details->token();
225 RestoreSessionCookies();
226 }
227
228 break;
229 }
230 default:
231 NOTREACHED();
232 break;
233 }
234 }
235
236 void OAuth2LoginManager::RestoreSessionCookies() {
237 VLOG(1) << "Fetched refresh token!";
238 DCHECK(!refresh_token_.empty());
239 if (!login_verifier_.get()) {
240 login_verifier_.reset(
241 new OAuth2LoginVerifier(this,
242 g_browser_process->system_request_context(),
243 user_profile_->GetRequestContext()));
244 }
245 login_verifier_->VerifyRefreshToken(refresh_token_);
246 }
247
248 void OAuth2LoginManager::FetchPolicyTokens() {
Joao da Silva 2013/01/11 16:45:07 This is never used. I think it should be called fr
zel 2013/01/11 19:51:16 It's actually just needed in RestoreSessionCookies
249 if (!oauth2_policy_fetcher_.get() || oauth2_policy_fetcher_->failed()) {
250 // Trigger OAuth2 token fetch for user policy.
251 oauth2_policy_fetcher_.reset(
252 new OAuth2PolicyFetcher(g_browser_process->system_request_context(),
253 refresh_token_));
254 oauth2_policy_fetcher_->Start();
255 }
256 }
257
258 void OAuth2LoginManager::OnOAuth2LoginVerifierSuccess(
259 const std::string& sid,
260 const std::string& lsid,
261 const std::string& auth) {
262 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
263 UserManager::Get()->SaveUserOAuthStatus(
264 UserManager::Get()->GetLoggedInUser()->email(),
265 User::OAUTH2_TOKEN_STATUS_VALID);
266 }
267
268 void OAuth2LoginManager::OnOAuth2LoginVerifierFaulure() {
Joao da Silva 2013/01/11 16:45:07 *Failure
zel 2013/01/11 19:51:16 Done.
269 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
270 UserManager::Get()->SaveUserOAuthStatus(
271 UserManager::Get()->GetLoggedInUser()->email(),
272 User::OAUTH2_TOKEN_STATUS_INVALID);
273 }
274
275 void OAuth2LoginManager::ReportOAuth2TokensLoaded() {
276 VLOG(1) << "Got OAuth2 refresh token!";
277 DCHECK(!loading_reported_);
278 loading_reported_ = true;
279 if (refresh_token_.empty()) {
280 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
281 UserManager::Get()->SaveUserOAuthStatus(
282 UserManager::Get()->GetLoggedInUser()->email(),
283 User::OAUTH2_TOKEN_STATUS_INVALID);
284 }
285 }
286
287 // OAuth1LoginManager.
288 // TODO(zelidrag): Nuke this one once we switch everything to OAuth2.
289
290 OAuth1LoginManager::OAuth1LoginManager(
291 OAuthLoginManager::Delegate* delegate)
292 : OAuthLoginManager(delegate) {
293 }
294
295 void OAuth1LoginManager::RestoreSession(
296 Profile* user_profile,
297 net::URLRequestContextGetter* auth_request_context,
298 bool restore_from_auth_cookies) {
299 user_profile_ = user_profile;
300 auth_request_context_ = auth_request_context;
301 state_ = OAuthLoginManager::SESSION_RESTORE_IN_PROGRESS;
302
303 // Reuse the access token fetched by the PolicyOAuthFetcher, if it was
304 // used to fetch policies before Profile creation.
305 if (policy_oauth_fetcher_.get() &&
306 !policy_oauth_fetcher_->oauth1_token().empty()) {
307 VLOG(1) << "Resuming profile creation after fetching policy token";
308 oauth1_token_ = policy_oauth_fetcher_->oauth1_token();
309 oauth1_secret_ = policy_oauth_fetcher_->oauth1_secret();
310 StoreOAuth1Tokens();
311 restore_from_auth_cookies = false;
312 }
313 restore_from_auth_cookies_ = restore_from_auth_cookies;
314 ContinueSessionRestore();
315 }
316
317 void OAuth1LoginManager::ContinueSessionRestore() {
318 // Have we even started session restore?
319 if (!user_profile_)
320 return;
321
322 if (restore_from_auth_cookies_) {
323 DCHECK(auth_request_context_.get());
324 // If we don't have it, fetch OAuth1 access token.
325 // Once we get that, we will kick off individual requests for OAuth2
326 // tokens for all our services.
327 // Use off-the-record profile that was used for this step. It should
328 // already contain all needed cookies that will let us skip GAIA's user
329 // authentication UI.
330 oauth1_token_fetcher_.reset(
331 new OAuth1TokenFetcher(this, auth_request_context_));
332 oauth1_token_fetcher_->Start();
333 } else if (ReadOAuth1Tokens()) {
334 // Verify OAuth access token when we find it in the profile and always if
335 // if we don't have cookies.
336 // TODO(xiyuan): Change back to use authenticator to verify token when
337 // we support Gaia in lock screen.
338 VerifyOAuth1AccessToken();
339 } else {
340 UserManager::Get()->SaveUserOAuthStatus(
341 UserManager::Get()->GetLoggedInUser()->email(),
342 User::OAUTH1_TOKEN_STATUS_INVALID);
343 }
344 }
345
346 void OAuth1LoginManager::RestorePolicyTokens(
347 net::URLRequestContextGetter* auth_request_context) {
348 DCHECK(!policy_oauth_fetcher_.get());
349 policy_oauth_fetcher_.reset(
350 new PolicyOAuthFetcher(auth_request_context));
351 policy_oauth_fetcher_->Start();
352 }
353
354 void OAuth1LoginManager::Stop() {
355 oauth1_token_fetcher_.reset();
356 oauth1_login_verifier_.reset();
357 state_ = OAuthLoginManager::SESSION_RESTORE_NOT_STARTED;
358 }
359
360 void OAuth1LoginManager::VerifyOAuth1AccessToken() {
361 // Kick off verification of OAuth1 access token (via OAuthLogin), this should
362 // let us fetch credentials that will be used to initialize sync engine.
363 FetchCredentialsWithOAuth1();
364 delegate_->OnFoundStoredTokens();
365 FetchPolicyTokens();
366 }
367
368 void OAuth1LoginManager::FetchPolicyTokens() {
369 if (!policy_oauth_fetcher_.get() || policy_oauth_fetcher_->failed()) {
370 // Trigger oauth token fetch for user policy.
371 policy_oauth_fetcher_.reset(
372 new PolicyOAuthFetcher(g_browser_process->system_request_context(),
373 oauth1_token_,
374 oauth1_secret_));
375 policy_oauth_fetcher_->Start();
376 }
377 }
378
379 void OAuth1LoginManager::FetchCredentialsWithOAuth1() {
380 oauth1_login_verifier_.reset(
381 new OAuth1LoginVerifier(this,
382 user_profile_->GetRequestContext(),
383 oauth1_token_,
384 oauth1_secret_,
385 UserManager::Get()->GetLoggedInUser()->email()));
386 oauth1_login_verifier_->StartOAuthVerification();
387 }
388
389 void OAuth1LoginManager::OnOAuth1AccessTokenAvailable(
390 const std::string& token,
391 const std::string& secret) {
392 oauth1_token_ = token;
393 oauth1_secret_ = secret;
394 StoreOAuth1Tokens();
395 // Verify OAuth1 token by doing OAuthLogin and fetching credentials. If we
396 // have just transfered auth cookies out of authenticated cookie jar, there
397 // is no need to try to mint them from OAuth token again.
398 VerifyOAuth1AccessToken();
399 }
400
401 void OAuth1LoginManager::OnOAuth1AccessTokenFetchFailed() {
402 // TODO(kochi): Show failure notification UI here?
403 LOG(ERROR) << "Failed to fetch OAuth1 access token.";
404 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
405 g_browser_process->browser_policy_connector()->RegisterForUserPolicy(
406 EmptyString());
407 }
408
409 void OAuth1LoginManager::OnOAuth1VerificationSucceeded(
410 const std::string& user_name, const std::string& sid,
411 const std::string& lsid, const std::string& auth) {
412 // Kick off sync engine.
413 GaiaAuthConsumer::ClientLoginResult credentials(sid, lsid, auth,
414 std::string());
415 TokenService* token_service =
416 TokenServiceFactory::GetForProfile(user_profile_);
417 token_service->UpdateCredentials(credentials);
418 CompleteAuthentication();
419 }
420
421 void OAuth1LoginManager::OnOAuth1VerificationFailed(
422 const std::string& user_name) {
423 state_ = OAuthLoginManager::SESSION_RESTORE_DONE;
424 UserManager::Get()->SaveUserOAuthStatus(user_name,
425 User::OAUTH1_TOKEN_STATUS_INVALID);
426 }
427
428 bool OAuth1LoginManager::ReadOAuth1Tokens() {
429 // Skip reading oauth token if user does not have a valid status.
430 if (UserManager::Get()->IsUserLoggedIn() &&
431 UserManager::Get()->GetLoggedInUser()->oauth_token_status() !=
432 User::OAUTH1_TOKEN_STATUS_VALID) {
433 return false;
434 }
435
436 PrefService* pref_service = user_profile_->GetPrefs();
437 std::string encoded_token = pref_service->GetString(prefs::kOAuth1Token);
438 std::string encoded_secret = pref_service->GetString(prefs::kOAuth1Secret);
439 if (!encoded_token.length() || !encoded_secret.length())
440 return false;
441
442 std::string decoded_token =
443 CrosLibrary::Get()->GetCertLibrary()->DecryptToken(encoded_token);
444 std::string decoded_secret =
445 CrosLibrary::Get()->GetCertLibrary()->DecryptToken(encoded_secret);
446
447 if (!decoded_token.length() || !decoded_secret.length())
448 return false;
449
450 oauth1_token_ = decoded_token;
451 oauth1_secret_ = decoded_secret;
452 return true;
453 }
454
455 void OAuth1LoginManager::StoreOAuth1Tokens() {
456 DCHECK(!oauth1_token_.empty());
457 DCHECK(!oauth1_secret_.empty());
458 // First store OAuth1 token + service for the current user profile...
459 std::string encrypted_token =
460 CrosLibrary::Get()->GetCertLibrary()->EncryptToken(oauth1_token_);
461 std::string encrypted_secret =
462 CrosLibrary::Get()->GetCertLibrary()->EncryptToken(oauth1_secret_);
463
464 PrefService* pref_service = user_profile_->GetPrefs();
465 User* user = UserManager::Get()->GetLoggedInUser();
466 if (!encrypted_token.empty() && !encrypted_secret.empty()) {
467 pref_service->SetString(prefs::kOAuth1Token, encrypted_token);
468 pref_service->SetString(prefs::kOAuth1Secret, encrypted_secret);
469
470 // ...then record the presence of valid OAuth token for this account in
471 // local state as well.
472 UserManager::Get()->SaveUserOAuthStatus(
473 user->email(), User::OAUTH1_TOKEN_STATUS_VALID);
474 } else {
475 LOG(WARNING) << "Failed to get OAuth1 token/secret encrypted.";
476 // Set the OAuth status invalid so that the user will go through full
477 // GAIA login next time.
478 UserManager::Get()->SaveUserOAuthStatus(
479 user->email(), User::OAUTH1_TOKEN_STATUS_INVALID);
480 }
481 }
482
483 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698