Add aws signature v4 signer

pull/24618/head
Chuan Ren 4 years ago
parent 850f0c7c86
commit bedaeb5265
  1. 2
      BUILD
  2. 2
      BUILD.gn
  3. 41
      CMakeLists.txt
  4. 2
      Makefile
  5. 15
      build_autogenerated.yaml
  6. 1
      config.m4
  7. 1
      config.w32
  8. 2
      gRPC-C++.podspec
  9. 3
      gRPC-Core.podspec
  10. 2
      grpc.gemspec
  11. 1
      grpc.gyp
  12. 2
      package.xml
  13. 208
      src/core/lib/security/credentials/external/aws_request_signer.cc
  14. 73
      src/core/lib/security/credentials/external/aws_request_signer.h
  15. 1
      src/python/grpcio/grpc_core_dependencies.py
  16. 13
      test/core/security/BUILD
  17. 283
      test/core/security/aws_request_signer_test.cc
  18. 2
      tools/doxygen/Doxyfile.c++.internal
  19. 2
      tools/doxygen/Doxyfile.core.internal
  20. 24
      tools/run_tests/generated/tests.json

@ -1812,6 +1812,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/composite/composite_credentials.cc",
"src/core/lib/security/credentials/credentials.cc",
"src/core/lib/security/credentials/credentials_metadata.cc",
"src/core/lib/security/credentials/external/aws_request_signer.cc",
"src/core/lib/security/credentials/external/external_account_credentials.cc",
"src/core/lib/security/credentials/external/file_external_account_credentials.cc",
"src/core/lib/security/credentials/external/url_external_account_credentials.cc",
@ -1857,6 +1858,7 @@ grpc_cc_library(
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
"src/core/lib/security/credentials/credentials.h",
"src/core/lib/security/credentials/external/aws_request_signer.h",
"src/core/lib/security/credentials/external/external_account_credentials.h",
"src/core/lib/security/credentials/external/file_external_account_credentials.h",
"src/core/lib/security/credentials/external/url_external_account_credentials.h",

@ -1009,6 +1009,8 @@ config("grpc_config") {
"src/core/lib/security/credentials/credentials.cc",
"src/core/lib/security/credentials/credentials.h",
"src/core/lib/security/credentials/credentials_metadata.cc",
"src/core/lib/security/credentials/external/aws_request_signer.cc",
"src/core/lib/security/credentials/external/aws_request_signer.h",
"src/core/lib/security/credentials/external/external_account_credentials.cc",
"src/core/lib/security/credentials/external/external_account_credentials.h",
"src/core/lib/security/credentials/external/file_external_account_credentials.cc",

@ -716,6 +716,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx async_end2end_test)
add_dependencies(buildtests_cxx auth_property_iterator_test)
add_dependencies(buildtests_cxx authorization_engine_test)
add_dependencies(buildtests_cxx aws_request_signer_test)
add_dependencies(buildtests_cxx backoff_test)
add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
add_dependencies(buildtests_cxx badreq_bad_client_test)
@ -1855,6 +1856,7 @@ add_library(grpc
src/core/lib/security/credentials/composite/composite_credentials.cc
src/core/lib/security/credentials/credentials.cc
src/core/lib/security/credentials/credentials_metadata.cc
src/core/lib/security/credentials/external/aws_request_signer.cc
src/core/lib/security/credentials/external/external_account_credentials.cc
src/core/lib/security/credentials/external/file_external_account_credentials.cc
src/core/lib/security/credentials/external/url_external_account_credentials.cc
@ -8497,6 +8499,45 @@ target_link_libraries(authorization_engine_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(aws_request_signer_test
test/core/security/aws_request_signer_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(aws_request_signer_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(aws_request_signer_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)

@ -2255,6 +2255,7 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.cc \
@ -4799,6 +4800,7 @@ src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc:
src/core/lib/security/credentials/composite/composite_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/credentials_metadata.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/aws_request_signer.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/external_account_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/file_external_account_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/url_external_account_credentials.cc: $(OPENSSL_DEP)

@ -767,6 +767,7 @@ libs:
- src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
- src/core/lib/security/credentials/composite/composite_credentials.h
- src/core/lib/security/credentials/credentials.h
- src/core/lib/security/credentials/external/aws_request_signer.h
- src/core/lib/security/credentials/external/external_account_credentials.h
- src/core/lib/security/credentials/external/file_external_account_credentials.h
- src/core/lib/security/credentials/external/url_external_account_credentials.h
@ -1281,6 +1282,7 @@ libs:
- src/core/lib/security/credentials/composite/composite_credentials.cc
- src/core/lib/security/credentials/credentials.cc
- src/core/lib/security/credentials/credentials_metadata.cc
- src/core/lib/security/credentials/external/aws_request_signer.cc
- src/core/lib/security/credentials/external/external_account_credentials.cc
- src/core/lib/security/credentials/external/file_external_account_credentials.cc
- src/core/lib/security/credentials/external/url_external_account_credentials.cc
@ -4843,6 +4845,19 @@ targets:
- gpr
- address_sorting
- upb
- name: aws_request_signer_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/security/aws_request_signer_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
- name: backoff_test
gtest: true
build: test

@ -502,6 +502,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.cc \

@ -469,6 +469,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\composite\\composite_credentials.cc " +
"src\\core\\lib\\security\\credentials\\credentials.cc " +
"src\\core\\lib\\security\\credentials\\credentials_metadata.cc " +
"src\\core\\lib\\security\\credentials\\external\\aws_request_signer.cc " +
"src\\core\\lib\\security\\credentials\\external\\external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\external\\file_external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\external\\url_external_account_credentials.cc " +

@ -612,6 +612,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',
@ -1221,6 +1222,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',

@ -1065,6 +1065,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',
@ -1751,6 +1753,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
'src/core/lib/security/credentials/external/aws_request_signer.h',
'src/core/lib/security/credentials/external/external_account_credentials.h',
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',

@ -982,6 +982,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/credentials.cc )
s.files += %w( src/core/lib/security/credentials/credentials.h )
s.files += %w( src/core/lib/security/credentials/credentials_metadata.cc )
s.files += %w( src/core/lib/security/credentials/external/aws_request_signer.cc )
s.files += %w( src/core/lib/security/credentials/external/aws_request_signer.h )
s.files += %w( src/core/lib/security/credentials/external/external_account_credentials.cc )
s.files += %w( src/core/lib/security/credentials/external/external_account_credentials.h )
s.files += %w( src/core/lib/security/credentials/external/file_external_account_credentials.cc )

@ -868,6 +868,7 @@
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',
'src/core/lib/security/credentials/external/url_external_account_credentials.cc',

@ -962,6 +962,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/credentials_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_request_signer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/aws_request_signer.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/external_account_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/external_account_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/file_external_account_credentials.cc" role="src" />

@ -0,0 +1,208 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/external/aws_request_signer.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
namespace grpc_core {
namespace {
const char kAlgorithm[] = "AWS4-HMAC-SHA256";
const char kDateFormat[] = "%a, %d %b %E4Y %H:%M:%S %Z";
const char kXAmzDateFormat[] = "%Y%m%dT%H%M%SZ";
void SHA256(const std::string& str, unsigned char out[SHA256_DIGEST_LENGTH]) {
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(out, &sha256);
}
std::string SHA256Hex(const std::string& str) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(str, hash);
std::string hash_str(reinterpret_cast<char const*>(hash),
SHA256_DIGEST_LENGTH);
return absl::BytesToHexString(hash_str);
}
std::string HMAC(const std::string& key, const std::string& msg) {
unsigned int len;
unsigned char digest[EVP_MAX_MD_SIZE];
HMAC(EVP_sha256(), key.c_str(), key.length(),
(const unsigned char*)msg.c_str(), msg.length(), digest, &len);
return std::string(digest, digest + len);
}
} // namespace
AwsRequestSigner::AwsRequestSigner(
std::string access_key_id, std::string secret_access_key, std::string token,
std::string method, std::string url, std::string region,
std::string request_payload,
std::map<std::string, std::string> additional_headers, grpc_error** error)
: access_key_id_(std::move(access_key_id)),
secret_access_key_(std::move(secret_access_key)),
token_(std::move(token)),
method_(std::move(method)),
region_(std::move(region)),
request_payload_(std::move(request_payload)),
additional_headers_(std::move(additional_headers)) {
auto amz_date_it = additional_headers_.find("x-amz-date");
auto date_it = additional_headers_.find("date");
if (amz_date_it != additional_headers_.end() &&
date_it != additional_headers_.end()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Only one of {date, x-amz-date} can be specified, not both.");
return;
}
if (amz_date_it != additional_headers_.end()) {
static_request_date_ = amz_date_it->second;
} else if (date_it != additional_headers_.end()) {
absl::Time request_date;
std::string err_str;
if (!absl::ParseTime(kDateFormat, date_it->second, &request_date,
&err_str)) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(err_str.c_str());
return;
}
static_request_date_ =
absl::FormatTime(kXAmzDateFormat, request_date, absl::UTCTimeZone());
}
url_ = grpc_uri_parse(url, false);
if (url_ == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid Aws request url.");
return;
}
}
AwsRequestSigner::~AwsRequestSigner() { grpc_uri_destroy(url_); }
std::map<std::string, std::string> AwsRequestSigner::GetSignedRequestHeaders() {
std::string request_date_full;
if (!static_request_date_.empty()) {
if (!request_headers_.empty()) {
return request_headers_;
}
request_date_full = static_request_date_;
} else {
absl::Time request_date = absl::Now();
request_date_full =
absl::FormatTime(kXAmzDateFormat, request_date, absl::UTCTimeZone());
}
std::string request_date_short = request_date_full.substr(0, 8);
// TASK 1: Create a canonical request for Signature Version 4
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
std::vector<absl::string_view> canonical_request_vector;
// 1. HTTPRequestMethod
canonical_request_vector.emplace_back(method_);
canonical_request_vector.emplace_back("\n");
// 2. CanonicalURI
canonical_request_vector.emplace_back(*url_->path == '\0' ? "/" : url_->path);
canonical_request_vector.emplace_back("\n");
// 3. CanonicalQueryString
canonical_request_vector.emplace_back(url_->query);
canonical_request_vector.emplace_back("\n");
// 4. CanonicalHeaders
if (request_headers_.empty()) {
request_headers_.insert({"host", url_->authority});
if (!token_.empty()) {
request_headers_.insert({"x-amz-security-token", token_});
}
for (const auto& header : additional_headers_) {
request_headers_.insert(
{absl::AsciiStrToLower(header.first), header.second});
}
}
if (additional_headers_.find("date") == additional_headers_.end()) {
request_headers_["x-amz-date"] = request_date_full;
}
std::vector<absl::string_view> canonical_headers_vector;
for (const auto& header : request_headers_) {
canonical_headers_vector.emplace_back(header.first);
canonical_headers_vector.emplace_back(":");
canonical_headers_vector.emplace_back(header.second);
canonical_headers_vector.emplace_back("\n");
}
std::string canonical_headers = absl::StrJoin(canonical_headers_vector, "");
canonical_request_vector.emplace_back(canonical_headers);
canonical_request_vector.emplace_back("\n");
// 5. SignedHeaders
std::vector<absl::string_view> signed_headers_vector;
for (const auto& header : request_headers_) {
signed_headers_vector.emplace_back(header.first);
}
std::string signed_headers = absl::StrJoin(signed_headers_vector, ";");
canonical_request_vector.emplace_back(signed_headers);
canonical_request_vector.emplace_back("\n");
// 6. RequestPayload
std::string hashed_request_payload = SHA256Hex(request_payload_);
canonical_request_vector.emplace_back(hashed_request_payload);
std::string canonical_request = absl::StrJoin(canonical_request_vector, "");
// TASK 2: Create a string to sign for Signature Version 4
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
std::vector<absl::string_view> string_to_sign_vector;
// 1. Algorithm
string_to_sign_vector.emplace_back("AWS4-HMAC-SHA256");
string_to_sign_vector.emplace_back("\n");
// 2. RequestDateTime
string_to_sign_vector.emplace_back(request_date_full);
string_to_sign_vector.emplace_back("\n");
// 3. CredentialScope
std::pair<absl::string_view, absl::string_view> host_parts =
absl::StrSplit(url_->authority, absl::MaxSplits('.', 1));
std::string service_name(host_parts.first);
std::string credential_scope = absl::StrFormat(
"%s/%s/%s/aws4_request", request_date_short, region_, service_name);
string_to_sign_vector.emplace_back(credential_scope);
string_to_sign_vector.emplace_back("\n");
// 4. HashedCanonicalRequest
std::string hashed_canonical_request = SHA256Hex(canonical_request);
string_to_sign_vector.emplace_back(hashed_canonical_request);
std::string string_to_sign = absl::StrJoin(string_to_sign_vector, "");
// TASK 3: Task 3: Calculate the signature for AWS Signature Version 4
// https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
// 1. Derive your signing key.
std::string date = HMAC("AWS4" + secret_access_key_, request_date_short);
std::string region = HMAC(date, region_);
std::string service = HMAC(region, service_name);
std::string signing = HMAC(service, "aws4_request");
// 2. Calculate the signature.
std::string signature_str = HMAC(signing, string_to_sign);
std::string signature = absl::BytesToHexString(signature_str);
// TASK 4: Add the signature to the HTTP request
// https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
std::string authorization_header = absl::StrFormat(
"%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", kAlgorithm,
access_key_id_, credential_scope, signed_headers, signature);
request_headers_["Authorization"] = authorization_header;
return request_headers_;
}
} // namespace grpc_core

@ -0,0 +1,73 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_REQUEST_SIGNER_H
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_REQUEST_SIGNER_H
#include <grpc/support/port_platform.h>
#include <map>
#include <string>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
// Implements an AWS API request signer based on the AWS Signature Version 4
// signing process.
// https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
// To retrieve the subject token in AwsExternalAccountCredentials, we need to
// sign an AWS request server and use the signed request as the subject token.
// This class is a utility to sign an AWS request.
class AwsRequestSigner {
public:
// Construct a signer with the necessary information to sign a request.
// `access_key_id`, `secret_access_key` and `token` are the AWS credentials
// required for signing. `method` and `url` are the HTTP method and url of the
// request. `region` is the region of the AWS environment. `request_payload`
// is the payload of the HTTP request. `additional_headers` are additional
// headers to be inject into the request.
AwsRequestSigner(std::string access_key_id, std::string secret_access_key,
std::string token, std::string method, std::string url,
std::string region, std::string request_payload,
std::map<std::string, std::string> additional_headers,
grpc_error** error);
~AwsRequestSigner();
// This method triggers the signing process then returns the headers of the
// signed request as a map. In case there is an error, the input `error`
// parameter will be updated and an empty map will be returned if there is
// error.
std::map<std::string, std::string> GetSignedRequestHeaders();
private:
std::string access_key_id_;
std::string secret_access_key_;
std::string token_;
std::string method_;
grpc_uri* url_ = nullptr;
std::string region_;
std::string request_payload_;
std::map<std::string, std::string> additional_headers_;
std::string static_request_date_;
std::map<std::string, std::string> request_headers_;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_EXTERNAL_AWS_REQUEST_SIGNER_H

@ -478,6 +478,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/credentials_metadata.cc',
'src/core/lib/security/credentials/external/aws_request_signer.cc',
'src/core/lib/security/credentials/external/external_account_credentials.cc',
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',
'src/core/lib/security/credentials/external/url_external_account_credentials.cc',

@ -95,6 +95,19 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "aws_request_signer_test",
srcs = ["aws_request_signer_test.cc"],
external_deps = ["gtest"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc_secure",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "evaluate_args_test",
srcs = ["evaluate_args_test.cc"],

@ -0,0 +1,283 @@
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "src/core/lib/security/credentials/external/aws_request_signer.h"
#include <gmock/gmock.h>
#include <grpc/grpc_security.h>
#include "test/core/util/test_config.h"
namespace testing {
namespace {
// Test cases of Aws endpoints that the aws-sourced credentials will depend
// on.
const char* kAmzTestAccessKeyId = "ASIARD4OQDT6A77FR3CL";
const char* kAmzTestSecretAccessKey =
"Y8AfSaucF37G4PpvfguKZ3/l7Id4uocLXxX0+VTx";
const char* kAmzTestToken =
"IQoJb3JpZ2luX2VjEIz//////////wEaCXVzLWVhc3QtMiJGMEQCIH7MHX/Oy/"
"OB8OlLQa9GrqU1B914+iMikqWQW7vPCKlgAiA/"
"Lsv8Jcafn14owfxXn95FURZNKaaphj0ykpmS+Ki+"
"CSq0AwhlEAAaDDA3NzA3MTM5MTk5NiIMx9sAeP1ovlMTMKLjKpEDwuJQg41/"
"QUKx0laTZYjPlQvjwSqS3OB9P1KAXPWSLkliVMMqaHqelvMF/WO/"
"glv3KwuTfQsavRNs3v5pcSEm4SPO3l7mCs7KrQUHwGP0neZhIKxEXy+Ls//1C/"
"Bqt53NL+LSbaGv6RPHaX82laz2qElphg95aVLdYgIFY6JWV5fzyjgnhz0DQmy62/"
"Vi8pNcM2/"
"VnxeCQ8CC8dRDSt52ry2v+nc77vstuI9xV5k8mPtnaPoJDRANh0bjwY5Sdwkbp+"
"mGRUJBAQRlNgHUJusefXQgVKBCiyJY4w3Csd8Bgj9IyDV+"
"Azuy1jQqfFZWgP68LSz5bURyIjlWDQunO82stZ0BgplKKAa/"
"KJHBPCp8Qi6i99uy7qh76FQAqgVTsnDuU6fGpHDcsDSGoCls2HgZjZFPeOj8mmRhFk1Xqvkb"
"juz8V1cJk54d3gIJvQt8gD2D6yJQZecnuGWd5K2e2HohvCc8Fc9kBl1300nUJPV+k4tr/"
"A5R/0QfEKOZL1/"
"k5lf1g9CREnrM8LVkGxCgdYMxLQow1uTL+QU67AHRRSp5PhhGX4Rek+"
"01vdYSnJCMaPhSEgcLqDlQkhk6MPsyT91QMXcWmyO+cAZwUPwnRamFepuP4K8k2KVXs/"
"LIJHLELwAZ0ekyaS7CptgOqS7uaSTFG3U+vzFZLEnGvWQ7y9IPNQZ+"
"Dffgh4p3vF4J68y9049sI6Sr5d5wbKkcbm8hdCDHZcv4lnqohquPirLiFQ3q7B17V9krMPu3"
"mz1cg4Ekgcrn/"
"E09NTsxAqD8NcZ7C7ECom9r+"
"X3zkDOxaajW6hu3Az8hGlyylDaMiFfRbBJpTIlxp7jfa7CxikNgNtEKLH9iCzvuSg2vhA==";
const char* kAmzTestDate = "20200811T065522Z";
// Test cases derived from the Aws signature v4 test suite.
// https://github.com/boto/botocore/tree/master/tests/unit/auth/aws4_testsuite
const char* kBotoTestAccessKeyId = "AKIDEXAMPLE";
const char* kBotoTestSecretAccessKey =
"wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
const char* kBotoTestToken = "";
const char* kBotoTestDate = "Mon, 09 Sep 2011 23:36:00 GMT";
} // namespace
// AWS official example from the developer doc.
// https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
"AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "", "GET",
"https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08",
"us-east-1", "",
{{"content-type", "application/x-www-form-urlencoded; charset=utf-8"},
{"x-amz-date", "20150830T123600Z"}},
&error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, "
"SignedHeaders=content-type;host;x-amz-date, "
"Signature="
"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7");
}
TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "GET",
"https://"
"ec2.us-east-2.amazonaws.com?Action=DescribeRegions&Version=2013-10-15",
"us-east-2", "", {{"x-amz-date", kAmzTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(
signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=ASIARD4OQDT6A77FR3CL/20200811/us-east-2/ec2/aws4_request, "
"SignedHeaders=host;x-amz-date;x-amz-security-token, "
"Signature="
"631ea80cddfaa545fdadb120dc92c9f18166e38a5c47b50fab9fce476e022855");
}
TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "POST",
"https://"
"sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
"us-east-2", "", {{"x-amz-date", kAmzTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(
signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=ASIARD4OQDT6A77FR3CL/20200811/us-east-2/sts/aws4_request, "
"SignedHeaders=host;x-amz-date;x-amz-security-token, "
"Signature="
"73452984e4a880ffdc5c392355733ec3f5ba310d5e0609a89244440cadfe7a7a");
}
TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kAmzTestAccessKeyId, kAmzTestSecretAccessKey, "", "POST",
"https://"
"sts.us-east-2.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15",
"us-east-2", "", {{"x-amz-date", kAmzTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(
signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=ASIARD4OQDT6A77FR3CL/20200811/us-east-2/sts/aws4_request, "
"SignedHeaders=host;x-amz-date, "
"Signature="
"d095ba304919cd0d5570ba8a3787884ee78b860f268ed040ba23831d55536d56");
}
TEST(GrpcAwsRequestSignerTest, GetHost) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(kBotoTestAccessKeyId,
kBotoTestSecretAccessKey, kBotoTestToken,
"GET", "https://host.foo.com", "us-east-1",
"", {{"date", kBotoTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host, "
"Signature="
"b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470");
}
TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "GET",
"https://host.foo.com/?foo=Zoo&foo=aha", "us-east-1", "",
{{"date", kBotoTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host, "
"Signature="
"be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09");
}
TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
"https://host.foo.com/", "us-east-1", "",
{{"date", kBotoTestDate}, {"ZOO", "zoobar"}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host;zoo, "
"Signature="
"b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a");
}
TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
"https://host.foo.com/", "us-east-1", "",
{{"date", kBotoTestDate}, {"zoo", "ZOOBAR"}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host;zoo, "
"Signature="
"273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7");
}
TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
"https://host.foo.com/", "us-east-1", "",
{{"date", kBotoTestDate}, {"p", "phfft"}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host;p, "
"Signature="
"debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592");
}
TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
"https://host.foo.com/", "us-east-1", "foo=bar",
{{"date", kBotoTestDate},
{"Content-Type", "application/x-www-form-urlencoded"}},
&error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=content-type;date;host, "
"Signature="
"5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc");
}
TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST",
"https://host.foo.com/?foo=bar", "us-east-1", "",
{{"date", kBotoTestDate}}, &error);
EXPECT_EQ(error, GRPC_ERROR_NONE);
EXPECT_EQ(signer.GetSignedRequestHeaders()["Authorization"],
"AWS4-HMAC-SHA256 "
"Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, "
"SignedHeaders=date;host, "
"Signature="
"b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92");
}
TEST(GrpcAwsRequestSignerTest, InvalidUrl) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer("access_key_id", "secret_access_key",
"token", "POST", "invalid_url",
"us-east-1", "", {}, &error);
grpc_slice expected_error_description =
grpc_slice_from_static_string("Invalid Aws request url.");
grpc_slice actual_error_description;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&actual_error_description));
EXPECT_TRUE(grpc_slice_cmp(expected_error_description,
actual_error_description) == 0);
GRPC_ERROR_UNREF(error);
}
TEST(GrpcAwsRequestSignerTest, DuplicateRequestDate) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_core::AwsRequestSigner signer(
"access_key_id", "secret_access_key", "token", "POST", "invalid_url",
"us-east-1", "", {{"date", kBotoTestDate}, {"x-amz-date", kAmzTestDate}},
&error);
grpc_slice expected_error_description = grpc_slice_from_static_string(
"Only one of {date, x-amz-date} can be specified, not both.");
grpc_slice actual_error_description;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&actual_error_description));
EXPECT_TRUE(grpc_slice_cmp(expected_error_description,
actual_error_description) == 0);
GRPC_ERROR_UNREF(error);
}
} // namespace testing
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -1914,6 +1914,8 @@ src/core/lib/security/credentials/composite/composite_credentials.h \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials.h \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/aws_request_signer.h \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/external_account_credentials.h \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \

@ -1756,6 +1756,8 @@ src/core/lib/security/credentials/composite/composite_credentials.h \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/credentials.h \
src/core/lib/security/credentials/credentials_metadata.cc \
src/core/lib/security/credentials/external/aws_request_signer.cc \
src/core/lib/security/credentials/external/aws_request_signer.h \
src/core/lib/security/credentials/external/external_account_credentials.cc \
src/core/lib/security/credentials/external/external_account_credentials.h \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \

@ -3335,6 +3335,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "aws_request_signer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save