Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "google_apis/gaia/gaia_oauth_client.h" | 5 #include "google_apis/gaia/gaia_oauth_client.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "base/values.h" | 13 #include "base/values.h" |
| 14 #include "google_apis/gaia/gaia_auth_util.h" | 14 #include "google_apis/gaia/gaia_auth_util.h" |
| 15 #include "google_apis/gaia/gaia_urls.h" | 15 #include "google_apis/gaia/gaia_urls.h" |
| 16 #include "net/base/escape.h" | 16 #include "net/base/escape.h" |
| 17 #include "net/base/load_flags.h" | 17 #include "net/base/load_flags.h" |
| 18 #include "net/http/http_status_code.h" | 18 #include "net/http/http_status_code.h" |
| 19 #include "net/traffic_annotation/network_traffic_annotation.h" | |
| 19 #include "net/url_request/url_fetcher.h" | 20 #include "net/url_request/url_fetcher.h" |
| 20 #include "net/url_request/url_fetcher_delegate.h" | 21 #include "net/url_request/url_fetcher_delegate.h" |
| 21 #include "net/url_request/url_request_context_getter.h" | 22 #include "net/url_request/url_request_context_getter.h" |
| 22 #include "url/gurl.h" | 23 #include "url/gurl.h" |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 const char kAccessTokenValue[] = "access_token"; | 26 const char kAccessTokenValue[] = "access_token"; |
| 26 const char kRefreshTokenValue[] = "refresh_token"; | 27 const char kRefreshTokenValue[] = "refresh_token"; |
| 27 const char kExpiresInValue[] = "expires_in"; | 28 const char kExpiresInValue[] = "expires_in"; |
| 28 } | 29 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 USER_ID, | 83 USER_ID, |
| 83 USER_INFO, | 84 USER_INFO, |
| 84 }; | 85 }; |
| 85 | 86 |
| 86 ~Core() override {} | 87 ~Core() override {} |
| 87 | 88 |
| 88 void GetUserInfoImpl(RequestType type, | 89 void GetUserInfoImpl(RequestType type, |
| 89 const std::string& oauth_access_token, | 90 const std::string& oauth_access_token, |
| 90 int max_retries, | 91 int max_retries, |
| 91 Delegate* delegate); | 92 Delegate* delegate); |
| 92 void MakeGaiaRequest(const GURL& url, | 93 void MakeGaiaRequest( |
| 93 const std::string& post_body, | 94 const GURL& url, |
| 94 int max_retries, | 95 const std::string& post_body, |
| 95 GaiaOAuthClient::Delegate* delegate); | 96 int max_retries, |
| 97 GaiaOAuthClient::Delegate* delegate, | |
| 98 const net::NetworkTrafficAnnotationTag& traffic_annotation); | |
| 96 void HandleResponse(const net::URLFetcher* source, | 99 void HandleResponse(const net::URLFetcher* source, |
| 97 bool* should_retry_request); | 100 bool* should_retry_request); |
| 98 | 101 |
| 99 int num_retries_; | 102 int num_retries_; |
| 100 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 103 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| 101 GaiaOAuthClient::Delegate* delegate_; | 104 GaiaOAuthClient::Delegate* delegate_; |
| 102 std::unique_ptr<net::URLFetcher> request_; | 105 std::unique_ptr<net::URLFetcher> request_; |
| 103 RequestType request_type_; | 106 RequestType request_type_; |
| 104 }; | 107 }; |
| 105 | 108 |
| 106 void GaiaOAuthClient::Core::GetTokensFromAuthCode( | 109 void GaiaOAuthClient::Core::GetTokensFromAuthCode( |
| 107 const OAuthClientInfo& oauth_client_info, | 110 const OAuthClientInfo& oauth_client_info, |
| 108 const std::string& auth_code, | 111 const std::string& auth_code, |
| 109 int max_retries, | 112 int max_retries, |
| 110 GaiaOAuthClient::Delegate* delegate) { | 113 GaiaOAuthClient::Delegate* delegate) { |
| 111 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); | 114 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); |
| 112 request_type_ = TOKENS_FROM_AUTH_CODE; | 115 request_type_ = TOKENS_FROM_AUTH_CODE; |
| 113 std::string post_body = | 116 std::string post_body = |
| 114 "code=" + net::EscapeUrlEncodedData(auth_code, true) + | 117 "code=" + net::EscapeUrlEncodedData(auth_code, true) + |
| 115 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | 118 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, |
| 116 true) + | 119 true) + |
| 117 "&client_secret=" + | 120 "&client_secret=" + |
| 118 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | 121 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + |
| 119 "&redirect_uri=" + | 122 "&redirect_uri=" + |
| 120 net::EscapeUrlEncodedData(oauth_client_info.redirect_uri, true) + | 123 net::EscapeUrlEncodedData(oauth_client_info.redirect_uri, true) + |
| 121 "&grant_type=authorization_code"; | 124 "&grant_type=authorization_code"; |
| 122 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()), | 125 net::NetworkTrafficAnnotationTag traffic_annotation = |
| 123 post_body, max_retries, delegate); | 126 net::DefineNetworkTrafficAnnotation("gaia_oauth_client_get_tokens", R"( |
| 127 semantics { | |
| 128 sender: "OAuth 2.0 calls" | |
| 129 description: | |
| 130 "This request exchanges an authorization code for an OAuth 2.0 " | |
| 131 "refresh token and an OAuth 2.0 access token." | |
| 132 trigger: | |
| 133 "This request is triggered when a Chrome service requires an " | |
| 134 "access token and a refresh token (e.g. Cloud Print, Chrome Remote " | |
| 135 "Desktop etc.) See https://developers.google.com/identity/protocols" | |
| 136 "/OAuth2 for more information about the Google implementation of " | |
| 137 "the OAuth 2.0 protocol." | |
| 138 data: | |
| 139 "The Google console client ID and client secret of the caller, the " | |
| 140 "OAuth authorization code and the redirect URI." | |
| 141 destination: GOOGLE_OWNED_SERVICE | |
| 142 } | |
| 143 policy { | |
| 144 cookies_allowed: false | |
| 145 setting: | |
| 146 "This feature cannot be disabled in settings, but if user signs " | |
|
msramek
2017/05/26 13:44:20
nit: the user (as in the other CL)
Ramin Halavati
2017/05/29 05:36:53
Done.
| |
| 147 "out of Chrome, this request would not be made." | |
| 148 chrome_policy { | |
| 149 SigninAllowed { | |
| 150 policy_options {mode: MANDATORY} | |
| 151 SigninAllowed: false | |
| 152 } | |
| 153 } | |
| 154 })"); | |
| 155 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()), post_body, | |
| 156 max_retries, delegate, traffic_annotation); | |
| 124 } | 157 } |
| 125 | 158 |
| 126 void GaiaOAuthClient::Core::RefreshToken( | 159 void GaiaOAuthClient::Core::RefreshToken( |
| 127 const OAuthClientInfo& oauth_client_info, | 160 const OAuthClientInfo& oauth_client_info, |
| 128 const std::string& refresh_token, | 161 const std::string& refresh_token, |
| 129 const std::vector<std::string>& scopes, | 162 const std::vector<std::string>& scopes, |
| 130 int max_retries, | 163 int max_retries, |
| 131 GaiaOAuthClient::Delegate* delegate) { | 164 GaiaOAuthClient::Delegate* delegate) { |
| 132 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); | 165 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); |
| 133 request_type_ = REFRESH_TOKEN; | 166 request_type_ = REFRESH_TOKEN; |
| 134 std::string post_body = | 167 std::string post_body = |
| 135 "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) + | 168 "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) + |
| 136 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | 169 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, |
| 137 true) + | 170 true) + |
| 138 "&client_secret=" + | 171 "&client_secret=" + |
| 139 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | 172 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + |
| 140 "&grant_type=refresh_token"; | 173 "&grant_type=refresh_token"; |
| 141 | 174 |
| 142 if (!scopes.empty()) { | 175 if (!scopes.empty()) { |
| 143 std::string scopes_string = base::JoinString(scopes, " "); | 176 std::string scopes_string = base::JoinString(scopes, " "); |
| 144 post_body += "&scope=" + net::EscapeUrlEncodedData(scopes_string, true); | 177 post_body += "&scope=" + net::EscapeUrlEncodedData(scopes_string, true); |
| 145 } | 178 } |
| 146 | 179 |
| 147 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()), | 180 net::NetworkTrafficAnnotationTag traffic_annotation = |
| 148 post_body, max_retries, delegate); | 181 net::DefineNetworkTrafficAnnotation("gaia_oauth_client_refresh_token", R"( |
| 182 semantics { | |
| 183 sender: "OAuth 2.0 calls" | |
| 184 description: | |
| 185 "This request fetches a fresh access token that can be used to " | |
| 186 "authenticate an API call to a Google web endpoint." | |
| 187 trigger: | |
| 188 "This is called whenever the caller needs a fresh OAuth 2.0 access " | |
| 189 "token." | |
| 190 data: | |
| 191 "The OAuth 2.0 refresh token, the Google console client ID and " | |
| 192 "client secret of the caller, and optionally the scopes of the API " | |
| 193 "for which the access token should be authorized." | |
| 194 destination: GOOGLE_OWNED_SERVICE | |
| 195 } | |
| 196 policy { | |
| 197 cookies_allowed: false | |
| 198 setting: | |
| 199 "This feature cannot be disabled in settings, but if user signs " | |
| 200 "out of Chrome, this request would not be made." | |
| 201 chrome_policy { | |
| 202 SigninAllowed { | |
| 203 policy_options {mode: MANDATORY} | |
| 204 SigninAllowed: false | |
| 205 } | |
| 206 } | |
| 207 })"); | |
| 208 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()), post_body, | |
| 209 max_retries, delegate, traffic_annotation); | |
| 149 } | 210 } |
| 150 | 211 |
| 151 void GaiaOAuthClient::Core::GetUserEmail(const std::string& oauth_access_token, | 212 void GaiaOAuthClient::Core::GetUserEmail(const std::string& oauth_access_token, |
| 152 int max_retries, | 213 int max_retries, |
| 153 Delegate* delegate) { | 214 Delegate* delegate) { |
| 154 GetUserInfoImpl(USER_EMAIL, oauth_access_token, max_retries, delegate); | 215 GetUserInfoImpl(USER_EMAIL, oauth_access_token, max_retries, delegate); |
| 155 } | 216 } |
| 156 | 217 |
| 157 void GaiaOAuthClient::Core::GetUserId(const std::string& oauth_access_token, | 218 void GaiaOAuthClient::Core::GetUserId(const std::string& oauth_access_token, |
| 158 int max_retries, | 219 int max_retries, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 169 void GaiaOAuthClient::Core::GetUserInfoImpl( | 230 void GaiaOAuthClient::Core::GetUserInfoImpl( |
| 170 RequestType type, | 231 RequestType type, |
| 171 const std::string& oauth_access_token, | 232 const std::string& oauth_access_token, |
| 172 int max_retries, | 233 int max_retries, |
| 173 Delegate* delegate) { | 234 Delegate* delegate) { |
| 174 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); | 235 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); |
| 175 DCHECK(!request_.get()); | 236 DCHECK(!request_.get()); |
| 176 request_type_ = type; | 237 request_type_ = type; |
| 177 delegate_ = delegate; | 238 delegate_ = delegate; |
| 178 num_retries_ = 0; | 239 num_retries_ = 0; |
| 240 net::NetworkTrafficAnnotationTag traffic_annotation = | |
| 241 net::DefineNetworkTrafficAnnotation("gaia_core_get_user_info", R"( | |
| 242 semantics { | |
| 243 sender: "OAuth 2.0 calls" | |
| 244 description: "This request is used to fetch user information." | |
|
msramek
2017/05/26 13:44:20
What kind of information?
Some basic information
msarda
2017/05/31 07:44:25
Let's rephrase this to something like:
"This reque
Ramin Halavati
2017/05/31 07:50:53
By "e.g." you mean other items may also be fetched
msarda
2017/05/31 08:32:14
The data we get is a dictionary. I do not know the
Ramin Halavati
2017/05/31 09:09:43
Thank you. I think as here we mostly care about wh
| |
| 245 trigger: | |
| 246 "The main trigger for this request in the AccountTrackerService " | |
|
msramek
2017/05/26 13:44:20
typo: is in
Ramin Halavati
2017/05/29 05:36:53
Done.
| |
| 247 "that fetches the user info soon after the user signs in." | |
| 248 data: | |
| 249 "The OAuth 2.0 access token of the account." | |
| 250 destination: GOOGLE_OWNED_SERVICE | |
| 251 } | |
| 252 policy { | |
| 253 cookies_allowed: false | |
| 254 setting: | |
| 255 "This feature cannot be disabled in settings, but if user signs " | |
| 256 "out of Chrome, this request would not be made." | |
| 257 chrome_policy { | |
| 258 SigninAllowed { | |
| 259 policy_options {mode: MANDATORY} | |
| 260 SigninAllowed: false | |
| 261 } | |
| 262 } | |
| 263 })"); | |
| 179 request_ = net::URLFetcher::Create( | 264 request_ = net::URLFetcher::Create( |
| 180 kUrlFetcherId, GURL(GaiaUrls::GetInstance()->oauth_user_info_url()), | 265 kUrlFetcherId, GURL(GaiaUrls::GetInstance()->oauth_user_info_url()), |
| 181 net::URLFetcher::GET, this); | 266 net::URLFetcher::GET, this, traffic_annotation); |
| 182 request_->SetRequestContext(request_context_getter_.get()); | 267 request_->SetRequestContext(request_context_getter_.get()); |
| 183 request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token); | 268 request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token); |
| 184 request_->SetMaxRetriesOn5xx(max_retries); | 269 request_->SetMaxRetriesOn5xx(max_retries); |
| 185 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 270 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 186 net::LOAD_DO_NOT_SAVE_COOKIES); | 271 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 187 MarkURLFetcherAsGaia(request_.get()); | 272 MarkURLFetcherAsGaia(request_.get()); |
| 188 | 273 |
| 189 // Fetchers are sometimes cancelled because a network change was detected, | 274 // Fetchers are sometimes cancelled because a network change was detected, |
| 190 // especially at startup and after sign-in on ChromeOS. Retrying once should | 275 // especially at startup and after sign-in on ChromeOS. Retrying once should |
| 191 // be enough in those cases; let the fetcher retry up to 3 times just in case. | 276 // be enough in those cases; let the fetcher retry up to 3 times just in case. |
| 192 // http://crbug.com/163710 | 277 // http://crbug.com/163710 |
| 193 request_->SetAutomaticallyRetryOnNetworkChanges(3); | 278 request_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 194 request_->Start(); | 279 request_->Start(); |
| 195 } | 280 } |
| 196 | 281 |
| 197 void GaiaOAuthClient::Core::GetTokenInfo(const std::string& qualifier, | 282 void GaiaOAuthClient::Core::GetTokenInfo(const std::string& qualifier, |
| 198 const std::string& query, | 283 const std::string& query, |
| 199 int max_retries, | 284 int max_retries, |
| 200 Delegate* delegate) { | 285 Delegate* delegate) { |
| 201 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); | 286 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); |
| 202 DCHECK(!request_.get()); | 287 DCHECK(!request_.get()); |
| 203 request_type_ = TOKEN_INFO; | 288 request_type_ = TOKEN_INFO; |
| 204 std::string post_body = | 289 std::string post_body = |
| 205 qualifier + "=" + net::EscapeUrlEncodedData(query, true); | 290 qualifier + "=" + net::EscapeUrlEncodedData(query, true); |
| 291 net::NetworkTrafficAnnotationTag traffic_annotation = | |
| 292 net::DefineNetworkTrafficAnnotation("...", R"( | |
| 293 semantics { | |
| 294 sender: "OAuth 2.0 calls" | |
| 295 description: | |
| 296 "This request fetches information about an OAuth 2.0 access token. " | |
| 297 "The response is a dictionary of response values. The provided " | |
| 298 "access token may have any scope, and basic results will be " | |
| 299 "returned: issued_to, audience, scope, expires_in, access_type. In " | |
| 300 "addition, if the https://www.googleapis.com/auth/userinfo.email " | |
| 301 "scope is present, the email and verified_email fields will be " | |
| 302 "returned. If the https://www.googleapis.com/auth/userinfo.profile " | |
| 303 "scope is present, the user_id field will be returned." | |
| 304 trigger: | |
| 305 "This is triggered after a Google account is added to the browser. " | |
| 306 "It it also triggered after each successful fetch of an OAuth 2.0 " | |
| 307 "access token." | |
| 308 data: "The OAuth 2.0 access token." | |
| 309 destination: GOOGLE_OWNED_SERVICE | |
| 310 } | |
| 311 policy { | |
| 312 cookies_allowed: false | |
| 313 setting: | |
| 314 "This feature cannot be disabled in settings, but if user signs " | |
| 315 "out of Chrome, this request would not be made." | |
| 316 chrome_policy { | |
| 317 SigninAllowed { | |
| 318 policy_options {mode: MANDATORY} | |
| 319 SigninAllowed: false | |
| 320 } | |
| 321 } | |
| 322 })"); | |
| 206 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_info_url()), | 323 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_info_url()), |
| 207 post_body, | 324 post_body, max_retries, delegate, traffic_annotation); |
| 208 max_retries, | |
| 209 delegate); | |
| 210 } | 325 } |
| 211 | 326 |
| 212 void GaiaOAuthClient::Core::MakeGaiaRequest( | 327 void GaiaOAuthClient::Core::MakeGaiaRequest( |
| 213 const GURL& url, | 328 const GURL& url, |
| 214 const std::string& post_body, | 329 const std::string& post_body, |
| 215 int max_retries, | 330 int max_retries, |
| 216 GaiaOAuthClient::Delegate* delegate) { | 331 GaiaOAuthClient::Delegate* delegate, |
| 332 const net::NetworkTrafficAnnotationTag& traffic_annotation) { | |
| 217 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; | 333 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; |
| 218 delegate_ = delegate; | 334 delegate_ = delegate; |
| 219 num_retries_ = 0; | 335 num_retries_ = 0; |
| 220 request_ = | 336 request_ = net::URLFetcher::Create(kUrlFetcherId, url, net::URLFetcher::POST, |
| 221 net::URLFetcher::Create(kUrlFetcherId, url, net::URLFetcher::POST, this); | 337 this, traffic_annotation); |
| 222 request_->SetRequestContext(request_context_getter_.get()); | 338 request_->SetRequestContext(request_context_getter_.get()); |
| 223 request_->SetUploadData("application/x-www-form-urlencoded", post_body); | 339 request_->SetUploadData("application/x-www-form-urlencoded", post_body); |
| 224 request_->SetMaxRetriesOn5xx(max_retries); | 340 request_->SetMaxRetriesOn5xx(max_retries); |
| 225 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 341 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 226 net::LOAD_DO_NOT_SAVE_COOKIES); | 342 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 227 MarkURLFetcherAsGaia(request_.get()); | 343 MarkURLFetcherAsGaia(request_.get()); |
| 228 // See comment on SetAutomaticallyRetryOnNetworkChanges() above. | 344 // See comment on SetAutomaticallyRetryOnNetworkChanges() above. |
| 229 request_->SetAutomaticallyRetryOnNetworkChanges(3); | 345 request_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 230 request_->Start(); | 346 request_->Start(); |
| 231 } | 347 } |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 } | 525 } |
| 410 | 526 |
| 411 void GaiaOAuthClient::GetTokenHandleInfo(const std::string& token_handle, | 527 void GaiaOAuthClient::GetTokenHandleInfo(const std::string& token_handle, |
| 412 int max_retries, | 528 int max_retries, |
| 413 Delegate* delegate) { | 529 Delegate* delegate) { |
| 414 return core_->GetTokenInfo("token_handle", token_handle, max_retries, | 530 return core_->GetTokenInfo("token_handle", token_handle, max_retries, |
| 415 delegate); | 531 delegate); |
| 416 } | 532 } |
| 417 | 533 |
| 418 } // namespace gaia | 534 } // namespace gaia |
| OLD | NEW |