LCOV - code coverage report
Current view: top level - source/extensions/common/aws - signer_base_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 11 64 17.2 %
Date: 2024-01-05 06:35:25 Functions: 2 7 28.6 %

          Line data    Source code
       1             : #include "source/extensions/common/aws/signer_base_impl.h"
       2             : 
       3             : #include <openssl/ssl.h>
       4             : 
       5             : #include <cstddef>
       6             : 
       7             : #include "envoy/common/exception.h"
       8             : 
       9             : #include "source/common/buffer/buffer_impl.h"
      10             : #include "source/common/common/fmt.h"
      11             : #include "source/common/common/hex.h"
      12             : #include "source/common/crypto/utility.h"
      13             : #include "source/common/http/headers.h"
      14             : #include "source/extensions/common/aws/utility.h"
      15             : 
      16             : #include "absl/strings/str_join.h"
      17             : 
      18             : namespace Envoy {
      19             : namespace Extensions {
      20             : namespace Common {
      21             : namespace Aws {
      22             : 
      23             : void SignerBaseImpl::sign(Http::RequestMessage& message, bool sign_body,
      24           0 :                           const absl::string_view override_region) {
      25             : 
      26           0 :   const auto content_hash = createContentHash(message, sign_body);
      27           0 :   auto& headers = message.headers();
      28           0 :   sign(headers, content_hash, override_region);
      29           0 : }
      30             : 
      31             : void SignerBaseImpl::signEmptyPayload(Http::RequestHeaderMap& headers,
      32           1 :                                       const absl::string_view override_region) {
      33           1 :   headers.setReference(SignatureHeaders::get().ContentSha256,
      34           1 :                        SignatureConstants::get().HashedEmptyString);
      35           1 :   sign(headers, SignatureConstants::get().HashedEmptyString, override_region);
      36           1 : }
      37             : 
      38             : void SignerBaseImpl::signUnsignedPayload(Http::RequestHeaderMap& headers,
      39           0 :                                          const absl::string_view override_region) {
      40           0 :   headers.setReference(SignatureHeaders::get().ContentSha256,
      41           0 :                        SignatureConstants::get().UnsignedPayload);
      42           0 :   sign(headers, SignatureConstants::get().UnsignedPayload, override_region);
      43           0 : }
      44             : 
      45             : // Required only for sigv4a
      46             : void SignerBaseImpl::addRegionHeader(
      47             :     ABSL_ATTRIBUTE_UNUSED Http::RequestHeaderMap& headers,
      48           0 :     ABSL_ATTRIBUTE_UNUSED const absl::string_view override_region) const {}
      49             : 
      50           0 : std::string SignerBaseImpl::getRegion() const { return region_; }
      51             : 
      52             : void SignerBaseImpl::sign(Http::RequestHeaderMap& headers, const std::string& content_hash,
      53           5 :                           const absl::string_view override_region) {
      54             : 
      55           5 :   headers.setReferenceKey(SignatureHeaders::get().ContentSha256, content_hash);
      56           5 :   const auto& credentials = credentials_provider_->getCredentials();
      57           5 :   if (!credentials.accessKeyId() || !credentials.secretAccessKey()) {
      58             :     // Empty or "anonymous" credentials are a valid use-case for non-production environments.
      59             :     // This behavior matches what the AWS SDK would do.
      60           5 :     return;
      61           5 :   }
      62           0 :   const auto* method_header = headers.Method();
      63           0 :   if (method_header == nullptr) {
      64           0 :     throw EnvoyException("Message is missing :method header");
      65           0 :   }
      66           0 :   const auto* path_header = headers.Path();
      67           0 :   if (path_header == nullptr) {
      68           0 :     throw EnvoyException("Message is missing :path header");
      69           0 :   }
      70             : 
      71           0 :   if (credentials.sessionToken()) {
      72           0 :     headers.addCopy(SignatureHeaders::get().SecurityToken, credentials.sessionToken().value());
      73           0 :   }
      74           0 :   const auto long_date = long_date_formatter_.now(time_source_);
      75           0 :   const auto short_date = short_date_formatter_.now(time_source_);
      76           0 :   headers.addCopy(SignatureHeaders::get().Date, long_date);
      77             : 
      78           0 :   addRegionHeader(headers, override_region);
      79             : 
      80             :   // Phase 1: Create a canonical request
      81           0 :   const auto canonical_headers = Utility::canonicalizeHeaders(headers, excluded_header_matchers_);
      82           0 :   const auto canonical_request = Utility::createCanonicalRequest(
      83           0 :       service_name_, method_header->value().getStringView(), path_header->value().getStringView(),
      84           0 :       canonical_headers, content_hash);
      85           0 :   ENVOY_LOG(debug, "Canonical request:\n{}", canonical_request);
      86             : 
      87             :   // Phase 2: Create a string to sign
      88           0 :   const auto credential_scope = createCredentialScope(short_date, override_region);
      89           0 :   const auto string_to_sign = createStringToSign(canonical_request, long_date, credential_scope);
      90           0 :   ENVOY_LOG(debug, "String to sign:\n{}", string_to_sign);
      91             : 
      92             :   // Phase 3: Create a signature
      93           0 :   const auto signature =
      94           0 :       createSignature(credentials.accessKeyId().value(), credentials.secretAccessKey().value(),
      95           0 :                       short_date, string_to_sign, override_region);
      96             :   // Phase 4: Sign request
      97           0 :   const auto authorization_header = createAuthorizationHeader(
      98           0 :       credentials.accessKeyId().value(), credential_scope, canonical_headers, signature);
      99           0 :   ENVOY_LOG(debug, "Signing request with: {}", authorization_header);
     100           0 :   headers.addCopy(Http::CustomHeaders::get().Authorization, authorization_header);
     101           0 : }
     102             : 
     103           0 : std::string SignerBaseImpl::createContentHash(Http::RequestMessage& message, bool sign_body) const {
     104           0 :   if (!sign_body) {
     105           0 :     return SignatureConstants::get().HashedEmptyString;
     106           0 :   }
     107           0 :   auto& crypto_util = Envoy::Common::Crypto::UtilitySingleton::get();
     108           0 :   const auto content_hash = message.body().length() > 0
     109           0 :                                 ? Hex::encode(crypto_util.getSha256Digest(message.body()))
     110           0 :                                 : SignatureConstants::get().HashedEmptyString;
     111           0 :   return content_hash;
     112           0 : }
     113             : 
     114             : } // namespace Aws
     115             : } // namespace Common
     116             : } // namespace Extensions
     117             : } // namespace Envoy

Generated by: LCOV version 1.15