mirror of https://github.com/grpc/grpc.git
Merge pull request #24127 from yashykt/meshcaconfig
Add parsing logic for GoogleMeshCaConfigpull/24173/head
commit
3ee45eceef
24 changed files with 1124 additions and 36 deletions
@ -0,0 +1,377 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2020 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h" |
||||||
|
|
||||||
|
#include <sstream> |
||||||
|
#include <type_traits> |
||||||
|
|
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
|
||||||
|
#include <grpc/support/string_util.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gpr/string.h" |
||||||
|
#include "src/core/lib/iomgr/error.h" |
||||||
|
#include "src/core/lib/json/json_util.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
const char* kMeshCaPlugin = "meshCA"; |
||||||
|
|
||||||
|
//
|
||||||
|
// Helper functions for extracting types from JSON
|
||||||
|
//
|
||||||
|
template <typename NumericType, typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
NumericType* output, ErrorVectorType* error_list) { |
||||||
|
static_assert(std::is_integral<NumericType>::value, "Integral required"); |
||||||
|
if (json.type() != Json::Type::NUMBER) { |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:type should be NUMBER") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
std::istringstream ss(json.string_value()); |
||||||
|
ss >> *output; |
||||||
|
// The JSON parsing API should have dealt with parsing errors, but check
|
||||||
|
// anyway
|
||||||
|
if (GPR_UNLIKELY(ss.bad())) { |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:failed to parse.").c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
bool* output, ErrorVectorType* error_list) { |
||||||
|
switch (json.type()) { |
||||||
|
case Json::Type::JSON_TRUE: |
||||||
|
*output = true; |
||||||
|
return true; |
||||||
|
case Json::Type::JSON_FALSE: |
||||||
|
*output = false; |
||||||
|
return true; |
||||||
|
default: |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:type should be BOOLEAN") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
std::string* output, ErrorVectorType* error_list) { |
||||||
|
if (json.type() != Json::Type::STRING) { |
||||||
|
*output = ""; |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:type should be STRING") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
*output = json.string_value(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
const Json::Array** output, ErrorVectorType* error_list) { |
||||||
|
if (json.type() != Json::Type::ARRAY) { |
||||||
|
*output = nullptr; |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:type should be ARRAY") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
*output = &json.array_value(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
const Json::Object** output, ErrorVectorType* error_list) { |
||||||
|
if (json.type() != Json::Type::OBJECT) { |
||||||
|
*output = nullptr; |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:type should be OBJECT") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
*output = &json.object_value(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename ErrorVectorType> |
||||||
|
bool ExtractJsonType(const Json& json, const std::string& field_name, |
||||||
|
grpc_millis* output, ErrorVectorType* error_list) { |
||||||
|
if (!ParseDurationFromJson(json, output)) { |
||||||
|
*output = GRPC_MILLIS_INF_PAST; |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, |
||||||
|
" error:type should be STRING of the form given by " |
||||||
|
"google.proto.Duration.") |
||||||
|
.c_str())); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T, typename ErrorVectorType> |
||||||
|
bool ParseJsonObjectField(const Json::Object& object, |
||||||
|
const std::string& field_name, T* output, |
||||||
|
ErrorVectorType* error_list, bool optional = false) { |
||||||
|
auto it = object.find(field_name); |
||||||
|
if (it == object.end()) { |
||||||
|
if (!optional) { |
||||||
|
error_list->push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( |
||||||
|
absl::StrCat("field:", field_name, " error:does not exist.") |
||||||
|
.c_str())); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
auto& child_object_json = it->second; |
||||||
|
return ExtractJsonType(child_object_json, field_name, output, error_list); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
//
|
||||||
|
// GoogleMeshCaCertificateProviderFactory::Config
|
||||||
|
//
|
||||||
|
|
||||||
|
const char* GoogleMeshCaCertificateProviderFactory::Config::name() const { |
||||||
|
return kMeshCaPlugin; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<grpc_error*> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectStsService( |
||||||
|
const Json::Object& sts_service) { |
||||||
|
std::vector<grpc_error*> error_list_sts_service; |
||||||
|
if (!ParseJsonObjectField(sts_service, "token_exchange_service_uri", |
||||||
|
&sts_config_.token_exchange_service_uri, |
||||||
|
&error_list_sts_service, true)) { |
||||||
|
sts_config_.token_exchange_service_uri = |
||||||
|
"securetoken.googleapis.com"; // default
|
||||||
|
} |
||||||
|
ParseJsonObjectField(sts_service, "resource", &sts_config_.resource, |
||||||
|
&error_list_sts_service, true); |
||||||
|
ParseJsonObjectField(sts_service, "audience", &sts_config_.audience, |
||||||
|
&error_list_sts_service, true); |
||||||
|
if (!ParseJsonObjectField(sts_service, "scope", &sts_config_.scope, |
||||||
|
&error_list_sts_service, true)) { |
||||||
|
sts_config_.scope = |
||||||
|
"https://www.googleapis.com/auth/cloud-platform"; // default
|
||||||
|
} |
||||||
|
ParseJsonObjectField(sts_service, "requested_token_type", |
||||||
|
&sts_config_.requested_token_type, |
||||||
|
&error_list_sts_service, true); |
||||||
|
ParseJsonObjectField(sts_service, "subject_token_path", |
||||||
|
&sts_config_.subject_token_path, |
||||||
|
&error_list_sts_service); |
||||||
|
ParseJsonObjectField(sts_service, "subject_token_type", |
||||||
|
&sts_config_.subject_token_type, |
||||||
|
&error_list_sts_service); |
||||||
|
ParseJsonObjectField(sts_service, "actor_token_path", |
||||||
|
&sts_config_.actor_token_path, &error_list_sts_service, |
||||||
|
true); |
||||||
|
ParseJsonObjectField(sts_service, "actor_token_type", |
||||||
|
&sts_config_.actor_token_type, &error_list_sts_service, |
||||||
|
true); |
||||||
|
return error_list_sts_service; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<grpc_error*> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectCallCredentials( |
||||||
|
const Json::Object& call_credentials) { |
||||||
|
std::vector<grpc_error*> error_list_call_credentials; |
||||||
|
const Json::Object* sts_service = nullptr; |
||||||
|
if (ParseJsonObjectField(call_credentials, "sts_service", &sts_service, |
||||||
|
&error_list_call_credentials)) { |
||||||
|
std::vector<grpc_error*> error_list_sts_service = |
||||||
|
ParseJsonObjectStsService(*sts_service); |
||||||
|
if (!error_list_sts_service.empty()) { |
||||||
|
error_list_call_credentials.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"field:sts_service", &error_list_sts_service)); |
||||||
|
} |
||||||
|
} |
||||||
|
return error_list_call_credentials; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<grpc_error*> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc( |
||||||
|
const Json::Object& google_grpc) { |
||||||
|
std::vector<grpc_error*> error_list_google_grpc; |
||||||
|
if (!ParseJsonObjectField(google_grpc, "target_uri", &endpoint_, |
||||||
|
&error_list_google_grpc, true)) { |
||||||
|
endpoint_ = "meshca.googleapis.com"; // Default target
|
||||||
|
} |
||||||
|
const Json::Array* call_credentials_array = nullptr; |
||||||
|
if (ParseJsonObjectField(google_grpc, "call_credentials", |
||||||
|
&call_credentials_array, &error_list_google_grpc)) { |
||||||
|
if (call_credentials_array->size() != 1) { |
||||||
|
error_list_google_grpc.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:call_credentials error:Need exactly one entry.")); |
||||||
|
} else { |
||||||
|
const Json::Object* call_credentials = nullptr; |
||||||
|
if (ExtractJsonType((*call_credentials_array)[0], "call_credentials[0]", |
||||||
|
&call_credentials, &error_list_google_grpc)) { |
||||||
|
std::vector<grpc_error*> error_list_call_credentials = |
||||||
|
ParseJsonObjectCallCredentials(*call_credentials); |
||||||
|
if (!error_list_call_credentials.empty()) { |
||||||
|
error_list_google_grpc.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"field:call_credentials", &error_list_call_credentials)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return error_list_google_grpc; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<grpc_error*> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGrpcServices( |
||||||
|
const Json::Object& grpc_service) { |
||||||
|
std::vector<grpc_error*> error_list_grpc_services; |
||||||
|
const Json::Object* google_grpc = nullptr; |
||||||
|
if (ParseJsonObjectField(grpc_service, "google_grpc", &google_grpc, |
||||||
|
&error_list_grpc_services)) { |
||||||
|
std::vector<grpc_error*> error_list_google_grpc = |
||||||
|
ParseJsonObjectGoogleGrpc(*google_grpc); |
||||||
|
if (!error_list_google_grpc.empty()) { |
||||||
|
error_list_grpc_services.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"field:google_grpc", &error_list_google_grpc)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!ParseJsonObjectField(grpc_service, "timeout", &timeout_, |
||||||
|
&error_list_grpc_services, true)) { |
||||||
|
timeout_ = 10 * 1000; // 10sec default
|
||||||
|
} |
||||||
|
return error_list_grpc_services; |
||||||
|
} |
||||||
|
|
||||||
|
std::vector<grpc_error*> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer( |
||||||
|
const Json::Object& server) { |
||||||
|
std::vector<grpc_error*> error_list_server; |
||||||
|
std::string api_type; |
||||||
|
if (ParseJsonObjectField(server, "api_type", &api_type, &error_list_server, |
||||||
|
true)) { |
||||||
|
if (api_type != "GRPC") { |
||||||
|
error_list_server.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:api_type error:Only GRPC is supported")); |
||||||
|
} |
||||||
|
} |
||||||
|
const Json::Array* grpc_services = nullptr; |
||||||
|
if (ParseJsonObjectField(server, "grpc_services", &grpc_services, |
||||||
|
&error_list_server)) { |
||||||
|
if (grpc_services->size() != 1) { |
||||||
|
error_list_server.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:grpc_services error:Need exactly one entry")); |
||||||
|
} else { |
||||||
|
const Json::Object* grpc_service = nullptr; |
||||||
|
if (ExtractJsonType((*grpc_services)[0], "grpc_services[0]", |
||||||
|
&grpc_service, &error_list_server)) { |
||||||
|
std::vector<grpc_error*> error_list_grpc_services = |
||||||
|
ParseJsonObjectGrpcServices(*grpc_service); |
||||||
|
if (!error_list_grpc_services.empty()) { |
||||||
|
error_list_server.push_back(GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"field:grpc_services", &error_list_grpc_services)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return error_list_server; |
||||||
|
} |
||||||
|
|
||||||
|
std::unique_ptr<GoogleMeshCaCertificateProviderFactory::Config> |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(const Json& config_json, |
||||||
|
grpc_error** error) { |
||||||
|
auto config = |
||||||
|
absl::make_unique<GoogleMeshCaCertificateProviderFactory::Config>(); |
||||||
|
if (config_json.type() != Json::Type::OBJECT) { |
||||||
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"error:config type should be OBJECT."); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
std::vector<grpc_error*> error_list; |
||||||
|
const Json::Object* server = nullptr; |
||||||
|
if (ParseJsonObjectField(config_json.object_value(), "server", &server, |
||||||
|
&error_list)) { |
||||||
|
std::vector<grpc_error*> error_list_server = |
||||||
|
config->ParseJsonObjectServer(*server); |
||||||
|
if (!error_list_server.empty()) { |
||||||
|
error_list.push_back( |
||||||
|
GRPC_ERROR_CREATE_FROM_VECTOR("field:server", &error_list_server)); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!ParseJsonObjectField(config_json.object_value(), "certificate_lifetime", |
||||||
|
&config->certificate_lifetime_, &error_list, |
||||||
|
true)) { |
||||||
|
config->certificate_lifetime_ = 24 * 60 * 60 * 1000; // 24hrs default
|
||||||
|
} |
||||||
|
if (!ParseJsonObjectField(config_json.object_value(), "renewal_grace_period", |
||||||
|
&config->renewal_grace_period_, &error_list, |
||||||
|
true)) { |
||||||
|
config->renewal_grace_period_ = 12 * 60 * 60 * 1000; // 12hrs default
|
||||||
|
} |
||||||
|
std::string key_type; |
||||||
|
if (ParseJsonObjectField(config_json.object_value(), "key_type", &key_type, |
||||||
|
&error_list, true)) { |
||||||
|
if (key_type != "RSA") { |
||||||
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"field:key_type error:Only RSA is supported.")); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!ParseJsonObjectField(config_json.object_value(), "key_size", |
||||||
|
&config->key_size_, &error_list, true)) { |
||||||
|
config->key_size_ = 2048; // default 2048 bit key size
|
||||||
|
} |
||||||
|
if (!ParseJsonObjectField(config_json.object_value(), "location", |
||||||
|
&config->location_, &error_list, true)) { |
||||||
|
// GCE/GKE Metadata server needs to be contacted to get the value.
|
||||||
|
} |
||||||
|
if (!error_list.empty()) { |
||||||
|
*error = GRPC_ERROR_CREATE_FROM_VECTOR( |
||||||
|
"Error parsing google Mesh CA config", &error_list); |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
return config; |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// GoogleMeshCaCertificateProviderFactory
|
||||||
|
//
|
||||||
|
|
||||||
|
const char* GoogleMeshCaCertificateProviderFactory::name() const { |
||||||
|
return kMeshCaPlugin; |
||||||
|
} |
||||||
|
|
||||||
|
std::unique_ptr<CertificateProviderFactory::Config> |
||||||
|
GoogleMeshCaCertificateProviderFactory::CreateCertificateProviderConfig( |
||||||
|
const Json& config_json, grpc_error** error) { |
||||||
|
return GoogleMeshCaCertificateProviderFactory::Config::Parse(config_json, |
||||||
|
error); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,102 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2020 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_XDS_GOOGLE_MESH_CA_CERTIFICATE_PROVIDER_FACTORY_H |
||||||
|
#define GRPC_CORE_EXT_XDS_GOOGLE_MESH_CA_CERTIFICATE_PROVIDER_FACTORY_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/xds/certificate_provider_factory.h" |
||||||
|
#include "src/core/lib/backoff/backoff.h" |
||||||
|
#include "src/core/lib/gprpp/ref_counted.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
class GoogleMeshCaCertificateProviderFactory |
||||||
|
: public CertificateProviderFactory { |
||||||
|
public: |
||||||
|
class Config : public CertificateProviderFactory::Config { |
||||||
|
public: |
||||||
|
struct StsConfig { |
||||||
|
std::string token_exchange_service_uri; |
||||||
|
std::string resource; |
||||||
|
std::string audience; |
||||||
|
std::string scope; |
||||||
|
std::string requested_token_type; |
||||||
|
std::string subject_token_path; |
||||||
|
std::string subject_token_type; |
||||||
|
std::string actor_token_path; |
||||||
|
std::string actor_token_type; |
||||||
|
}; |
||||||
|
|
||||||
|
const char* name() const override; |
||||||
|
|
||||||
|
const std::string& endpoint() const { return endpoint_; } |
||||||
|
|
||||||
|
const StsConfig& sts_config() const { return sts_config_; } |
||||||
|
|
||||||
|
grpc_millis timeout() const { return timeout_; } |
||||||
|
|
||||||
|
grpc_millis certificate_lifetime() const { return certificate_lifetime_; } |
||||||
|
|
||||||
|
grpc_millis renewal_grace_period() const { return renewal_grace_period_; } |
||||||
|
|
||||||
|
uint32_t key_size() const { return key_size_; } |
||||||
|
|
||||||
|
const std::string& location() const { return location_; } |
||||||
|
|
||||||
|
static std::unique_ptr<Config> Parse(const Json& config_json, |
||||||
|
grpc_error** error); |
||||||
|
|
||||||
|
private: |
||||||
|
// Helpers for parsing the config
|
||||||
|
std::vector<grpc_error*> ParseJsonObjectStsService( |
||||||
|
const Json::Object& sts_service); |
||||||
|
std::vector<grpc_error*> ParseJsonObjectCallCredentials( |
||||||
|
const Json::Object& call_credentials); |
||||||
|
std::vector<grpc_error*> ParseJsonObjectGoogleGrpc( |
||||||
|
const Json::Object& google_grpc); |
||||||
|
std::vector<grpc_error*> ParseJsonObjectGrpcServices( |
||||||
|
const Json::Object& grpc_service); |
||||||
|
std::vector<grpc_error*> ParseJsonObjectServer(const Json::Object& server); |
||||||
|
|
||||||
|
std::string endpoint_; |
||||||
|
StsConfig sts_config_; |
||||||
|
grpc_millis timeout_; |
||||||
|
grpc_millis certificate_lifetime_; |
||||||
|
grpc_millis renewal_grace_period_; |
||||||
|
uint32_t key_size_; |
||||||
|
std::string location_; |
||||||
|
}; |
||||||
|
|
||||||
|
const char* name() const override; |
||||||
|
|
||||||
|
std::unique_ptr<CertificateProviderFactory::Config> |
||||||
|
CreateCertificateProviderConfig(const Json& config_json, |
||||||
|
grpc_error** error) override; |
||||||
|
|
||||||
|
RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider( |
||||||
|
std::unique_ptr<CertificateProviderFactory::Config> config) override { |
||||||
|
// TODO(yashykt) : To be implemented
|
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_EXT_XDS_GOOGLE_MESH_CA_CERTIFICATE_PROVIDER_FACTORY_H
|
@ -0,0 +1,58 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2020 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/json/json_util.h" |
||||||
|
|
||||||
|
#include <grpc/support/string_util.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gpr/string.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
bool ParseDurationFromJson(const Json& field, grpc_millis* duration) { |
||||||
|
if (field.type() != Json::Type::STRING) return false; |
||||||
|
size_t len = field.string_value().size(); |
||||||
|
if (field.string_value()[len - 1] != 's') return false; |
||||||
|
grpc_core::UniquePtr<char> buf(gpr_strdup(field.string_value().c_str())); |
||||||
|
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
|
||||||
|
char* decimal_point = strchr(buf.get(), '.'); |
||||||
|
int nanos = 0; |
||||||
|
if (decimal_point != nullptr) { |
||||||
|
*decimal_point = '\0'; |
||||||
|
nanos = gpr_parse_nonnegative_int(decimal_point + 1); |
||||||
|
if (nanos == -1) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
int num_digits = static_cast<int>(strlen(decimal_point + 1)); |
||||||
|
if (num_digits > 9) { // We don't accept greater precision than nanos.
|
||||||
|
return false; |
||||||
|
} |
||||||
|
for (int i = 0; i < (9 - num_digits); ++i) { |
||||||
|
nanos *= 10; |
||||||
|
} |
||||||
|
} |
||||||
|
int seconds = |
||||||
|
decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get()); |
||||||
|
if (seconds == -1) return false; |
||||||
|
*duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,37 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2020 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_JSON_JSON_UTIL_H |
||||||
|
#define GRPC_CORE_LIB_JSON_JSON_UTIL_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/exec_ctx.h" |
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// Parses a JSON field of the form generated for a google.proto.Duration
|
||||||
|
// proto message, as per:
|
||||||
|
// https://developers.google.com/protocol-buffers/docs/proto3#json
|
||||||
|
// Returns true on success, false otherwise.
|
||||||
|
bool ParseDurationFromJson(const Json& field, grpc_millis* duration); |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_LIB_JSON_JSON_UTIL_H
|
@ -0,0 +1,31 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") |
||||||
|
|
||||||
|
grpc_package(name = "test/core/client_channel") |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "google_mesh_ca_certificate_provider_factory_test", |
||||||
|
srcs = ["google_mesh_ca_certificate_provider_factory_test.cc"], |
||||||
|
external_deps = ["gtest"], |
||||||
|
language = "C++", |
||||||
|
deps = [ |
||||||
|
"//:gpr", |
||||||
|
"//:grpc", |
||||||
|
"//test/core/util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,367 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// 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 <gmock/gmock.h> |
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
|
||||||
|
#include "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace testing { |
||||||
|
namespace { |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, Basic) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"target_uri\": \"newmeshca.googleapis.com\"," |
||||||
|
" \"channel_credentials\": { \"google_default\": {}}," |
||||||
|
" \"call_credentials\": [{" |
||||||
|
" \"sts_service\": {" |
||||||
|
" \"token_exchange_service_uri\": " |
||||||
|
"\"newsecuretoken.googleapis.com\"," |
||||||
|
" \"resource\": \"newmeshca.googleapis.com\"," |
||||||
|
" \"audience\": \"newmeshca.googleapis.com\"," |
||||||
|
" \"scope\": " |
||||||
|
"\"https://www.newgoogleapis.com/auth/cloud-platform\"," |
||||||
|
" \"requested_token_type\": " |
||||||
|
"\"urn:ietf:params:oauth:token-type:jwt\"," |
||||||
|
" \"subject_token_path\": \"/etc/secret/sajwt.token\"," |
||||||
|
" \"subject_token_type\": " |
||||||
|
"\"urn:ietf:params:oauth:token-type:jwt\"," |
||||||
|
" \"actor_token_path\": \"/etc/secret/sajwt.token\"," |
||||||
|
" \"actor_token_type\": " |
||||||
|
"\"urn:ietf:params:oauth:token-type:jwt\"" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"timeout\": \"20s\"" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"certificate_lifetime\": \"400s\"," |
||||||
|
" \"renewal_grace_period\": \"100s\"," |
||||||
|
" \"key_type\": \"RSA\"," |
||||||
|
" \"key_size\": 1024," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
EXPECT_EQ(config->endpoint(), "newmeshca.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().token_exchange_service_uri, |
||||||
|
"newsecuretoken.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().resource, "newmeshca.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().audience, "newmeshca.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().scope, |
||||||
|
"https://www.newgoogleapis.com/auth/cloud-platform"); |
||||||
|
EXPECT_EQ(config->sts_config().requested_token_type, |
||||||
|
"urn:ietf:params:oauth:token-type:jwt"); |
||||||
|
EXPECT_EQ(config->sts_config().subject_token_path, "/etc/secret/sajwt.token"); |
||||||
|
EXPECT_EQ(config->sts_config().subject_token_type, |
||||||
|
"urn:ietf:params:oauth:token-type:jwt"); |
||||||
|
EXPECT_EQ(config->sts_config().actor_token_path, "/etc/secret/sajwt.token"); |
||||||
|
EXPECT_EQ(config->sts_config().actor_token_type, |
||||||
|
"urn:ietf:params:oauth:token-type:jwt"); |
||||||
|
EXPECT_EQ(config->timeout(), 20 * 1000); |
||||||
|
EXPECT_EQ(config->certificate_lifetime(), 400 * 1000); |
||||||
|
EXPECT_EQ(config->renewal_grace_period(), 100 * 1000); |
||||||
|
EXPECT_EQ(config->key_size(), 1024); |
||||||
|
EXPECT_EQ(config->location(), |
||||||
|
"https://container.googleapis.com/v1/project/test-project1/" |
||||||
|
"locations/test-zone2/clusters/test-cluster3"); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, Defaults) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"call_credentials\": [{" |
||||||
|
" \"sts_service\": {" |
||||||
|
" \"scope\": " |
||||||
|
"\"https://www.googleapis.com/auth/cloud-platform\"," |
||||||
|
" \"subject_token_path\": \"/etc/secret/sajwt.token\"," |
||||||
|
" \"subject_token_type\": " |
||||||
|
"\"urn:ietf:params:oauth:token-type:jwt\"" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
EXPECT_EQ(config->endpoint(), "meshca.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().token_exchange_service_uri, |
||||||
|
"securetoken.googleapis.com"); |
||||||
|
EXPECT_EQ(config->sts_config().resource, ""); |
||||||
|
EXPECT_EQ(config->sts_config().audience, ""); |
||||||
|
EXPECT_EQ(config->sts_config().scope, |
||||||
|
"https://www.googleapis.com/auth/cloud-platform"); |
||||||
|
EXPECT_EQ(config->sts_config().requested_token_type, ""); |
||||||
|
EXPECT_EQ(config->sts_config().subject_token_path, "/etc/secret/sajwt.token"); |
||||||
|
EXPECT_EQ(config->sts_config().subject_token_type, |
||||||
|
"urn:ietf:params:oauth:token-type:jwt"); |
||||||
|
EXPECT_EQ(config->sts_config().actor_token_path, ""); |
||||||
|
EXPECT_EQ(config->sts_config().actor_token_type, ""); |
||||||
|
EXPECT_EQ(config->timeout(), 10 * 1000); |
||||||
|
EXPECT_EQ(config->certificate_lifetime(), 24 * 60 * 60 * 1000); |
||||||
|
EXPECT_EQ(config->renewal_grace_period(), 12 * 60 * 60 * 1000); |
||||||
|
EXPECT_EQ(config->key_size(), 2048); |
||||||
|
EXPECT_EQ(config->location(), |
||||||
|
"https://container.googleapis.com/v1/project/test-project1/" |
||||||
|
"locations/test-zone2/clusters/test-cluster3"); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, WrongExpectedValues) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"REST\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"call_credentials\": [{" |
||||||
|
" \"sts_service\": {" |
||||||
|
" \"scope\": " |
||||||
|
"\"https://www.googleapis.com/auth/cloud-platform\"," |
||||||
|
" \"subject_token_path\": \"/etc/secret/sajwt.token\"," |
||||||
|
" \"subject_token_type\": " |
||||||
|
"\"urn:ietf:params:oauth:token-type:jwt\"" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"key_type\": \"DSA\"," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT( |
||||||
|
grpc_error_string(error), |
||||||
|
::testing::ContainsRegex("field:api_type error:Only GRPC is supported.*" |
||||||
|
"field:key_type error:Only RSA is supported")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, WrongTypes) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": 123," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"target_uri\": 123," |
||||||
|
" \"call_credentials\": [{" |
||||||
|
" \"sts_service\": {" |
||||||
|
" \"token_exchange_service_uri\": 123," |
||||||
|
" \"resource\": 123," |
||||||
|
" \"audience\": 123," |
||||||
|
" \"scope\": 123," |
||||||
|
" \"requested_token_type\": 123," |
||||||
|
" \"subject_token_path\": 123," |
||||||
|
" \"subject_token_type\": 123," |
||||||
|
" \"actor_token_path\": 123," |
||||||
|
" \"actor_token_type\": 123" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"timeout\": 20" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"certificate_lifetime\": 400," |
||||||
|
" \"renewal_grace_period\": 100," |
||||||
|
" \"key_type\": 123," |
||||||
|
" \"key_size\": \"1024\"," |
||||||
|
" \"location\": 123" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT( |
||||||
|
grpc_error_string(error), |
||||||
|
::testing::ContainsRegex( |
||||||
|
"field:server.*field:api_type error:type should be STRING.*" |
||||||
|
"field:grpc_services.*field:google_grpc.*field:target_uri " |
||||||
|
"error:type should be STRING.*" |
||||||
|
"field:call_credentials.*field:sts_service.*field:token_exchange_" |
||||||
|
"service_uri error:type should be STRING.*" |
||||||
|
"field:resource error:type should be STRING.*" |
||||||
|
"field:audience error:type should be STRING.*" |
||||||
|
"field:scope error:type should be STRING.*" |
||||||
|
"field:requested_token_type error:type should be STRING.*" |
||||||
|
"field:subject_token_path error:type should be STRING.*" |
||||||
|
"field:subject_token_type error:type should be STRING.*" |
||||||
|
"field:actor_token_path error:type should be STRING.*" |
||||||
|
"field:actor_token_type error:type should be STRING.*" |
||||||
|
"field:timeout error:type should be STRING of the form given by " |
||||||
|
"google.proto.Duration.*" |
||||||
|
"field:certificate_lifetime error:type should be STRING of the form " |
||||||
|
"given by google.proto.Duration.*" |
||||||
|
"field:renewal_grace_period error:type should be STRING of the form " |
||||||
|
"given by google.proto.Duration..*" |
||||||
|
"field:key_type error:type should be STRING.*" |
||||||
|
"field:key_size error:type should be NUMBER.*" |
||||||
|
"field:location error:type should be STRING")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, GrpcServicesNotAnArray) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": 123" |
||||||
|
" }," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT( |
||||||
|
grpc_error_string(error), |
||||||
|
::testing::ContainsRegex( |
||||||
|
"field:server.*field:grpc_services error:type should be ARRAY")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, GoogleGrpcNotAnObject) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": 123" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT( |
||||||
|
grpc_error_string(error), |
||||||
|
::testing::ContainsRegex("field:server.*field:grpc_services.*field:" |
||||||
|
"google_grpc error:type should be OBJECT")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, CallCredentialsNotAnArray) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"call_credentials\": 123" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT(grpc_error_string(error), |
||||||
|
::testing::ContainsRegex( |
||||||
|
"field:server.*field:grpc_services.*field:google_grpc.*" |
||||||
|
"field:call_credentials error:type should be ARRAY")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(GoogleMeshCaConfigTest, StsServiceNotAnObject) { |
||||||
|
const char* json_str = |
||||||
|
"{" |
||||||
|
" \"server\": {" |
||||||
|
" \"api_type\": \"GRPC\"," |
||||||
|
" \"grpc_services\": [{" |
||||||
|
" \"google_grpc\": {" |
||||||
|
" \"call_credentials\": [{" |
||||||
|
" \"sts_service\": 123" |
||||||
|
" }]" |
||||||
|
" }" |
||||||
|
" }]" |
||||||
|
" }," |
||||||
|
" \"location\": " |
||||||
|
"\"https://container.googleapis.com/v1/project/test-project1/locations/" |
||||||
|
"test-zone2/clusters/test-cluster3\"" |
||||||
|
"}"; |
||||||
|
grpc_error* error = GRPC_ERROR_NONE; |
||||||
|
Json json = Json::Parse(json_str, &error); |
||||||
|
ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error); |
||||||
|
auto config = |
||||||
|
GoogleMeshCaCertificateProviderFactory::Config::Parse(json, &error); |
||||||
|
EXPECT_THAT( |
||||||
|
grpc_error_string(error), |
||||||
|
::testing::ContainsRegex( |
||||||
|
"field:server.*field:grpc_services.*field:google_grpc.*field:" |
||||||
|
"call_credentials.*field:sts_service error:type should be OBJECT")); |
||||||
|
GRPC_ERROR_UNREF(error); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
grpc::testing::TestEnvironment env(argc, argv); |
||||||
|
grpc_init(); |
||||||
|
auto result = RUN_ALL_TESTS(); |
||||||
|
grpc_shutdown(); |
||||||
|
return result; |
||||||
|
} |
Loading…
Reference in new issue