diff --git a/BUILD b/BUILD
index aae25b18ed3..4d182f30292 100644
--- a/BUILD
+++ b/BUILD
@@ -774,6 +774,7 @@ grpc_cc_library(
"src/core/lib/iomgr/wakeup_fd_posix.cc",
"src/core/lib/iomgr/work_serializer.cc",
"src/core/lib/json/json_reader.cc",
+ "src/core/lib/json/json_util.cc",
"src/core/lib/json/json_writer.cc",
"src/core/lib/slice/b64.cc",
"src/core/lib/slice/percent_encoding.cc",
@@ -919,6 +920,7 @@ grpc_cc_library(
"src/core/lib/iomgr/wakeup_fd_posix.h",
"src/core/lib/iomgr/work_serializer.h",
"src/core/lib/json/json.h",
+ "src/core/lib/json/json_util.h",
"src/core/lib/slice/b64.h",
"src/core/lib/slice/percent_encoding.h",
"src/core/lib/slice/slice_internal.h",
@@ -1323,11 +1325,27 @@ grpc_cc_library(
"envoy_ads_upb",
"grpc_base",
"grpc_client_channel",
+ "grpc_google_mesh_ca_certificate_provider_factory",
"grpc_secure",
"grpc_xds_api_header",
],
)
+grpc_cc_library(
+ name = "grpc_google_mesh_ca_certificate_provider_factory",
+ srcs = [
+ "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc",
+ ],
+ hdrs = [
+ "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h",
+ ],
+ language = "c++",
+ deps = [
+ "grpc_base",
+ "grpc_secure",
+ ],
+)
+
grpc_cc_library(
name = "grpc_lb_policy_cds",
srcs = [
diff --git a/BUILD.gn b/BUILD.gn
index f1c05da02d5..5a5adb0c61c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -547,6 +547,8 @@ config("grpc_config") {
"src/core/ext/xds/certificate_provider_registry.cc",
"src/core/ext/xds/certificate_provider_registry.h",
"src/core/ext/xds/certificate_provider_store.h",
+ "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc",
+ "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h",
"src/core/ext/xds/xds_api.cc",
"src/core/ext/xds/xds_api.h",
"src/core/ext/xds/xds_bootstrap.cc",
@@ -790,6 +792,8 @@ config("grpc_config") {
"src/core/lib/iomgr/work_serializer.h",
"src/core/lib/json/json.h",
"src/core/lib/json/json_reader.cc",
+ "src/core/lib/json/json_util.cc",
+ "src/core/lib/json/json_util.h",
"src/core/lib/json/json_writer.cc",
"src/core/lib/security/authorization/authorization_engine.cc",
"src/core/lib/security/authorization/authorization_engine.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35d78737639..b4fbaf2538e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -822,6 +822,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx global_config_env_test)
endif()
add_dependencies(buildtests_cxx global_config_test)
+ 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_credentials_options_test)
@@ -1598,6 +1599,7 @@ add_library(grpc
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
src/core/ext/upb-generated/validate/validate.upb.c
src/core/ext/xds/certificate_provider_registry.cc
+ src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
src/core/ext/xds/xds_api.cc
src/core/ext/xds/xds_bootstrap.cc
src/core/ext/xds/xds_client.cc
@@ -1725,6 +1727,7 @@ add_library(grpc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
+ src/core/lib/json/json_util.cc
src/core/lib/json/json_writer.cc
src/core/lib/security/authorization/authorization_engine.cc
src/core/lib/security/authorization/evaluate_args.cc
@@ -2340,6 +2343,7 @@ add_library(grpc_unsecure
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
+ src/core/lib/json/json_util.cc
src/core/lib/json/json_writer.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
@@ -11096,6 +11100,45 @@ target_link_libraries(global_config_test
)
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(google_mesh_ca_certificate_provider_factory_test
+ test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(google_mesh_ca_certificate_provider_factory_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(google_mesh_ca_certificate_provider_factory_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc
+ gpr
+ address_sorting
+ upb
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+
endif()
if(gRPC_BUILD_TESTS)
diff --git a/Makefile b/Makefile
index 609b1079cfa..8e94ae2d76a 100644
--- a/Makefile
+++ b/Makefile
@@ -2003,6 +2003,7 @@ LIBGRPC_SRC = \
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/xds/certificate_provider_registry.cc \
+ src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_client.cc \
@@ -2130,6 +2131,7 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
+ src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/security/authorization/authorization_engine.cc \
src/core/lib/security/authorization/evaluate_args.cc \
@@ -2612,6 +2614,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
+ src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
@@ -4567,6 +4570,7 @@ src/core/ext/upb-generated/udpa/annotations/sensitive.upb.c: $(OPENSSL_DEP)
src/core/ext/upb-generated/udpa/annotations/status.upb.c: $(OPENSSL_DEP)
src/core/ext/upb-generated/udpa/annotations/versioning.upb.c: $(OPENSSL_DEP)
src/core/ext/xds/certificate_provider_registry.cc: $(OPENSSL_DEP)
+src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_api.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_bootstrap.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_client.cc: $(OPENSSL_DEP)
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 5292f07fd48..f5bd90cd61b 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -538,6 +538,7 @@ libs:
- src/core/ext/xds/certificate_provider_factory.h
- src/core/ext/xds/certificate_provider_registry.h
- src/core/ext/xds/certificate_provider_store.h
+ - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
- src/core/ext/xds/xds_api.h
- src/core/ext/xds/xds_bootstrap.h
- src/core/ext/xds/xds_channel_args.h
@@ -654,6 +655,7 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/iomgr/work_serializer.h
- src/core/lib/json/json.h
+ - src/core/lib/json/json_util.h
- src/core/lib/security/authorization/authorization_engine.h
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/mock_cel/activation.h
@@ -945,6 +947,7 @@ libs:
- src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c
- src/core/ext/upb-generated/validate/validate.upb.c
- src/core/ext/xds/certificate_provider_registry.cc
+ - src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
- src/core/ext/xds/xds_api.cc
- src/core/ext/xds/xds_bootstrap.cc
- src/core/ext/xds/xds_client.cc
@@ -1072,6 +1075,7 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/iomgr/work_serializer.cc
- src/core/lib/json/json_reader.cc
+ - src/core/lib/json/json_util.cc
- src/core/lib/json/json_writer.cc
- src/core/lib/security/authorization/authorization_engine.cc
- src/core/lib/security/authorization/evaluate_args.cc
@@ -1541,6 +1545,7 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/iomgr/work_serializer.h
- src/core/lib/json/json.h
+ - src/core/lib/json/json_util.h
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice_internal.h
@@ -1813,6 +1818,7 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/iomgr/work_serializer.cc
- src/core/lib/json/json_reader.cc
+ - src/core/lib/json/json_util.cc
- src/core/lib/json/json_writer.cc
- src/core/lib/slice/b64.cc
- src/core/lib/slice/percent_encoding.cc
@@ -5821,6 +5827,19 @@ targets:
- address_sorting
- upb
uses_polling: false
+- name: google_mesh_ca_certificate_provider_factory_test
+ gtest: true
+ build: test
+ language: c++
+ headers: []
+ src:
+ - test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr
+ - address_sorting
+ - upb
- name: grpc_cli
build: test
run: false
diff --git a/config.m4 b/config.m4
index 40c9c782c9b..8296eac7ec4 100644
--- a/config.m4
+++ b/config.m4
@@ -224,6 +224,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/xds/certificate_provider_registry.cc \
+ src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_bootstrap.cc \
src/core/ext/xds/xds_client.cc \
@@ -390,6 +391,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
+ src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
diff --git a/config.w32 b/config.w32
index fb5633d68ad..ddc90795dcb 100644
--- a/config.w32
+++ b/config.w32
@@ -191,6 +191,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\upb-generated\\udpa\\data\\orca\\v1\\orca_load_report.upb.c " +
"src\\core\\ext\\upb-generated\\validate\\validate.upb.c " +
"src\\core\\ext\\xds\\certificate_provider_registry.cc " +
+ "src\\core\\ext\\xds\\google_mesh_ca_certificate_provider_factory.cc " +
"src\\core\\ext\\xds\\xds_api.cc " +
"src\\core\\ext\\xds\\xds_bootstrap.cc " +
"src\\core\\ext\\xds\\xds_client.cc " +
@@ -357,6 +358,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\wakeup_fd_posix.cc " +
"src\\core\\lib\\iomgr\\work_serializer.cc " +
"src\\core\\lib\\json\\json_reader.cc " +
+ "src\\core\\lib\\json\\json_util.cc " +
"src\\core\\lib\\json\\json_writer.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +
"src\\core\\lib\\profiling\\stap_timers.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 02f640f68fa..54c226e2b61 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -360,6 +360,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@@ -503,6 +504,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
+ 'src/core/lib/json/json_util.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
@@ -864,6 +866,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@@ -1007,6 +1010,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
+ 'src/core/lib/json/json_util.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 2a52e0a7acb..36a77bad83e 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -533,6 +533,8 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_registry.cc',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.cc',
@@ -842,6 +844,8 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/json/json_reader.cc',
+ 'src/core/lib/json/json_util.cc',
+ 'src/core/lib/json/json_util.h',
'src/core/lib/json/json_writer.cc',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
@@ -1289,6 +1293,7 @@ Pod::Spec.new do |s|
'src/core/ext/xds/certificate_provider_factory.h',
'src/core/ext/xds/certificate_provider_registry.h',
'src/core/ext/xds/certificate_provider_store.h',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h',
'src/core/ext/xds/xds_api.h',
'src/core/ext/xds/xds_bootstrap.h',
'src/core/ext/xds/xds_channel_args.h',
@@ -1432,6 +1437,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
+ 'src/core/lib/json/json_util.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 6826e2435cf..a27b1fe4c02 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -451,6 +451,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/xds/certificate_provider_registry.cc )
s.files += %w( src/core/ext/xds/certificate_provider_registry.h )
s.files += %w( src/core/ext/xds/certificate_provider_store.h )
+ s.files += %w( src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc )
+ s.files += %w( src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h )
s.files += %w( src/core/ext/xds/xds_api.cc )
s.files += %w( src/core/ext/xds/xds_api.h )
s.files += %w( src/core/ext/xds/xds_bootstrap.cc )
@@ -760,6 +762,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/work_serializer.h )
s.files += %w( src/core/lib/json/json.h )
s.files += %w( src/core/lib/json/json_reader.cc )
+ s.files += %w( src/core/lib/json/json_util.cc )
+ s.files += %w( src/core/lib/json/json_util.h )
s.files += %w( src/core/lib/json/json_writer.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc )
s.files += %w( src/core/lib/profiling/stap_timers.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 426bab801d4..f7e8e3de654 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -629,6 +629,7 @@
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/xds/certificate_provider_registry.cc',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_client.cc',
@@ -756,6 +757,7 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
+ 'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/security/authorization/authorization_engine.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
@@ -1201,6 +1203,7 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
+ 'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
diff --git a/package.xml b/package.xml
index 3f6e0e3aef7..dcb8a80f9a8 100644
--- a/package.xml
+++ b/package.xml
@@ -431,6 +431,8 @@
+
+
@@ -740,6 +742,8 @@
+
+
diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc
index 5203748388d..cbf8de83f3d 100644
--- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc
+++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc
@@ -38,6 +38,7 @@
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/json/json_util.h"
#include "src/core/lib/uri/uri_parser.h"
// As per the retry design, we do not allow more than 5 retry attempts.
@@ -62,38 +63,6 @@ void ClientChannelServiceConfigParser::Register() {
namespace {
-// 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
-bool ParseDuration(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 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(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;
-}
-
std::unique_ptr ParseRetryPolicy(
const Json& json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
@@ -128,7 +97,7 @@ std::unique_ptr ParseRetryPolicy(
// Parse initialBackoff.
it = json.object_value().find("initialBackoff");
if (it != json.object_value().end()) {
- if (!ParseDuration(it->second, &retry_policy->initial_backoff)) {
+ if (!ParseDurationFromJson(it->second, &retry_policy->initial_backoff)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:Failed to parse"));
} else if (retry_policy->initial_backoff == 0) {
@@ -139,7 +108,7 @@ std::unique_ptr ParseRetryPolicy(
// Parse maxBackoff.
it = json.object_value().find("maxBackoff");
if (it != json.object_value().end()) {
- if (!ParseDuration(it->second, &retry_policy->max_backoff)) {
+ if (!ParseDurationFromJson(it->second, &retry_policy->max_backoff)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:failed to parse"));
} else if (retry_policy->max_backoff == 0) {
@@ -416,7 +385,7 @@ ClientChannelServiceConfigParser::ParsePerMethodParams(const Json& json,
// Parse timeout.
it = json.object_value().find("timeout");
if (it != json.object_value().end()) {
- if (!ParseDuration(it->second, &timeout)) {
+ if (!ParseDurationFromJson(it->second, &timeout)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:timeout error:Failed parsing"));
};
diff --git a/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc b/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
new file mode 100644
index 00000000000..8e1f7b5a456
--- /dev/null
+++ b/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc
@@ -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
+
+#include "src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h"
+
+#include
+#include
+
+#include "absl/strings/str_cat.h"
+
+#include
+
+#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
+bool ExtractJsonType(const Json& json, const std::string& field_name,
+ NumericType* output, ErrorVectorType* error_list) {
+ static_assert(std::is_integral::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
+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
+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
+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
+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
+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
+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
+GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectStsService(
+ const Json::Object& sts_service) {
+ std::vector 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
+GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectCallCredentials(
+ const Json::Object& call_credentials) {
+ std::vector error_list_call_credentials;
+ const Json::Object* sts_service = nullptr;
+ if (ParseJsonObjectField(call_credentials, "sts_service", &sts_service,
+ &error_list_call_credentials)) {
+ std::vector 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
+GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGoogleGrpc(
+ const Json::Object& google_grpc) {
+ std::vector 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 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
+GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectGrpcServices(
+ const Json::Object& grpc_service) {
+ std::vector error_list_grpc_services;
+ const Json::Object* google_grpc = nullptr;
+ if (ParseJsonObjectField(grpc_service, "google_grpc", &google_grpc,
+ &error_list_grpc_services)) {
+ std::vector 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
+GoogleMeshCaCertificateProviderFactory::Config::ParseJsonObjectServer(
+ const Json::Object& server) {
+ std::vector 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 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::Parse(const Json& config_json,
+ grpc_error** error) {
+ auto config =
+ absl::make_unique();
+ if (config_json.type() != Json::Type::OBJECT) {
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "error:config type should be OBJECT.");
+ return nullptr;
+ }
+ std::vector error_list;
+ const Json::Object* server = nullptr;
+ if (ParseJsonObjectField(config_json.object_value(), "server", &server,
+ &error_list)) {
+ std::vector 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
+GoogleMeshCaCertificateProviderFactory::CreateCertificateProviderConfig(
+ const Json& config_json, grpc_error** error) {
+ return GoogleMeshCaCertificateProviderFactory::Config::Parse(config_json,
+ error);
+}
+
+} // namespace grpc_core
diff --git a/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h b/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
new file mode 100644
index 00000000000..a48b1c65b26
--- /dev/null
+++ b/src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h
@@ -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
+
+#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 Parse(const Json& config_json,
+ grpc_error** error);
+
+ private:
+ // Helpers for parsing the config
+ std::vector ParseJsonObjectStsService(
+ const Json::Object& sts_service);
+ std::vector ParseJsonObjectCallCredentials(
+ const Json::Object& call_credentials);
+ std::vector ParseJsonObjectGoogleGrpc(
+ const Json::Object& google_grpc);
+ std::vector ParseJsonObjectGrpcServices(
+ const Json::Object& grpc_service);
+ std::vector 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
+ CreateCertificateProviderConfig(const Json& config_json,
+ grpc_error** error) override;
+
+ RefCountedPtr CreateCertificateProvider(
+ std::unique_ptr config) override {
+ // TODO(yashykt) : To be implemented
+ return nullptr;
+ }
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_CORE_EXT_XDS_GOOGLE_MESH_CA_CERTIFICATE_PROVIDER_FACTORY_H
diff --git a/src/core/lib/json/json_util.cc b/src/core/lib/json/json_util.cc
new file mode 100644
index 00000000000..1c90aeb5b47
--- /dev/null
+++ b/src/core/lib/json/json_util.cc
@@ -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
+
+#include "src/core/lib/json/json_util.h"
+
+#include
+
+#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 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(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
diff --git a/src/core/lib/json/json_util.h b/src/core/lib/json/json_util.h
new file mode 100644
index 00000000000..071087f7658
--- /dev/null
+++ b/src/core/lib/json/json_util.h
@@ -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
+
+#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
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index f68603d8a5e..dc5e0fd167c 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -200,6 +200,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/xds/certificate_provider_registry.cc',
+ 'src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc',
'src/core/ext/xds/xds_api.cc',
'src/core/ext/xds/xds_bootstrap.cc',
'src/core/ext/xds/xds_client.cc',
@@ -366,6 +367,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
+ 'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
diff --git a/test/core/security/authorization_engine_test.cc b/test/core/security/authorization_engine_test.cc
index 95d2a1e19d2..4b456a93550 100644
--- a/test/core/security/authorization_engine_test.cc
+++ b/test/core/security/authorization_engine_test.cc
@@ -77,4 +77,4 @@ TEST_F(AuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/test/core/xds/BUILD b/test/core/xds/BUILD
new file mode 100644
index 00000000000..1aad0470b3e
--- /dev/null
+++ b/test/core/xds/BUILD
@@ -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",
+ ],
+)
diff --git a/test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc b/test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
new file mode 100644
index 00000000000..8d336c3d3e9
--- /dev/null
+++ b/test/core/xds/google_mesh_ca_certificate_provider_factory_test.cc
@@ -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
+#include
+
+#include
+
+#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;
+}
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index da554e3bd73..b29d607492e 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1387,6 +1387,8 @@ src/core/ext/xds/certificate_provider_factory.h \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/certificate_provider_registry.h \
src/core/ext/xds/certificate_provider_store.h \
+src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \
+src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@@ -1696,6 +1698,8 @@ src/core/lib/iomgr/work_serializer.cc \
src/core/lib/iomgr/work_serializer.h \
src/core/lib/json/json.h \
src/core/lib/json/json_reader.cc \
+src/core/lib/json/json_util.cc \
+src/core/lib/json/json_util.h \
src/core/lib/json/json_writer.cc \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 7eb5f8d9434..7812de9c5a0 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1222,6 +1222,8 @@ src/core/ext/xds/certificate_provider_factory.h \
src/core/ext/xds/certificate_provider_registry.cc \
src/core/ext/xds/certificate_provider_registry.h \
src/core/ext/xds/certificate_provider_store.h \
+src/core/ext/xds/google_mesh_ca_certificate_provider_factory.cc \
+src/core/ext/xds/google_mesh_ca_certificate_provider_factory.h \
src/core/ext/xds/xds_api.cc \
src/core/ext/xds/xds_api.h \
src/core/ext/xds/xds_bootstrap.cc \
@@ -1536,6 +1538,8 @@ src/core/lib/iomgr/work_serializer.cc \
src/core/lib/iomgr/work_serializer.h \
src/core/lib/json/json.h \
src/core/lib/json/json_reader.cc \
+src/core/lib/json/json_util.cc \
+src/core/lib/json/json_util.h \
src/core/lib/json/json_writer.cc \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 67d7e8aca6c..de8acb8ca5d 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -4503,6 +4503,30 @@
],
"uses_polling": false
},
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "google_mesh_ca_certificate_provider_factory_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
{
"args": [],
"benchmark": false,