| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/printing/oauth2/ipp_endpoint_token_fetcher.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "base/containers/flat_set.h" |
| #include "base/functional/bind.h" |
| #include "chrome/browser/ash/printing/oauth2/http_exchange.h" |
| #include "chrome/browser/ash/printing/oauth2/status_code.h" |
| #include "chromeos/printing/uri.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "url/gurl.h" |
| |
| namespace ash { |
| namespace printing { |
| namespace oauth2 { |
| |
| IppEndpointTokenFetcher::IppEndpointTokenFetcher( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| const GURL& token_endpoint_uri, |
| const chromeos::Uri& ipp_endpoint, |
| base::flat_set<std::string>&& scope) |
| : token_endpoint_uri_(token_endpoint_uri), |
| ipp_endpoint_uri_(ipp_endpoint), |
| scope_(scope), |
| http_exchange_(url_loader_factory) {} |
| |
| IppEndpointTokenFetcher::~IppEndpointTokenFetcher() = default; |
| |
| void IppEndpointTokenFetcher::AddToWaitingList(StatusCallback callback) { |
| callbacks_.push_back(std::move(callback)); |
| } |
| |
| std::vector<StatusCallback> IppEndpointTokenFetcher::TakeWaitingList() { |
| std::vector<StatusCallback> waitlist; |
| waitlist.swap(callbacks_); |
| return waitlist; |
| } |
| |
| void IppEndpointTokenFetcher::SendTokenExchangeRequest( |
| const std::string& access_token, |
| StatusCallback callback) { |
| net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation = |
| net::DefinePartialNetworkTrafficAnnotation( |
| "printing_oauth2_token_exchange_request", |
| "printing_oauth2_http_exchange", R"( |
| semantics { |
| description: |
| "This request asks Authorization Server for an endpoint access token " |
| "to use for communication with a particular printer." |
| data: |
| "Address of the printer and the access token of the current OAuth 2 " |
| "session with the Authorization Server." |
| })"); |
| http_exchange_.Clear(); |
| |
| // Move query parameters from URL to the content. |
| chromeos::Uri uri(token_endpoint_uri_.spec()); |
| auto query = uri.GetQuery(); |
| for (const auto& kv : query) { |
| http_exchange_.AddParamString(kv.first, kv.second); |
| } |
| uri.SetQuery({}); |
| |
| // Prepare the request. |
| http_exchange_.AddParamString( |
| "grant_type", "urn:ietf:params:oauth:grant-type:token-exchange"); |
| http_exchange_.AddParamString("resource", ipp_endpoint_uri_.GetNormalized()); |
| http_exchange_.AddParamString("subject_token", access_token); |
| http_exchange_.AddParamString( |
| "subject_token_type", "urn:ietf:params:oauth:token-type:access_token"); |
| http_exchange_.Exchange( |
| "POST", GURL(uri.GetNormalized()), ContentFormat::kXWwwFormUrlencoded, |
| 200, 400, partial_traffic_annotation, |
| base::BindOnce(&IppEndpointTokenFetcher::OnTokenExchangeResponse, |
| base::Unretained(this), access_token, |
| std::move(callback))); |
| } |
| |
| void IppEndpointTokenFetcher::OnTokenExchangeResponse( |
| const std::string& access_token, |
| StatusCallback callback, |
| StatusCode status) { |
| if (status == StatusCode::kInvalidAccessToken) { |
| std::move(callback).Run(status, access_token); |
| return; |
| } |
| |
| if (status != StatusCode::kOK) { |
| std::move(callback).Run(status, http_exchange_.GetErrorMessage()); |
| return; |
| } |
| |
| const bool ok = |
| http_exchange_.ParamStringGet("access_token", true, |
| &endpoint_access_token_) && |
| http_exchange_.ParamStringGet("issued_token_type", true, nullptr) && |
| http_exchange_.ParamStringEquals("token_type", true, "bearer"); |
| if (!ok) { |
| // Error occurred. |
| endpoint_access_token_.clear(); |
| std::move(callback).Run(StatusCode::kInvalidResponse, |
| http_exchange_.GetErrorMessage()); |
| return; |
| } |
| |
| // Success! |
| std::move(callback).Run(StatusCode::kOK, endpoint_access_token_); |
| } |
| |
| } // namespace oauth2 |
| } // namespace printing |
| } // namespace ash |