| 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 the user " |
| 147 "signs 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 the user " |
| 200 "signs 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: |
| 245 "This request is used to fetch profile information about the user, " |
| 246 "like the email, the ID of the account, the full name, and the " |
| 247 "profile picture." |
| 248 trigger: |
| 249 "The main trigger for this request is in the AccountTrackerService " |
| 250 "that fetches the user info soon after the user signs in." |
| 251 data: |
| 252 "The OAuth 2.0 access token of the account." |
| 253 destination: GOOGLE_OWNED_SERVICE |
| 254 } |
| 255 policy { |
| 256 cookies_allowed: false |
| 257 setting: |
| 258 "This feature cannot be disabled in settings, but if the user " |
| 259 "signs out of Chrome, this request would not be made." |
| 260 chrome_policy { |
| 261 SigninAllowed { |
| 262 policy_options {mode: MANDATORY} |
| 263 SigninAllowed: false |
| 264 } |
| 265 } |
| 266 })"); |
| 179 request_ = net::URLFetcher::Create( | 267 request_ = net::URLFetcher::Create( |
| 180 kUrlFetcherId, GURL(GaiaUrls::GetInstance()->oauth_user_info_url()), | 268 kUrlFetcherId, GURL(GaiaUrls::GetInstance()->oauth_user_info_url()), |
| 181 net::URLFetcher::GET, this); | 269 net::URLFetcher::GET, this, traffic_annotation); |
| 182 request_->SetRequestContext(request_context_getter_.get()); | 270 request_->SetRequestContext(request_context_getter_.get()); |
| 183 request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token); | 271 request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token); |
| 184 request_->SetMaxRetriesOn5xx(max_retries); | 272 request_->SetMaxRetriesOn5xx(max_retries); |
| 185 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 273 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 186 net::LOAD_DO_NOT_SAVE_COOKIES); | 274 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 187 MarkURLFetcherAsGaia(request_.get()); | 275 MarkURLFetcherAsGaia(request_.get()); |
| 188 | 276 |
| 189 // Fetchers are sometimes cancelled because a network change was detected, | 277 // Fetchers are sometimes cancelled because a network change was detected, |
| 190 // especially at startup and after sign-in on ChromeOS. Retrying once should | 278 // 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. | 279 // be enough in those cases; let the fetcher retry up to 3 times just in case. |
| 192 // http://crbug.com/163710 | 280 // http://crbug.com/163710 |
| 193 request_->SetAutomaticallyRetryOnNetworkChanges(3); | 281 request_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 194 request_->Start(); | 282 request_->Start(); |
| 195 } | 283 } |
| 196 | 284 |
| 197 void GaiaOAuthClient::Core::GetTokenInfo(const std::string& qualifier, | 285 void GaiaOAuthClient::Core::GetTokenInfo(const std::string& qualifier, |
| 198 const std::string& query, | 286 const std::string& query, |
| 199 int max_retries, | 287 int max_retries, |
| 200 Delegate* delegate) { | 288 Delegate* delegate) { |
| 201 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); | 289 DCHECK_EQ(request_type_, NO_PENDING_REQUEST); |
| 202 DCHECK(!request_.get()); | 290 DCHECK(!request_.get()); |
| 203 request_type_ = TOKEN_INFO; | 291 request_type_ = TOKEN_INFO; |
| 204 std::string post_body = | 292 std::string post_body = |
| 205 qualifier + "=" + net::EscapeUrlEncodedData(query, true); | 293 qualifier + "=" + net::EscapeUrlEncodedData(query, true); |
| 294 net::NetworkTrafficAnnotationTag traffic_annotation = |
| 295 net::DefineNetworkTrafficAnnotation("...", R"( |
| 296 semantics { |
| 297 sender: "OAuth 2.0 calls" |
| 298 description: |
| 299 "This request fetches information about an OAuth 2.0 access token. " |
| 300 "The response is a dictionary of response values. The provided " |
| 301 "access token may have any scope, and basic results will be " |
| 302 "returned: issued_to, audience, scope, expires_in, access_type. In " |
| 303 "addition, if the https://www.googleapis.com/auth/userinfo.email " |
| 304 "scope is present, the email and verified_email fields will be " |
| 305 "returned. If the https://www.googleapis.com/auth/userinfo.profile " |
| 306 "scope is present, the user_id field will be returned." |
| 307 trigger: |
| 308 "This is triggered after a Google account is added to the browser. " |
| 309 "It it also triggered after each successful fetch of an OAuth 2.0 " |
| 310 "access token." |
| 311 data: "The OAuth 2.0 access token." |
| 312 destination: GOOGLE_OWNED_SERVICE |
| 313 } |
| 314 policy { |
| 315 cookies_allowed: false |
| 316 setting: |
| 317 "This feature cannot be disabled in settings, but if the user " |
| 318 "signs out of Chrome, this request would not be made." |
| 319 chrome_policy { |
| 320 SigninAllowed { |
| 321 policy_options {mode: MANDATORY} |
| 322 SigninAllowed: false |
| 323 } |
| 324 } |
| 325 })"); |
| 206 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_info_url()), | 326 MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_info_url()), |
| 207 post_body, | 327 post_body, max_retries, delegate, traffic_annotation); |
| 208 max_retries, | |
| 209 delegate); | |
| 210 } | 328 } |
| 211 | 329 |
| 212 void GaiaOAuthClient::Core::MakeGaiaRequest( | 330 void GaiaOAuthClient::Core::MakeGaiaRequest( |
| 213 const GURL& url, | 331 const GURL& url, |
| 214 const std::string& post_body, | 332 const std::string& post_body, |
| 215 int max_retries, | 333 int max_retries, |
| 216 GaiaOAuthClient::Delegate* delegate) { | 334 GaiaOAuthClient::Delegate* delegate, |
| 335 const net::NetworkTrafficAnnotationTag& traffic_annotation) { |
| 217 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; | 336 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; |
| 218 delegate_ = delegate; | 337 delegate_ = delegate; |
| 219 num_retries_ = 0; | 338 num_retries_ = 0; |
| 220 request_ = | 339 request_ = net::URLFetcher::Create(kUrlFetcherId, url, net::URLFetcher::POST, |
| 221 net::URLFetcher::Create(kUrlFetcherId, url, net::URLFetcher::POST, this); | 340 this, traffic_annotation); |
| 222 request_->SetRequestContext(request_context_getter_.get()); | 341 request_->SetRequestContext(request_context_getter_.get()); |
| 223 request_->SetUploadData("application/x-www-form-urlencoded", post_body); | 342 request_->SetUploadData("application/x-www-form-urlencoded", post_body); |
| 224 request_->SetMaxRetriesOn5xx(max_retries); | 343 request_->SetMaxRetriesOn5xx(max_retries); |
| 225 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 344 request_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 226 net::LOAD_DO_NOT_SAVE_COOKIES); | 345 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 227 MarkURLFetcherAsGaia(request_.get()); | 346 MarkURLFetcherAsGaia(request_.get()); |
| 228 // See comment on SetAutomaticallyRetryOnNetworkChanges() above. | 347 // See comment on SetAutomaticallyRetryOnNetworkChanges() above. |
| 229 request_->SetAutomaticallyRetryOnNetworkChanges(3); | 348 request_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 230 request_->Start(); | 349 request_->Start(); |
| 231 } | 350 } |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 } | 528 } |
| 410 | 529 |
| 411 void GaiaOAuthClient::GetTokenHandleInfo(const std::string& token_handle, | 530 void GaiaOAuthClient::GetTokenHandleInfo(const std::string& token_handle, |
| 412 int max_retries, | 531 int max_retries, |
| 413 Delegate* delegate) { | 532 Delegate* delegate) { |
| 414 return core_->GetTokenInfo("token_handle", token_handle, max_retries, | 533 return core_->GetTokenInfo("token_handle", token_handle, max_retries, |
| 415 delegate); | 534 delegate); |
| 416 } | 535 } |
| 417 | 536 |
| 418 } // namespace gaia | 537 } // namespace gaia |
| OLD | NEW |