Add File Watcher Certificate Provider API
This commit is contained in:
parent
e6e6be4b0b
commit
d74e43da95
|
|
@ -830,6 +830,7 @@ if(gRPC_BUILD_TESTS)
|
|||
add_dependencies(buildtests_cxx google_mesh_ca_certificate_provider_factory_test)
|
||||
add_dependencies(buildtests_cxx grpc_cli)
|
||||
add_dependencies(buildtests_cxx grpc_tls_certificate_distributor_test)
|
||||
add_dependencies(buildtests_cxx grpc_tls_certificate_provider_test)
|
||||
add_dependencies(buildtests_cxx grpc_tls_credentials_options_test)
|
||||
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
|
||||
add_dependencies(buildtests_cxx grpc_tool_test)
|
||||
|
|
@ -11696,6 +11697,7 @@ if(gRPC_BUILD_TESTS)
|
|||
|
||||
add_executable(grpc_tls_certificate_distributor_test
|
||||
test/core/security/grpc_tls_certificate_distributor_test.cc
|
||||
test/core/security/tls_utils.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
|
@ -11729,11 +11731,51 @@ target_link_libraries(grpc_tls_certificate_distributor_test
|
|||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(grpc_tls_certificate_provider_test
|
||||
test/core/security/grpc_tls_certificate_provider_test.cc
|
||||
test/core/security/tls_utils.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
||||
target_include_directories(grpc_tls_certificate_provider_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(grpc_tls_certificate_provider_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
grpc_test_util
|
||||
grpc
|
||||
gpr
|
||||
address_sorting
|
||||
upb
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(grpc_tls_credentials_options_test
|
||||
test/core/security/grpc_tls_credentials_options_test.cc
|
||||
test/core/security/tls_utils.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6208,9 +6208,26 @@ targets:
|
|||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers: []
|
||||
headers:
|
||||
- test/core/security/tls_utils.h
|
||||
src:
|
||||
- test/core/security/grpc_tls_certificate_distributor_test.cc
|
||||
- test/core/security/tls_utils.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
- grpc
|
||||
- gpr
|
||||
- address_sorting
|
||||
- upb
|
||||
- name: grpc_tls_certificate_provider_test
|
||||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers:
|
||||
- test/core/security/tls_utils.h
|
||||
src:
|
||||
- test/core/security/grpc_tls_certificate_provider_test.cc
|
||||
- test/core/security/tls_utils.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
- grpc
|
||||
|
|
@ -6221,9 +6238,11 @@ targets:
|
|||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers: []
|
||||
headers:
|
||||
- test/core/security/tls_utils.h
|
||||
src:
|
||||
- test/core/security/grpc_tls_credentials_options_test.cc
|
||||
- test/core/security/tls_utils.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
- grpc
|
||||
|
|
|
|||
1
grpc.def
1
grpc.def
|
|
@ -139,6 +139,7 @@ EXPORTS
|
|||
grpc_tls_identity_pairs_add_pair
|
||||
grpc_tls_identity_pairs_destroy
|
||||
grpc_tls_certificate_provider_static_data_create
|
||||
grpc_tls_certificate_provider_file_watcher_create
|
||||
grpc_tls_certificate_provider_release
|
||||
grpc_tls_credentials_options_create
|
||||
grpc_tls_credentials_options_set_cert_request_type
|
||||
|
|
|
|||
|
|
@ -807,6 +807,31 @@ GRPCAPI grpc_tls_certificate_provider*
|
|||
grpc_tls_certificate_provider_static_data_create(
|
||||
const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs);
|
||||
|
||||
/**
|
||||
* Creates a grpc_tls_certificate_provider that will watch the credential
|
||||
* changes on the file system. This provider will always return the up-to-date
|
||||
* cert data for all the cert names callers set through
|
||||
* |grpc_tls_credentials_options|. Note that this API only supports one key-cert
|
||||
* file and hence one set of identity key-cert pair, so SNI(Server Name
|
||||
* Indication) is not supported.
|
||||
* - private_key_path is the file path of the private key. This must be set if
|
||||
* |identity_certificate_path| is set. Otherwise, it could be null if no
|
||||
* identity credentials are needed.
|
||||
* - identity_certificate_path is the file path of the identity certificate
|
||||
* chain. This must be set if |private_key_path| is set. Otherwise, it could
|
||||
* be null if no identity credentials are needed.
|
||||
* - root_cert_path is the file path to the root certificate bundle. This
|
||||
* may be null if no root certs are needed.
|
||||
* - refresh_interval_sec is the refreshing interval that we will check the
|
||||
* files for updates.
|
||||
* It does not take ownership of parameters.
|
||||
* It is used for experimental purpose for now and subject to change.
|
||||
*/
|
||||
GRPCAPI grpc_tls_certificate_provider*
|
||||
grpc_tls_certificate_provider_file_watcher_create(
|
||||
const char* private_key_path, const char* identity_certificate_path,
|
||||
const char* root_cert_path, unsigned int refresh_interval_sec);
|
||||
|
||||
/**
|
||||
* Releases a grpc_tls_certificate_provider object. The creator of the
|
||||
* grpc_tls_certificate_provider object is responsible for its release. It is
|
||||
|
|
|
|||
|
|
@ -66,7 +66,57 @@ class StaticDataCertificateProvider : public CertificateProviderInterface {
|
|||
const std::vector<IdentityKeyCertPair>& identity_key_cert_pairs)
|
||||
: StaticDataCertificateProvider("", identity_key_cert_pairs) {}
|
||||
|
||||
~StaticDataCertificateProvider();
|
||||
~StaticDataCertificateProvider() override;
|
||||
|
||||
grpc_tls_certificate_provider* c_provider() override { return c_provider_; }
|
||||
|
||||
private:
|
||||
grpc_tls_certificate_provider* c_provider_ = nullptr;
|
||||
};
|
||||
|
||||
// A CertificateProviderInterface implementation that will watch the credential
|
||||
// changes on the file system. This provider will always return the up-to-date
|
||||
// cert data for all the cert names callers set through |TlsCredentialsOptions|.
|
||||
// Several things to note:
|
||||
// 1. This API only supports one key-cert file and hence one set of identity
|
||||
// key-cert pair, so SNI(Server Name Indication) is not supported.
|
||||
// 2. The private key and identity certificate should always match. This API
|
||||
// guarantees atomic read, and it is the callers' responsibility to do atomic
|
||||
// updates. There are many ways to atomically update the key and certs in the
|
||||
// file system. To name a few:
|
||||
// 1) creating a new directory, renaming the old directory to a new name, and
|
||||
// then renaming the new directory to the original name of the old directory.
|
||||
// 2) using a symlink for the directory. When need to change, put new
|
||||
// credential data in a new directory, and change symlink.
|
||||
class FileWatcherCertificateProvider final
|
||||
: public CertificateProviderInterface {
|
||||
public:
|
||||
// Constructor to get credential updates from root and identity file paths.
|
||||
//
|
||||
// @param private_key_path is the file path of the private key.
|
||||
// @param identity_certificate_path is the file path of the identity
|
||||
// certificate chain.
|
||||
// @param root_cert_path is the file path to the root certificate bundle.
|
||||
// @param refresh_interval_sec is the refreshing interval that we will check
|
||||
// the files for updates.
|
||||
FileWatcherCertificateProvider(const std::string& private_key_path,
|
||||
const std::string& identity_certificate_path,
|
||||
const std::string& root_cert_path,
|
||||
unsigned int refresh_interval_sec);
|
||||
// Constructor to get credential updates from identity file paths only.
|
||||
FileWatcherCertificateProvider(const std::string& private_key_path,
|
||||
const std::string& identity_certificate_path,
|
||||
unsigned int refresh_interval_sec)
|
||||
: FileWatcherCertificateProvider(private_key_path,
|
||||
identity_certificate_path, "",
|
||||
refresh_interval_sec) {}
|
||||
// Constructor to get credential updates from root file path only.
|
||||
FileWatcherCertificateProvider(const std::string& root_cert_path,
|
||||
unsigned int refresh_interval_sec)
|
||||
: FileWatcherCertificateProvider("", "", root_cert_path,
|
||||
refresh_interval_sec) {}
|
||||
|
||||
~FileWatcherCertificateProvider() override;
|
||||
|
||||
grpc_tls_certificate_provider* c_provider() override { return c_provider_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -72,12 +72,7 @@ struct grpc_tls_certificate_distributor
|
|||
grpc_error* identity_cert_error) = 0;
|
||||
};
|
||||
|
||||
// Sets the key materials based on their certificate name. Note that we are
|
||||
// not doing any copies for pem_root_certs and pem_key_cert_pairs. For
|
||||
// pem_root_certs, the original string contents need to outlive the
|
||||
// distributor; for pem_key_cert_pairs, internally it is taking two
|
||||
// unique_ptr(s) to the credential string, so the ownership is actually
|
||||
// transferred.
|
||||
// Sets the key materials based on their certificate name.
|
||||
//
|
||||
// @param cert_name The name of the certificates being updated.
|
||||
// @param pem_root_certs The content of root certificates.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
|
||||
#include "src/core/lib/gprpp/stat.h"
|
||||
#include "src/core/lib/slice/slice_internal.h"
|
||||
#include "src/core/lib/surface/api_trace.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
|
@ -35,20 +37,334 @@ StaticDataCertificateProvider::StaticDataCertificateProvider(
|
|||
distributor_->SetWatchStatusCallback([this](std::string cert_name,
|
||||
bool root_being_watched,
|
||||
bool identity_being_watched) {
|
||||
if (!root_being_watched && !identity_being_watched) return;
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
absl::optional<std::string> root_certificate;
|
||||
absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
|
||||
if (root_being_watched) {
|
||||
StaticDataCertificateProvider::WatcherInfo& info = watcher_info_[cert_name];
|
||||
if (!info.root_being_watched && root_being_watched &&
|
||||
!root_certificate_.empty()) {
|
||||
root_certificate = root_certificate_;
|
||||
}
|
||||
if (identity_being_watched) {
|
||||
info.root_being_watched = root_being_watched;
|
||||
if (!info.identity_being_watched && identity_being_watched &&
|
||||
!pem_key_cert_pairs_.empty()) {
|
||||
pem_key_cert_pairs = pem_key_cert_pairs_;
|
||||
}
|
||||
distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
|
||||
std::move(pem_key_cert_pairs));
|
||||
info.identity_being_watched = identity_being_watched;
|
||||
if (!info.root_being_watched && !info.identity_being_watched) {
|
||||
watcher_info_.erase(cert_name);
|
||||
}
|
||||
const bool root_has_update = root_certificate.has_value();
|
||||
const bool identity_has_update = pem_key_cert_pairs.has_value();
|
||||
if (root_has_update || identity_has_update) {
|
||||
distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
|
||||
std::move(pem_key_cert_pairs));
|
||||
}
|
||||
grpc_error* root_cert_error = GRPC_ERROR_NONE;
|
||||
grpc_error* identity_cert_error = GRPC_ERROR_NONE;
|
||||
if (root_being_watched && !root_has_update) {
|
||||
root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest root certificates.");
|
||||
}
|
||||
if (identity_being_watched && !identity_has_update) {
|
||||
identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest identity certificates.");
|
||||
}
|
||||
if (root_cert_error != GRPC_ERROR_NONE ||
|
||||
identity_cert_error != GRPC_ERROR_NONE) {
|
||||
distributor_->SetErrorForCert(cert_name, root_cert_error,
|
||||
identity_cert_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
StaticDataCertificateProvider::~StaticDataCertificateProvider() {
|
||||
// Reset distributor's callback to make sure the callback won't be invoked
|
||||
// again after this object(provider) is destroyed.
|
||||
distributor_->SetWatchStatusCallback(nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
gpr_timespec TimeoutSecondsToDeadline(int64_t seconds) {
|
||||
return gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(seconds, GPR_TIMESPAN));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FileWatcherCertificateProvider::FileWatcherCertificateProvider(
|
||||
std::string private_key_path, std::string identity_certificate_path,
|
||||
std::string root_cert_path, unsigned int refresh_interval_sec)
|
||||
: private_key_path_(std::move(private_key_path)),
|
||||
identity_certificate_path_(std::move(identity_certificate_path)),
|
||||
root_cert_path_(std::move(root_cert_path)),
|
||||
refresh_interval_sec_(refresh_interval_sec),
|
||||
distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
|
||||
// Private key and identity cert files must be both set or both unset.
|
||||
GPR_ASSERT(private_key_path_.empty() == identity_certificate_path_.empty());
|
||||
// Must be watching either root or identity certs.
|
||||
GPR_ASSERT(!private_key_path_.empty() || !root_cert_path_.empty());
|
||||
gpr_event_init(&shutdown_event_);
|
||||
ForceUpdate();
|
||||
auto thread_lambda = [](void* arg) {
|
||||
FileWatcherCertificateProvider* provider =
|
||||
static_cast<FileWatcherCertificateProvider*>(arg);
|
||||
GPR_ASSERT(provider != nullptr);
|
||||
while (true) {
|
||||
void* value = gpr_event_wait(
|
||||
&provider->shutdown_event_,
|
||||
TimeoutSecondsToDeadline(provider->refresh_interval_sec_));
|
||||
if (value != nullptr) {
|
||||
return;
|
||||
};
|
||||
provider->ForceUpdate();
|
||||
}
|
||||
};
|
||||
refresh_thread_ = grpc_core::Thread(
|
||||
"FileWatcherCertificateProvider_refreshing_thread", thread_lambda, this);
|
||||
refresh_thread_.Start();
|
||||
distributor_->SetWatchStatusCallback([this](std::string cert_name,
|
||||
bool root_being_watched,
|
||||
bool identity_being_watched) {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
absl::optional<std::string> root_certificate;
|
||||
absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
|
||||
FileWatcherCertificateProvider::WatcherInfo& info =
|
||||
watcher_info_[cert_name];
|
||||
if (!info.root_being_watched && root_being_watched &&
|
||||
!root_certificate_.empty()) {
|
||||
root_certificate = root_certificate_;
|
||||
}
|
||||
info.root_being_watched = root_being_watched;
|
||||
if (!info.identity_being_watched && identity_being_watched &&
|
||||
!pem_key_cert_pairs_.empty()) {
|
||||
pem_key_cert_pairs = pem_key_cert_pairs_;
|
||||
}
|
||||
info.identity_being_watched = identity_being_watched;
|
||||
if (!info.root_being_watched && !info.identity_being_watched) {
|
||||
watcher_info_.erase(cert_name);
|
||||
}
|
||||
ExecCtx exec_ctx;
|
||||
if (root_certificate.has_value() || pem_key_cert_pairs.has_value()) {
|
||||
distributor_->SetKeyMaterials(cert_name, root_certificate,
|
||||
pem_key_cert_pairs);
|
||||
}
|
||||
grpc_error* root_cert_error = GRPC_ERROR_NONE;
|
||||
grpc_error* identity_cert_error = GRPC_ERROR_NONE;
|
||||
if (root_being_watched && !root_certificate.has_value()) {
|
||||
root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest root certificates.");
|
||||
}
|
||||
if (identity_being_watched && !pem_key_cert_pairs.has_value()) {
|
||||
identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest identity certificates.");
|
||||
}
|
||||
if (root_cert_error != GRPC_ERROR_NONE ||
|
||||
identity_cert_error != GRPC_ERROR_NONE) {
|
||||
distributor_->SetErrorForCert(cert_name, root_cert_error,
|
||||
identity_cert_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FileWatcherCertificateProvider::~FileWatcherCertificateProvider() {
|
||||
// Reset distributor's callback to make sure the callback won't be invoked
|
||||
// again after this object(provider) is destroyed.
|
||||
distributor_->SetWatchStatusCallback(nullptr);
|
||||
gpr_event_set(&shutdown_event_, (void*)(1));
|
||||
refresh_thread_.Join();
|
||||
}
|
||||
|
||||
void FileWatcherCertificateProvider::ForceUpdate() {
|
||||
absl::optional<std::string> root_certificate;
|
||||
absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
|
||||
if (!root_cert_path_.empty()) {
|
||||
root_certificate = ReadRootCertificatesFromFile(root_cert_path_);
|
||||
}
|
||||
if (!private_key_path_.empty()) {
|
||||
pem_key_cert_pairs = ReadIdentityKeyCertPairFromFiles(
|
||||
private_key_path_, identity_certificate_path_);
|
||||
}
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
const bool root_cert_changed =
|
||||
(!root_certificate.has_value() && !root_certificate_.empty()) ||
|
||||
(root_certificate.has_value() && root_certificate_ != *root_certificate);
|
||||
if (root_cert_changed) {
|
||||
if (root_certificate.has_value()) {
|
||||
root_certificate_ = std::move(*root_certificate);
|
||||
} else {
|
||||
root_certificate_ = "";
|
||||
}
|
||||
}
|
||||
const bool identity_cert_changed =
|
||||
(!pem_key_cert_pairs.has_value() && !pem_key_cert_pairs_.empty()) ||
|
||||
(pem_key_cert_pairs.has_value() &&
|
||||
pem_key_cert_pairs_ != *pem_key_cert_pairs);
|
||||
if (identity_cert_changed) {
|
||||
if (pem_key_cert_pairs.has_value()) {
|
||||
pem_key_cert_pairs_ = std::move(*pem_key_cert_pairs);
|
||||
} else {
|
||||
pem_key_cert_pairs_ = {};
|
||||
}
|
||||
}
|
||||
if (root_cert_changed || identity_cert_changed) {
|
||||
ExecCtx exec_ctx;
|
||||
grpc_error* root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest root certificates.");
|
||||
grpc_error* identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
||||
"Unable to get latest identity certificates.");
|
||||
for (const auto& p : watcher_info_) {
|
||||
const std::string& cert_name = p.first;
|
||||
const WatcherInfo& info = p.second;
|
||||
absl::optional<std::string> root_to_report;
|
||||
absl::optional<grpc_core::PemKeyCertPairList> identity_to_report;
|
||||
// Set key materials to the distributor if their contents changed.
|
||||
if (info.root_being_watched && !root_certificate_.empty() &&
|
||||
root_cert_changed) {
|
||||
root_to_report = root_certificate_;
|
||||
}
|
||||
if (info.identity_being_watched && !pem_key_cert_pairs_.empty() &&
|
||||
identity_cert_changed) {
|
||||
identity_to_report = pem_key_cert_pairs_;
|
||||
}
|
||||
if (root_to_report.has_value() || identity_to_report.has_value()) {
|
||||
distributor_->SetKeyMaterials(cert_name, std::move(root_to_report),
|
||||
std::move(identity_to_report));
|
||||
}
|
||||
// Report errors to the distributor if the contents are empty.
|
||||
const bool report_root_error =
|
||||
info.root_being_watched && root_certificate_.empty();
|
||||
const bool report_identity_error =
|
||||
info.identity_being_watched && pem_key_cert_pairs_.empty();
|
||||
if (report_root_error || report_identity_error) {
|
||||
distributor_->SetErrorForCert(
|
||||
cert_name,
|
||||
report_root_error ? GRPC_ERROR_REF(root_cert_error)
|
||||
: GRPC_ERROR_NONE,
|
||||
report_identity_error ? GRPC_ERROR_REF(identity_cert_error)
|
||||
: GRPC_ERROR_NONE);
|
||||
}
|
||||
}
|
||||
GRPC_ERROR_UNREF(root_cert_error);
|
||||
GRPC_ERROR_UNREF(identity_cert_error);
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<std::string>
|
||||
FileWatcherCertificateProvider::ReadRootCertificatesFromFile(
|
||||
const std::string& root_cert_full_path) {
|
||||
// Read the root file.
|
||||
grpc_slice root_slice = grpc_empty_slice();
|
||||
grpc_error* root_error =
|
||||
grpc_load_file(root_cert_full_path.c_str(), 0, &root_slice);
|
||||
if (root_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR, "Reading file %s failed: %s",
|
||||
root_cert_full_path.c_str(), grpc_error_string(root_error));
|
||||
GRPC_ERROR_UNREF(root_error);
|
||||
return absl::nullopt;
|
||||
}
|
||||
std::string root_cert(StringViewFromSlice(root_slice));
|
||||
grpc_slice_unref_internal(root_slice);
|
||||
return root_cert;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This helper function gets the last-modified time of |filename|. When failed,
|
||||
// it logs the error and returns 0.
|
||||
time_t GetModificationTime(const char* filename) {
|
||||
time_t ts = 0;
|
||||
absl::Status status = grpc_core::GetFileModificationTime(filename, &ts);
|
||||
return ts;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::optional<PemKeyCertPairList>
|
||||
FileWatcherCertificateProvider::ReadIdentityKeyCertPairFromFiles(
|
||||
const std::string& private_key_path,
|
||||
const std::string& identity_certificate_path) {
|
||||
struct SliceWrapper {
|
||||
grpc_slice slice = grpc_empty_slice();
|
||||
~SliceWrapper() { grpc_slice_unref_internal(slice); }
|
||||
};
|
||||
const int kNumRetryAttempts = 3;
|
||||
for (int i = 0; i < kNumRetryAttempts; ++i) {
|
||||
// TODO(ZhenLian): replace the timestamp approach with key-match approach
|
||||
// once the latter is implemented.
|
||||
// Checking the last modification of identity files before reading.
|
||||
time_t identity_key_ts_before =
|
||||
GetModificationTime(private_key_path.c_str());
|
||||
if (identity_key_ts_before == 0) {
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"Failed to get the file's modification time of %s. Start retrying...",
|
||||
private_key_path.c_str());
|
||||
continue;
|
||||
}
|
||||
time_t identity_cert_ts_before =
|
||||
GetModificationTime(identity_certificate_path.c_str());
|
||||
if (identity_cert_ts_before == 0) {
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"Failed to get the file's modification time of %s. Start retrying...",
|
||||
identity_certificate_path.c_str());
|
||||
continue;
|
||||
}
|
||||
// Read the identity files.
|
||||
SliceWrapper key_slice, cert_slice;
|
||||
grpc_error* key_error =
|
||||
grpc_load_file(private_key_path.c_str(), 0, &key_slice.slice);
|
||||
if (key_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
|
||||
private_key_path.c_str(), grpc_error_string(key_error));
|
||||
GRPC_ERROR_UNREF(key_error);
|
||||
continue;
|
||||
}
|
||||
grpc_error* cert_error =
|
||||
grpc_load_file(identity_certificate_path.c_str(), 0, &cert_slice.slice);
|
||||
if (cert_error != GRPC_ERROR_NONE) {
|
||||
gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
|
||||
identity_certificate_path.c_str(), grpc_error_string(cert_error));
|
||||
GRPC_ERROR_UNREF(cert_error);
|
||||
continue;
|
||||
}
|
||||
std::string private_key(StringViewFromSlice(key_slice.slice));
|
||||
std::string cert_chain(StringViewFromSlice(cert_slice.slice));
|
||||
grpc_ssl_pem_key_cert_pair* ssl_pair =
|
||||
static_cast<grpc_ssl_pem_key_cert_pair*>(
|
||||
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
|
||||
ssl_pair->private_key = gpr_strdup(private_key.c_str());
|
||||
ssl_pair->cert_chain = gpr_strdup(cert_chain.c_str());
|
||||
PemKeyCertPairList identity_pairs;
|
||||
identity_pairs.emplace_back(ssl_pair);
|
||||
// Checking the last modification of identity files before reading.
|
||||
time_t identity_key_ts_after =
|
||||
GetModificationTime(private_key_path.c_str());
|
||||
if (identity_key_ts_before != identity_key_ts_after) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Last modified time before and after reading %s is not the same. "
|
||||
"Start retrying...",
|
||||
private_key_path.c_str());
|
||||
continue;
|
||||
}
|
||||
time_t identity_cert_ts_after =
|
||||
GetModificationTime(identity_certificate_path.c_str());
|
||||
if (identity_cert_ts_before != identity_cert_ts_after) {
|
||||
gpr_log(GPR_ERROR,
|
||||
"Last modified time before and after reading %s is not the same. "
|
||||
"Start retrying...",
|
||||
identity_certificate_path.c_str());
|
||||
continue;
|
||||
}
|
||||
return identity_pairs;
|
||||
}
|
||||
gpr_log(GPR_ERROR,
|
||||
"All retry attempts failed. Will try again after the next interval.");
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
/** -- Wrapper APIs declared in grpc_security.h -- **/
|
||||
|
|
@ -69,6 +385,16 @@ grpc_tls_certificate_provider* grpc_tls_certificate_provider_static_data_create(
|
|||
std::move(root_cert_core), std::move(identity_pairs_core));
|
||||
}
|
||||
|
||||
grpc_tls_certificate_provider*
|
||||
grpc_tls_certificate_provider_file_watcher_create(
|
||||
const char* private_key_path, const char* identity_certificate_path,
|
||||
const char* root_cert_path, unsigned int refresh_interval_sec) {
|
||||
return new grpc_core::FileWatcherCertificateProvider(
|
||||
private_key_path == nullptr ? "" : private_key_path,
|
||||
identity_certificate_path == nullptr ? "" : identity_certificate_path,
|
||||
root_cert_path == nullptr ? "" : root_cert_path, refresh_interval_sec);
|
||||
}
|
||||
|
||||
void grpc_tls_certificate_provider_release(
|
||||
grpc_tls_certificate_provider* provider) {
|
||||
GRPC_API_TRACE("grpc_tls_certificate_provider_release(provider=%p)", 1,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/gprpp/thd.h"
|
||||
#include "src/core/lib/iomgr/load_file.h"
|
||||
#include "src/core/lib/iomgr/pollset_set.h"
|
||||
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
|
||||
#include "src/core/lib/security/security_connector/ssl_utils.h"
|
||||
|
|
@ -59,14 +61,76 @@ class StaticDataCertificateProvider final
|
|||
std::string root_certificate,
|
||||
grpc_core::PemKeyCertPairList pem_key_cert_pairs);
|
||||
|
||||
~StaticDataCertificateProvider() override;
|
||||
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
|
||||
return distributor_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct WatcherInfo {
|
||||
bool root_being_watched = false;
|
||||
bool identity_being_watched = false;
|
||||
};
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
|
||||
std::string root_certificate_;
|
||||
grpc_core::PemKeyCertPairList pem_key_cert_pairs_;
|
||||
// Guards members below.
|
||||
grpc_core::Mutex mu_;
|
||||
// Stores each cert_name we get from the distributor callback and its watcher
|
||||
// information.
|
||||
std::map<std::string, WatcherInfo> watcher_info_;
|
||||
};
|
||||
|
||||
// A provider class that will watch the credential changes on the file system.
|
||||
class FileWatcherCertificateProvider final
|
||||
: public grpc_tls_certificate_provider {
|
||||
public:
|
||||
FileWatcherCertificateProvider(std::string private_key_path,
|
||||
std::string identity_certificate_path,
|
||||
std::string root_cert_path,
|
||||
unsigned int refresh_interval_sec);
|
||||
|
||||
~FileWatcherCertificateProvider() override;
|
||||
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
|
||||
return distributor_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct WatcherInfo {
|
||||
bool root_being_watched = false;
|
||||
bool identity_being_watched = false;
|
||||
};
|
||||
// Force an update from the file system regardless of the interval.
|
||||
void ForceUpdate();
|
||||
// Read the root certificates from files and update the distributor.
|
||||
absl::optional<std::string> ReadRootCertificatesFromFile(
|
||||
const std::string& root_cert_full_path);
|
||||
// Read the root certificates from files and update the distributor.
|
||||
absl::optional<PemKeyCertPairList> ReadIdentityKeyCertPairFromFiles(
|
||||
const std::string& private_key_file_name,
|
||||
const std::string& identity_certificate_file_name);
|
||||
|
||||
// Information that is used by the refreshing thread.
|
||||
std::string private_key_path_;
|
||||
std::string identity_certificate_path_;
|
||||
std::string root_cert_path_;
|
||||
unsigned int refresh_interval_sec_ = 0;
|
||||
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
|
||||
grpc_core::Thread refresh_thread_;
|
||||
gpr_event shutdown_event_;
|
||||
|
||||
// Guards members below.
|
||||
grpc_core::Mutex mu_;
|
||||
// The most-recent credential data. It will be empty if the most recent read
|
||||
// attempt failed.
|
||||
std::string root_certificate_;
|
||||
grpc_core::PemKeyCertPairList pem_key_cert_pairs_;
|
||||
// Stores each cert_name we get from the distributor callback and its watcher
|
||||
// information.
|
||||
std::map<std::string, WatcherInfo> watcher_info_;
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
|
|||
|
|
@ -147,7 +147,6 @@ struct grpc_tls_credentials_options
|
|||
server_authorization_check_config_ = std::move(config);
|
||||
}
|
||||
// Sets the provider in the options.
|
||||
// This should only be used by C-core API for Tls*Creds case.
|
||||
void set_certificate_provider(
|
||||
grpc_core::RefCountedPtr<grpc_tls_certificate_provider> provider) {
|
||||
provider_ = std::move(provider);
|
||||
|
|
|
|||
|
|
@ -74,13 +74,12 @@ class TlsChannelSecurityConnector final
|
|||
return client_handshaker_factory_;
|
||||
};
|
||||
|
||||
const absl::optional<absl::string_view>& RootCertsForTesting() {
|
||||
absl::optional<absl::string_view> RootCertsForTesting() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
return pem_root_certs_;
|
||||
}
|
||||
|
||||
const absl::optional<grpc_core::PemKeyCertPairList>&
|
||||
KeyCertPairListForTesting() {
|
||||
absl::optional<grpc_core::PemKeyCertPairList> KeyCertPairListForTesting() {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
return pem_key_cert_pair_list_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,5 +41,19 @@ StaticDataCertificateProvider::~StaticDataCertificateProvider() {
|
|||
grpc_tls_certificate_provider_release(c_provider_);
|
||||
};
|
||||
|
||||
FileWatcherCertificateProvider::FileWatcherCertificateProvider(
|
||||
const std::string& private_key_path,
|
||||
const std::string& identity_certificate_path,
|
||||
const std::string& root_cert_path, unsigned int refresh_interval_sec) {
|
||||
c_provider_ = grpc_tls_certificate_provider_file_watcher_create(
|
||||
private_key_path.c_str(), identity_certificate_path.c_str(),
|
||||
root_cert_path.c_str(), refresh_interval_sec);
|
||||
GPR_ASSERT(c_provider_ != nullptr);
|
||||
};
|
||||
|
||||
FileWatcherCertificateProvider::~FileWatcherCertificateProvider() {
|
||||
grpc_tls_certificate_provider_release(c_provider_);
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace grpc
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ grpc_tls_identity_pairs_create_type grpc_tls_identity_pairs_create_import;
|
|||
grpc_tls_identity_pairs_add_pair_type grpc_tls_identity_pairs_add_pair_import;
|
||||
grpc_tls_identity_pairs_destroy_type grpc_tls_identity_pairs_destroy_import;
|
||||
grpc_tls_certificate_provider_static_data_create_type grpc_tls_certificate_provider_static_data_create_import;
|
||||
grpc_tls_certificate_provider_file_watcher_create_type grpc_tls_certificate_provider_file_watcher_create_import;
|
||||
grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_release_import;
|
||||
grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import;
|
||||
grpc_tls_credentials_options_set_cert_request_type_type grpc_tls_credentials_options_set_cert_request_type_import;
|
||||
|
|
@ -440,6 +441,7 @@ void grpc_rb_load_imports(HMODULE library) {
|
|||
grpc_tls_identity_pairs_add_pair_import = (grpc_tls_identity_pairs_add_pair_type) GetProcAddress(library, "grpc_tls_identity_pairs_add_pair");
|
||||
grpc_tls_identity_pairs_destroy_import = (grpc_tls_identity_pairs_destroy_type) GetProcAddress(library, "grpc_tls_identity_pairs_destroy");
|
||||
grpc_tls_certificate_provider_static_data_create_import = (grpc_tls_certificate_provider_static_data_create_type) GetProcAddress(library, "grpc_tls_certificate_provider_static_data_create");
|
||||
grpc_tls_certificate_provider_file_watcher_create_import = (grpc_tls_certificate_provider_file_watcher_create_type) GetProcAddress(library, "grpc_tls_certificate_provider_file_watcher_create");
|
||||
grpc_tls_certificate_provider_release_import = (grpc_tls_certificate_provider_release_type) GetProcAddress(library, "grpc_tls_certificate_provider_release");
|
||||
grpc_tls_credentials_options_create_import = (grpc_tls_credentials_options_create_type) GetProcAddress(library, "grpc_tls_credentials_options_create");
|
||||
grpc_tls_credentials_options_set_cert_request_type_import = (grpc_tls_credentials_options_set_cert_request_type_type) GetProcAddress(library, "grpc_tls_credentials_options_set_cert_request_type");
|
||||
|
|
|
|||
|
|
@ -461,6 +461,9 @@ extern grpc_tls_identity_pairs_destroy_type grpc_tls_identity_pairs_destroy_impo
|
|||
typedef grpc_tls_certificate_provider*(*grpc_tls_certificate_provider_static_data_create_type)(const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs);
|
||||
extern grpc_tls_certificate_provider_static_data_create_type grpc_tls_certificate_provider_static_data_create_import;
|
||||
#define grpc_tls_certificate_provider_static_data_create grpc_tls_certificate_provider_static_data_create_import
|
||||
typedef grpc_tls_certificate_provider*(*grpc_tls_certificate_provider_file_watcher_create_type)(const char* private_key_path, const char* identity_certificate_path, const char* root_cert_path, unsigned int refresh_interval_sec);
|
||||
extern grpc_tls_certificate_provider_file_watcher_create_type grpc_tls_certificate_provider_file_watcher_create_import;
|
||||
#define grpc_tls_certificate_provider_file_watcher_create grpc_tls_certificate_provider_file_watcher_create_import
|
||||
typedef void(*grpc_tls_certificate_provider_release_type)(grpc_tls_certificate_provider* provider);
|
||||
extern grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_release_import;
|
||||
#define grpc_tls_certificate_provider_release grpc_tls_certificate_provider_release_import
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "test/core/util/port.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
// For normal TLS connections.
|
||||
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
|
||||
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
|
||||
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
|
||||
|
|
@ -60,7 +61,7 @@ struct fullstack_secure_fixture_data {
|
|||
grpc_tls_certificate_provider* server_provider = nullptr;
|
||||
};
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_static_data(
|
||||
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
|
||||
grpc_tls_version tls_version) {
|
||||
grpc_end2end_test_fixture f;
|
||||
|
|
@ -101,16 +102,47 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
|
|||
return f;
|
||||
}
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_2(
|
||||
grpc_channel_args* client_args, grpc_channel_args* server_args) {
|
||||
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
|
||||
grpc_tls_version::TLS1_2);
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher(
|
||||
grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
|
||||
grpc_tls_version tls_version) {
|
||||
grpc_end2end_test_fixture f;
|
||||
int port = grpc_pick_unused_port_or_die();
|
||||
fullstack_secure_fixture_data* ffd = new fullstack_secure_fixture_data();
|
||||
memset(&f, 0, sizeof(f));
|
||||
ffd->localaddr = grpc_core::JoinHostPort("localhost", port);
|
||||
ffd->tls_version = tls_version;
|
||||
ffd->client_provider = grpc_tls_certificate_provider_file_watcher_create(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
ffd->server_provider = grpc_tls_certificate_provider_file_watcher_create(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
f.fixture_data = ffd;
|
||||
f.cq = grpc_completion_queue_create_for_next(nullptr);
|
||||
f.shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
|
||||
return f;
|
||||
}
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_3(
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_static_data_tls1_2(
|
||||
grpc_channel_args* client_args, grpc_channel_args* server_args) {
|
||||
return chttp2_create_fixture_secure_fullstack(client_args, server_args,
|
||||
grpc_tls_version::TLS1_3);
|
||||
return chttp2_create_fixture_static_data(client_args, server_args,
|
||||
grpc_tls_version::TLS1_2);
|
||||
}
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_static_data_tls1_3(
|
||||
grpc_channel_args* client_args, grpc_channel_args* server_args) {
|
||||
return chttp2_create_fixture_static_data(client_args, server_args,
|
||||
grpc_tls_version::TLS1_3);
|
||||
}
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher_tls1_2(
|
||||
grpc_channel_args* client_args, grpc_channel_args* server_args) {
|
||||
return chttp2_create_fixture_cert_watcher(client_args, server_args,
|
||||
grpc_tls_version::TLS1_2);
|
||||
}
|
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher_tls1_3(
|
||||
grpc_channel_args* client_args, grpc_channel_args* server_args) {
|
||||
return chttp2_create_fixture_cert_watcher(client_args, server_args,
|
||||
grpc_tls_version::TLS1_3);
|
||||
}
|
||||
|
||||
static void process_auth_failure(void* state, grpc_auth_context* /*ctx*/,
|
||||
|
|
@ -262,21 +294,47 @@ static void chttp2_init_server(grpc_end2end_test_fixture* f,
|
|||
}
|
||||
|
||||
static grpc_end2end_test_config configs[] = {
|
||||
/* client sync reload async authz + server sync reload. */
|
||||
// client: static data provider + async custom verification
|
||||
// server: static data provider
|
||||
// extra: TLS 1.2
|
||||
{"chttp2/simple_ssl_fullstack_tls1_2",
|
||||
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
|
||||
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
|
||||
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
|
||||
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
|
||||
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_2,
|
||||
"foo.test.google.fr", chttp2_create_fixture_static_data_tls1_2,
|
||||
chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
|
||||
// client: static data provider + async custom verification
|
||||
// server: static data provider
|
||||
// extra: TLS 1.3
|
||||
{"chttp2/simple_ssl_fullstack_tls1_3",
|
||||
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
|
||||
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
|
||||
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
|
||||
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
|
||||
"foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_3,
|
||||
"foo.test.google.fr", chttp2_create_fixture_static_data_tls1_3,
|
||||
chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
|
||||
// client: certificate watcher provider + async custom verification
|
||||
// server: certificate watcher provider
|
||||
// extra: TLS 1.2
|
||||
{"chttp2/reloading_from_files_ssl_fullstack_tls1_2",
|
||||
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
|
||||
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
|
||||
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
|
||||
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
|
||||
"foo.test.google.fr", chttp2_create_fixture_cert_watcher_tls1_2,
|
||||
chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
|
||||
// client: certificate watcher provider + async custom verification
|
||||
// server: certificate watcher provider
|
||||
// extra: TLS 1.3
|
||||
{"chttp2/reloading_from_files_ssl_fullstack_tls1_3",
|
||||
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
|
||||
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
|
||||
FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
|
||||
FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
|
||||
"foo.test.google.fr", chttp2_create_fixture_cert_watcher_tls1_3,
|
||||
chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
|
|
|||
|
|
@ -287,6 +287,15 @@ grpc_cc_test(
|
|||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "tls_utils",
|
||||
srcs = ["tls_utils.cc"],
|
||||
hdrs = ["tls_utils.h"],
|
||||
language = "C++",
|
||||
visibility = ["//test/cpp:__subpackages__"],
|
||||
deps = ["//:grpc"],
|
||||
)
|
||||
|
||||
grpc_cc_test(
|
||||
name = "tls_security_connector_test",
|
||||
srcs = ["tls_security_connector_test.cc"],
|
||||
|
|
@ -318,12 +327,17 @@ grpc_cc_test(
|
|||
srcs = ["grpc_tls_credentials_options_test.cc"],
|
||||
data = [
|
||||
"//src/core/tsi/test_creds:ca.pem",
|
||||
"//src/core/tsi/test_creds:multi-domain.key",
|
||||
"//src/core/tsi/test_creds:multi-domain.pem",
|
||||
"//src/core/tsi/test_creds:server0.key",
|
||||
"//src/core/tsi/test_creds:server0.pem",
|
||||
"//src/core/tsi/test_creds:server1.key",
|
||||
"//src/core/tsi/test_creds:server1.pem",
|
||||
],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
deps = [
|
||||
":tls_utils",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//:grpc_secure",
|
||||
|
|
@ -337,6 +351,30 @@ grpc_cc_test(
|
|||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
deps = [
|
||||
":tls_utils",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//:grpc_secure",
|
||||
"//test/core/util:grpc_test_util",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_test(
|
||||
name = "grpc_tls_certificate_provider_test",
|
||||
srcs = ["grpc_tls_certificate_provider_test.cc"],
|
||||
data = [
|
||||
"//src/core/tsi/test_creds:ca.pem",
|
||||
"//src/core/tsi/test_creds:multi-domain.key",
|
||||
"//src/core/tsi/test_creds:multi-domain.pem",
|
||||
"//src/core/tsi/test_creds:server0.key",
|
||||
"//src/core/tsi/test_creds:server0.pem",
|
||||
"//src/core/tsi/test_creds:server1.key",
|
||||
"//src/core/tsi/test_creds:server1.pem",
|
||||
],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
deps = [
|
||||
":tls_utils",
|
||||
"//:gpr",
|
||||
"//:grpc",
|
||||
"//:grpc_secure",
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@
|
|||
#include <thread>
|
||||
|
||||
#include "src/core/lib/slice/slice_internal.h"
|
||||
#include "test/core/security/tls_utils.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace testing {
|
||||
|
||||
constexpr const char* kCertName1 = "cert_1_name";
|
||||
|
|
@ -53,29 +56,14 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
// Forward declaration.
|
||||
class TlsCertificatesTestWatcher;
|
||||
|
||||
static grpc_core::PemKeyCertPairList MakeCertKeyPairs(const char* private_key,
|
||||
const char* certs) {
|
||||
if (strcmp(private_key, "") == 0 && strcmp(certs, "") == 0) {
|
||||
return {};
|
||||
}
|
||||
grpc_ssl_pem_key_cert_pair* ssl_pair =
|
||||
static_cast<grpc_ssl_pem_key_cert_pair*>(
|
||||
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
|
||||
ssl_pair->private_key = gpr_strdup(private_key);
|
||||
ssl_pair->cert_chain = gpr_strdup(certs);
|
||||
grpc_core::PemKeyCertPairList pem_key_cert_pairs;
|
||||
pem_key_cert_pairs.emplace_back(ssl_pair);
|
||||
return pem_key_cert_pairs;
|
||||
}
|
||||
|
||||
// CredentialInfo contains the parameters when calling OnCertificatesChanged
|
||||
// of a watcher. When OnCertificatesChanged is invoked, we will push a
|
||||
// CredentialInfo to the cert_update_queue of state_, and check in each test
|
||||
// if the status updates are correct.
|
||||
struct CredentialInfo {
|
||||
std::string root_certs;
|
||||
grpc_core::PemKeyCertPairList key_cert_pairs;
|
||||
CredentialInfo(std::string root, grpc_core::PemKeyCertPairList key_cert)
|
||||
PemKeyCertPairList key_cert_pairs;
|
||||
CredentialInfo(std::string root, PemKeyCertPairList key_cert)
|
||||
: root_certs(std::move(root)), key_cert_pairs(std::move(key_cert)) {}
|
||||
bool operator==(const CredentialInfo& other) const {
|
||||
return root_certs == other.root_certs &&
|
||||
|
|
@ -128,12 +116,12 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
|
||||
void OnCertificatesChanged(
|
||||
absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override {
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) override {
|
||||
std::string updated_root;
|
||||
if (root_certs.has_value()) {
|
||||
updated_root = std::string(*root_certs);
|
||||
}
|
||||
grpc_core::PemKeyCertPairList updated_identity;
|
||||
PemKeyCertPairList updated_identity;
|
||||
if (key_cert_pairs.has_value()) {
|
||||
updated_identity = std::move(*key_cert_pairs);
|
||||
}
|
||||
|
|
@ -151,8 +139,7 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
grpc_slice root_error_slice;
|
||||
GPR_ASSERT(grpc_error_get_str(
|
||||
root_cert_error, GRPC_ERROR_STR_DESCRIPTION, &root_error_slice));
|
||||
root_error_str =
|
||||
std::string(grpc_core::StringViewFromSlice(root_error_slice));
|
||||
root_error_str = std::string(StringViewFromSlice(root_error_slice));
|
||||
}
|
||||
if (identity_cert_error != GRPC_ERROR_NONE) {
|
||||
grpc_slice identity_error_slice;
|
||||
|
|
@ -160,7 +147,7 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
GRPC_ERROR_STR_DESCRIPTION,
|
||||
&identity_error_slice));
|
||||
identity_error_str =
|
||||
std::string(grpc_core::StringViewFromSlice(identity_error_slice));
|
||||
std::string(StringViewFromSlice(identity_error_slice));
|
||||
}
|
||||
state_->error_queue.emplace_back(std::move(root_error_str),
|
||||
std::move(identity_error_str));
|
||||
|
|
@ -202,7 +189,7 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
|
||||
WatcherState* MakeWatcher(absl::optional<std::string> root_cert_name,
|
||||
absl::optional<std::string> identity_cert_name) {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
MutexLock lock(&mu_);
|
||||
watchers_.emplace_back();
|
||||
// TlsCertificatesTestWatcher ctor takes a pointer to the WatcherState.
|
||||
// It sets WatcherState::watcher to point to itself.
|
||||
|
|
@ -217,7 +204,7 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
}
|
||||
|
||||
void CancelWatch(WatcherState* state) {
|
||||
grpc_core::MutexLock lock(&mu_);
|
||||
MutexLock lock(&mu_);
|
||||
distributor_.CancelTlsCertificatesWatch(state->watcher);
|
||||
EXPECT_EQ(state->watcher, nullptr);
|
||||
}
|
||||
|
|
@ -234,7 +221,7 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test {
|
|||
std::list<WatcherState> watchers_;
|
||||
std::deque<CallbackStatus> callback_queue_;
|
||||
// This is to make watchers_ and callback_queue_ thread-safe.
|
||||
grpc_core::Mutex mu_;
|
||||
Mutex mu_;
|
||||
};
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest, BasicCredentialBehaviors) {
|
||||
|
|
@ -257,21 +244,21 @@ TEST_F(GrpcTlsCertificateDistributorTest, BasicCredentialBehaviors) {
|
|||
TEST_F(GrpcTlsCertificateDistributorTest, UpdateCredentialsOnAnySide) {
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// SetKeyMaterials should trigger watcher's OnCertificatesChanged method.
|
||||
distributor_.SetKeyMaterials(
|
||||
kCertName1, kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
// Set root certs should trigger watcher's OnCertificatesChanged again.
|
||||
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert2Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
// Set identity certs should trigger watcher's OnCertificatesChanged again.
|
||||
|
|
@ -280,7 +267,7 @@ TEST_F(GrpcTlsCertificateDistributorTest, UpdateCredentialsOnAnySide) {
|
|||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert2Contents,
|
||||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
|
||||
CancelWatch(watcher_state_1);
|
||||
|
|
@ -292,12 +279,12 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameIdentityNameDiffRootName) {
|
|||
MakeWatcher(kRootCert1Name, kIdentityCert1Name);
|
||||
EXPECT_THAT(
|
||||
GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, true)));
|
||||
// Register watcher 2.
|
||||
WatcherState* watcher_state_2 =
|
||||
MakeWatcher(kRootCert2Name, kIdentityCert1Name);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
|
||||
kRootCert2Name, true, false)));
|
||||
// Push credential updates to kRootCert1Name and check if the status works as
|
||||
// expected.
|
||||
|
|
@ -305,13 +292,13 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameIdentityNameDiffRootName) {
|
|||
absl::nullopt);
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
// Push credential updates to kRootCert2Name.
|
||||
distributor_.SetKeyMaterials(kRootCert2Name, kRootCert2Contents,
|
||||
absl::nullopt);
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
// Push credential updates to kIdentityCert1Name and check if the status works
|
||||
// as expected.
|
||||
distributor_.SetKeyMaterials(
|
||||
|
|
@ -320,24 +307,24 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameIdentityNameDiffRootName) {
|
|||
// Check the updates are delivered to watcher 1 and watcher 2.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
EXPECT_THAT(
|
||||
watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert2Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
|
||||
kRootCert1Name, false, false)));
|
||||
// Cancel watcher 2.
|
||||
CancelWatch(watcher_state_2);
|
||||
EXPECT_THAT(
|
||||
GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kRootCert2Name, false, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kRootCert2Name, false, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
|
||||
|
|
@ -346,12 +333,12 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
|
|||
MakeWatcher(kRootCert1Name, kIdentityCert1Name);
|
||||
EXPECT_THAT(
|
||||
GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
|
||||
CallbackStatus(kIdentityCert1Name, false, true)));
|
||||
// Register watcher 2.
|
||||
WatcherState* watcher_state_2 =
|
||||
MakeWatcher(kRootCert1Name, kIdentityCert2Name);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
|
||||
kIdentityCert2Name, false, true)));
|
||||
// Push credential updates to kRootCert1Name and check if the status works as
|
||||
// expected.
|
||||
|
|
@ -359,10 +346,10 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
|
|||
absl::nullopt);
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
// Push credential updates to SetKeyMaterials.
|
||||
distributor_.SetKeyMaterials(
|
||||
kIdentityCert1Name, absl::nullopt,
|
||||
|
|
@ -370,7 +357,7 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
|
|||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
// Push credential updates to kIdentityCert2Name.
|
||||
|
|
@ -380,19 +367,19 @@ TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
|
|||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(
|
||||
watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
|
||||
kIdentityCert1Name, false, false)));
|
||||
// Cancel watcher 2.
|
||||
CancelWatch(watcher_state_2);
|
||||
EXPECT_THAT(
|
||||
GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kRootCert1Name, false, false),
|
||||
CallbackStatus(kIdentityCert2Name, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kRootCert1Name, false, false),
|
||||
CallbackStatus(kIdentityCert2Name, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest,
|
||||
|
|
@ -400,7 +387,7 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Register watcher 1 watching kCertName1 for both root and identity certs.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// Push credential updates to kCertName1 and check if the status works as
|
||||
// expected.
|
||||
distributor_.SetKeyMaterials(
|
||||
|
|
@ -409,13 +396,13 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest,
|
||||
|
|
@ -423,11 +410,11 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Register watcher 1 watching kCertName1 for root certs.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, absl::nullopt);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
|
||||
// Register watcher 2 watching kCertName1 for identity certs.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// Push credential updates to kCertName1 and check if the status works as
|
||||
// expected.
|
||||
distributor_.SetKeyMaterials(
|
||||
|
|
@ -435,39 +422,39 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(kIdentityCert1PrivateKey,
|
||||
kIdentityCert1Contents))));
|
||||
// Push root cert updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
// Check the updates are not delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Push identity cert updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(
|
||||
kCertName1, absl::nullopt,
|
||||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
|
||||
// Check the updates are not delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
|
||||
kIdentityCert2Contents))));
|
||||
watcher_state_2->cert_update_queue.clear();
|
||||
// Cancel watcher 2.
|
||||
CancelWatch(watcher_state_2);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest,
|
||||
|
|
@ -475,11 +462,11 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Register watcher 1 watching kCertName1 for identity certs.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(absl::nullopt, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
|
||||
// Register watcher 2 watching kCertName1 for root certs.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, absl::nullopt);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// Push credential updates to kCertName1 and check if the status works as
|
||||
// expected.
|
||||
distributor_.SetKeyMaterials(
|
||||
|
|
@ -487,38 +474,38 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(kIdentityCert1PrivateKey,
|
||||
kIdentityCert1Contents))));
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
|
||||
// Push root cert updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
|
||||
// Check the updates are delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
// Check the updates are not delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Push identity cert updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(
|
||||
kCertName1, absl::nullopt,
|
||||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
|
||||
// Check the updates are not delivered to watcher 2.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
|
||||
kIdentityCert2Contents))));
|
||||
// Cancel watcher 2.
|
||||
CancelWatch(watcher_state_2);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest,
|
||||
|
|
@ -527,24 +514,24 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// certs.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
|
||||
// Push credential updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(
|
||||
kCertName1, kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
|
||||
// Cancel watcher 2.
|
||||
CancelWatch(watcher_state_2);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
|
||||
// Cancel watcher 1.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
// Register watcher 3 watching kCertName for root and identity certs.
|
||||
WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// Push credential updates to kCertName1.
|
||||
distributor_.SetKeyMaterials(
|
||||
kCertName1, kRootCert2Contents,
|
||||
|
|
@ -552,25 +539,25 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Check the updates are delivered to watcher 3.
|
||||
EXPECT_THAT(
|
||||
watcher_state_3->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert2Contents,
|
||||
MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
|
||||
// Cancel watcher 3.
|
||||
CancelWatch(watcher_state_3);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest, ResetCallbackToNull) {
|
||||
// Register watcher 1 watching kCertName1 for root and identity certs.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
|
||||
EXPECT_THAT(GetCallbackQueue(),
|
||||
testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
|
||||
// Reset callback to nullptr.
|
||||
distributor_.SetWatchStatusCallback(nullptr);
|
||||
// Cancel watcher 1 shouldn't trigger any callback.
|
||||
CancelWatch(watcher_state_1);
|
||||
EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) {
|
||||
|
|
@ -586,7 +573,7 @@ TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) {
|
|||
// Check the updates are delivered to watcher 1.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents, MakeCertKeyPairs(kIdentityCert1PrivateKey,
|
||||
kIdentityCert1Contents))));
|
||||
CancelWatch(watcher_state_1);
|
||||
|
|
@ -621,7 +608,7 @@ TEST_F(GrpcTlsCertificateDistributorTest, WatchACertInfoWithValidCredentials) {
|
|||
// watcher 1 should receive the credentials right away.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
CancelWatch(watcher_state_1);
|
||||
|
|
@ -629,13 +616,13 @@ TEST_F(GrpcTlsCertificateDistributorTest, WatchACertInfoWithValidCredentials) {
|
|||
WatcherState* watcher_state_2 = MakeWatcher(kRootCert2Name, absl::nullopt);
|
||||
// watcher 2 should receive the root credentials right away.
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
|
||||
// Register watcher 3.
|
||||
WatcherState* watcher_state_3 =
|
||||
MakeWatcher(absl::nullopt, kIdentityCert2Name);
|
||||
// watcher 3 should received the identity credentials right away.
|
||||
EXPECT_THAT(watcher_state_3->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(kIdentityCert2PrivateKey,
|
||||
kIdentityCert2Contents))));
|
||||
CancelWatch(watcher_state_2);
|
||||
|
|
@ -652,7 +639,7 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
// Calling SetErrorForCert on root cert name should call OnError
|
||||
// on watcher 1 again.
|
||||
|
|
@ -661,14 +648,14 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
absl::nullopt);
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kErrorMessage, kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo(kErrorMessage, kIdentityErrorMessage)));
|
||||
// Calling SetErrorForCert on identity cert name should call OnError
|
||||
// on watcher 1 again.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName1, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
|
||||
distributor_.CancelTlsCertificatesWatch(watcher_state_1->watcher);
|
||||
EXPECT_EQ(watcher_state_1->watcher, nullptr);
|
||||
}
|
||||
|
|
@ -682,18 +669,18 @@ TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertForRootOrIdentity) {
|
|||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
// Calling SetErrorForCert on identity name should do nothing.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName1, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on both names should still get one OnError call.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
CancelWatch(watcher_state_1);
|
||||
// Register watcher 2.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
|
||||
|
|
@ -703,18 +690,18 @@ TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertForRootOrIdentity) {
|
|||
kCertName1, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
// Calling SetErrorForCert on root name should do nothing.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on both names should still get one OnError call.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_2);
|
||||
}
|
||||
|
||||
|
|
@ -728,14 +715,14 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
|
||||
// Should trigger OnError call right away since kCertName1 has error.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError with both
|
||||
// errors, because kCertName1 also has error.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
|
@ -750,14 +737,14 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
|
||||
// Should trigger OnError call right away since kCertName2 has error.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError with both
|
||||
// errors, because kCertName1 also has error.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
|
@ -767,25 +754,25 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// Register watcher 1 for kCertName1 as root and kCertName2 as identity.
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
|
||||
// Should not trigger OnError.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
// Register watcher 2 for kCertName2 as identity and a non-existing name
|
||||
// kRootCert1Name as root.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(kRootCert1Name, kCertName2);
|
||||
// Should not trigger OnError.
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, absl::nullopt,
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_2->error_queue,
|
||||
testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_2);
|
||||
}
|
||||
|
||||
|
|
@ -793,25 +780,25 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
SetErrorForRootNameWithPreexistingErrorForIdentityName) {
|
||||
WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
|
||||
// Should not trigger OnError.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
CancelWatch(watcher_state_1);
|
||||
// Register watcher 2 for kCertName2 as root and a non-existing name
|
||||
// kIdentityCert1Name as identity.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(kCertName2, kIdentityCert1Name);
|
||||
// Should not trigger OnError.
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
|
||||
// Calling SetErrorForCert on kCertName2 should trigger OnError.
|
||||
distributor_.SetErrorForCert(
|
||||
kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
|
||||
CancelWatch(watcher_state_2);
|
||||
}
|
||||
|
||||
|
|
@ -825,14 +812,14 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
|
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
// When watcher 1 is removed, the cert info entry should be removed.
|
||||
CancelWatch(watcher_state_1);
|
||||
// Register watcher 2 on the same cert name.
|
||||
WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
|
||||
// Should not trigger OnError call on watcher 2 right away.
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_2);
|
||||
}
|
||||
|
||||
|
|
@ -851,11 +838,11 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// watcher 1 should receive both the old credentials and the error right away.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
|
@ -876,10 +863,10 @@ TEST_F(GrpcTlsCertificateDistributorTest,
|
|||
// the previous error is wiped out by a successful update.
|
||||
EXPECT_THAT(
|
||||
watcher_state_1->GetCredentialQueue(),
|
||||
testing::ElementsAre(CredentialInfo(
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
kRootCert1Contents,
|
||||
MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
|
|
@ -893,11 +880,11 @@ TEST_F(GrpcTlsCertificateDistributorTest, WatchCertInfoThenInvokeSetError) {
|
|||
MakeWatcher(absl::nullopt, kIdentityCert1Name);
|
||||
distributor_.SetError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo(kErrorMessage, "")));
|
||||
::testing::ElementsAre(ErrorInfo(kErrorMessage, "")));
|
||||
EXPECT_THAT(watcher_state_3->GetErrorQueue(),
|
||||
testing::ElementsAre(ErrorInfo("", kErrorMessage)));
|
||||
::testing::ElementsAre(ErrorInfo("", kErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
CancelWatch(watcher_state_2);
|
||||
CancelWatch(watcher_state_3);
|
||||
|
|
@ -915,12 +902,12 @@ TEST_F(GrpcTlsCertificateDistributorTest, WatchErroredCertInfoBySetError) {
|
|||
// Register watcher 3 watching kCertName1 as root and kCertName2 as identity
|
||||
// should not get the error updates.
|
||||
WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName2);
|
||||
EXPECT_THAT(watcher_state_3->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_3->GetErrorQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_3);
|
||||
// Register watcher 4 watching kCertName2 as root and kCertName1 as identity
|
||||
// should not get the error updates.
|
||||
WatcherState* watcher_state_4 = MakeWatcher(kCertName2, kCertName1);
|
||||
EXPECT_THAT(watcher_state_4->GetErrorQueue(), testing::ElementsAre());
|
||||
EXPECT_THAT(watcher_state_4->GetErrorQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_4);
|
||||
}
|
||||
|
||||
|
|
@ -936,7 +923,7 @@ TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertInCallback) {
|
|||
WatcherState* watcher_state_1 = MakeWatcher(cert_name, cert_name);
|
||||
// Check the errors are delivered to watcher 1.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
testing::ElementsAre(
|
||||
::testing::ElementsAre(
|
||||
ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
|
||||
CancelWatch(watcher_state_1);
|
||||
};
|
||||
|
|
@ -955,6 +942,8 @@ TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertInCallback) {
|
|||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
grpc::testing::TestEnvironment env(argc, argv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,509 @@
|
|||
//
|
||||
// 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/tls/grpc_tls_certificate_provider.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <grpc/support/alloc.h>
|
||||
#include <grpc/support/log.h>
|
||||
#include <grpc/support/string_util.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
|
||||
#include "src/core/lib/gpr/tmpfile.h"
|
||||
#include "src/core/lib/iomgr/load_file.h"
|
||||
#include "src/core/lib/slice/slice_internal.h"
|
||||
#include "test/core/security/tls_utils.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
|
||||
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
|
||||
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
|
||||
#define CA_CERT_PATH_2 "src/core/tsi/test_creds/multi-domain.pem"
|
||||
#define SERVER_CERT_PATH_2 "src/core/tsi/test_creds/server0.pem"
|
||||
#define SERVER_KEY_PATH_2 "src/core/tsi/test_creds/server0.key"
|
||||
#define INVALID_PATH "invalid/path"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace testing {
|
||||
|
||||
constexpr const char* kCertName = "cert_name";
|
||||
constexpr const char* kRootError = "Unable to get latest root certificates.";
|
||||
constexpr const char* kIdentityError =
|
||||
"Unable to get latest identity certificates.";
|
||||
|
||||
class GrpcTlsCertificateProviderTest : public ::testing::Test {
|
||||
protected:
|
||||
// Forward declaration.
|
||||
class TlsCertificatesTestWatcher;
|
||||
|
||||
// CredentialInfo contains the parameters when calling OnCertificatesChanged
|
||||
// of a watcher. When OnCertificatesChanged is invoked, we will push a
|
||||
// CredentialInfo to the cert_update_queue of state_, and check in each test
|
||||
// if the status updates are correct.
|
||||
struct CredentialInfo {
|
||||
std::string root_certs;
|
||||
PemKeyCertPairList key_cert_pairs;
|
||||
CredentialInfo(std::string root, PemKeyCertPairList key_cert)
|
||||
: root_certs(std::move(root)), key_cert_pairs(std::move(key_cert)) {}
|
||||
bool operator==(const CredentialInfo& other) const {
|
||||
return root_certs == other.root_certs &&
|
||||
key_cert_pairs == other.key_cert_pairs;
|
||||
}
|
||||
};
|
||||
|
||||
// ErrorInfo contains the parameters when calling OnError of a watcher. When
|
||||
// OnError is invoked, we will push a ErrorInfo to the error_queue of state_,
|
||||
// and check in each test if the status updates are correct.
|
||||
struct ErrorInfo {
|
||||
std::string root_cert_str;
|
||||
std::string identity_cert_str;
|
||||
ErrorInfo(std::string root, std::string identity)
|
||||
: root_cert_str(std::move(root)),
|
||||
identity_cert_str(std::move(identity)) {}
|
||||
bool operator==(const ErrorInfo& other) const {
|
||||
return root_cert_str == other.root_cert_str &&
|
||||
identity_cert_str == other.identity_cert_str;
|
||||
}
|
||||
};
|
||||
|
||||
struct WatcherState {
|
||||
TlsCertificatesTestWatcher* watcher = nullptr;
|
||||
std::deque<CredentialInfo> cert_update_queue;
|
||||
std::deque<ErrorInfo> error_queue;
|
||||
Mutex mu;
|
||||
|
||||
std::deque<CredentialInfo> GetCredentialQueue() {
|
||||
// We move the data member value so the data member will be re-initiated
|
||||
// with size 0, and ready for the next check.
|
||||
MutexLock lock(&mu);
|
||||
return std::move(cert_update_queue);
|
||||
}
|
||||
std::deque<ErrorInfo> GetErrorQueue() {
|
||||
// We move the data member value so the data member will be re-initiated
|
||||
// with size 0, and ready for the next check.
|
||||
MutexLock lock(&mu);
|
||||
return std::move(error_queue);
|
||||
}
|
||||
};
|
||||
|
||||
class TlsCertificatesTestWatcher : public grpc_tls_certificate_distributor::
|
||||
TlsCertificatesWatcherInterface {
|
||||
public:
|
||||
// ctor sets state->watcher to this.
|
||||
explicit TlsCertificatesTestWatcher(WatcherState* state) : state_(state) {
|
||||
state_->watcher = this;
|
||||
}
|
||||
|
||||
// dtor sets state->watcher to nullptr.
|
||||
~TlsCertificatesTestWatcher() override { state_->watcher = nullptr; }
|
||||
|
||||
void OnCertificatesChanged(
|
||||
absl::optional<absl::string_view> root_certs,
|
||||
absl::optional<PemKeyCertPairList> key_cert_pairs) override {
|
||||
MutexLock lock(&state_->mu);
|
||||
std::string updated_root;
|
||||
if (root_certs.has_value()) {
|
||||
updated_root = std::string(*root_certs);
|
||||
}
|
||||
PemKeyCertPairList updated_identity;
|
||||
if (key_cert_pairs.has_value()) {
|
||||
updated_identity = std::move(*key_cert_pairs);
|
||||
}
|
||||
state_->cert_update_queue.emplace_back(std::move(updated_root),
|
||||
std::move(updated_identity));
|
||||
}
|
||||
|
||||
void OnError(grpc_error* root_cert_error,
|
||||
grpc_error* identity_cert_error) override {
|
||||
MutexLock lock(&state_->mu);
|
||||
GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
|
||||
identity_cert_error != GRPC_ERROR_NONE);
|
||||
std::string root_error_str;
|
||||
std::string identity_error_str;
|
||||
if (root_cert_error != GRPC_ERROR_NONE) {
|
||||
grpc_slice root_error_slice;
|
||||
GPR_ASSERT(grpc_error_get_str(
|
||||
root_cert_error, GRPC_ERROR_STR_DESCRIPTION, &root_error_slice));
|
||||
root_error_str = std::string(StringViewFromSlice(root_error_slice));
|
||||
}
|
||||
if (identity_cert_error != GRPC_ERROR_NONE) {
|
||||
grpc_slice identity_error_slice;
|
||||
GPR_ASSERT(grpc_error_get_str(identity_cert_error,
|
||||
GRPC_ERROR_STR_DESCRIPTION,
|
||||
&identity_error_slice));
|
||||
identity_error_str =
|
||||
std::string(StringViewFromSlice(identity_error_slice));
|
||||
}
|
||||
state_->error_queue.emplace_back(std::move(root_error_str),
|
||||
std::move(identity_error_str));
|
||||
GRPC_ERROR_UNREF(root_cert_error);
|
||||
GRPC_ERROR_UNREF(identity_cert_error);
|
||||
}
|
||||
|
||||
private:
|
||||
WatcherState* state_;
|
||||
};
|
||||
|
||||
void SetUp() override {
|
||||
root_cert_ = GetFileContents(CA_CERT_PATH);
|
||||
cert_chain_ = GetFileContents(SERVER_CERT_PATH);
|
||||
private_key_ = GetFileContents(SERVER_KEY_PATH);
|
||||
root_cert_2_ = GetFileContents(CA_CERT_PATH_2);
|
||||
cert_chain_2_ = GetFileContents(SERVER_CERT_PATH_2);
|
||||
private_key_2_ = GetFileContents(SERVER_KEY_PATH_2);
|
||||
}
|
||||
|
||||
WatcherState* MakeWatcher(
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor,
|
||||
absl::optional<std::string> root_cert_name,
|
||||
absl::optional<std::string> identity_cert_name) {
|
||||
MutexLock lock(&mu_);
|
||||
distributor_ = distributor;
|
||||
watchers_.emplace_back();
|
||||
// TlsCertificatesTestWatcher ctor takes a pointer to the WatcherState.
|
||||
// It sets WatcherState::watcher to point to itself.
|
||||
// The TlsCertificatesTestWatcher dtor will set WatcherState::watcher back
|
||||
// to nullptr to indicate that it's been destroyed.
|
||||
auto watcher =
|
||||
absl::make_unique<TlsCertificatesTestWatcher>(&watchers_.back());
|
||||
distributor_->WatchTlsCertificates(std::move(watcher),
|
||||
std::move(root_cert_name),
|
||||
std::move(identity_cert_name));
|
||||
return &watchers_.back();
|
||||
}
|
||||
|
||||
void CancelWatch(WatcherState* state) {
|
||||
MutexLock lock(&mu_);
|
||||
distributor_->CancelTlsCertificatesWatch(state->watcher);
|
||||
EXPECT_EQ(state->watcher, nullptr);
|
||||
}
|
||||
|
||||
std::string root_cert_;
|
||||
std::string private_key_;
|
||||
std::string cert_chain_;
|
||||
std::string root_cert_2_;
|
||||
std::string private_key_2_;
|
||||
std::string cert_chain_2_;
|
||||
RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
|
||||
// Use a std::list<> here to avoid the address invalidation caused by internal
|
||||
// reallocation of std::vector<>.
|
||||
std::list<WatcherState> watchers_;
|
||||
// This is to make watchers_ thread-safe.
|
||||
Mutex mu_;
|
||||
};
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest, StaticDataCertificateProviderCreation) {
|
||||
StaticDataCertificateProvider provider(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
// Watcher watching both root and identity certs.
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
CancelWatch(watcher_state_1);
|
||||
// Watcher watching only root certs.
|
||||
WatcherState* watcher_state_2 =
|
||||
MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(root_cert_, {})));
|
||||
CancelWatch(watcher_state_2);
|
||||
// Watcher watching only identity certs.
|
||||
WatcherState* watcher_state_3 =
|
||||
MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
|
||||
EXPECT_THAT(
|
||||
watcher_state_3->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()))));
|
||||
CancelWatch(watcher_state_3);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderWithGoodPaths) {
|
||||
FileWatcherCertificateProvider provider(SERVER_KEY_PATH, SERVER_CERT_PATH,
|
||||
CA_CERT_PATH, 1);
|
||||
// Watcher watching both root and identity certs.
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
CancelWatch(watcher_state_1);
|
||||
// Watcher watching only root certs.
|
||||
WatcherState* watcher_state_2 =
|
||||
MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(root_cert_, {})));
|
||||
CancelWatch(watcher_state_2);
|
||||
// Watcher watching only identity certs.
|
||||
WatcherState* watcher_state_3 =
|
||||
MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
|
||||
EXPECT_THAT(
|
||||
watcher_state_3->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
"", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()))));
|
||||
CancelWatch(watcher_state_3);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderWithBadPaths) {
|
||||
FileWatcherCertificateProvider provider(INVALID_PATH, INVALID_PATH,
|
||||
INVALID_PATH, 1);
|
||||
// Watcher watching both root and identity certs.
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
::testing::ElementsAre(ErrorInfo(kRootError, kIdentityError)));
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_1);
|
||||
// Watcher watching only root certs.
|
||||
WatcherState* watcher_state_2 =
|
||||
MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
|
||||
EXPECT_THAT(watcher_state_2->GetErrorQueue(),
|
||||
::testing::ElementsAre(ErrorInfo(kRootError, "")));
|
||||
EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_2);
|
||||
// Watcher watching only identity certs.
|
||||
WatcherState* watcher_state_3 =
|
||||
MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
|
||||
EXPECT_THAT(watcher_state_3->GetErrorQueue(),
|
||||
::testing::ElementsAre(ErrorInfo("", kIdentityError)));
|
||||
EXPECT_THAT(watcher_state_3->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
CancelWatch(watcher_state_3);
|
||||
}
|
||||
|
||||
// The following tests write credential data to temporary files to test the
|
||||
// transition behavior of the provider.
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderOnBothCertsRefreshed) {
|
||||
// Create temporary files and copy cert data into them.
|
||||
TmpFile tmp_root_cert(root_cert_);
|
||||
TmpFile tmp_identity_key(private_key_);
|
||||
TmpFile tmp_identity_cert(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key.name(),
|
||||
tmp_identity_cert.name(),
|
||||
tmp_root_cert.name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// Expect to see the credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Copy new data to files.
|
||||
// TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
|
||||
// update when the directory renaming is added in gpr.
|
||||
tmp_root_cert.RewriteFile(root_cert_2_);
|
||||
tmp_identity_key.RewriteFile(private_key_2_);
|
||||
tmp_identity_cert.RewriteFile(cert_chain_2_);
|
||||
// Wait 2 seconds for the provider's refresh thread to read the updated files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see the new credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_2_, MakeCertKeyPairs(private_key_2_.c_str(),
|
||||
cert_chain_2_.c_str()))));
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderOnRootCertsRefreshed) {
|
||||
// Create temporary files and copy cert data into them.
|
||||
TmpFile tmp_root_cert(root_cert_);
|
||||
TmpFile tmp_identity_key(private_key_);
|
||||
TmpFile tmp_identity_cert(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key.name(),
|
||||
tmp_identity_cert.name(),
|
||||
tmp_root_cert.name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// Expect to see the credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Copy new data to files.
|
||||
// TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
|
||||
// update when the directory renaming is added in gpr.
|
||||
tmp_root_cert.RewriteFile(root_cert_2_);
|
||||
// Wait 2 seconds for the provider's refresh thread to read the updated files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see the new credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_2_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderOnIdentityCertsRefreshed) {
|
||||
// Create temporary files and copy cert data into them.
|
||||
TmpFile tmp_root_cert(root_cert_);
|
||||
TmpFile tmp_identity_key(private_key_);
|
||||
TmpFile tmp_identity_cert(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key.name(),
|
||||
tmp_identity_cert.name(),
|
||||
tmp_root_cert.name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// Expect to see the credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Copy new data to files.
|
||||
// TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
|
||||
// update when the directory renaming is added in gpr.
|
||||
tmp_identity_key.RewriteFile(private_key_2_);
|
||||
tmp_identity_cert.RewriteFile(cert_chain_2_);
|
||||
// Wait 2 seconds for the provider's refresh thread to read the updated files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see the new credential data.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_2_.c_str(),
|
||||
cert_chain_2_.c_str()))));
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderWithGoodAtFirstThenDeletedBothCerts) {
|
||||
// Create temporary files and copy cert data into it.
|
||||
auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
|
||||
auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
|
||||
auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key->name(),
|
||||
tmp_identity_cert->name(),
|
||||
tmp_root_cert->name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// The initial data is all good, so we expect to have successful credential
|
||||
// updates.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Delete TmpFile objects, which will remove the corresponding files.
|
||||
tmp_root_cert.reset();
|
||||
tmp_identity_key.reset();
|
||||
tmp_identity_cert.reset();
|
||||
// Wait 2 seconds for the provider's refresh thread to read the deleted files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see errors sent to watchers, and no credential updates.
|
||||
// We have no ideas on how many errors we will receive, so we only check once.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
::testing::Contains(ErrorInfo(kRootError, kIdentityError)));
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderWithGoodAtFirstThenDeletedRootCerts) {
|
||||
// Create temporary files and copy cert data into it.
|
||||
auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
|
||||
TmpFile tmp_identity_key(private_key_);
|
||||
TmpFile tmp_identity_cert(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key.name(),
|
||||
tmp_identity_cert.name(),
|
||||
tmp_root_cert->name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// The initial data is all good, so we expect to have successful credential
|
||||
// updates.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Delete root TmpFile object, which will remove the corresponding file.
|
||||
tmp_root_cert.reset();
|
||||
// Wait 2 seconds for the provider's refresh thread to read the deleted files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see errors sent to watchers, and no credential updates.
|
||||
// We have no ideas on how many errors we will receive, so we only check once.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
::testing::Contains(ErrorInfo(kRootError, "")));
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCertificateProviderTest,
|
||||
FileWatcherCertificateProviderWithGoodAtFirstThenDeletedIdentityCerts) {
|
||||
// Create temporary files and copy cert data into it.
|
||||
TmpFile tmp_root_cert(root_cert_);
|
||||
auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
|
||||
auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
|
||||
// Create FileWatcherCertificateProvider.
|
||||
FileWatcherCertificateProvider provider(tmp_identity_key->name(),
|
||||
tmp_identity_cert->name(),
|
||||
tmp_root_cert.name(), 1);
|
||||
WatcherState* watcher_state_1 =
|
||||
MakeWatcher(provider.distributor(), kCertName, kCertName);
|
||||
// The initial data is all good, so we expect to have successful credential
|
||||
// updates.
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
|
||||
::testing::ElementsAre(CredentialInfo(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(),
|
||||
cert_chain_.c_str()))));
|
||||
// Delete identity TmpFile objects, which will remove the corresponding files.
|
||||
tmp_identity_key.reset();
|
||||
tmp_identity_cert.reset();
|
||||
// Wait 2 seconds for the provider's refresh thread to read the deleted files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see errors sent to watchers, and no credential updates.
|
||||
// We have no ideas on how many errors we will receive, so we only check once.
|
||||
EXPECT_THAT(watcher_state_1->GetErrorQueue(),
|
||||
::testing::Contains(ErrorInfo("", kIdentityError)));
|
||||
EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
|
||||
// Clean up.
|
||||
CancelWatch(watcher_state_1);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -24,24 +24,440 @@
|
|||
#include <grpc/support/string_util.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "src/core/lib/gpr/tmpfile.h"
|
||||
#include "src/core/lib/iomgr/load_file.h"
|
||||
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
|
||||
#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
|
||||
#include "test/core/security/tls_utils.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
|
||||
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
|
||||
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
|
||||
#define CA_CERT_PATH_2 "src/core/tsi/test_creds/multi-domain.pem"
|
||||
#define SERVER_CERT_PATH_2 "src/core/tsi/test_creds/server0.pem"
|
||||
#define SERVER_KEY_PATH_2 "src/core/tsi/test_creds/server0.key"
|
||||
#define INVALID_PATH "invalid/path"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace testing {
|
||||
|
||||
TEST(GrpcTlsCredentialsOptionsTest, ErrorDetails) {
|
||||
class GrpcTlsCredentialsOptionsTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
root_cert_ = GetFileContents(CA_CERT_PATH);
|
||||
cert_chain_ = GetFileContents(SERVER_CERT_PATH);
|
||||
private_key_ = GetFileContents(SERVER_KEY_PATH);
|
||||
root_cert_2_ = GetFileContents(CA_CERT_PATH_2);
|
||||
cert_chain_2_ = GetFileContents(SERVER_CERT_PATH_2);
|
||||
private_key_2_ = GetFileContents(SERVER_KEY_PATH_2);
|
||||
}
|
||||
|
||||
std::string root_cert_;
|
||||
std::string private_key_;
|
||||
std::string cert_chain_;
|
||||
std::string root_cert_2_;
|
||||
std::string private_key_2_;
|
||||
std::string cert_chain_2_;
|
||||
};
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest, ErrorDetails) {
|
||||
grpc_tls_error_details error_details;
|
||||
EXPECT_STREQ(error_details.error_details().c_str(), "");
|
||||
error_details.set_error_details("test error details");
|
||||
EXPECT_STREQ(error_details.error_details().c_str(), "test error details");
|
||||
}
|
||||
|
||||
// Tests for StaticDataCertificateProvider.
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithStaticDataProviderOnBothCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithStaticDataProviderOnRootCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
root_cert_, PemKeyCertPairList());
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_FALSE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithStaticDataProviderOnNotProvidedCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
"", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithStaticDataProviderOnBothCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(
|
||||
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithStaticDataProviderOnIdentityCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
"", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_FALSE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithStaticDataProviderOnNotProvidedCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<StaticDataCertificateProvider>(
|
||||
root_cert_, PemKeyCertPairList());
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
//// Tests for FileWatcherCertificateProvider.
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnBothCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnRootCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider =
|
||||
MakeRefCounted<FileWatcherCertificateProvider>("", "", CA_CERT_PATH, 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_FALSE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnNotProvidedCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, "", 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnBadTrustCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider =
|
||||
MakeRefCounted<FileWatcherCertificateProvider>("", "", INVALID_PATH, 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithCertWatcherProviderOnBothCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(
|
||||
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithCertWatcherProviderOnIdentityCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, "", 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
EXPECT_FALSE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithCertWatcherProviderOnNotProvidedCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider =
|
||||
MakeRefCounted<FileWatcherCertificateProvider>("", "", CA_CERT_PATH, 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ServerOptionsWithCertWatcherProviderOnBadIdentityCerts) {
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
INVALID_PATH, INVALID_PATH, "", 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
|
||||
auto credentials = MakeRefCounted<TlsServerCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
auto connector = credentials->create_security_connector();
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsServerSecurityConnector* tls_connector =
|
||||
static_cast<TlsServerSecurityConnector*>(connector.get());
|
||||
EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
|
||||
}
|
||||
|
||||
// The following tests write credential data to temporary files to test the
|
||||
// transition behavior of the provider.
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnCertificateRefreshed) {
|
||||
// Create temporary files and copy cert data into them.
|
||||
TmpFile tmp_root_cert(root_cert_);
|
||||
TmpFile tmp_identity_key(private_key_);
|
||||
TmpFile tmp_identity_cert(cert_chain_);
|
||||
// Create ClientOptions using FileWatcherCertificateProvider.
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
tmp_identity_key.name(), tmp_identity_cert.name(), tmp_root_cert.name(),
|
||||
1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
// Expect to see the credential data.
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
|
||||
ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
|
||||
MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
// Copy new data to files.
|
||||
// TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
|
||||
// update when the directory renaming is added in gpr.
|
||||
tmp_root_cert.RewriteFile(root_cert_2_);
|
||||
tmp_identity_key.RewriteFile(private_key_2_);
|
||||
tmp_identity_cert.RewriteFile(cert_chain_2_);
|
||||
// Wait 2 seconds for the provider's refresh thread to read the updated files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// Expect to see new credential data loaded by the security connector.
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_2_);
|
||||
ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
|
||||
MakeCertKeyPairs(private_key_2_.c_str(), cert_chain_2_.c_str()));
|
||||
}
|
||||
|
||||
TEST_F(GrpcTlsCredentialsOptionsTest,
|
||||
ClientOptionsWithCertWatcherProviderOnDeletedFiles) {
|
||||
// Create temporary files and copy cert data into it.
|
||||
auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
|
||||
auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
|
||||
auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
|
||||
// Create ClientOptions using FileWatcherCertificateProvider.
|
||||
auto options = MakeRefCounted<grpc_tls_credentials_options>();
|
||||
auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
|
||||
tmp_identity_key->name(), tmp_identity_cert->name(),
|
||||
tmp_root_cert->name(), 1);
|
||||
options->set_certificate_provider(std::move(provider));
|
||||
options->set_watch_root_cert(true);
|
||||
options->set_watch_identity_pair(true);
|
||||
options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto credentials = MakeRefCounted<TlsCredentials>(options);
|
||||
ASSERT_NE(credentials, nullptr);
|
||||
grpc_channel_args* new_args = nullptr;
|
||||
auto connector = credentials->create_security_connector(
|
||||
nullptr, "random targets", nullptr, &new_args);
|
||||
grpc_channel_args_destroy(new_args);
|
||||
ASSERT_NE(connector, nullptr);
|
||||
TlsChannelSecurityConnector* tls_connector =
|
||||
static_cast<TlsChannelSecurityConnector*>(connector.get());
|
||||
// The initial data is all good, so we expect to have successful credential
|
||||
// updates.
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
|
||||
ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
|
||||
MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
// Delete TmpFile objects, which will remove the corresponding files.
|
||||
tmp_root_cert.reset();
|
||||
tmp_identity_key.reset();
|
||||
tmp_identity_cert.reset();
|
||||
// Wait 2 seconds for the provider's refresh thread to read the deleted files.
|
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
|
||||
gpr_time_from_seconds(2, GPR_TIMESPAN)));
|
||||
// It's a bit hard to test if errors are sent to the security connector,
|
||||
// because the security connector simply logs the error. We will see the err
|
||||
// messages if we open the log.
|
||||
// The old certs should still being used.
|
||||
EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
|
||||
ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
|
||||
ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
|
||||
EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
|
||||
MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
grpc::testing::TestEnvironment env(argc, argv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// 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 "test/core/security/tls_utils.h"
|
||||
|
||||
#include "src/core/lib/gpr/tmpfile.h"
|
||||
#include "src/core/lib/iomgr/load_file.h"
|
||||
#include "src/core/lib/slice/slice_internal.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace testing {
|
||||
|
||||
TmpFile::TmpFile(absl::string_view credential_data) {
|
||||
name_ = CreateTmpFileAndWriteData(credential_data);
|
||||
GPR_ASSERT(!name_.empty());
|
||||
}
|
||||
|
||||
TmpFile::~TmpFile() { GPR_ASSERT(remove(name_.c_str()) == 0); }
|
||||
|
||||
void TmpFile::RewriteFile(absl::string_view credential_data) {
|
||||
// Create a new file containing new data.
|
||||
std::string new_name = CreateTmpFileAndWriteData(credential_data);
|
||||
GPR_ASSERT(!new_name.empty());
|
||||
// Remove the old file.
|
||||
GPR_ASSERT(remove(name_.c_str()) == 0);
|
||||
// Rename the new file to the original name.
|
||||
GPR_ASSERT(rename(new_name.c_str(), name_.c_str()) == 0);
|
||||
}
|
||||
|
||||
std::string TmpFile::CreateTmpFileAndWriteData(
|
||||
absl::string_view credential_data) {
|
||||
char* name = nullptr;
|
||||
FILE* file_descriptor = gpr_tmpfile("GrpcTlsCertificateProviderTest", &name);
|
||||
GPR_ASSERT(fwrite(credential_data.data(), 1, credential_data.size(),
|
||||
file_descriptor) == credential_data.size());
|
||||
GPR_ASSERT(fclose(file_descriptor) == 0);
|
||||
GPR_ASSERT(file_descriptor != nullptr);
|
||||
GPR_ASSERT(name != nullptr);
|
||||
std::string name_to_return = name;
|
||||
gpr_free(name);
|
||||
return name_to_return;
|
||||
}
|
||||
|
||||
PemKeyCertPairList MakeCertKeyPairs(const char* private_key,
|
||||
const char* certs) {
|
||||
if (strcmp(private_key, "") == 0 && strcmp(certs, "") == 0) {
|
||||
return {};
|
||||
}
|
||||
grpc_ssl_pem_key_cert_pair* ssl_pair =
|
||||
static_cast<grpc_ssl_pem_key_cert_pair*>(
|
||||
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
|
||||
ssl_pair->private_key = gpr_strdup(private_key);
|
||||
ssl_pair->cert_chain = gpr_strdup(certs);
|
||||
PemKeyCertPairList pem_key_cert_pairs;
|
||||
pem_key_cert_pairs.emplace_back(ssl_pair);
|
||||
return pem_key_cert_pairs;
|
||||
}
|
||||
|
||||
std::string GetFileContents(const char* path) {
|
||||
grpc_slice slice = grpc_empty_slice();
|
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file", grpc_load_file(path, 0, &slice)));
|
||||
std::string credential = std::string(StringViewFromSlice(slice));
|
||||
grpc_slice_unref(slice);
|
||||
return credential;
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// 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/security_connector/ssl_utils.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
namespace testing {
|
||||
|
||||
class TmpFile {
|
||||
public:
|
||||
// Create a temporary file with |credential_data| written in.
|
||||
explicit TmpFile(absl::string_view credential_data);
|
||||
|
||||
~TmpFile();
|
||||
|
||||
const std::string& name() { return name_; }
|
||||
|
||||
// Rewrite |credential_data| to the temporary file, in an atomic way.
|
||||
void RewriteFile(absl::string_view credential_data);
|
||||
|
||||
private:
|
||||
std::string CreateTmpFileAndWriteData(absl::string_view credential_data);
|
||||
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
PemKeyCertPairList MakeCertKeyPairs(const char* private_key, const char* certs);
|
||||
|
||||
std::string GetFileContents(const char* path);
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
@ -206,6 +206,7 @@ int main(int argc, char **argv) {
|
|||
printf("%lx", (unsigned long) grpc_tls_identity_pairs_add_pair);
|
||||
printf("%lx", (unsigned long) grpc_tls_identity_pairs_destroy);
|
||||
printf("%lx", (unsigned long) grpc_tls_certificate_provider_static_data_create);
|
||||
printf("%lx", (unsigned long) grpc_tls_certificate_provider_file_watcher_create);
|
||||
printf("%lx", (unsigned long) grpc_tls_certificate_provider_release);
|
||||
printf("%lx", (unsigned long) grpc_tls_credentials_options_create);
|
||||
printf("%lx", (unsigned long) grpc_tls_credentials_options_set_cert_request_type);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ grpc_package(name = "test/cpp/client")
|
|||
grpc_cc_test(
|
||||
name = "credentials_test",
|
||||
srcs = ["credentials_test.cc"],
|
||||
data = [
|
||||
"//src/core/tsi/test_creds:ca.pem",
|
||||
"//src/core/tsi/test_creds:server1.key",
|
||||
"//src/core/tsi/test_creds:server1.pem",
|
||||
],
|
||||
external_deps = [
|
||||
"gtest",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@
|
|||
#include "src/cpp/client/secure_credentials.h"
|
||||
#include "src/cpp/common/tls_credentials_options_util.h"
|
||||
|
||||
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
|
||||
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
|
||||
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kRootCertName = "root_cert_name";
|
||||
|
|
@ -40,6 +44,7 @@ constexpr const char* kIdentityCertName = "identity_cert_name";
|
|||
constexpr const char* kIdentityCertPrivateKey = "identity_private_key";
|
||||
constexpr const char* kIdentityCertContents = "identity_cert_contents";
|
||||
|
||||
using ::grpc::experimental::FileWatcherCertificateProvider;
|
||||
using ::grpc::experimental::StaticDataCertificateProvider;
|
||||
using ::grpc::experimental::TlsServerAuthorizationCheckArg;
|
||||
using ::grpc::experimental::TlsServerAuthorizationCheckConfig;
|
||||
|
|
@ -407,6 +412,52 @@ TEST(CredentialsTest,
|
|||
GPR_ASSERT(channel_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
TEST(
|
||||
CredentialsTest,
|
||||
TlsChannelCredentialsWithFileWatcherCertificateProviderLoadingRootAndIdentity) {
|
||||
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
grpc::experimental::TlsChannelCredentialsOptions options(
|
||||
certificate_provider);
|
||||
options.watch_root_certs();
|
||||
options.set_root_cert_name(kRootCertName);
|
||||
options.watch_identity_key_cert_pairs();
|
||||
options.set_identity_cert_name(kIdentityCertName);
|
||||
options.set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto test_server_authorization_check =
|
||||
std::make_shared<TestTlsServerAuthorizationCheck>();
|
||||
auto server_authorization_check_config =
|
||||
std::make_shared<TlsServerAuthorizationCheckConfig>(
|
||||
test_server_authorization_check);
|
||||
options.set_server_authorization_check_config(
|
||||
server_authorization_check_config);
|
||||
auto channel_credentials = grpc::experimental::TlsCredentials(options);
|
||||
GPR_ASSERT(channel_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
// ChannelCredentials should always have root credential presented.
|
||||
// Otherwise the system root certificates will be loaded, which will cause
|
||||
// failure in some tests under MacOS/Windows.
|
||||
TEST(CredentialsTest,
|
||||
TlsChannelCredentialsWithFileWatcherCertificateProviderLoadingRootOnly) {
|
||||
auto certificate_provider =
|
||||
std::make_shared<FileWatcherCertificateProvider>(CA_CERT_PATH, 1);
|
||||
grpc::experimental::TlsChannelCredentialsOptions options(
|
||||
certificate_provider);
|
||||
options.watch_root_certs();
|
||||
options.set_root_cert_name(kRootCertName);
|
||||
options.set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
|
||||
auto test_server_authorization_check =
|
||||
std::make_shared<TestTlsServerAuthorizationCheck>();
|
||||
auto server_authorization_check_config =
|
||||
std::make_shared<TlsServerAuthorizationCheckConfig>(
|
||||
test_server_authorization_check);
|
||||
options.set_server_authorization_check_config(
|
||||
server_authorization_check_config);
|
||||
auto channel_credentials = grpc::experimental::TlsCredentials(options);
|
||||
GPR_ASSERT(channel_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
TEST(CredentialsTest, TlsServerAuthorizationCheckConfigErrorMessages) {
|
||||
std::shared_ptr<TlsServerAuthorizationCheckConfig> config(
|
||||
new TlsServerAuthorizationCheckConfig(nullptr));
|
||||
|
|
|
|||
|
|
@ -63,6 +63,11 @@ grpc_cc_test(
|
|||
grpc_cc_test(
|
||||
name = "credentials_test",
|
||||
srcs = ["credentials_test.cc"],
|
||||
data = [
|
||||
"//src/core/tsi/test_creds:ca.pem",
|
||||
"//src/core/tsi/test_creds:server1.key",
|
||||
"//src/core/tsi/test_creds:server1.pem",
|
||||
],
|
||||
external_deps = [
|
||||
"gtest",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
#include "test/core/util/port.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
|
||||
#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
|
||||
#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kRootCertName = "root_cert_name";
|
||||
|
|
@ -35,6 +39,7 @@ constexpr const char* kIdentityCertName = "identity_cert_name";
|
|||
constexpr const char* kIdentityCertPrivateKey = "identity_private_key";
|
||||
constexpr const char* kIdentityCertContents = "identity_cert_contents";
|
||||
|
||||
using ::grpc::experimental::FileWatcherCertificateProvider;
|
||||
using ::grpc::experimental::StaticDataCertificateProvider;
|
||||
|
||||
} // namespace
|
||||
|
|
@ -86,6 +91,38 @@ TEST(CredentialsTest,
|
|||
GPR_ASSERT(server_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
TEST(
|
||||
CredentialsTest,
|
||||
TlsServerCredentialsWithFileWatcherCertificateProviderLoadingRootAndIdentity) {
|
||||
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
|
||||
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
|
||||
options.watch_root_certs();
|
||||
options.set_root_cert_name(kRootCertName);
|
||||
options.watch_identity_key_cert_pairs();
|
||||
options.set_identity_cert_name(kIdentityCertName);
|
||||
options.set_cert_request_type(
|
||||
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
|
||||
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
|
||||
GPR_ASSERT(server_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
// ServerCredentials should always have identity credential presented.
|
||||
// Otherwise gRPC stack will fail.
|
||||
TEST(
|
||||
CredentialsTest,
|
||||
TlsServerCredentialsWithFileWatcherCertificateProviderLoadingIdentityOnly) {
|
||||
auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
|
||||
SERVER_KEY_PATH, SERVER_CERT_PATH, 1);
|
||||
grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
|
||||
options.watch_identity_key_cert_pairs();
|
||||
options.set_identity_cert_name(kIdentityCertName);
|
||||
options.set_cert_request_type(
|
||||
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
|
||||
auto server_credentials = grpc::experimental::TlsServerCredentials(options);
|
||||
GPR_ASSERT(server_credentials.get() != nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
|
|
|||
|
|
@ -4643,6 +4643,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": "grpc_tls_certificate_provider_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": true
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
|
|||
Loading…
Reference in New Issue