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

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

Powered by Google App Engine
This is Rietveld 408576698