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

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

Issue 11649055: OAuth2 sign-in flow for ChromeOS (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: clang fix 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/oauth2_login_verifier.h"
6
7 #include <vector>
8
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/string_util.h"
12 #include "base/stringprintf.h"
13 #include "base/time.h"
14 #include "chrome/browser/chromeos/cros/cros_library.h"
15 #include "chrome/browser/chromeos/cros/network_library.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "google_apis/gaia/gaia_constants.h"
18 #include "google_apis/gaia/gaia_urls.h"
19
20 using content::BrowserThread;
21
22 namespace {
23
24 // OAuth token request max retry count.
25 const int kMaxRequestAttemptCount = 5;
26 // OAuth token request retry delay in milliseconds.
27 const int kRequestRestartDelay = 3000;
28
29 } // namespace
30
31 namespace chromeos {
32
33 OAuth2LoginVerifier::OAuth2LoginVerifier(
34 OAuth2LoginVerifier::Delegate* delegate,
35 net::URLRequestContextGetter* system_request_context,
36 net::URLRequestContextGetter* user_request_context)
37 : delegate_(delegate),
38 ALLOW_THIS_IN_INITIALIZER_LIST(token_fetcher_(
39 this, system_request_context)),
40 ALLOW_THIS_IN_INITIALIZER_LIST(gaia_system_fetcher_(
41 this, std::string(GaiaConstants::kChromeOSSource),
42 system_request_context)),
43 ALLOW_THIS_IN_INITIALIZER_LIST(gaia_fetcher_(
44 this, std::string(GaiaConstants::kChromeOSSource),
45 user_request_context)),
46 retry_count_(0) {
47 DCHECK(delegate);
48 }
49
50 OAuth2LoginVerifier::~OAuth2LoginVerifier() {
51 }
52
53 void OAuth2LoginVerifier::VerifyTokens(const std::string& oauth2_refresh_token,
54 const std::string& gaia_token) {
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56 if (CrosLibrary::Get()->libcros_loaded()) {
57 // Delay the verification if the network is not connected or on a captive
58 // portal.
59 const Network* network =
60 CrosLibrary::Get()->GetNetworkLibrary()->active_network();
61 if (!network || !network->connected() || network->restricted_pool()) {
62 // If network is offline, defer the token fetching until online.
63 VLOG(1) << "Network is offline. Deferring OAuth2 access token fetch.";
64 BrowserThread::PostDelayedTask(
65 BrowserThread::UI, FROM_HERE,
66 base::Bind(&OAuth2LoginVerifier::VerifyTokens,
67 AsWeakPtr(),
68 oauth2_refresh_token,
69 gaia_token),
70 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
71 return;
72 }
73 }
74
75 access_token_.clear();
76 refresh_token_ = oauth2_refresh_token;
77 gaia_token_ = gaia_token;
78 if (gaia_token_.empty()) {
79 // If we have no token for GAIA service and can't merge the session
80 // immediately, attempt to perform OAuthLogin and reconstruct all service
81 // tokens.
82 RestoreSessionFromOAuth2RefreshToken();
83 } else {
84 // If GAIA token is present, we can attempt to shortcut the process straight
85 // to /MergeSession call.
86 RestoreSessionFromGaiaToken();
87 }
88 }
89
90
91 void OAuth2LoginVerifier::RestoreSessionFromOAuth2RefreshToken() {
92 type_ = RESTORE_FROM_OAUTH2_REFRESH_TOKEN;
93 StartFetchingOAuthLoginAccessToken();
94 }
95
96 void OAuth2LoginVerifier::RestoreSessionFromGaiaToken() {
97 type_ = RESTORE_FROM_GAIA_TOKEN;
98 StartMergeSession();
99 }
100
101 void OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken() {
102 access_token_.clear();
103 gaia_token_.clear();
104 std::vector<std::string> scopes;
105 scopes.push_back(GaiaUrls::GetInstance()->oauth1_login_scope());
106 token_fetcher_.Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
107 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
108 refresh_token_,
109 scopes);
110 }
111
112 void OAuth2LoginVerifier::OnGetTokenSuccess(
113 const std::string& access_token, const base::Time& expiration_time) {
114 LOG(INFO) << "Got OAuth2 access token!";
115 retry_count_ = 0;
116 access_token_ = access_token;
117 StartOAuthLoginForUberToken();
118 }
119
120 void OAuth2LoginVerifier::OnGetTokenFailure(
121 const GoogleServiceAuthError& error) {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 LOG(ERROR) << "Failed to get OAuth2 access token, "
124 << " error: " << error.state();
125 RetryOnError(
126 "GetOAuth2AccessToken", error,
127 base::Bind(&OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken,
128 AsWeakPtr()),
129 base::Bind(&Delegate::OnOAuthLoginFailure,
130 base::Unretained(delegate_)));
131 }
132
133 void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
134 // No service will fetch us uber auth token.
135 gaia_system_fetcher_.StartTokenFetchForUberAuthExchange(access_token_);
136 }
137
138
139 void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
140 const std::string& uber_token) {
141 LOG(INFO) << "OAuthLogin(uber_token) successful!";
142 retry_count_ = 0;
143 gaia_token_ = uber_token;
144 StartMergeSession();
145 }
146
147 void OAuth2LoginVerifier::OnUberAuthTokenFailure(
148 const GoogleServiceAuthError& error) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150 LOG(ERROR) << "OAuthLogin(uber_token) failed,"
151 << " error: " << error.state();
152 RetryOnError("OAuthLoginUberToken", error,
153 base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForUberToken,
154 AsWeakPtr()),
155 base::Bind(&Delegate::OnOAuthLoginFailure,
156 base::Unretained(delegate_)));
157 }
158
159 void OAuth2LoginVerifier::StartOAuthLoginForGaiaCredentials() {
160 // No service will fetch us uber auth token.
161 gaia_system_fetcher_.StartOAuthLogin(access_token_, EmptyString());
162 }
163
164 void OAuth2LoginVerifier::OnClientLoginSuccess(
165 const ClientLoginResult& gaia_credentials) {
166 LOG(INFO) << "OAuthLogin(SID+LSID) successful!";
167 retry_count_ = 0;
168 gaia_credentials_ = gaia_credentials;
169 delegate_->OnOAuthLoginSuccess(gaia_credentials_);
170 }
171
172 void OAuth2LoginVerifier::OnClientLoginFailure(
173 const GoogleServiceAuthError& error) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 LOG(ERROR) << "OAuthLogin(SID+LSID failed),"
176 << " error: " << error.state();
177 RetryOnError(
178 "OAuthLoginGaiaCred", error,
179 base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForGaiaCredentials,
180 AsWeakPtr()),
181 base::Bind(&Delegate::OnOAuthLoginFailure,
182 base::Unretained(delegate_)));
183 }
184
185 void OAuth2LoginVerifier::StartMergeSession() {
186 DCHECK(!gaia_token_.empty());
187 gaia_fetcher_.StartMergeSession(gaia_token_);
188 }
189
190 void OAuth2LoginVerifier::OnMergeSessionSuccess(const std::string& data) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 LOG(INFO) << "MergeSession successful.";
193 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionOrigin", type_, 2);
194 delegate_->OnSessionMergeSuccess();
195 // Get GAIA credentials needed to kick off TokenService and friends.
196 StartOAuthLoginForGaiaCredentials();
197 }
198
199 void OAuth2LoginVerifier::OnMergeSessionFailure(
200 const GoogleServiceAuthError& error) {
201 LOG(ERROR) << "Failed MergeSession request,"
202 << " error: " << error.state();
203 // If MergeSession from GAIA service token fails, retry the session restore
204 // from OAuth2 refresh token. If that failed too, signal the delegate.
205 RetryOnError(
206 (type_ == RESTORE_FROM_GAIA_TOKEN) ?
207 "MergeSessionGAIA" : "MergeSessionOAuth2",
208 error,
209 base::Bind(&OAuth2LoginVerifier::StartMergeSession,
210 AsWeakPtr()),
211 (type_ == RESTORE_FROM_GAIA_TOKEN) ?
212 base::Bind(&OAuth2LoginVerifier::RestoreSessionFromOAuth2RefreshToken,
213 AsWeakPtr()) :
214 base::Bind(&Delegate::OnSessionMergeFailure,
215 base::Unretained(delegate_)));
216 }
217
218 void OAuth2LoginVerifier::RetryOnError(const char* operation_id,
219 const GoogleServiceAuthError& error,
220 const base::Closure& task_to_retry,
221 const base::Closure& error_handler) {
222 if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
223 error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
224 error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
225 retry_count_ < kMaxRequestAttemptCount) {
226 retry_count_++;
227 UMA_HISTOGRAM_ENUMERATION(
228 base::StringPrintf("OAuth2Login.%sWithRetry", operation_id),
229 error.state(),
230 GoogleServiceAuthError::NUM_STATES);
231 BrowserThread::PostDelayedTask(
232 BrowserThread::UI, FROM_HERE, task_to_retry,
233 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
234 return;
235 }
236
237 LOG(ERROR) << "Unrecoverable error or retry count max reached for "
238 << operation_id;
239 UMA_HISTOGRAM_ENUMERATION(
240 base::StringPrintf("OAuth2Login.%sFailureCause", operation_id),
241 error.state(),
242 GoogleServiceAuthError::NUM_STATES);
243 error_handler.Run();
244 }
245
246 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698