diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1393b57a180..f18cd94d649 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1123,6 +1123,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx fuzzing_event_engine_test)
endif()
add_dependencies(buildtests_cxx fuzzing_event_engine_unittest)
+ add_dependencies(buildtests_cxx gcp_authentication_filter_test)
add_dependencies(buildtests_cxx generic_end2end_test)
add_dependencies(buildtests_cxx glob_test)
add_dependencies(buildtests_cxx goaway_server_test)
@@ -1222,6 +1223,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx log_too_many_open_files_test)
endif()
add_dependencies(buildtests_cxx loop_test)
+ add_dependencies(buildtests_cxx lru_cache_test)
add_dependencies(buildtests_cxx map_pipe_test)
add_dependencies(buildtests_cxx match_test)
add_dependencies(buildtests_cxx matchers_test)
@@ -1592,6 +1594,9 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx xds_fault_injection_end2end_test)
endif()
+ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+ add_dependencies(buildtests_cxx xds_gcp_authn_end2end_test)
+ endif()
add_dependencies(buildtests_cxx xds_http_filters_test)
add_dependencies(buildtests_cxx xds_lb_policy_registry_test)
add_dependencies(buildtests_cxx xds_listener_resource_type_test)
@@ -1876,6 +1881,8 @@ add_library(grpc
src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc
src/core/ext/filters/fault_injection/fault_injection_filter.cc
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
+ src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
+ src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc
src/core/ext/filters/http/client/http_client_filter.cc
src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/http_filters_plugin.cc
@@ -2441,6 +2448,7 @@ add_library(grpc
src/core/lib/security/credentials/external/file_external_account_credentials.cc
src/core/lib/security/credentials/external/url_external_account_credentials.cc
src/core/lib/security/credentials/fake/fake_credentials.cc
+ src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
src/core/lib/security/credentials/google_default/credentials_generic.cc
src/core/lib/security/credentials/google_default/google_default_credentials.cc
src/core/lib/security/credentials/iam/iam_credentials.cc
@@ -2640,6 +2648,7 @@ add_library(grpc
src/core/xds/grpc/xds_health_status.cc
src/core/xds/grpc/xds_http_fault_filter.cc
src/core/xds/grpc/xds_http_filter_registry.cc
+ src/core/xds/grpc/xds_http_gcp_authn_filter.cc
src/core/xds/grpc/xds_http_rbac_filter.cc
src/core/xds/grpc/xds_http_stateful_session_filter.cc
src/core/xds/grpc/xds_lb_policy_registry.cc
@@ -15335,6 +15344,55 @@ target_link_libraries(fuzzing_event_engine_unittest
)
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(gcp_authentication_filter_test
+ ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h
+ test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
+ test/core/filters/filter_test.cc
+ test/core/filters/gcp_authentication_filter_test.cc
+)
+if(WIN32 AND MSVC)
+ if(BUILD_SHARED_LIBS)
+ target_compile_definitions(gcp_authentication_filter_test
+ PRIVATE
+ "GPR_DLL_IMPORTS"
+ "GRPC_DLL_IMPORTS"
+ )
+ endif()
+endif()
+target_compile_features(gcp_authentication_filter_test PUBLIC cxx_std_14)
+target_include_directories(gcp_authentication_filter_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_XXHASH_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(gcp_authentication_filter_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ gtest
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ grpc_test_util
+)
+
+
endif()
if(gRPC_BUILD_TESTS)
@@ -19656,6 +19714,42 @@ target_link_libraries(loop_test
)
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(lru_cache_test
+ test/core/util/lru_cache_test.cc
+)
+target_compile_features(lru_cache_test PUBLIC cxx_std_14)
+target_include_directories(lru_cache_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_XXHASH_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(lru_cache_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ gtest
+ absl::flat_hash_map
+ absl::any_invocable
+ absl::check
+ absl::statusor
+)
+
+
endif()
if(gRPC_BUILD_TESTS)
@@ -30612,7 +30706,6 @@ add_executable(test_core_security_credentials_test
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h
${_gRPC_PROTO_GENS_DIR}/test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.grpc.pb.h
- src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
test/core/event_engine/event_engine_test_utils.cc
test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
test/core/security/credentials_test.cc
@@ -35568,6 +35661,184 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
)
+endif()
+endif()
+if(gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+ add_executable(xds_gcp_authn_end2end_test
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/address.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/ads.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/base.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/discovery.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/endpoint.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/expr.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/extension.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/health_check.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/listener.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/load_report.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/load_report.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/load_report.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/load_report.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/lrs.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/lrs.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/lrs.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/lrs.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/metadata.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/outlier_detection.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/path.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/percent.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/protocol.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/range.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/rbac.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/regex.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/router.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.h
+ test/cpp/end2end/test_service_impl.cc
+ test/cpp/end2end/xds/xds_end2end_test_lib.cc
+ test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc
+ test/cpp/end2end/xds/xds_server.cc
+ test/cpp/end2end/xds/xds_utils.cc
+ test/cpp/util/tls_test_utils.cc
+ )
+ if(WIN32 AND MSVC)
+ if(BUILD_SHARED_LIBS)
+ target_compile_definitions(xds_gcp_authn_end2end_test
+ PRIVATE
+ "GPR_DLL_IMPORTS"
+ "GRPC_DLL_IMPORTS"
+ "GRPCXX_DLL_IMPORTS"
+ )
+ endif()
+ endif()
+ target_compile_features(xds_gcp_authn_end2end_test PUBLIC cxx_std_14)
+ target_include_directories(xds_gcp_authn_end2end_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_XXHASH_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(xds_gcp_authn_end2end_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ gtest
+ grpc++_test_util
+ )
+
+
endif()
endif()
if(gRPC_BUILD_TESTS)
@@ -35605,6 +35876,10 @@ add_executable(xds_http_filters_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/fault_common.grpc.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.grpc.pb.cc
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.pb.h
+ ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/gcp_authn.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h
diff --git a/Makefile b/Makefile
index 87fecd8ba58..35f58665d34 100644
--- a/Makefile
+++ b/Makefile
@@ -694,6 +694,8 @@ LIBGRPC_SRC = \
src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
+ src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc \
+ src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \
@@ -1278,6 +1280,7 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/external/file_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.cc \
src/core/lib/security/credentials/fake/fake_credentials.cc \
+ src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc \
src/core/lib/security/credentials/google_default/credentials_generic.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.cc \
src/core/lib/security/credentials/iam/iam_credentials.cc \
@@ -1499,6 +1502,7 @@ LIBGRPC_SRC = \
src/core/xds/grpc/xds_health_status.cc \
src/core/xds/grpc/xds_http_fault_filter.cc \
src/core/xds/grpc/xds_http_filter_registry.cc \
+ src/core/xds/grpc/xds_http_gcp_authn_filter.cc \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
src/core/xds/grpc/xds_lb_policy_registry.cc \
diff --git a/Package.swift b/Package.swift
index 719b25c4a81..a550e5f6dac 100644
--- a/Package.swift
+++ b/Package.swift
@@ -177,6 +177,10 @@ let package = Package(
"src/core/ext/filters/fault_injection/fault_injection_filter.h",
"src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc",
"src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h",
+ "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc",
+ "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h",
+ "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc",
+ "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h",
"src/core/ext/filters/http/client/http_client_filter.cc",
"src/core/ext/filters/http/client/http_client_filter.h",
"src/core/ext/filters/http/client_authority_filter.cc",
@@ -1570,6 +1574,8 @@ let package = Package(
"src/core/lib/security/credentials/external/url_external_account_credentials.h",
"src/core/lib/security/credentials/fake/fake_credentials.cc",
"src/core/lib/security/credentials/fake/fake_credentials.h",
+ "src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc",
+ "src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h",
"src/core/lib/security/credentials/google_default/credentials_generic.cc",
"src/core/lib/security/credentials/google_default/google_default_credentials.cc",
"src/core/lib/security/credentials/google_default/google_default_credentials.h",
@@ -1940,6 +1946,7 @@ let package = Package(
"src/core/util/latent_see.h",
"src/core/util/linux/cpu.cc",
"src/core/util/log.cc",
+ "src/core/util/lru_cache.h",
"src/core/util/msys/tmpfile.cc",
"src/core/util/posix/cpu.cc",
"src/core/util/posix/string.cc",
@@ -1998,6 +2005,8 @@ let package = Package(
"src/core/xds/grpc/xds_http_filter.h",
"src/core/xds/grpc/xds_http_filter_registry.cc",
"src/core/xds/grpc/xds_http_filter_registry.h",
+ "src/core/xds/grpc/xds_http_gcp_authn_filter.cc",
+ "src/core/xds/grpc/xds_http_gcp_authn_filter.h",
"src/core/xds/grpc/xds_http_rbac_filter.cc",
"src/core/xds/grpc/xds_http_rbac_filter.h",
"src/core/xds/grpc/xds_http_stateful_session_filter.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 67457572413..47c8f39b36d 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -251,6 +251,8 @@ libs:
- src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h
- src/core/ext/filters/fault_injection/fault_injection_filter.h
- src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h
+ - src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
+ - src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h
- src/core/ext/filters/http/client/http_client_filter.h
- src/core/ext/filters/http/client_authority_filter.h
- src/core/ext/filters/http/message_compress/compression_filter.h
@@ -1037,6 +1039,7 @@ libs:
- src/core/lib/security/credentials/external/file_external_account_credentials.h
- src/core/lib/security/credentials/external/url_external_account_credentials.h
- src/core/lib/security/credentials/fake/fake_credentials.h
+ - src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
- src/core/lib/security/credentials/google_default/google_default_credentials.h
- src/core/lib/security/credentials/iam/iam_credentials.h
- src/core/lib/security/credentials/insecure/insecure_credentials.h
@@ -1218,6 +1221,7 @@ libs:
- src/core/util/json/json_util.h
- src/core/util/json/json_writer.h
- src/core/util/latent_see.h
+ - src/core/util/lru_cache.h
- src/core/util/ring_buffer.h
- src/core/util/spinlock.h
- src/core/util/unique_ptr_with_bitset.h
@@ -1239,6 +1243,7 @@ libs:
- src/core/xds/grpc/xds_http_fault_filter.h
- src/core/xds/grpc/xds_http_filter.h
- src/core/xds/grpc/xds_http_filter_registry.h
+ - src/core/xds/grpc/xds_http_gcp_authn_filter.h
- src/core/xds/grpc/xds_http_rbac_filter.h
- src/core/xds/grpc/xds_http_stateful_session_filter.h
- src/core/xds/grpc/xds_lb_policy_registry.h
@@ -1291,6 +1296,8 @@ libs:
- src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc
- src/core/ext/filters/fault_injection/fault_injection_filter.cc
- src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
+ - src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
+ - src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc
- src/core/ext/filters/http/client/http_client_filter.cc
- src/core/ext/filters/http/client_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc
@@ -1856,6 +1863,7 @@ libs:
- src/core/lib/security/credentials/external/file_external_account_credentials.cc
- src/core/lib/security/credentials/external/url_external_account_credentials.cc
- src/core/lib/security/credentials/fake/fake_credentials.cc
+ - src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
- src/core/lib/security/credentials/google_default/credentials_generic.cc
- src/core/lib/security/credentials/google_default/google_default_credentials.cc
- src/core/lib/security/credentials/iam/iam_credentials.cc
@@ -2055,6 +2063,7 @@ libs:
- src/core/xds/grpc/xds_health_status.cc
- src/core/xds/grpc/xds_http_fault_filter.cc
- src/core/xds/grpc/xds_http_filter_registry.cc
+ - src/core/xds/grpc/xds_http_gcp_authn_filter.cc
- src/core/xds/grpc/xds_http_rbac_filter.cc
- src/core/xds/grpc/xds_http_stateful_session_filter.cc
- src/core/xds/grpc/xds_lb_policy_registry.cc
@@ -10882,6 +10891,23 @@ targets:
- gtest
- protobuf
- grpc_test_util
+- name: gcp_authentication_filter_test
+ gtest: true
+ build: test
+ language: c++
+ headers:
+ - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
+ - test/core/filters/filter_test.h
+ src:
+ - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto
+ - test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
+ - test/core/filters/filter_test.cc
+ - test/core/filters/gcp_authentication_filter_test.cc
+ deps:
+ - gtest
+ - protobuf
+ - grpc_test_util
+ uses_polling: false
- name: generic_end2end_test
gtest: true
build: test
@@ -12976,6 +13002,21 @@ targets:
- absl/status:statusor
- gpr
uses_polling: false
+- name: lru_cache_test
+ gtest: true
+ build: test
+ language: c++
+ headers:
+ - src/core/util/lru_cache.h
+ src:
+ - test/core/util/lru_cache_test.cc
+ deps:
+ - gtest
+ - absl/container:flat_hash_map
+ - absl/functional:any_invocable
+ - absl/log:check
+ - absl/status:statusor
+ uses_polling: false
- name: map_pipe_test
gtest: true
build: test
@@ -19660,7 +19701,6 @@ targets:
build: test
language: c++
headers:
- - src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
- test/core/event_engine/event_engine_test_utils.h
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
- test/core/test_util/cmdline.h
@@ -19675,7 +19715,6 @@ targets:
- test/core/test_util/tracer_util.h
src:
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.proto
- - src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
- test/core/event_engine/event_engine_test_utils.cc
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.cc
- test/core/security/credentials_test.cc
@@ -21834,6 +21873,65 @@ targets:
- linux
- posix
- mac
+- name: xds_gcp_authn_end2end_test
+ gtest: true
+ build: test
+ run: false
+ language: c++
+ headers:
+ - test/core/test_util/scoped_env_var.h
+ - test/cpp/end2end/counted_service.h
+ - test/cpp/end2end/test_service_impl.h
+ - test/cpp/end2end/xds/xds_end2end_test_lib.h
+ - test/cpp/end2end/xds/xds_server.h
+ - test/cpp/end2end/xds/xds_utils.h
+ - test/cpp/util/tls_test_utils.h
+ src:
+ - src/proto/grpc/testing/duplicate/echo_duplicate.proto
+ - src/proto/grpc/testing/echo.proto
+ - src/proto/grpc/testing/echo_messages.proto
+ - src/proto/grpc/testing/simple_messages.proto
+ - src/proto/grpc/testing/xds/v3/address.proto
+ - src/proto/grpc/testing/xds/v3/ads.proto
+ - src/proto/grpc/testing/xds/v3/base.proto
+ - src/proto/grpc/testing/xds/v3/cluster.proto
+ - src/proto/grpc/testing/xds/v3/config_source.proto
+ - src/proto/grpc/testing/xds/v3/discovery.proto
+ - src/proto/grpc/testing/xds/v3/endpoint.proto
+ - src/proto/grpc/testing/xds/v3/expr.proto
+ - src/proto/grpc/testing/xds/v3/extension.proto
+ - src/proto/grpc/testing/xds/v3/gcp_authn.proto
+ - src/proto/grpc/testing/xds/v3/health_check.proto
+ - src/proto/grpc/testing/xds/v3/http_connection_manager.proto
+ - src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
+ - src/proto/grpc/testing/xds/v3/listener.proto
+ - src/proto/grpc/testing/xds/v3/load_report.proto
+ - src/proto/grpc/testing/xds/v3/lrs.proto
+ - src/proto/grpc/testing/xds/v3/metadata.proto
+ - src/proto/grpc/testing/xds/v3/orca_load_report.proto
+ - src/proto/grpc/testing/xds/v3/outlier_detection.proto
+ - src/proto/grpc/testing/xds/v3/path.proto
+ - src/proto/grpc/testing/xds/v3/percent.proto
+ - src/proto/grpc/testing/xds/v3/protocol.proto
+ - src/proto/grpc/testing/xds/v3/range.proto
+ - src/proto/grpc/testing/xds/v3/rbac.proto
+ - src/proto/grpc/testing/xds/v3/regex.proto
+ - src/proto/grpc/testing/xds/v3/route.proto
+ - src/proto/grpc/testing/xds/v3/router.proto
+ - src/proto/grpc/testing/xds/v3/string.proto
+ - test/cpp/end2end/test_service_impl.cc
+ - test/cpp/end2end/xds/xds_end2end_test_lib.cc
+ - test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc
+ - test/cpp/end2end/xds/xds_server.cc
+ - test/cpp/end2end/xds/xds_utils.cc
+ - test/cpp/util/tls_test_utils.cc
+ deps:
+ - gtest
+ - grpc++_test_util
+ platforms:
+ - linux
+ - posix
+ - mac
- name: xds_http_filters_test
gtest: true
build: test
@@ -21855,6 +21953,7 @@ targets:
- src/proto/grpc/testing/xds/v3/extension.proto
- src/proto/grpc/testing/xds/v3/fault.proto
- src/proto/grpc/testing/xds/v3/fault_common.proto
+ - src/proto/grpc/testing/xds/v3/gcp_authn.proto
- src/proto/grpc/testing/xds/v3/http_filter_rbac.proto
- src/proto/grpc/testing/xds/v3/metadata.proto
- src/proto/grpc/testing/xds/v3/path.proto
diff --git a/config.m4 b/config.m4
index 17886c07dd5..903e5727bbb 100644
--- a/config.m4
+++ b/config.m4
@@ -69,6 +69,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
+ src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc \
+ src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \
@@ -653,6 +655,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/external/file_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.cc \
src/core/lib/security/credentials/fake/fake_credentials.cc \
+ src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc \
src/core/lib/security/credentials/google_default/credentials_generic.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.cc \
src/core/lib/security/credentials/iam/iam_credentials.cc \
@@ -874,6 +877,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/xds/grpc/xds_health_status.cc \
src/core/xds/grpc/xds_http_fault_filter.cc \
src/core/xds/grpc/xds_http_filter_registry.cc \
+ src/core/xds/grpc/xds_http_gcp_authn_filter.cc \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
src/core/xds/grpc/xds_lb_policy_registry.cc \
@@ -1400,6 +1404,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/census)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/channel_idle)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/fault_injection)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/gcp_authentication)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/client)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/http/message_compress)
@@ -1552,6 +1557,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/composite)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/external)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/fake)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/gcp_service_account_identity)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/google_default)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/iam)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/insecure)
diff --git a/config.w32 b/config.w32
index 2f087a6943b..0734ce7cfaf 100644
--- a/config.w32
+++ b/config.w32
@@ -34,6 +34,8 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\channel_idle\\legacy_channel_idle_filter.cc " +
"src\\core\\ext\\filters\\fault_injection\\fault_injection_filter.cc " +
"src\\core\\ext\\filters\\fault_injection\\fault_injection_service_config_parser.cc " +
+ "src\\core\\ext\\filters\\gcp_authentication\\gcp_authentication_filter.cc " +
+ "src\\core\\ext\\filters\\gcp_authentication\\gcp_authentication_service_config_parser.cc " +
"src\\core\\ext\\filters\\http\\client\\http_client_filter.cc " +
"src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
"src\\core\\ext\\filters\\http\\http_filters_plugin.cc " +
@@ -618,6 +620,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\external\\file_external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\external\\url_external_account_credentials.cc " +
"src\\core\\lib\\security\\credentials\\fake\\fake_credentials.cc " +
+ "src\\core\\lib\\security\\credentials\\gcp_service_account_identity\\gcp_service_account_identity_credentials.cc " +
"src\\core\\lib\\security\\credentials\\google_default\\credentials_generic.cc " +
"src\\core\\lib\\security\\credentials\\google_default\\google_default_credentials.cc " +
"src\\core\\lib\\security\\credentials\\iam\\iam_credentials.cc " +
@@ -839,6 +842,7 @@ if (PHP_GRPC != "no") {
"src\\core\\xds\\grpc\\xds_health_status.cc " +
"src\\core\\xds\\grpc\\xds_http_fault_filter.cc " +
"src\\core\\xds\\grpc\\xds_http_filter_registry.cc " +
+ "src\\core\\xds\\grpc\\xds_http_gcp_authn_filter.cc " +
"src\\core\\xds\\grpc\\xds_http_rbac_filter.cc " +
"src\\core\\xds\\grpc\\xds_http_stateful_session_filter.cc " +
"src\\core\\xds\\grpc\\xds_lb_policy_registry.cc " +
@@ -1394,6 +1398,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\census");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\channel_idle");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\fault_injection");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\gcp_authentication");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http\\client");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\http\\message_compress");
@@ -1692,6 +1697,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\composite");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\external");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\fake");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\gcp_service_account_identity");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\google_default");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\iam");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\insecure");
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index e88102ca5d4..388db1822d3 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -302,6 +302,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/compression_filter.h',
@@ -1145,6 +1147,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/insecure/insecure_credentials.h',
@@ -1327,6 +1330,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
+ 'src/core/util/lru_cache.h',
'src/core/util/ring_buffer.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
@@ -1353,6 +1357,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_http_fault_filter.h',
'src/core/xds/grpc/xds_http_filter.h',
'src/core/xds/grpc/xds_http_filter_registry.h',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
@@ -1612,6 +1617,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/compression_filter.h',
@@ -2437,6 +2444,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/insecure/insecure_credentials.h',
@@ -2619,6 +2627,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
+ 'src/core/util/lru_cache.h',
'src/core/util/ring_buffer.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
@@ -2645,6 +2654,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_http_fault_filter.h',
'src/core/xds/grpc/xds_http_filter.h',
'src/core/xds/grpc/xds_http_filter_registry.h',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index a4751ea0e1b..3427505b1c3 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -297,6 +297,10 @@ Pod::Spec.new do |s|
'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.cc',
@@ -1686,6 +1690,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/external/url_external_account_credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.cc',
'src/core/lib/security/credentials/fake/fake_credentials.h',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h',
'src/core/lib/security/credentials/google_default/credentials_generic.cc',
'src/core/lib/security/credentials/google_default/google_default_credentials.cc',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
@@ -2056,6 +2062,7 @@ Pod::Spec.new do |s|
'src/core/util/latent_see.h',
'src/core/util/linux/cpu.cc',
'src/core/util/log.cc',
+ 'src/core/util/lru_cache.h',
'src/core/util/msys/tmpfile.cc',
'src/core/util/posix/cpu.cc',
'src/core/util/posix/string.cc',
@@ -2114,6 +2121,8 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_http_filter.h',
'src/core/xds/grpc/xds_http_filter_registry.cc',
'src/core/xds/grpc/xds_http_filter_registry.h',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.cc',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.h',
'src/core/xds/grpc/xds_http_rbac_filter.cc',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.cc',
@@ -2412,6 +2421,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/compression_filter.h',
@@ -3217,6 +3228,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/external/file_external_account_credentials.h',
'src/core/lib/security/credentials/external/url_external_account_credentials.h',
'src/core/lib/security/credentials/fake/fake_credentials.h',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h',
'src/core/lib/security/credentials/google_default/google_default_credentials.h',
'src/core/lib/security/credentials/iam/iam_credentials.h',
'src/core/lib/security/credentials/insecure/insecure_credentials.h',
@@ -3399,6 +3411,7 @@ Pod::Spec.new do |s|
'src/core/util/json/json_util.h',
'src/core/util/json/json_writer.h',
'src/core/util/latent_see.h',
+ 'src/core/util/lru_cache.h',
'src/core/util/ring_buffer.h',
'src/core/util/spinlock.h',
'src/core/util/string.h',
@@ -3424,6 +3437,7 @@ Pod::Spec.new do |s|
'src/core/xds/grpc/xds_http_fault_filter.h',
'src/core/xds/grpc/xds_http_filter.h',
'src/core/xds/grpc/xds_http_filter_registry.h',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.h',
'src/core/xds/grpc/xds_http_rbac_filter.h',
'src/core/xds/grpc/xds_http_stateful_session_filter.h',
'src/core/xds/grpc/xds_lb_policy_registry.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index f8c9988b45a..b56dffe06e6 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -183,6 +183,10 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.h )
s.files += %w( src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc )
s.files += %w( src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h )
+ s.files += %w( src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc )
+ s.files += %w( src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h )
+ s.files += %w( src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc )
+ s.files += %w( src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.cc )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )
@@ -1572,6 +1576,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/external/url_external_account_credentials.h )
s.files += %w( src/core/lib/security/credentials/fake/fake_credentials.cc )
s.files += %w( src/core/lib/security/credentials/fake/fake_credentials.h )
+ s.files += %w( src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc )
+ s.files += %w( src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h )
s.files += %w( src/core/lib/security/credentials/google_default/credentials_generic.cc )
s.files += %w( src/core/lib/security/credentials/google_default/google_default_credentials.cc )
s.files += %w( src/core/lib/security/credentials/google_default/google_default_credentials.h )
@@ -1942,6 +1948,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/util/latent_see.h )
s.files += %w( src/core/util/linux/cpu.cc )
s.files += %w( src/core/util/log.cc )
+ s.files += %w( src/core/util/lru_cache.h )
s.files += %w( src/core/util/msys/tmpfile.cc )
s.files += %w( src/core/util/posix/cpu.cc )
s.files += %w( src/core/util/posix/string.cc )
@@ -2000,6 +2007,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/xds/grpc/xds_http_filter.h )
s.files += %w( src/core/xds/grpc/xds_http_filter_registry.cc )
s.files += %w( src/core/xds/grpc/xds_http_filter_registry.h )
+ s.files += %w( src/core/xds/grpc/xds_http_gcp_authn_filter.cc )
+ s.files += %w( src/core/xds/grpc/xds_http_gcp_authn_filter.h )
s.files += %w( src/core/xds/grpc/xds_http_rbac_filter.cc )
s.files += %w( src/core/xds/grpc/xds_http_rbac_filter.h )
s.files += %w( src/core/xds/grpc/xds_http_stateful_session_filter.cc )
diff --git a/package.xml b/package.xml
index de24f221508..6a05e868d26 100644
--- a/package.xml
+++ b/package.xml
@@ -165,6 +165,10 @@
+
+
+
+
@@ -1554,6 +1558,8 @@
+
+
@@ -1924,6 +1930,7 @@
+
@@ -1982,6 +1989,8 @@
+
+
diff --git a/src/core/BUILD b/src/core/BUILD
index 07dec2bba1d..dee69ed3bd7 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -4993,6 +4993,48 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "gcp_authentication_filter",
+ srcs = [
+ "ext/filters/gcp_authentication/gcp_authentication_filter.cc",
+ "ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc",
+ ],
+ hdrs = [
+ "ext/filters/gcp_authentication/gcp_authentication_filter.h",
+ "ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h",
+ ],
+ external_deps = [
+ "absl/log:check",
+ "absl/status",
+ "absl/status:statusor",
+ "absl/strings",
+ "absl/types:optional",
+ ],
+ language = "c++",
+ deps = [
+ "arena",
+ "channel_args",
+ "channel_fwd",
+ "context",
+ "gcp_service_account_identity_credentials",
+ "grpc_resolver_xds_attributes",
+ "grpc_service_config",
+ "json",
+ "json_args",
+ "json_object_loader",
+ "lru_cache",
+ "service_config_parser",
+ "validation_errors",
+ "xds_config",
+ "//:config",
+ "//:gpr",
+ "//:grpc_base",
+ "//:grpc_security_base",
+ "//:grpc_trace",
+ "//:ref_counted_ptr",
+ ],
+)
+
grpc_cc_library(
name = "grpc_lb_policy_grpclb",
srcs = [
@@ -5194,6 +5236,23 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "lru_cache",
+ hdrs = [
+ "util/lru_cache.h",
+ ],
+ external_deps = [
+ "absl/container:flat_hash_map",
+ "absl/functional:any_invocable",
+ "absl/log:check",
+ "absl/types:optional",
+ ],
+ language = "c++",
+ # TODO(roth): Remove this unnecessary dependency once
+ # yaqs/eng/q/6510477728410501120 is resolved.
+ deps = ["//:grpc_public_hdrs"],
+)
+
grpc_cc_library(
name = "upb_utils",
hdrs = [
@@ -5584,6 +5643,7 @@ grpc_cc_library(
"xds/grpc/xds_endpoint_parser.cc",
"xds/grpc/xds_http_fault_filter.cc",
"xds/grpc/xds_http_filter_registry.cc",
+ "xds/grpc/xds_http_gcp_authn_filter.cc",
"xds/grpc/xds_http_rbac_filter.cc",
"xds/grpc/xds_http_stateful_session_filter.cc",
"xds/grpc/xds_lb_policy_registry.cc",
@@ -5603,6 +5663,7 @@ grpc_cc_library(
"xds/grpc/xds_endpoint_parser.h",
"xds/grpc/xds_http_fault_filter.h",
"xds/grpc/xds_http_filter_registry.h",
+ "xds/grpc/xds_http_gcp_authn_filter.h",
"xds/grpc/xds_http_rbac_filter.h",
"xds/grpc/xds_http_stateful_session_filter.h",
"xds/grpc/xds_lb_policy_registry.h",
@@ -5696,6 +5757,7 @@ grpc_cc_library(
"envoy_type_upb",
"error",
"error_utils",
+ "gcp_authentication_filter",
"google_rpc_status_upb",
"grpc_audit_logging",
"grpc_fake_credentials",
diff --git a/src/core/client_channel/client_channel.cc b/src/core/client_channel/client_channel.cc
index 5e1e2ec8eb3..f700b39463e 100644
--- a/src/core/client_channel/client_channel.cc
+++ b/src/core/client_channel/client_channel.cc
@@ -1105,6 +1105,10 @@ void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
service_config = std::move(*result.service_config);
config_selector = result.args.GetObjectRef();
}
+ // Remove the config selector from channel args so that we're not holding
+ // unnecessary refs that cause it to be destroyed somewhere other than in
+ // the WorkSerializer.
+ result.args = result.args.Remove(GRPC_ARG_CONFIG_SELECTOR);
// Note: The only case in which service_config is null here is if the
// resolver returned a service config error and we don't have a previous
// service config to fall back to.
@@ -1138,6 +1142,7 @@ void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
<< "client_channel=" << this << ": service config not changed";
}
// Create or update LB policy, as needed.
+ ChannelArgs new_args = result.args;
resolver_result_status = CreateOrUpdateLbPolicyLocked(
std::move(lb_policy_config),
parsed_service_config->health_check_service_name(), std::move(result));
@@ -1146,7 +1151,7 @@ void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
// the ConfigSelector may need the LB policy to know about new
// destinations before it can send RPCs to those destinations.
if (service_config_changed || config_selector_changed) {
- UpdateServiceConfigInDataPlaneLocked();
+ UpdateServiceConfigInDataPlaneLocked(new_args);
}
}
// Invoke resolver callback if needed.
@@ -1196,10 +1201,7 @@ absl::Status ClientChannel::CreateOrUpdateLbPolicyLocked(
}
update_args.config = std::move(lb_policy_config);
update_args.resolution_note = std::move(result.resolution_note);
- // Remove the config selector from channel args so that we're not holding
- // unnecessary refs that cause it to be destroyed somewhere other than in
- // the WorkSerializer.
- update_args.args = result.args.Remove(GRPC_ARG_CONFIG_SELECTOR);
+ update_args.args = std::move(result.args);
// Add health check service name to channel args.
if (health_check_service_name.has_value()) {
update_args.args = update_args.args.Set(GRPC_ARG_HEALTH_CHECK_SERVICE_NAME,
@@ -1264,7 +1266,8 @@ void ClientChannel::UpdateServiceConfigInControlPlaneLocked(
}
}
-void ClientChannel::UpdateServiceConfigInDataPlaneLocked() {
+void ClientChannel::UpdateServiceConfigInDataPlaneLocked(
+ const ChannelArgs& args) {
GRPC_TRACE_LOG(client_channel, INFO)
<< "client_channel=" << this << ": switching to ConfigSelector "
<< saved_config_selector_.get();
@@ -1275,7 +1278,7 @@ void ClientChannel::UpdateServiceConfigInDataPlaneLocked() {
MakeRefCounted(saved_service_config_);
}
// Construct filter stack.
- InterceptionChainBuilder builder(channel_args_.SetObject(this));
+ InterceptionChainBuilder builder(args.SetObject(this));
if (idle_timeout_ != Duration::Zero()) {
builder.AddOnServerTrailingMetadata([this](ServerMetadata&) {
if (idle_state_.DecreaseCallCount()) StartIdleTimer();
diff --git a/src/core/client_channel/client_channel.h b/src/core/client_channel/client_channel.h
index 13809c04471..7a73a2259d0 100644
--- a/src/core/client_channel/client_channel.h
+++ b/src/core/client_channel/client_channel.h
@@ -149,7 +149,7 @@ class ClientChannel : public Channel {
RefCountedPtr config_selector, std::string lb_policy_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_);
- void UpdateServiceConfigInDataPlaneLocked()
+ void UpdateServiceConfigInDataPlaneLocked(const ChannelArgs& args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_);
void UpdateStateLocked(grpc_connectivity_state state,
diff --git a/src/core/client_channel/client_channel_filter.cc b/src/core/client_channel/client_channel_filter.cc
index 0443002c520..f80f20cc88d 100644
--- a/src/core/client_channel/client_channel_filter.cc
+++ b/src/core/client_channel/client_channel_filter.cc
@@ -1319,6 +1319,10 @@ void ClientChannelFilter::OnResolverResultChangedLocked(
service_config = std::move(*result.service_config);
config_selector = result.args.GetObjectRef();
}
+ // Remove the config selector from channel args so that we're not holding
+ // unnecessary refs that cause it to be destroyed somewhere other than in the
+ // WorkSerializer.
+ result.args = result.args.Remove(GRPC_ARG_CONFIG_SELECTOR);
// Note: The only case in which service_config is null here is if the resolver
// returned a service config error and we don't have a previous service
// config to fall back to.
@@ -1349,6 +1353,7 @@ void ClientChannelFilter::OnResolverResultChangedLocked(
<< "chand=" << this << ": service config not changed";
}
// Create or update LB policy, as needed.
+ ChannelArgs new_args = result.args;
resolver_result_status = CreateOrUpdateLbPolicyLocked(
std::move(lb_policy_config),
parsed_service_config->health_check_service_name(), std::move(result));
@@ -1357,7 +1362,7 @@ void ClientChannelFilter::OnResolverResultChangedLocked(
// This needs to happen after the LB policy has been updated, since
// the ConfigSelector may need the LB policy to know about new
// destinations before it can send RPCs to those destinations.
- UpdateServiceConfigInDataPlaneLocked();
+ UpdateServiceConfigInDataPlaneLocked(new_args);
// TODO(ncteisen): might be worth somehow including a snippet of the
// config in the trace, at the risk of bloating the trace logs.
trace_strings.push_back("Service config changed");
@@ -1413,10 +1418,7 @@ absl::Status ClientChannelFilter::CreateOrUpdateLbPolicyLocked(
}
update_args.config = std::move(lb_policy_config);
update_args.resolution_note = std::move(result.resolution_note);
- // Remove the config selector from channel args so that we're not holding
- // unnecessary refs that cause it to be destroyed somewhere other than in the
- // WorkSerializer.
- update_args.args = result.args.Remove(GRPC_ARG_CONFIG_SELECTOR);
+ update_args.args = std::move(result.args);
// Add health check service name to channel args.
if (health_check_service_name.has_value()) {
update_args.args = update_args.args.Set(GRPC_ARG_HEALTH_CHECK_SERVICE_NAME,
@@ -1480,7 +1482,8 @@ void ClientChannelFilter::UpdateServiceConfigInControlPlaneLocked(
<< saved_config_selector_.get();
}
-void ClientChannelFilter::UpdateServiceConfigInDataPlaneLocked() {
+void ClientChannelFilter::UpdateServiceConfigInDataPlaneLocked(
+ const ChannelArgs& args) {
// Grab ref to service config.
RefCountedPtr service_config = saved_service_config_;
// Grab ref to config selector. Use default if resolver didn't supply one.
@@ -1492,8 +1495,7 @@ void ClientChannelFilter::UpdateServiceConfigInDataPlaneLocked() {
config_selector =
MakeRefCounted(saved_service_config_);
}
- ChannelArgs new_args =
- channel_args_.SetObject(this).SetObject(service_config);
+ ChannelArgs new_args = args.SetObject(this).SetObject(service_config);
bool enable_retries =
!new_args.WantMinimalStack() &&
new_args.GetBool(GRPC_ARG_ENABLE_RETRIES).value_or(true);
diff --git a/src/core/client_channel/client_channel_filter.h b/src/core/client_channel/client_channel_filter.h
index 9b119b4e021..7ecf787ca74 100644
--- a/src/core/client_channel/client_channel_filter.h
+++ b/src/core/client_channel/client_channel_filter.h
@@ -247,7 +247,7 @@ class ClientChannelFilter final {
RefCountedPtr config_selector, std::string lb_policy_name)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_);
- void UpdateServiceConfigInDataPlaneLocked()
+ void UpdateServiceConfigInDataPlaneLocked(const ChannelArgs& args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_);
void CreateResolverLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*work_serializer_);
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
new file mode 100644
index 00000000000..c3a6ab3e71b
--- /dev/null
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
@@ -0,0 +1,167 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h"
+
+#include
+#include
+#include
+
+#include "absl/log/check.h"
+#include "absl/strings/str_cat.h"
+
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/config/core_configuration.h"
+#include "src/core/lib/promise/context.h"
+#include "src/core/lib/resource_quota/arena.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h"
+#include "src/core/lib/transport/transport.h"
+#include "src/core/resolver/xds/xds_resolver_attributes.h"
+#include "src/core/service_config/service_config.h"
+#include "src/core/service_config/service_config_call_data.h"
+
+namespace grpc_core {
+
+const NoInterceptor GcpAuthenticationFilter::Call::OnClientToServerMessage;
+const NoInterceptor GcpAuthenticationFilter::Call::OnClientToServerHalfClose;
+const NoInterceptor GcpAuthenticationFilter::Call::OnServerInitialMetadata;
+const NoInterceptor GcpAuthenticationFilter::Call::OnServerToClientMessage;
+const NoInterceptor GcpAuthenticationFilter::Call::OnServerTrailingMetadata;
+const NoInterceptor GcpAuthenticationFilter::Call::OnFinalize;
+
+absl::Status GcpAuthenticationFilter::Call::OnClientInitialMetadata(
+ ClientMetadata& /*md*/, GcpAuthenticationFilter* filter) {
+ // Get the cluster name chosen for this RPC.
+ auto* service_config_call_data = GetContext();
+ auto cluster_attribute =
+ service_config_call_data->GetCallAttribute();
+ if (cluster_attribute == nullptr) {
+ // Can't happen, but be defensive.
+ return absl::InternalError(
+ "GCP authentication filter: call has no xDS cluster attribute");
+ }
+ absl::string_view cluster_name = cluster_attribute->cluster();
+ if (!absl::ConsumePrefix(&cluster_name, "cluster:")) {
+ return absl::OkStatus(); // Cluster specifier plugin.
+ }
+ // Look up the CDS resource for the cluster.
+ auto it = filter->xds_config_->clusters.find(cluster_name);
+ if (it == filter->xds_config_->clusters.end()) {
+ // Can't happen, but be defensive.
+ return absl::InternalError(
+ absl::StrCat("GCP authentication filter: xDS cluster ", cluster_name,
+ " not found in XdsConfig"));
+ }
+ if (!it->second.ok()) {
+ // Cluster resource had an error, so fail the call.
+ // Note: For wait_for_ready calls, this does the wrong thing by
+ // failing the call instead of queuing it, but there's no easy
+ // way to queue the call here until we get a valid CDS resource,
+ // because once that happens, a new instance of this filter will be
+ // swapped in for subsequent calls, but *this* call is already tied
+ // to this filter instance, which will never see the update.
+ return absl::UnavailableError(
+ absl::StrCat("GCP authentication filter: CDS resource unavailable for ",
+ cluster_name));
+ }
+ if (it->second->cluster == nullptr) {
+ // Can't happen, but be defensive.
+ return absl::InternalError(absl::StrCat(
+ "GCP authentication filter: CDS resource not present for cluster ",
+ cluster_name));
+ }
+ auto& metadata_map = it->second->cluster->metadata;
+ const XdsMetadataValue* metadata_value =
+ metadata_map.Find(filter->filter_config_->filter_instance_name);
+ // If no audience in the cluster, then no need to add call creds.
+ if (metadata_value == nullptr) return absl::OkStatus();
+ // If the entry is present but the wrong type, fail the RPC.
+ if (metadata_value->type() != XdsGcpAuthnAudienceMetadataValue::Type()) {
+ return absl::UnavailableError(absl::StrCat(
+ "GCP authentication filter: audience metadata in wrong format for "
+ "cluster ",
+ cluster_name));
+ }
+ // Get the call creds instance.
+ auto creds = filter->GetCallCredentials(
+ DownCast(metadata_value)->url());
+ // Add the call creds instance to the call.
+ auto* arena = GetContext();
+ auto* security_ctx = DownCast(
+ arena->GetContext());
+ if (security_ctx == nullptr) {
+ security_ctx = arena->New(std::move(creds));
+ arena->SetContext(security_ctx);
+ } else {
+ security_ctx->creds = std::move(creds);
+ }
+ return absl::OkStatus();
+}
+
+const grpc_channel_filter GcpAuthenticationFilter::kFilter =
+ MakePromiseBasedFilter();
+
+absl::StatusOr>
+GcpAuthenticationFilter::Create(const ChannelArgs& args,
+ ChannelFilter::Args filter_args) {
+ auto* service_config = args.GetObject();
+ if (service_config == nullptr) {
+ return absl::InvalidArgumentError(
+ "gcp_auth: no service config in channel args");
+ }
+ auto* config = static_cast(
+ service_config->GetGlobalParsedConfig(
+ GcpAuthenticationServiceConfigParser::ParserIndex()));
+ if (config == nullptr) {
+ return absl::InvalidArgumentError("gcp_auth: parsed config not found");
+ }
+ auto* filter_config = config->GetConfig(filter_args.instance_id());
+ if (filter_config == nullptr) {
+ return absl::InvalidArgumentError(
+ "gcp_auth: filter instance ID not found in filter config");
+ }
+ auto xds_config = args.GetObjectRef();
+ if (xds_config == nullptr) {
+ return absl::InvalidArgumentError(
+ "gcp_auth: xds config not found in channel args");
+ }
+ return std::make_unique(filter_config,
+ std::move(xds_config));
+}
+
+GcpAuthenticationFilter::GcpAuthenticationFilter(
+ const GcpAuthenticationParsedConfig::Config* filter_config,
+ RefCountedPtr xds_config)
+ : filter_config_(filter_config),
+ xds_config_(std::move(xds_config)),
+ cache_(filter_config->cache_size) {}
+
+RefCountedPtr
+GcpAuthenticationFilter::GetCallCredentials(const std::string& audience) {
+ MutexLock lock(&mu_);
+ return cache_.GetOrInsert(audience, [](const std::string& audience) {
+ return MakeRefCounted(audience);
+ });
+}
+
+void GcpAuthenticationFilterRegister(CoreConfiguration::Builder* builder) {
+ GcpAuthenticationServiceConfigParser::Register(builder);
+}
+
+} // namespace grpc_core
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
new file mode 100644
index 00000000000..927e2de05ef
--- /dev/null
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
@@ -0,0 +1,82 @@
+//
+// Copyright 2024 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_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_FILTER_H
+#define GRPC_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_FILTER_H
+
+#include
+#include
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_fwd.h"
+#include "src/core/lib/channel/promise_based_filter.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/sync.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/transport/transport.h"
+#include "src/core/resolver/xds/xds_config.h"
+#include "src/core/util/lru_cache.h"
+
+namespace grpc_core {
+
+// xDS GCP Authentication filter.
+// https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/gcp_authn_filter
+class GcpAuthenticationFilter
+ : public ImplementChannelFilter {
+ public:
+ static const grpc_channel_filter kFilter;
+
+ static absl::string_view TypeName() { return "gcp_authentication_filter"; }
+
+ static absl::StatusOr> Create(
+ const ChannelArgs& args, ChannelFilter::Args filter_args);
+
+ GcpAuthenticationFilter(
+ const GcpAuthenticationParsedConfig::Config* filter_config,
+ RefCountedPtr xds_config);
+
+ class Call {
+ public:
+ absl::Status OnClientInitialMetadata(ClientMetadata& /*md*/,
+ GcpAuthenticationFilter* filter);
+ static const NoInterceptor OnClientToServerMessage;
+ static const NoInterceptor OnClientToServerHalfClose;
+ static const NoInterceptor OnServerInitialMetadata;
+ static const NoInterceptor OnServerToClientMessage;
+ static const NoInterceptor OnServerTrailingMetadata;
+ static const NoInterceptor OnFinalize;
+ };
+
+ private:
+ RefCountedPtr GetCallCredentials(
+ const std::string& audience);
+
+ const GcpAuthenticationParsedConfig::Config* filter_config_;
+ const RefCountedPtr xds_config_;
+
+ Mutex mu_;
+ LruCache>
+ cache_ ABSL_GUARDED_BY(&mu_);
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_FILTER_H
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc b/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc
new file mode 100644
index 00000000000..4af33e528f7
--- /dev/null
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc
@@ -0,0 +1,81 @@
+//
+// Copyright 2024 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/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
+
+#include
+
+#include "absl/types/optional.h"
+
+#include "src/core/lib/channel/channel_args.h"
+
+namespace grpc_core {
+
+const JsonLoaderInterface* GcpAuthenticationParsedConfig::Config::JsonLoader(
+ const JsonArgs&) {
+ static const auto* loader =
+ JsonObjectLoader()
+ .Field("filter_instance_name", &Config::filter_instance_name)
+ .OptionalField("cache_size", &Config::cache_size)
+ .Finish();
+ return loader;
+}
+
+void GcpAuthenticationParsedConfig::Config::JsonPostLoad(
+ const Json&, const JsonArgs&, ValidationErrors* errors) {
+ if (cache_size == 0) {
+ ValidationErrors::ScopedField field(errors, ".cache_size");
+ errors->AddError("must be non-zero");
+ }
+}
+
+const JsonLoaderInterface* GcpAuthenticationParsedConfig::JsonLoader(
+ const JsonArgs&) {
+ static const auto* loader =
+ JsonObjectLoader()
+ .OptionalField("gcp_authentication",
+ &GcpAuthenticationParsedConfig::configs_)
+ .Finish();
+ return loader;
+}
+
+std::unique_ptr
+GcpAuthenticationServiceConfigParser::ParseGlobalParams(
+ const ChannelArgs& args, const Json& json, ValidationErrors* errors) {
+ // Only parse config if the following channel arg is enabled.
+ if (!args.GetBool(GRPC_ARG_PARSE_GCP_AUTHENTICATION_METHOD_CONFIG)
+ .value_or(false)) {
+ return nullptr;
+ }
+ // Parse config from json.
+ return LoadFromJson>(
+ json, JsonArgs(), errors);
+}
+
+void GcpAuthenticationServiceConfigParser::Register(
+ CoreConfiguration::Builder* builder) {
+ builder->service_config_parser()->RegisterParser(
+ std::make_unique());
+}
+
+size_t GcpAuthenticationServiceConfigParser::ParserIndex() {
+ return CoreConfiguration::Get().service_config_parser().GetParserIndex(
+ parser_name());
+}
+
+} // namespace grpc_core
diff --git a/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h b/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h
new file mode 100644
index 00000000000..97df008e968
--- /dev/null
+++ b/src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h
@@ -0,0 +1,87 @@
+//
+// Copyright 2024 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_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_SERVICE_CONFIG_PARSER_H
+#define GRPC_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_SERVICE_CONFIG_PARSER_H
+
+#include
+
+#include
+#include
+#include
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
+#include "src/core/lib/gprpp/validation_errors.h"
+#include "src/core/service_config/service_config_parser.h"
+#include "src/core/util/json/json.h"
+#include "src/core/util/json/json_args.h"
+#include "src/core/util/json/json_object_loader.h"
+
+// Channel arg key for enabling parsing fault injection via method config.
+#define GRPC_ARG_PARSE_GCP_AUTHENTICATION_METHOD_CONFIG \
+ "grpc.internal.parse_gcp_authentication_method_config"
+
+namespace grpc_core {
+
+class GcpAuthenticationParsedConfig : public ServiceConfigParser::ParsedConfig {
+ public:
+ struct Config {
+ std::string filter_instance_name;
+ uint64_t cache_size = 10;
+
+ static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
+ void JsonPostLoad(const Json&, const JsonArgs&, ValidationErrors* errors);
+ };
+
+ // Returns the config at the specified index. There might be multiple
+ // GCP auth filters in the list of HTTP filters at the same time.
+ // The order of the list is stable, and an index is used to keep track of
+ // their relative positions. Each filter instance uses this method to
+ // access the appropriate parsed config for that instance.
+ const Config* GetConfig(size_t index) const {
+ if (index >= configs_.size()) return nullptr;
+ return &configs_[index];
+ }
+
+ static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
+
+ private:
+ std::vector configs_;
+};
+
+class GcpAuthenticationServiceConfigParser final
+ : public ServiceConfigParser::Parser {
+ public:
+ absl::string_view name() const override { return parser_name(); }
+ std::unique_ptr ParseGlobalParams(
+ const ChannelArgs& args, const Json& json,
+ ValidationErrors* errors) override;
+ // Returns the parser index for the parser.
+ static size_t ParserIndex();
+ // Registers the parser.
+ static void Register(CoreConfiguration::Builder* builder);
+
+ private:
+ static absl::string_view parser_name() { return "gcp_auth"; }
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_SERVICE_CONFIG_PARSER_H
diff --git a/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc b/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
index dba35759431..11aa4e158d7 100644
--- a/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
+++ b/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
@@ -161,7 +161,7 @@ std::string GcpServiceAccountIdentityCallCredentials::debug_string() {
")");
}
-UniqueTypeName GcpServiceAccountIdentityCallCredentials::type() const {
+UniqueTypeName GcpServiceAccountIdentityCallCredentials::Type() {
static UniqueTypeName::Factory kFactory("GcpServiceAccountIdentity");
return kFactory.Create();
}
diff --git a/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h b/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
index 1581b5a499f..231e9bbccc6 100644
--- a/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
+++ b/src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
@@ -57,6 +57,7 @@ class JwtTokenFetcherCallCredentials : public TokenFetcherCredentials {
};
// GCP service account identity call credentials.
+// See gRFC A83 (https://github.com/grpc/proposal/pull/438).
class GcpServiceAccountIdentityCallCredentials
: public JwtTokenFetcherCallCredentials {
public:
@@ -65,7 +66,9 @@ class GcpServiceAccountIdentityCallCredentials
std::string debug_string() override;
- UniqueTypeName type() const override;
+ static UniqueTypeName Type();
+
+ UniqueTypeName type() const override { return Type(); }
absl::string_view audience() const { return audience_; }
diff --git a/src/core/plugin_registry/grpc_plugin_registry_extra.cc b/src/core/plugin_registry/grpc_plugin_registry_extra.cc
index a6013c24965..5b9dde4cf1e 100644
--- a/src/core/plugin_registry/grpc_plugin_registry_extra.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry_extra.cc
@@ -23,6 +23,8 @@ namespace grpc_core {
#ifndef GRPC_NO_XDS
extern void RbacFilterRegister(CoreConfiguration::Builder* builder);
extern void StatefulSessionFilterRegister(CoreConfiguration::Builder* builder);
+extern void GcpAuthenticationFilterRegister(
+ CoreConfiguration::Builder* builder);
extern void RegisterXdsChannelStackModifier(
CoreConfiguration::Builder* builder);
extern void RegisterChannelDefaultCreds(CoreConfiguration::Builder* builder);
@@ -47,6 +49,7 @@ void RegisterExtraFilters(CoreConfiguration::Builder* builder) {
// re2 library by default
RbacFilterRegister(builder);
StatefulSessionFilterRegister(builder);
+ GcpAuthenticationFilterRegister(builder);
RegisterXdsChannelStackModifier(builder);
RegisterChannelDefaultCreds(builder);
RegisterXdsResolver(builder);
diff --git a/src/core/resolver/xds/xds_resolver.cc b/src/core/resolver/xds/xds_resolver.cc
index 9cb49098534..9013474cca7 100644
--- a/src/core/resolver/xds/xds_resolver.cc
+++ b/src/core/resolver/xds/xds_resolver.cc
@@ -510,7 +510,7 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
// Handle xDS HTTP filters.
const auto& hcm = absl::get(
resolver->current_config_->listener->listener);
- auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
+ auto result = XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
static_cast(resolver->xds_client_->bootstrap())
.http_filter_registry(),
hcm.http_filters, *resolver->current_config_->virtual_host, route,
@@ -1041,18 +1041,27 @@ XdsResolver::CreateServiceConfig() {
}
std::vector config_parts;
config_parts.push_back(
- "{\n"
- " \"loadBalancingConfig\":[\n"
- " { \"xds_cluster_manager_experimental\":{\n"
- " \"children\":{\n");
- config_parts.push_back(absl::StrJoin(clusters, ",\n"));
- config_parts.push_back(
- " }\n"
- " } }\n"
- " ]\n"
- "}");
- std::string json = absl::StrJoin(config_parts, "");
- return ServiceConfigImpl::Create(args_, json.c_str());
+ absl::StrCat(" \"loadBalancingConfig\":[\n"
+ " { \"xds_cluster_manager_experimental\":{\n"
+ " \"children\":{\n",
+ absl::StrJoin(clusters, ",\n"),
+ " }\n"
+ " } }\n"
+ " ]"));
+ auto& hcm = absl::get(
+ current_config_->listener->listener);
+ auto filter_configs =
+ XdsRouting::GeneratePerHTTPFilterConfigsForServiceConfig(
+ static_cast(xds_client_->bootstrap())
+ .http_filter_registry(),
+ hcm.http_filters, args_);
+ if (!filter_configs.ok()) return filter_configs.status();
+ for (const auto& p : filter_configs->per_filter_configs) {
+ config_parts.emplace_back(absl::StrCat(
+ " \"", p.first, "\": [\n", absl::StrJoin(p.second, ",\n"), "\n ]"));
+ }
+ std::string json = absl::StrCat("{", absl::StrJoin(config_parts, ",\n"), "}");
+ return ServiceConfigImpl::Create(filter_configs->args, json.c_str());
}
void XdsResolver::GenerateResult() {
diff --git a/src/core/server/xds_server_config_fetcher.cc b/src/core/server/xds_server_config_fetcher.cc
index 52a37031712..1bd258bd3d3 100644
--- a/src/core/server/xds_server_config_fetcher.cc
+++ b/src/core/server/xds_server_config_fetcher.cc
@@ -1176,7 +1176,7 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
config_selector_route.unsupported_action =
absl::get_if(
&route.action) == nullptr;
- auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
+ auto result = XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
http_filter_registry, http_filters, vhost, route, nullptr,
ChannelArgs());
if (!result.ok()) return result.status();
diff --git a/src/core/service_config/service_config_call_data.h b/src/core/service_config/service_config_call_data.h
index a376b751bdb..6d11caedab0 100644
--- a/src/core/service_config/service_config_call_data.h
+++ b/src/core/service_config/service_config_call_data.h
@@ -35,9 +35,8 @@
namespace grpc_core {
/// Stores the service config data associated with an individual call.
-/// A pointer to this object is stored in the call_context
-/// GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA element, so that filters can
-/// easily access method and global parameters for the call.
+/// A pointer to this object is stored in the call context, so that
+/// filters can easily access method and global parameters for the call.
///
/// Must be accessed when holding the call combiner (legacy filter) or from
/// inside the activity (promise-based filter).
diff --git a/src/core/util/http_client/httpcli.cc b/src/core/util/http_client/httpcli.cc
index 4220cb58b65..e28f9b8b758 100644
--- a/src/core/util/http_client/httpcli.cc
+++ b/src/core/util/http_client/httpcli.cc
@@ -70,14 +70,14 @@ OrphanablePtr HttpRequest::Get(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr channel_creds) {
- absl::optional> test_only_generate_response;
+ absl::optional> test_only_generate_response;
if (g_get_override != nullptr) {
test_only_generate_response = [request, uri, deadline, on_done,
response]() {
// Note that capturing request here assumes it will remain alive
// until after Start is called. This avoids making a copy as this
// code path is only used for test mocks.
- g_get_override(request, uri, deadline, on_done, response);
+ return g_get_override(request, uri, deadline, on_done, response);
};
}
std::string name =
@@ -95,13 +95,13 @@ OrphanablePtr HttpRequest::Post(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr channel_creds) {
- absl::optional> test_only_generate_response;
+ absl::optional> test_only_generate_response;
if (g_post_override != nullptr) {
test_only_generate_response = [request, uri, deadline, on_done,
response]() {
- g_post_override(request, uri,
- absl::string_view(request->body, request->body_length),
- deadline, on_done, response);
+ return g_post_override(
+ request, uri, absl::string_view(request->body, request->body_length),
+ deadline, on_done, response);
};
}
std::string name =
@@ -119,13 +119,13 @@ OrphanablePtr HttpRequest::Put(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr channel_creds) {
- absl::optional> test_only_generate_response;
+ absl::optional> test_only_generate_response;
if (g_put_override != nullptr) {
test_only_generate_response = [request, uri, deadline, on_done,
response]() {
- g_put_override(request, uri,
- absl::string_view(request->body, request->body_length),
- deadline, on_done, response);
+ return g_put_override(
+ request, uri, absl::string_view(request->body, request->body_length),
+ deadline, on_done, response);
};
}
std::string name =
@@ -155,7 +155,7 @@ HttpRequest::HttpRequest(
URI uri, const grpc_slice& request_text, grpc_http_response* response,
Timestamp deadline, const grpc_channel_args* channel_args,
grpc_closure* on_done, grpc_polling_entity* pollent, const char* name,
- absl::optional> test_only_generate_response,
+ absl::optional> test_only_generate_response,
RefCountedPtr channel_creds)
: uri_(std::move(uri)),
request_text_(request_text),
@@ -202,8 +202,7 @@ HttpRequest::~HttpRequest() {
void HttpRequest::Start() {
MutexLock lock(&mu_);
if (test_only_generate_response_.has_value()) {
- test_only_generate_response_.value()();
- return;
+ if (test_only_generate_response_.value()()) return;
}
Ref().release(); // ref held by pending DNS resolution
dns_request_handle_ = resolver_->LookupHostname(
diff --git a/src/core/util/http_client/httpcli.h b/src/core/util/http_client/httpcli.h
index dd676a5b1c9..c5939da61fa 100644
--- a/src/core/util/http_client/httpcli.h
+++ b/src/core/util/http_client/httpcli.h
@@ -165,7 +165,7 @@ class HttpRequest : public InternallyRefCounted {
grpc_http_response* response, Timestamp deadline,
const grpc_channel_args* channel_args, grpc_closure* on_done,
grpc_polling_entity* pollent, const char* name,
- absl::optional> test_only_generate_response,
+ absl::optional> test_only_generate_response,
RefCountedPtr channel_creds);
~HttpRequest() override;
@@ -250,7 +250,7 @@ class HttpRequest : public InternallyRefCounted {
ResourceQuotaRefPtr resource_quota_;
grpc_polling_entity* pollent_;
grpc_pollset_set* pollset_set_;
- const absl::optional> test_only_generate_response_;
+ const absl::optional> test_only_generate_response_;
Mutex mu_;
RefCountedPtr handshake_mgr_ ABSL_GUARDED_BY(mu_);
bool cancelled_ ABSL_GUARDED_BY(mu_) = false;
diff --git a/src/core/util/lru_cache.h b/src/core/util/lru_cache.h
new file mode 100644
index 00000000000..d0bf5934f4b
--- /dev/null
+++ b/src/core/util/lru_cache.h
@@ -0,0 +1,104 @@
+//
+// Copyright 2024 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_SRC_CORE_UTIL_LRU_CACHE_H
+#define GRPC_SRC_CORE_UTIL_LRU_CACHE_H
+
+#include
+#include
+#include
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/functional/any_invocable.h"
+#include "absl/log/check.h"
+#include "absl/types/optional.h"
+
+namespace grpc_core {
+
+// A simple LRU cache. Retains at most max_size entries.
+// Caller is responsible for synchronization.
+// TODO(roth): Support heterogenous lookups.
+template
+class LruCache {
+ public:
+ explicit LruCache(size_t max_size) : max_size_(max_size) {
+ CHECK_GT(max_size, 0UL);
+ }
+
+ // Returns the value for key, or nullopt if not present.
+ absl::optional Get(Key key);
+
+ // If key is present in the cache, returns the corresponding value.
+ // Otherwise, inserts a new entry in the map, calling create() to
+ // construct the new value. If inserting a new entry causes the cache
+ // to be too large, removes the least recently used entry.
+ Value GetOrInsert(Key key, absl::AnyInvocable create);
+
+ private:
+ struct CacheEntry {
+ Value value;
+ typename std::list::iterator lru_iterator;
+
+ explicit CacheEntry(Value v) : value(std::move(v)) {}
+ };
+
+ const size_t max_size_;
+ absl::flat_hash_map cache_;
+ std::list lru_list_;
+};
+
+//
+// implementation -- no user-serviceable parts below
+//
+
+template
+absl::optional LruCache::Get(Key key) {
+ auto it = cache_.find(key);
+ if (it == cache_.end()) return absl::nullopt;
+ // Found the entry. Move the entry to the end of the LRU list.
+ auto new_lru_it = lru_list_.insert(lru_list_.end(), *it->second.lru_iterator);
+ lru_list_.erase(it->second.lru_iterator);
+ it->second.lru_iterator = new_lru_it;
+ return it->second.value;
+}
+
+template
+Value LruCache::GetOrInsert(
+ Key key, absl::AnyInvocable create) {
+ auto value = Get(key);
+ if (value.has_value()) return std::move(*value);
+ // Entry not found. We'll need to insert a new entry.
+ // If the cache is at max size, remove the least recently used entry.
+ if (cache_.size() == max_size_) {
+ auto lru_it = lru_list_.begin();
+ CHECK(lru_it != lru_list_.end());
+ auto cache_it = cache_.find(*lru_it);
+ CHECK(cache_it != cache_.end());
+ cache_.erase(cache_it);
+ lru_list_.pop_front();
+ }
+ // Create a new entry, insert it, and return it.
+ auto it = cache_
+ .emplace(std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(create(key)))
+ .first;
+ it->second.lru_iterator = lru_list_.insert(lru_list_.end(), std::move(key));
+ return it->second.value;
+}
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_UTIL_LRU_CACHE_H
diff --git a/src/core/xds/grpc/xds_http_fault_filter.cc b/src/core/xds/grpc/xds_http_fault_filter.cc
index e46eeb79f1b..6bc74df8203 100644
--- a/src/core/xds/grpc/xds_http_fault_filter.cc
+++ b/src/core/xds/grpc/xds_http_fault_filter.cc
@@ -87,6 +87,7 @@ void XdsHttpFaultFilter::PopulateSymtab(upb_DefPool* symtab) const {
absl::optional
XdsHttpFaultFilter::GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -208,11 +209,13 @@ XdsHttpFaultFilter::GenerateFilterConfig(
absl::optional
XdsHttpFaultFilter::GenerateFilterConfigOverride(
+ absl::string_view instance_name,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
// HTTPFault filter has the same message type in HTTP connection manager's
// filter config and in overriding filter config field.
- return GenerateFilterConfig(context, std::move(extension), errors);
+ return GenerateFilterConfig(instance_name, context, std::move(extension),
+ errors);
}
void XdsHttpFaultFilter::AddFilter(InterceptionChainBuilder& builder) const {
@@ -229,7 +232,7 @@ ChannelArgs XdsHttpFaultFilter::ModifyChannelArgs(
}
absl::StatusOr
-XdsHttpFaultFilter::GenerateServiceConfig(
+XdsHttpFaultFilter::GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const {
Json policy_json = filter_config_override != nullptr
@@ -239,4 +242,10 @@ XdsHttpFaultFilter::GenerateServiceConfig(
return ServiceConfigJsonEntry{"faultInjectionPolicy", JsonDump(policy_json)};
}
+absl::StatusOr
+XdsHttpFaultFilter::GenerateServiceConfig(
+ const FilterConfig& /*hcm_filter_config*/) const {
+ return ServiceConfigJsonEntry{"", ""};
+}
+
} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_http_fault_filter.h b/src/core/xds/grpc/xds_http_fault_filter.h
index b99b1d30085..c269ff17f05 100644
--- a/src/core/xds/grpc/xds_http_fault_filter.h
+++ b/src/core/xds/grpc/xds_http_fault_filter.h
@@ -39,17 +39,21 @@ class XdsHttpFaultFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
- absl::StatusOr GenerateServiceConfig(
+ absl::StatusOr GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
+ absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return true; }
bool IsSupportedOnServers() const override { return false; }
};
diff --git a/src/core/xds/grpc/xds_http_filter.h b/src/core/xds/grpc/xds_http_filter.h
index 6e8c79d1284..8a9c54c6ef8 100644
--- a/src/core/xds/grpc/xds_http_filter.h
+++ b/src/core/xds/grpc/xds_http_filter.h
@@ -60,6 +60,7 @@ class XdsHttpFilterImpl {
// The value of this field in the method config will be a JSON array,
// which will be populated with the elements returned by each filter
// instance.
+ // Entry will be skipped if this field is empty.
std::string service_config_field_name;
// The element to add to the JSON array.
std::string element;
@@ -80,12 +81,14 @@ class XdsHttpFilterImpl {
// Generates a Config from the xDS filter config proto.
// Used for the top-level config in the HCM HTTP filter list.
virtual absl::optional GenerateFilterConfig(
+ absl::string_view instance_name,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const = 0;
// Generates a Config from the xDS filter config proto.
// Used for the typed_per_filter_config override in VirtualHost and Route.
virtual absl::optional GenerateFilterConfigOverride(
+ absl::string_view instance_name,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const = 0;
@@ -106,10 +109,17 @@ class XdsHttpFilterImpl {
// The filter_config_override comes from the first of the ClusterWeight,
// Route, or VirtualHost entries that it is found in, or null if
// there is no override in any of those locations.
- virtual absl::StatusOr GenerateServiceConfig(
+ virtual absl::StatusOr GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const = 0;
+ // Function to convert the Configs into a JSON string to be added to the
+ // top level of the service config.
+ // The hcm_filter_config comes from the HttpConnectionManager config.
+ // Currently used only on the client side.
+ virtual absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const = 0;
+
// Returns true if the filter is supported on clients; false otherwise
virtual bool IsSupportedOnClients() const = 0;
diff --git a/src/core/xds/grpc/xds_http_filter_registry.cc b/src/core/xds/grpc/xds_http_filter_registry.cc
index 9a6f18e226b..9decfded32d 100644
--- a/src/core/xds/grpc/xds_http_filter_registry.cc
+++ b/src/core/xds/grpc/xds_http_filter_registry.cc
@@ -29,8 +29,10 @@
#include "src/core/util/json/json.h"
#include "src/core/xds/grpc/xds_http_fault_filter.h"
+#include "src/core/xds/grpc/xds_http_gcp_authn_filter.h"
#include "src/core/xds/grpc/xds_http_rbac_filter.h"
#include "src/core/xds/grpc/xds_http_stateful_session_filter.h"
+#include "src/core/xds/grpc/xds_metadata_parser.h"
namespace grpc_core {
@@ -52,6 +54,7 @@ void XdsHttpRouterFilter::PopulateSymtab(upb_DefPool* symtab) const {
absl::optional
XdsHttpRouterFilter::GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -71,6 +74,7 @@ XdsHttpRouterFilter::GenerateFilterConfig(
absl::optional
XdsHttpRouterFilter::GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& /*context*/,
XdsExtension /*extension*/, ValidationErrors* errors) const {
errors->AddError("router filter does not support config override");
@@ -87,6 +91,9 @@ XdsHttpFilterRegistry::XdsHttpFilterRegistry(bool register_builtins) {
RegisterFilter(std::make_unique());
RegisterFilter(std::make_unique());
RegisterFilter(std::make_unique());
+ if (XdsGcpAuthFilterEnabled()) {
+ RegisterFilter(std::make_unique());
+ }
}
}
diff --git a/src/core/xds/grpc/xds_http_filter_registry.h b/src/core/xds/grpc/xds_http_filter_registry.h
index d25dc378b8b..37950d01f15 100644
--- a/src/core/xds/grpc/xds_http_filter_registry.h
+++ b/src/core/xds/grpc/xds_http_filter_registry.h
@@ -45,19 +45,26 @@ class XdsHttpRouterFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& /*builder*/) const override {}
const grpc_channel_filter* channel_filter() const override { return nullptr; }
- absl::StatusOr GenerateServiceConfig(
+ absl::StatusOr GenerateMethodConfig(
const FilterConfig& /*hcm_filter_config*/,
const FilterConfig* /*filter_config_override*/) const override {
// This will never be called, since channel_filter() returns null.
return absl::UnimplementedError("router filter should never be called");
}
+ absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& /*hcm_filter_config*/) const override {
+ // This will never be called, since channel_filter() returns null.
+ return absl::UnimplementedError("router filter should never be called");
+ }
bool IsSupportedOnClients() const override { return true; }
bool IsSupportedOnServers() const override { return true; }
bool IsTerminalFilter() const override { return true; }
diff --git a/src/core/xds/grpc/xds_http_gcp_authn_filter.cc b/src/core/xds/grpc/xds_http_gcp_authn_filter.cc
new file mode 100644
index 00000000000..3378284c9c2
--- /dev/null
+++ b/src/core/xds/grpc/xds_http_gcp_authn_filter.cc
@@ -0,0 +1,142 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/xds/grpc/xds_http_gcp_authn_filter.h"
+
+#include
+#include
+
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/variant.h"
+#include "envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.upb.h"
+#include "envoy/extensions/filters/http/gcp_authn/v3/gcp_authn.upbdefs.h"
+
+#include
+
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h"
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gprpp/validation_errors.h"
+#include "src/core/util/json/json.h"
+#include "src/core/util/json/json_writer.h"
+#include "src/core/xds/grpc/xds_common_types.h"
+#include "src/core/xds/grpc/xds_common_types_parser.h"
+#include "src/core/xds/grpc/xds_http_filter.h"
+
+namespace grpc_core {
+
+absl::string_view XdsHttpGcpAuthnFilter::ConfigProtoName() const {
+ return "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig";
+}
+
+absl::string_view XdsHttpGcpAuthnFilter::OverrideConfigProtoName() const {
+ return "";
+}
+
+void XdsHttpGcpAuthnFilter::PopulateSymtab(upb_DefPool* symtab) const {
+ envoy_extensions_filters_http_gcp_authn_v3_GcpAuthnFilterConfig_getmsgdef(
+ symtab);
+}
+
+namespace {
+
+Json::Object ValidateFilterConfig(
+ absl::string_view instance_name,
+ const envoy_extensions_filters_http_gcp_authn_v3_GcpAuthnFilterConfig*
+ gcp_auth,
+ ValidationErrors* errors) {
+ Json::Object config = {
+ {"filter_instance_name", Json::FromString(std::string(instance_name))}};
+ const auto* cache_config =
+ envoy_extensions_filters_http_gcp_authn_v3_GcpAuthnFilterConfig_cache_config(
+ gcp_auth);
+ if (cache_config == nullptr) return config;
+ uint64_t cache_size =
+ ParseUInt64Value(
+ envoy_extensions_filters_http_gcp_authn_v3_TokenCacheConfig_cache_size(
+ cache_config))
+ .value_or(10);
+ if (cache_size == 0 || cache_size >= INT64_MAX) {
+ ValidationErrors::ScopedField field(errors, ".cache_config.cache_size");
+ errors->AddError("must be in the range (0, INT64_MAX)");
+ }
+ config["cache_size"] = Json::FromNumber(cache_size);
+ return config;
+}
+
+} // namespace
+
+absl::optional
+XdsHttpGcpAuthnFilter::GenerateFilterConfig(
+ absl::string_view instance_name,
+ const XdsResourceType::DecodeContext& context, XdsExtension extension,
+ ValidationErrors* errors) const {
+ absl::string_view* serialized_filter_config =
+ absl::get_if(&extension.value);
+ if (serialized_filter_config == nullptr) {
+ errors->AddError("could not parse GCP auth filter config");
+ return absl::nullopt;
+ }
+ auto* gcp_auth =
+ envoy_extensions_filters_http_gcp_authn_v3_GcpAuthnFilterConfig_parse(
+ serialized_filter_config->data(), serialized_filter_config->size(),
+ context.arena);
+ if (gcp_auth == nullptr) {
+ errors->AddError("could not parse GCP auth filter config");
+ return absl::nullopt;
+ }
+ return FilterConfig{ConfigProtoName(), Json::FromObject(ValidateFilterConfig(
+ instance_name, gcp_auth, errors))};
+}
+
+absl::optional
+XdsHttpGcpAuthnFilter::GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
+ const XdsResourceType::DecodeContext& /*context*/,
+ XdsExtension /*extension*/, ValidationErrors* errors) const {
+ errors->AddError("GCP auth filter does not support config override");
+ return absl::nullopt;
+}
+
+void XdsHttpGcpAuthnFilter::AddFilter(InterceptionChainBuilder& builder) const {
+ builder.Add();
+}
+
+const grpc_channel_filter* XdsHttpGcpAuthnFilter::channel_filter() const {
+ return &GcpAuthenticationFilter::kFilter;
+}
+
+ChannelArgs XdsHttpGcpAuthnFilter::ModifyChannelArgs(
+ const ChannelArgs& args) const {
+ return args.Set(GRPC_ARG_PARSE_GCP_AUTHENTICATION_METHOD_CONFIG, 1);
+}
+
+absl::StatusOr
+XdsHttpGcpAuthnFilter::GenerateMethodConfig(
+ const FilterConfig& /*hcm_filter_config*/,
+ const FilterConfig* /*filter_config_override*/) const {
+ return ServiceConfigJsonEntry{"", ""};
+}
+
+absl::StatusOr
+XdsHttpGcpAuthnFilter::GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const {
+ return ServiceConfigJsonEntry{"gcp_authentication",
+ JsonDump(hcm_filter_config.config)};
+}
+
+} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_http_gcp_authn_filter.h b/src/core/xds/grpc/xds_http_gcp_authn_filter.h
new file mode 100644
index 00000000000..662e2c456a7
--- /dev/null
+++ b/src/core/xds/grpc/xds_http_gcp_authn_filter.h
@@ -0,0 +1,61 @@
+//
+// Copyright 2024 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_SRC_CORE_XDS_GRPC_XDS_HTTP_GCP_AUTHN_FILTER_H
+#define GRPC_SRC_CORE_XDS_GRPC_XDS_HTTP_GCP_AUTHN_FILTER_H
+
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "upb/reflection/def.h"
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/channel_fwd.h"
+#include "src/core/lib/gprpp/validation_errors.h"
+#include "src/core/xds/grpc/xds_common_types.h"
+#include "src/core/xds/grpc/xds_http_filter.h"
+#include "src/core/xds/xds_client/xds_resource_type.h"
+
+namespace grpc_core {
+
+class XdsHttpGcpAuthnFilter final : public XdsHttpFilterImpl {
+ public:
+ absl::string_view ConfigProtoName() const override;
+ absl::string_view OverrideConfigProtoName() const override;
+ void PopulateSymtab(upb_DefPool* symtab) const override;
+ absl::optional GenerateFilterConfig(
+ absl::string_view instance_name,
+ const XdsResourceType::DecodeContext& context, XdsExtension extension,
+ ValidationErrors* errors) const override;
+ absl::optional GenerateFilterConfigOverride(
+ absl::string_view instance_name,
+ const XdsResourceType::DecodeContext& context, XdsExtension extension,
+ ValidationErrors* errors) const override;
+ void AddFilter(InterceptionChainBuilder& builder) const override;
+ const grpc_channel_filter* channel_filter() const override;
+ ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
+ absl::StatusOr GenerateMethodConfig(
+ const FilterConfig& hcm_filter_config,
+ const FilterConfig* filter_config_override) const override;
+ absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const override;
+ bool IsSupportedOnClients() const override { return true; }
+ bool IsSupportedOnServers() const override { return false; }
+};
+
+} // namespace grpc_core
+
+#endif // GRPC_SRC_CORE_XDS_GRPC_XDS_HTTP_GCP_AUTHN_FILTER_H
diff --git a/src/core/xds/grpc/xds_http_rbac_filter.cc b/src/core/xds/grpc/xds_http_rbac_filter.cc
index 64a793abad7..4508ae41b9b 100644
--- a/src/core/xds/grpc/xds_http_rbac_filter.cc
+++ b/src/core/xds/grpc/xds_http_rbac_filter.cc
@@ -515,6 +515,7 @@ void XdsHttpRbacFilter::PopulateSymtab(upb_DefPool* symtab) const {
absl::optional
XdsHttpRbacFilter::GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -536,6 +537,7 @@ XdsHttpRbacFilter::GenerateFilterConfig(
absl::optional
XdsHttpRbacFilter::GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -578,7 +580,7 @@ ChannelArgs XdsHttpRbacFilter::ModifyChannelArgs(
}
absl::StatusOr
-XdsHttpRbacFilter::GenerateServiceConfig(
+XdsHttpRbacFilter::GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const {
const Json& policy_json = filter_config_override != nullptr
@@ -588,4 +590,10 @@ XdsHttpRbacFilter::GenerateServiceConfig(
return ServiceConfigJsonEntry{"rbacPolicy", JsonDump(policy_json)};
}
+absl::StatusOr
+XdsHttpRbacFilter::GenerateServiceConfig(
+ const FilterConfig& /*hcm_filter_config*/) const {
+ return ServiceConfigJsonEntry{"", ""};
+}
+
} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_http_rbac_filter.h b/src/core/xds/grpc/xds_http_rbac_filter.h
index 8aac5bf1d63..c7550575b72 100644
--- a/src/core/xds/grpc/xds_http_rbac_filter.h
+++ b/src/core/xds/grpc/xds_http_rbac_filter.h
@@ -39,17 +39,21 @@ class XdsHttpRbacFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
- absl::StatusOr GenerateServiceConfig(
+ absl::StatusOr GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
+ absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return false; }
bool IsSupportedOnServers() const override { return true; }
};
diff --git a/src/core/xds/grpc/xds_http_stateful_session_filter.cc b/src/core/xds/grpc/xds_http_stateful_session_filter.cc
index dd239bc0094..8216d51ad06 100644
--- a/src/core/xds/grpc/xds_http_stateful_session_filter.cc
+++ b/src/core/xds/grpc/xds_http_stateful_session_filter.cc
@@ -141,6 +141,7 @@ Json::Object ValidateStatefulSession(
absl::optional
XdsHttpStatefulSessionFilter::GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -164,6 +165,7 @@ XdsHttpStatefulSessionFilter::GenerateFilterConfig(
absl::optional
XdsHttpStatefulSessionFilter::GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const {
absl::string_view* serialized_filter_config =
@@ -211,7 +213,7 @@ ChannelArgs XdsHttpStatefulSessionFilter::ModifyChannelArgs(
}
absl::StatusOr
-XdsHttpStatefulSessionFilter::GenerateServiceConfig(
+XdsHttpStatefulSessionFilter::GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const {
const Json& config = filter_config_override != nullptr
@@ -220,4 +222,10 @@ XdsHttpStatefulSessionFilter::GenerateServiceConfig(
return ServiceConfigJsonEntry{"stateful_session", JsonDump(config)};
}
+absl::StatusOr
+XdsHttpStatefulSessionFilter::GenerateServiceConfig(
+ const FilterConfig& /*hcm_filter_config*/) const {
+ return ServiceConfigJsonEntry{"", ""};
+}
+
} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_http_stateful_session_filter.h b/src/core/xds/grpc/xds_http_stateful_session_filter.h
index fb3ce72b59f..28df742b6c2 100644
--- a/src/core/xds/grpc/xds_http_stateful_session_filter.h
+++ b/src/core/xds/grpc/xds_http_stateful_session_filter.h
@@ -39,17 +39,21 @@ class XdsHttpStatefulSessionFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional GenerateFilterConfig(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional GenerateFilterConfigOverride(
+ absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
- absl::StatusOr GenerateServiceConfig(
+ absl::StatusOr GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
+ absl::StatusOr GenerateServiceConfig(
+ const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return true; }
bool IsSupportedOnServers() const override { return false; }
};
diff --git a/src/core/xds/grpc/xds_listener_parser.cc b/src/core/xds/grpc/xds_listener_parser.cc
index b536472a80f..e16efa43fae 100644
--- a/src/core/xds/grpc/xds_listener_parser.cc
+++ b/src/core/xds/grpc/xds_listener_parser.cc
@@ -268,8 +268,8 @@ XdsListenerResource::HttpConnectionManager HttpConnectionManagerParse(
continue;
}
absl::optional filter_config =
- filter_impl->GenerateFilterConfig(context, std::move(*extension),
- errors);
+ filter_impl->GenerateFilterConfig(name, context,
+ std::move(*extension), errors);
if (filter_config.has_value()) {
http_connection_manager.http_filters.emplace_back(
XdsListenerResource::HttpConnectionManager::HttpFilter{
diff --git a/src/core/xds/grpc/xds_route_config_parser.cc b/src/core/xds/grpc/xds_route_config_parser.cc
index d6ac0f858a7..d23f162456a 100644
--- a/src/core/xds/grpc/xds_route_config_parser.cc
+++ b/src/core/xds/grpc/xds_route_config_parser.cc
@@ -441,7 +441,7 @@ XdsRouteConfigResource::TypedPerFilterConfig ParseTypedPerFilterConfig(
}
absl::optional filter_config =
filter_impl->GenerateFilterConfigOverride(
- context, std::move(*extension_to_use), errors);
+ key, context, std::move(*extension_to_use), errors);
if (filter_config.has_value()) {
typed_per_filter_config[std::string(key)] = std::move(*filter_config);
}
diff --git a/src/core/xds/grpc/xds_routing.cc b/src/core/xds/grpc/xds_routing.cc
index 83c9d620e48..2a3a29088d8 100644
--- a/src/core/xds/grpc/xds_routing.cc
+++ b/src/core/xds/grpc/xds_routing.cc
@@ -215,23 +215,21 @@ const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
return nullptr;
}
-} // namespace
-
absl::StatusOr
-XdsRouting::GeneratePerHTTPFilterConfigs(
+GeneratePerHTTPFilterConfigs(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector&
http_filters,
- const XdsRouteConfigResource::VirtualHost& vhost,
- const XdsRouteConfigResource::Route& route,
- const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
- cluster_weight,
- const ChannelArgs& args) {
- GeneratePerHttpFilterConfigsResult result;
+ const ChannelArgs& args,
+ absl::FunctionRef(
+ const XdsHttpFilterImpl&,
+ const XdsListenerResource::HttpConnectionManager::HttpFilter&)>
+ generate_service_config) {
+ XdsRouting::GeneratePerHttpFilterConfigsResult result;
result.args = args;
for (const auto& http_filter : http_filters) {
// Find filter. This is guaranteed to succeed, because it's checked
- // at config validation time in the XdsApi code.
+ // at config validation time in the listener parsing code.
const XdsHttpFilterImpl* filter_impl =
http_filter_registry.GetFilterForType(
http_filter.config.config_proto_type_name);
@@ -242,22 +240,60 @@ XdsRouting::GeneratePerHTTPFilterConfigs(
// Allow filter to add channel args that may affect service config
// parsing.
result.args = filter_impl->ModifyChannelArgs(result.args);
- // Find config override, if any.
- const XdsHttpFilterImpl::FilterConfig* config_override =
- FindFilterConfigOverride(http_filter.name, vhost, route,
- cluster_weight);
// Generate service config for filter.
- auto method_config_field =
- filter_impl->GenerateServiceConfig(http_filter.config, config_override);
- if (!method_config_field.ok()) {
+ auto service_config_field =
+ generate_service_config(*filter_impl, http_filter);
+ if (!service_config_field.ok()) {
return absl::FailedPreconditionError(absl::StrCat(
- "failed to generate method config for HTTP filter ", http_filter.name,
- ": ", method_config_field.status().ToString()));
+ "failed to generate service config for HTTP filter ",
+ http_filter.name, ": ", service_config_field.status().ToString()));
}
- result.per_filter_configs[method_config_field->service_config_field_name]
- .push_back(method_config_field->element);
+ if (service_config_field->service_config_field_name.empty()) continue;
+ result.per_filter_configs[service_config_field->service_config_field_name]
+ .push_back(service_config_field->element);
}
return result;
}
+} // namespace
+
+absl::StatusOr
+XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
+ const XdsHttpFilterRegistry& http_filter_registry,
+ const std::vector&
+ http_filters,
+ const XdsRouteConfigResource::VirtualHost& vhost,
+ const XdsRouteConfigResource::Route& route,
+ const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
+ cluster_weight,
+ const ChannelArgs& args) {
+ return GeneratePerHTTPFilterConfigs(
+ http_filter_registry, http_filters, args,
+ [&](const XdsHttpFilterImpl& filter_impl,
+ const XdsListenerResource::HttpConnectionManager::HttpFilter&
+ http_filter) {
+ const XdsHttpFilterImpl::FilterConfig* config_override =
+ FindFilterConfigOverride(http_filter.name, vhost, route,
+ cluster_weight);
+ // Generate service config for filter.
+ return filter_impl.GenerateMethodConfig(http_filter.config,
+ config_override);
+ });
+}
+
+absl::StatusOr
+XdsRouting::GeneratePerHTTPFilterConfigsForServiceConfig(
+ const XdsHttpFilterRegistry& http_filter_registry,
+ const std::vector&
+ http_filters,
+ const ChannelArgs& args) {
+ return GeneratePerHTTPFilterConfigs(
+ http_filter_registry, http_filters, args,
+ [&](const XdsHttpFilterImpl& filter_impl,
+ const XdsListenerResource::HttpConnectionManager::HttpFilter&
+ http_filter) {
+ return filter_impl.GenerateServiceConfig(http_filter.config);
+ });
+}
+
} // namespace grpc_core
diff --git a/src/core/xds/grpc/xds_routing.h b/src/core/xds/grpc/xds_routing.h
index 1d4966961d1..696599d8463 100644
--- a/src/core/xds/grpc/xds_routing.h
+++ b/src/core/xds/grpc/xds_routing.h
@@ -88,9 +88,9 @@ class XdsRouting final {
ChannelArgs args;
};
- // Generates a map of per_filter_configs. \a args is consumed.
+ // Generates per-HTTP filter configs for a method config.
static absl::StatusOr
- GeneratePerHTTPFilterConfigs(
+ GeneratePerHTTPFilterConfigsForMethodConfig(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector&
http_filters,
@@ -99,6 +99,14 @@ class XdsRouting final {
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight*
cluster_weight,
const ChannelArgs& args);
+
+ // Generates per-HTTP filter configs for the top-level service config.
+ static absl::StatusOr
+ GeneratePerHTTPFilterConfigsForServiceConfig(
+ const XdsHttpFilterRegistry& http_filter_registry,
+ const std::vector&
+ http_filters,
+ const ChannelArgs& args);
};
} // namespace grpc_core
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index c27a3690636..08aadfbab32 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -43,6 +43,8 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/channel_idle/legacy_channel_idle_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc',
+ 'src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc',
'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc',
@@ -627,6 +629,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/external/file_external_account_credentials.cc',
'src/core/lib/security/credentials/external/url_external_account_credentials.cc',
'src/core/lib/security/credentials/fake/fake_credentials.cc',
+ 'src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc',
'src/core/lib/security/credentials/google_default/credentials_generic.cc',
'src/core/lib/security/credentials/google_default/google_default_credentials.cc',
'src/core/lib/security/credentials/iam/iam_credentials.cc',
@@ -848,6 +851,7 @@ CORE_SOURCE_FILES = [
'src/core/xds/grpc/xds_health_status.cc',
'src/core/xds/grpc/xds_http_fault_filter.cc',
'src/core/xds/grpc/xds_http_filter_registry.cc',
+ 'src/core/xds/grpc/xds_http_gcp_authn_filter.cc',
'src/core/xds/grpc/xds_http_rbac_filter.cc',
'src/core/xds/grpc/xds_http_stateful_session_filter.cc',
'src/core/xds/grpc/xds_lb_policy_registry.cc',
diff --git a/test/core/filters/BUILD b/test/core/filters/BUILD
index 33a7c41ea6e..c14d98de853 100644
--- a/test/core/filters/BUILD
+++ b/test/core/filters/BUILD
@@ -120,6 +120,27 @@ grpc_cc_test(
],
)
+grpc_cc_test(
+ name = "gcp_authentication_filter_test",
+ srcs = ["gcp_authentication_filter_test.cc"],
+ external_deps = [
+ "absl/status",
+ "absl/status:statusor",
+ "absl/strings",
+ "gtest",
+ ],
+ language = "c++",
+ uses_event_engine = False,
+ uses_polling = False,
+ deps = [
+ "filter_test",
+ "//:grpc",
+ "//:grpc_security_base",
+ "//:ref_counted_ptr",
+ "//src/core:channel_args",
+ ],
+)
+
grpc_cc_benchmark(
name = "bm_http_client_filter",
srcs = ["bm_http_client_filter.cc"],
diff --git a/test/core/filters/filter_test.cc b/test/core/filters/filter_test.cc
index 1c5151ee5d0..694c26350b9 100644
--- a/test/core/filters/filter_test.cc
+++ b/test/core/filters/filter_test.cc
@@ -56,7 +56,7 @@ class FilterTestBase::Call::Impl
: call_(call), channel_(std::move(channel)) {}
~Impl();
- Arena* arena() { return arena_.get(); }
+ Arena* arena() const { return arena_.get(); }
const std::shared_ptr& channel() const { return channel_; }
CallFinalization* call_finalization() { return &call_finalization_; }
@@ -336,7 +336,7 @@ FilterTestBase::Call::Call(const Channel& channel)
FilterTestBase::Call::~Call() { ScopedContext x(std::move(impl_)); }
-Arena* FilterTestBase::Call::arena() { return impl_->arena(); }
+Arena* FilterTestBase::Call::arena() const { return impl_->arena(); }
ClientMetadataHandle FilterTestBase::Call::NewClientMetadata(
std::initializer_list>
diff --git a/test/core/filters/filter_test.h b/test/core/filters/filter_test.h
index f48890f2a58..e905b84c8c6 100644
--- a/test/core/filters/filter_test.h
+++ b/test/core/filters/filter_test.h
@@ -163,7 +163,7 @@ class FilterTestBase : public ::testing::Test {
// metadata.
void FinishNextFilter(ServerMetadataHandle md);
- Arena* arena();
+ Arena* arena() const;
private:
friend class Channel;
@@ -222,7 +222,7 @@ class FilterTest : public FilterTestBase {
};
absl::StatusOr MakeChannel(const ChannelArgs& args) {
- auto filter = Filter::Create(args, ChannelFilter::Args());
+ auto filter = Filter::Create(args, ChannelFilter::Args(/*instance_id=*/0));
if (!filter.ok()) return filter.status();
return Channel(std::move(*filter), this);
}
diff --git a/test/core/filters/gcp_authentication_filter_test.cc b/test/core/filters/gcp_authentication_filter_test.cc
new file mode 100644
index 00000000000..4c677df2b45
--- /dev/null
+++ b/test/core/filters/gcp_authentication_filter_test.cc
@@ -0,0 +1,386 @@
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h"
+
+#include
+#include
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/promise_based_filter.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/unique_type_name.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h"
+#include "src/core/resolver/xds/xds_config.h"
+#include "src/core/resolver/xds/xds_resolver_attributes.h"
+#include "src/core/service_config/service_config_call_data.h"
+#include "src/core/service_config/service_config_impl.h"
+#include "test/core/filters/filter_test.h"
+
+namespace grpc_core {
+namespace {
+
+class GcpAuthenticationFilterTest : public FilterTest {
+ protected:
+ static RefCountedPtr MakeServiceConfig(
+ absl::string_view service_config_json) {
+ auto service_config = ServiceConfigImpl::Create(
+ ChannelArgs().Set(GRPC_ARG_PARSE_GCP_AUTHENTICATION_METHOD_CONFIG,
+ true),
+ service_config_json);
+ CHECK(service_config.ok()) << service_config.status();
+ return *service_config;
+ }
+
+ static RefCountedPtr MakeXdsConfig(
+ absl::string_view cluster, absl::string_view filter_instance_name,
+ std::unique_ptr audience_metadata) {
+ auto xds_config = MakeRefCounted();
+ if (!cluster.empty()) {
+ auto cluster_resource = std::make_shared();
+ if (audience_metadata != nullptr) {
+ cluster_resource->metadata.Insert(filter_instance_name,
+ std::move(audience_metadata));
+ }
+ xds_config->clusters[cluster].emplace(std::move(cluster_resource),
+ nullptr, "");
+ }
+ return xds_config;
+ }
+
+ static RefCountedPtr MakeXdsConfigWithCluster(
+ absl::string_view cluster,
+ absl::StatusOr cluster_config) {
+ auto xds_config = MakeRefCounted();
+ xds_config->clusters[cluster] = std::move(cluster_config);
+ return xds_config;
+ }
+
+ ChannelArgs MakeChannelArgs(
+ absl::string_view service_config_json, absl::string_view cluster,
+ absl::string_view filter_instance_name,
+ std::unique_ptr audience_metadata) {
+ auto service_config = MakeServiceConfig(service_config_json);
+ auto xds_config = MakeXdsConfig(cluster, filter_instance_name,
+ std::move(audience_metadata));
+ return ChannelArgs()
+ .SetObject(std::move(service_config))
+ .SetObject(std::move(xds_config));
+ }
+
+ static RefCountedPtr GetCallCreds(const Call& call) {
+ auto* security_ctx = DownCast(
+ call.arena()->GetContext());
+ if (security_ctx == nullptr) return nullptr;
+ return security_ctx->creds;
+ }
+};
+
+TEST_F(GcpAuthenticationFilterTest, CreateSucceeds) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args = MakeChannelArgs(kServiceConfigJson, kClusterName,
+ kFilterInstanceName, nullptr);
+ auto filter = GcpAuthenticationFilter::Create(
+ channel_args, ChannelFilter::Args(/*instance_id=*/0));
+ EXPECT_TRUE(filter.ok()) << filter.status();
+}
+
+TEST_F(GcpAuthenticationFilterTest, CreateFailsWithoutServiceConfig) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ auto channel_args = ChannelArgs().SetObject(
+ MakeXdsConfig(kClusterName, kFilterInstanceName, nullptr));
+ auto filter = GcpAuthenticationFilter::Create(
+ channel_args, ChannelFilter::Args(/*instance_id=*/0));
+ EXPECT_EQ(filter.status(),
+ absl::InvalidArgumentError(
+ "gcp_auth: no service config in channel args"));
+}
+
+TEST_F(GcpAuthenticationFilterTest,
+ CreateFailsFilterConfigMissingFromServiceConfig) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson = "{}";
+ auto channel_args = MakeChannelArgs(kServiceConfigJson, kClusterName,
+ kFilterInstanceName, nullptr);
+ auto filter = GcpAuthenticationFilter::Create(
+ channel_args, ChannelFilter::Args(/*instance_id=*/0));
+ EXPECT_EQ(filter.status(),
+ absl::InvalidArgumentError(
+ "gcp_auth: filter instance ID not found in filter config"));
+}
+
+TEST_F(GcpAuthenticationFilterTest, CreateFailsXdsConfigNotFoundInChannelArgs) {
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args =
+ ChannelArgs().SetObject(MakeServiceConfig(kServiceConfigJson));
+ auto filter = GcpAuthenticationFilter::Create(
+ channel_args, ChannelFilter::Args(/*instance_id=*/0));
+ EXPECT_EQ(filter.status(),
+ absl::InvalidArgumentError(
+ "gcp_auth: xds config not found in channel args"));
+}
+
+TEST_F(GcpAuthenticationFilterTest, FailsCallIfNoXdsClusterAttribute) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args = MakeChannelArgs(kServiceConfigJson, kClusterName,
+ kFilterInstanceName, nullptr);
+ Call call(MakeChannel(channel_args).value());
+ call.arena()->New(call.arena());
+ call.Start(call.NewClientMetadata());
+ EXPECT_EVENT(Finished(
+ &call,
+ HasMetadataResult(absl::InternalError(
+ "GCP authentication filter: call has no xDS cluster attribute"))));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, NoOpIfClusterAttributeHasWrongPrefix) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ constexpr absl::string_view kAudience = "bar";
+ auto channel_args = MakeChannelArgs(
+ kServiceConfigJson, kClusterName, kFilterInstanceName,
+ std::make_unique(kAudience));
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ XdsClusterAttribute xds_cluster_attribute(kClusterName);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ EXPECT_EVENT(Started(&call, ::testing::_));
+ call.Start(call.NewClientMetadata());
+ call.FinishNextFilter(call.NewServerMetadata({{"grpc-status", "0"}}));
+ EXPECT_EVENT(Finished(&call, HasMetadataResult(absl::OkStatus())));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, FailsCallIfClusterNotPresentInXdsConfig) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args = MakeChannelArgs(kServiceConfigJson, /*cluster=*/"",
+ /*filter_instance_name=*/"", nullptr);
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ call.Start(call.NewClientMetadata());
+ EXPECT_EVENT(
+ Finished(&call, HasMetadataResult(absl::InternalError(absl::StrCat(
+ "GCP authentication filter: xDS cluster ",
+ kClusterName, " not found in XdsConfig")))));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, FailsCallIfClusterNotOkayInXdsConfig) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args = ChannelArgs()
+ .SetObject(MakeServiceConfig(kServiceConfigJson))
+ .SetObject(MakeXdsConfigWithCluster(
+ kClusterName, absl::UnavailableError("nope")));
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ call.Start(call.NewClientMetadata());
+ EXPECT_EVENT(Finished(
+ &call, HasMetadataResult(absl::UnavailableError(absl::StrCat(
+ "GCP authentication filter: CDS resource unavailable for ",
+ kClusterName)))));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest,
+ FailsCallIfClusterResourceMissingInXdsConfig) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args =
+ ChannelArgs()
+ .SetObject(MakeServiceConfig(kServiceConfigJson))
+ .SetObject(MakeXdsConfigWithCluster(
+ kClusterName, XdsConfig::ClusterConfig(nullptr, nullptr, "")));
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ call.Start(call.NewClientMetadata());
+ EXPECT_EVENT(Finished(
+ &call,
+ HasMetadataResult(absl::InternalError(absl::StrCat(
+ "GCP authentication filter: CDS resource not present for cluster ",
+ kClusterName)))));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, NoOpIfClusterHasNoAudience) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args = MakeChannelArgs(kServiceConfigJson, kClusterName,
+ kFilterInstanceName, nullptr);
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ EXPECT_EVENT(Started(&call, ::testing::_));
+ call.Start(call.NewClientMetadata());
+ call.FinishNextFilter(call.NewServerMetadata({{"grpc-status", "0"}}));
+ EXPECT_EVENT(Finished(&call, HasMetadataResult(absl::OkStatus())));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, FailsCallIfAudienceMetadataWrongType) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ auto channel_args =
+ MakeChannelArgs(kServiceConfigJson, kClusterName, kFilterInstanceName,
+ std::make_unique(Json()));
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ call.Start(call.NewClientMetadata());
+ EXPECT_EVENT(Finished(
+ &call, HasMetadataResult(absl::UnavailableError(absl::StrCat(
+ "GCP authentication filter: audience metadata in wrong format "
+ "for cluster ",
+ kClusterName)))));
+ Step();
+ // Call creds were not set.
+ EXPECT_EQ(GetCallCreds(call), nullptr);
+}
+
+TEST_F(GcpAuthenticationFilterTest, SetsCallCredsIfClusterHasAudience) {
+ constexpr absl::string_view kClusterName = "foo";
+ constexpr absl::string_view kFilterInstanceName = "gcp_authn_filter";
+ constexpr absl::string_view kServiceConfigJson =
+ "{\n"
+ " \"gcp_authentication\": [\n"
+ " {\"filter_instance_name\": \"gcp_authn_filter\"}\n"
+ " ]\n"
+ "}";
+ constexpr absl::string_view kAudience = "bar";
+ auto channel_args = MakeChannelArgs(
+ kServiceConfigJson, kClusterName, kFilterInstanceName,
+ std::make_unique(kAudience));
+ Call call(MakeChannel(channel_args).value());
+ auto* service_config_call_data =
+ call.arena()->New(call.arena());
+ std::string cluster_name_with_prefix = absl::StrCat("cluster:", kClusterName);
+ XdsClusterAttribute xds_cluster_attribute(cluster_name_with_prefix);
+ service_config_call_data->SetCallAttribute(&xds_cluster_attribute);
+ EXPECT_EVENT(Started(&call, ::testing::_));
+ call.Start(call.NewClientMetadata());
+ call.FinishNextFilter(call.NewServerMetadata({{"grpc-status", "0"}}));
+ EXPECT_EVENT(Finished(&call, HasMetadataResult(absl::OkStatus())));
+ Step();
+ // Call creds were set with the right audience.
+ auto call_creds = GetCallCreds(call);
+ ASSERT_NE(call_creds, nullptr);
+ EXPECT_EQ(call_creds->type(),
+ GcpServiceAccountIdentityCallCredentials::Type());
+ EXPECT_EQ(call_creds->debug_string(),
+ absl::StrCat("GcpServiceAccountIdentityCallCredentials(", kAudience,
+ ")"));
+}
+
+} // namespace
+} // namespace grpc_core
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 41f7fc72549..869a9b96672 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -150,3 +150,15 @@ grpc_cc_test(
"//src/core:ring_buffer",
],
)
+
+grpc_cc_test(
+ name = "lru_cache_test",
+ srcs = ["lru_cache_test.cc"],
+ external_deps = ["gtest"],
+ language = "C++",
+ uses_event_engine = False,
+ uses_polling = False,
+ deps = [
+ "//src/core:lru_cache",
+ ],
+)
diff --git a/test/core/util/lru_cache_test.cc b/test/core/util/lru_cache_test.cc
new file mode 100644
index 00000000000..fbb9ce1f37f
--- /dev/null
+++ b/test/core/util/lru_cache_test.cc
@@ -0,0 +1,74 @@
+//
+// Copyright 2024 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/util/lru_cache.h"
+
+#include "absl/log/check.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace grpc_core {
+
+TEST(LruCache, Basic) {
+ std::vector created_list;
+ auto create = [&](const std::string& key) {
+ int value;
+ CHECK(absl::SimpleAtoi(key, &value));
+ created_list.push_back(value);
+ return value;
+ };
+ // Create a cache with max size 5.
+ LruCache cache(5);
+ // Insert 5 values.
+ const std::array kOrder = {3, 1, 2, 0, 4};
+ for (int i : kOrder) {
+ std::string key = absl::StrCat(i);
+ EXPECT_EQ(absl::nullopt, cache.Get(key));
+ EXPECT_EQ(i, cache.GetOrInsert(key, create));
+ EXPECT_EQ(i, cache.Get(key));
+ }
+ EXPECT_THAT(created_list, ::testing::ElementsAreArray(kOrder));
+ created_list.clear();
+ // Get those same 5 values. This should not trigger any more insertions.
+ for (int i : kOrder) {
+ std::string key = absl::StrCat(i);
+ EXPECT_EQ(i, cache.GetOrInsert(key, create));
+ }
+ EXPECT_THAT(created_list, ::testing::ElementsAre());
+ // Now insert new elements.
+ // Each insertion should remove the least recently used element.
+ const std::array kOrder2 = {7, 6, 8, 5, 9};
+ for (size_t i = 0; i < kOrder2.size(); ++i) {
+ int value2 = kOrder2[i];
+ std::string key2 = absl::StrCat(value2);
+ EXPECT_EQ(absl::nullopt, cache.Get(key2));
+ EXPECT_EQ(value2, cache.GetOrInsert(key2, create));
+ EXPECT_EQ(value2, cache.Get(key2));
+ int value1 = kOrder[i];
+ std::string key1 = absl::StrCat(value1);
+ EXPECT_EQ(absl::nullopt, cache.Get(key1));
+ }
+ EXPECT_THAT(created_list, ::testing::ElementsAreArray(kOrder2));
+}
+
+} // namespace grpc_core
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/core/xds/BUILD b/test/core/xds/BUILD
index f91ac8e1009..85652f14e99 100644
--- a/test/core/xds/BUILD
+++ b/test/core/xds/BUILD
@@ -262,6 +262,7 @@ grpc_cc_test(
"//:gpr",
"//:grpc",
"//src/proto/grpc/testing/xds/v3:fault_proto",
+ "//src/proto/grpc/testing/xds/v3:gcp_authn_proto",
"//src/proto/grpc/testing/xds/v3:http_filter_rbac_proto",
"//src/proto/grpc/testing/xds/v3:router_proto",
"//src/proto/grpc/testing/xds/v3:stateful_session_cookie_proto",
diff --git a/test/core/xds/xds_http_filters_test.cc b/test/core/xds/xds_http_filters_test.cc
index d57d5f5650c..f1811d7c6ad 100644
--- a/test/core/xds/xds_http_filters_test.cc
+++ b/test/core/xds/xds_http_filters_test.cc
@@ -38,6 +38,8 @@
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
#include "src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h"
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h"
+#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
#include "src/core/ext/filters/rbac/rbac_filter.h"
#include "src/core/ext/filters/rbac/rbac_service_config_parser.h"
#include "src/core/ext/filters/stateful_session/stateful_session_filter.h"
@@ -55,6 +57,7 @@
#include "src/proto/grpc/testing/xds/v3/extension.pb.h"
#include "src/proto/grpc/testing/xds/v3/fault.pb.h"
#include "src/proto/grpc/testing/xds/v3/fault_common.pb.h"
+#include "src/proto/grpc/testing/xds/v3/gcp_authn.pb.h"
#include "src/proto/grpc/testing/xds/v3/http_filter_rbac.pb.h"
#include "src/proto/grpc/testing/xds/v3/metadata.pb.h"
#include "src/proto/grpc/testing/xds/v3/path.pb.h"
@@ -78,13 +81,14 @@ namespace testing {
namespace {
using ::envoy::extensions::filters::http::fault::v3::HTTPFault;
+using ::envoy::extensions::filters::http::gcp_authn::v3::GcpAuthnFilterConfig;
using ::envoy::extensions::filters::http::rbac::v3::RBAC;
using ::envoy::extensions::filters::http::rbac::v3::RBACPerRoute;
using ::envoy::extensions::filters::http::router::v3::Router;
using ::envoy::extensions::filters::http::stateful_session::v3::StatefulSession;
-using ::envoy::extensions::filters::http::stateful_session::v3 ::
+using ::envoy::extensions::filters::http::stateful_session::v3::
StatefulSessionPerRoute;
-using ::envoy::extensions::http::stateful_session::cookie::v3 ::
+using ::envoy::extensions::http::stateful_session::cookie::v3::
CookieBasedSessionState;
//
@@ -209,7 +213,7 @@ TEST_F(XdsRouterFilterTest, Accessors) {
TEST_F(XdsRouterFilterTest, GenerateFilterConfig) {
XdsExtension extension = MakeXdsExtension(Router());
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
ASSERT_TRUE(errors_.ok()) << errors_.status(
absl::StatusCode::kInvalidArgument, "unexpected errors");
@@ -221,7 +225,7 @@ TEST_F(XdsRouterFilterTest, GenerateFilterConfig) {
TEST_F(XdsRouterFilterTest, GenerateFilterConfigTypedStruct) {
XdsExtension extension = MakeXdsExtension(Router());
extension.value = Json();
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -238,7 +242,7 @@ TEST_F(XdsRouterFilterTest, GenerateFilterConfigUnparseable) {
XdsExtension extension = MakeXdsExtension(Router());
std::string serialized_resource("\0", 1);
extension.value = absl::string_view(serialized_resource);
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -254,7 +258,7 @@ TEST_F(XdsRouterFilterTest, GenerateFilterConfigUnparseable) {
TEST_F(XdsRouterFilterTest, GenerateFilterConfigOverride) {
XdsExtension extension = MakeXdsExtension(Router());
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
@@ -298,28 +302,37 @@ TEST_F(XdsFaultInjectionFilterTest, ModifyChannelArgs) {
EXPECT_EQ(*value, 1);
}
-TEST_F(XdsFaultInjectionFilterTest, GenerateServiceConfigTopLevelConfig) {
+TEST_F(XdsFaultInjectionFilterTest, GenerateMethodConfigTopLevelConfig) {
XdsHttpFilterImpl::FilterConfig config;
config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
- auto service_config = filter_->GenerateServiceConfig(config, nullptr);
+ auto service_config = filter_->GenerateMethodConfig(config, nullptr);
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ(service_config->service_config_field_name, "faultInjectionPolicy");
EXPECT_EQ(service_config->element, "{\"foo\":\"bar\"}");
}
-TEST_F(XdsFaultInjectionFilterTest, GenerateServiceConfigOverrideConfig) {
+TEST_F(XdsFaultInjectionFilterTest, GenerateMethodConfigOverrideConfig) {
XdsHttpFilterImpl::FilterConfig top_config;
top_config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
XdsHttpFilterImpl::FilterConfig override_config;
override_config.config =
Json::FromObject({{"baz", Json::FromString("quux")}});
auto service_config =
- filter_->GenerateServiceConfig(top_config, &override_config);
+ filter_->GenerateMethodConfig(top_config, &override_config);
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ(service_config->service_config_field_name, "faultInjectionPolicy");
EXPECT_EQ(service_config->element, "{\"baz\":\"quux\"}");
}
+TEST_F(XdsFaultInjectionFilterTest, GenerateServiceConfig) {
+ XdsHttpFilterImpl::FilterConfig config;
+ config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
+ auto service_config = filter_->GenerateServiceConfig(config);
+ ASSERT_TRUE(service_config.ok()) << service_config.status();
+ EXPECT_EQ(service_config->service_config_field_name, "");
+ EXPECT_EQ(service_config->element, "");
+}
+
// For the fault injection filter, GenerateFilterConfig() and
// GenerateFilterConfigOverride() accept the same input, so we want to
// run all tests for both.
@@ -331,10 +344,10 @@ class XdsFaultInjectionFilterConfigTest
XdsExtension extension) {
if (GetParam()) {
return filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
}
- return filter_->GenerateFilterConfig(decode_context_, std::move(extension),
- &errors_);
+ return filter_->GenerateFilterConfig("", decode_context_,
+ std::move(extension), &errors_);
}
};
@@ -506,7 +519,7 @@ TEST_F(XdsRbacFilterTest, ModifyChannelArgs) {
TEST_F(XdsRbacFilterTest, GenerateFilterConfig) {
XdsExtension extension = MakeXdsExtension(RBAC());
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
ASSERT_TRUE(errors_.ok()) << errors_.status(
absl::StatusCode::kInvalidArgument, "unexpected errors");
@@ -518,7 +531,7 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfig) {
TEST_F(XdsRbacFilterTest, GenerateFilterConfigTypedStruct) {
XdsExtension extension = MakeXdsExtension(RBAC());
extension.value = Json();
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -535,7 +548,7 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfigUnparseable) {
XdsExtension extension = MakeXdsExtension(RBAC());
std::string serialized_resource("\0", 1);
extension.value = absl::string_view(serialized_resource);
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -551,7 +564,7 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfigUnparseable) {
TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverride) {
XdsExtension extension = MakeXdsExtension(RBACPerRoute());
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
ASSERT_TRUE(errors_.ok()) << errors_.status(
absl::StatusCode::kInvalidArgument, "unexpected errors");
ASSERT_TRUE(config.has_value());
@@ -563,7 +576,7 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverrideTypedStruct) {
XdsExtension extension = MakeXdsExtension(RBACPerRoute());
extension.value = Json();
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
@@ -579,7 +592,7 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverrideUnparseable) {
std::string serialized_resource("\0", 1);
extension.value = absl::string_view(serialized_resource);
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
@@ -590,17 +603,26 @@ TEST_F(XdsRbacFilterTest, GenerateFilterConfigOverrideUnparseable) {
<< status;
}
-TEST_F(XdsRbacFilterTest, GenerateServiceConfig) {
+TEST_F(XdsRbacFilterTest, GenerateMethodConfig) {
XdsHttpFilterImpl::FilterConfig hcm_config = {
filter_->ConfigProtoName(),
Json::FromObject({{"name", Json::FromString("foo")}})};
- auto config = filter_->GenerateServiceConfig(hcm_config, nullptr);
+ auto config = filter_->GenerateMethodConfig(hcm_config, nullptr);
ASSERT_TRUE(config.ok()) << config.status();
EXPECT_EQ(config->service_config_field_name, "rbacPolicy");
EXPECT_EQ(config->element,
JsonDump(Json::FromObject({{"name", Json::FromString("foo")}})));
}
+TEST_F(XdsRbacFilterTest, GenerateServiceConfig) {
+ XdsHttpFilterImpl::FilterConfig config;
+ config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
+ auto service_config = filter_->GenerateServiceConfig(config);
+ ASSERT_TRUE(service_config.ok()) << service_config.status();
+ EXPECT_EQ(service_config->service_config_field_name, "");
+ EXPECT_EQ(service_config->element, "");
+}
+
// For the RBAC filter, the override config is a superset of the
// top-level config, so we test all of the common fields as input for
// both GenerateFilterConfig() and GenerateFilterConfigOverride().
@@ -613,11 +635,11 @@ class XdsRbacFilterConfigTest : public XdsRbacFilterTest,
*rbac_per_route.mutable_rbac() = rbac;
XdsExtension extension = MakeXdsExtension(rbac_per_route);
return filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
}
XdsExtension extension = MakeXdsExtension(rbac);
- return filter_->GenerateFilterConfig(decode_context_, std::move(extension),
- &errors_);
+ return filter_->GenerateFilterConfig("", decode_context_,
+ std::move(extension), &errors_);
}
std::string FieldPrefix() {
@@ -1138,7 +1160,7 @@ TEST_F(XdsStatefulSessionFilterTest, OverrideConfigDisabled) {
stateful_session_per_route.set_disabled(true);
XdsExtension extension = MakeXdsExtension(stateful_session_per_route);
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
ASSERT_TRUE(errors_.ok()) << errors_.status(
absl::StatusCode::kInvalidArgument, "unexpected errors");
ASSERT_TRUE(config.has_value());
@@ -1146,35 +1168,44 @@ TEST_F(XdsStatefulSessionFilterTest, OverrideConfigDisabled) {
EXPECT_EQ(config->config, Json::FromObject({})) << JsonDump(config->config);
}
-TEST_F(XdsStatefulSessionFilterTest, GenerateServiceConfigNoOverride) {
+TEST_F(XdsStatefulSessionFilterTest, GenerateMethodConfigNoOverride) {
XdsHttpFilterImpl::FilterConfig hcm_config = {
filter_->ConfigProtoName(),
Json::FromObject({{"name", Json::FromString("foo")}})};
- auto config = filter_->GenerateServiceConfig(hcm_config, nullptr);
+ auto config = filter_->GenerateMethodConfig(hcm_config, nullptr);
ASSERT_TRUE(config.ok()) << config.status();
EXPECT_EQ(config->service_config_field_name, "stateful_session");
EXPECT_EQ(config->element,
JsonDump(Json::FromObject({{"name", Json::FromString("foo")}})));
}
-TEST_F(XdsStatefulSessionFilterTest, GenerateServiceConfigWithOverride) {
+TEST_F(XdsStatefulSessionFilterTest, GenerateMethodConfigWithOverride) {
XdsHttpFilterImpl::FilterConfig hcm_config = {
filter_->ConfigProtoName(),
Json::FromObject({{"name", Json::FromString("foo")}})};
XdsHttpFilterImpl::FilterConfig override_config = {
filter_->OverrideConfigProtoName(),
Json::FromObject({{"name", Json::FromString("bar")}})};
- auto config = filter_->GenerateServiceConfig(hcm_config, &override_config);
+ auto config = filter_->GenerateMethodConfig(hcm_config, &override_config);
ASSERT_TRUE(config.ok()) << config.status();
EXPECT_EQ(config->service_config_field_name, "stateful_session");
EXPECT_EQ(config->element,
JsonDump(Json::FromObject({{"name", Json::FromString("bar")}})));
}
+TEST_F(XdsStatefulSessionFilterTest, GenerateServiceConfig) {
+ XdsHttpFilterImpl::FilterConfig config;
+ config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
+ auto service_config = filter_->GenerateServiceConfig(config);
+ ASSERT_TRUE(service_config.ok()) << service_config.status();
+ EXPECT_EQ(service_config->service_config_field_name, "");
+ EXPECT_EQ(service_config->element, "");
+}
+
TEST_F(XdsStatefulSessionFilterTest, GenerateFilterConfigTypedStruct) {
XdsExtension extension = MakeXdsExtension(StatefulSession());
extension.value = Json();
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -1192,7 +1223,7 @@ TEST_F(XdsStatefulSessionFilterTest, GenerateFilterConfigUnparseable) {
XdsExtension extension = MakeXdsExtension(StatefulSession());
std::string serialized_resource("\0", 1);
extension.value = absl::string_view(serialized_resource);
- auto config = filter_->GenerateFilterConfig(decode_context_,
+ auto config = filter_->GenerateFilterConfig("", decode_context_,
std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
@@ -1210,7 +1241,7 @@ TEST_F(XdsStatefulSessionFilterTest, GenerateFilterConfigOverrideTypedStruct) {
XdsExtension extension = MakeXdsExtension(StatefulSessionPerRoute());
extension.value = Json();
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
@@ -1228,7 +1259,7 @@ TEST_F(XdsStatefulSessionFilterTest, GenerateFilterConfigOverrideUnparseable) {
std::string serialized_resource("\0", 1);
extension.value = absl::string_view(serialized_resource);
auto config = filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
"errors validating filter config");
EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
@@ -1255,11 +1286,11 @@ class XdsStatefulSessionFilterConfigTest
*stateful_session_per_route.mutable_stateful_session() = stateful_session;
XdsExtension extension = MakeXdsExtension(stateful_session_per_route);
return filter_->GenerateFilterConfigOverride(
- decode_context_, std::move(extension), &errors_);
+ "", decode_context_, std::move(extension), &errors_);
}
XdsExtension extension = MakeXdsExtension(stateful_session);
- return filter_->GenerateFilterConfig(decode_context_, std::move(extension),
- &errors_);
+ return filter_->GenerateFilterConfig("", decode_context_,
+ std::move(extension), &errors_);
}
std::string FieldPrefix() {
@@ -1446,6 +1477,193 @@ TEST_P(XdsStatefulSessionFilterConfigTest, UnparseableSessionState) {
<< status;
}
+//
+// GCP auth filter tests
+//
+
+using XdsGcpAuthnFilterNotRegisteredTest = XdsHttpFilterTest;
+
+TEST_F(XdsGcpAuthnFilterNotRegisteredTest, NotPresentWithoutEnvVar) {
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ EXPECT_EQ(GetFilter(extension.type), nullptr);
+}
+
+class XdsGcpAuthnFilterTest : public XdsHttpFilterTest {
+ protected:
+ XdsGcpAuthnFilterTest() {
+ // Re-initialize registry with env var set.
+ ScopedExperimentalEnvVar env_var(
+ "GRPC_EXPERIMENTAL_XDS_GCP_AUTHENTICATION_FILTER");
+ registry_ = XdsHttpFilterRegistry();
+ // Now the filter will be found in the registry.
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ filter_ = GetFilter(extension.type);
+ CHECK_NE(filter_, nullptr) << extension.type;
+ }
+
+ const XdsHttpFilterImpl* filter_;
+};
+
+TEST_F(XdsGcpAuthnFilterTest, Accessors) {
+ EXPECT_EQ(filter_->ConfigProtoName(),
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig");
+ EXPECT_EQ(filter_->OverrideConfigProtoName(), "");
+ EXPECT_EQ(filter_->channel_filter(), &GcpAuthenticationFilter::kFilter);
+ EXPECT_TRUE(filter_->IsSupportedOnClients());
+ EXPECT_FALSE(filter_->IsSupportedOnServers());
+ EXPECT_FALSE(filter_->IsTerminalFilter());
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigEmpty) {
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ auto config = filter_->GenerateFilterConfig("enterprise", decode_context_,
+ std::move(extension), &errors_);
+ ASSERT_TRUE(errors_.ok()) << errors_.status(
+ absl::StatusCode::kInvalidArgument, "unexpected errors");
+ ASSERT_TRUE(config.has_value());
+ EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
+ EXPECT_EQ(config->config,
+ Json::FromObject(
+ {{"filter_instance_name", Json::FromString("enterprise")}}))
+ << JsonDump(config->config);
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigCacheSizeDefault) {
+ GcpAuthnFilterConfig proto;
+ proto.mutable_cache_config();
+ XdsExtension extension = MakeXdsExtension(proto);
+ auto config = filter_->GenerateFilterConfig("yorktown", decode_context_,
+ std::move(extension), &errors_);
+ ASSERT_TRUE(errors_.ok()) << errors_.status(
+ absl::StatusCode::kInvalidArgument, "unexpected errors");
+ ASSERT_TRUE(config.has_value());
+ EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
+ EXPECT_EQ(
+ config->config,
+ Json::FromObject({{"filter_instance_name", Json::FromString("yorktown")},
+ {"cache_size", Json::FromNumber(10)}}))
+ << JsonDump(config->config);
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigCacheSize) {
+ GcpAuthnFilterConfig proto;
+ proto.mutable_cache_config()->mutable_cache_size()->set_value(6);
+ XdsExtension extension = MakeXdsExtension(proto);
+ auto config = filter_->GenerateFilterConfig("hornet", decode_context_,
+ std::move(extension), &errors_);
+ ASSERT_TRUE(errors_.ok()) << errors_.status(
+ absl::StatusCode::kInvalidArgument, "unexpected errors");
+ ASSERT_TRUE(config.has_value());
+ EXPECT_EQ(config->config_proto_type_name, filter_->ConfigProtoName());
+ EXPECT_EQ(
+ config->config,
+ Json::FromObject({{"filter_instance_name", Json::FromString("hornet")},
+ {"cache_size", Json::FromNumber(6)}}))
+ << JsonDump(config->config);
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigCacheSizeZero) {
+ GcpAuthnFilterConfig proto;
+ proto.mutable_cache_config()->mutable_cache_size()->set_value(0);
+ XdsExtension extension = MakeXdsExtension(proto);
+ auto config = filter_->GenerateFilterConfig("ranger", decode_context_,
+ std::move(extension), &errors_);
+ absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
+ "errors validating filter config");
+ EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status.message(),
+ "errors validating filter config: ["
+ "field:http_filter.value["
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig]"
+ ".cache_config.cache_size "
+ "error:must be in the range (0, INT64_MAX)]")
+ << status;
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigCacheSizeTooBig) {
+ GcpAuthnFilterConfig proto;
+ proto.mutable_cache_config()->mutable_cache_size()->set_value(INT64_MAX);
+ XdsExtension extension = MakeXdsExtension(proto);
+ auto config = filter_->GenerateFilterConfig("langley", decode_context_,
+ std::move(extension), &errors_);
+ absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
+ "errors validating filter config");
+ EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status.message(),
+ "errors validating filter config: ["
+ "field:http_filter.value["
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig]"
+ ".cache_config.cache_size "
+ "error:must be in the range (0, INT64_MAX)]")
+ << status;
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigTypedStruct) {
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ extension.value = Json();
+ auto config = filter_->GenerateFilterConfig("lexington", decode_context_,
+ std::move(extension), &errors_);
+ absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
+ "errors validating filter config");
+ EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status.message(),
+ "errors validating filter config: ["
+ "field:http_filter.value["
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig] "
+ "error:could not parse GCP auth filter config]")
+ << status;
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigUnparseable) {
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ std::string serialized_resource("\0", 1);
+ extension.value = absl::string_view(serialized_resource);
+ auto config = filter_->GenerateFilterConfig("saratoga", decode_context_,
+ std::move(extension), &errors_);
+ absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
+ "errors validating filter config");
+ EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status.message(),
+ "errors validating filter config: ["
+ "field:http_filter.value["
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig] "
+ "error:could not parse GCP auth filter config]")
+ << status;
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateFilterConfigOverride) {
+ XdsExtension extension = MakeXdsExtension(GcpAuthnFilterConfig());
+ auto config = filter_->GenerateFilterConfigOverride(
+ "wasp", decode_context_, std::move(extension), &errors_);
+ absl::Status status = errors_.status(absl::StatusCode::kInvalidArgument,
+ "errors validating filter config");
+ EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status.message(),
+ "errors validating filter config: ["
+ "field:http_filter.value["
+ "envoy.extensions.filters.http.gcp_authn.v3.GcpAuthnFilterConfig] "
+ "error:GCP auth filter does not support config override]")
+ << status;
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateMethodConfig) {
+ XdsHttpFilterImpl::FilterConfig config;
+ config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
+ auto service_config = filter_->GenerateMethodConfig(config, nullptr);
+ ASSERT_TRUE(service_config.ok()) << service_config.status();
+ EXPECT_EQ(service_config->service_config_field_name, "");
+ EXPECT_EQ(service_config->element, "");
+}
+
+TEST_F(XdsGcpAuthnFilterTest, GenerateServiceConfig) {
+ XdsHttpFilterImpl::FilterConfig config;
+ config.config = Json::FromObject({{"foo", Json::FromString("bar")}});
+ auto service_config = filter_->GenerateServiceConfig(config);
+ ASSERT_TRUE(service_config.ok()) << service_config.status();
+ EXPECT_EQ(service_config->service_config_field_name, "gcp_authentication");
+ EXPECT_EQ(service_config->element, "{\"foo\":\"bar\"}");
+}
+
} // namespace
} // namespace testing
} // namespace grpc_core
diff --git a/test/cpp/end2end/xds/BUILD b/test/cpp/end2end/xds/BUILD
index 2a66bca252c..07e486e6b62 100644
--- a/test/cpp/end2end/xds/BUILD
+++ b/test/cpp/end2end/xds/BUILD
@@ -298,6 +298,43 @@ grpc_cc_test(
],
)
+grpc_cc_test(
+ name = "xds_gcp_authn_end2end_test",
+ size = "large",
+ srcs = ["xds_gcp_authn_end2end_test.cc"],
+ data = [
+ "//src/core/tsi/test_creds:badclient.key",
+ "//src/core/tsi/test_creds:badclient.pem",
+ "//src/core/tsi/test_creds:ca.pem",
+ "//src/core/tsi/test_creds:client.key",
+ "//src/core/tsi/test_creds:client.pem",
+ "//src/core/tsi/test_creds:server1.key",
+ "//src/core/tsi/test_creds:server1.pem",
+ ],
+ external_deps = [
+ "gtest",
+ ],
+ flaky = True,
+ linkstatic = True, # Fixes dyld error on MacOS
+ tags = [
+ "no_test_ios",
+ "no_windows",
+ "xds_end2end_test",
+ ], # TODO(jtattermusch): fix test on windows
+ deps = [
+ ":xds_end2end_test_lib",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing/xds/v3:cluster_proto",
+ "//src/proto/grpc/testing/xds/v3:gcp_authn_proto",
+ "//src/proto/grpc/testing/xds/v3:http_connection_manager_proto",
+ "//src/proto/grpc/testing/xds/v3:router_proto",
+ "//test/core/test_util:grpc_test_util",
+ "//test/core/test_util:scoped_env_var",
+ ],
+)
+
grpc_cc_test(
name = "xds_outlier_detection_end2end_test",
size = "large",
diff --git a/test/cpp/end2end/xds/xds_end2end_test_lib.cc b/test/cpp/end2end/xds/xds_end2end_test_lib.cc
index 4e67467896a..88dd6af93c6 100644
--- a/test/cpp/end2end/xds/xds_end2end_test_lib.cc
+++ b/test/cpp/end2end/xds/xds_end2end_test_lib.cc
@@ -353,6 +353,9 @@ void XdsEnd2endTest::RpcOptions::SetupRpc(ClientContext* context,
if (echo_host_from_authority_header) {
request->mutable_param()->set_echo_host_from_authority_header(true);
}
+ if (echo_metadata_initially) {
+ request->mutable_param()->set_echo_metadata_initially(true);
+ }
}
//
@@ -847,6 +850,11 @@ XdsEnd2endTest::MakeIdentityKeyCertPairForTlsCreds() {
std::shared_ptr
XdsEnd2endTest::CreateXdsChannelCredentials() {
+ return XdsCredentials(CreateTlsChannelCredentials());
+}
+
+std::shared_ptr
+XdsEnd2endTest::CreateTlsChannelCredentials() {
auto certificate_provider = std::make_shared(
grpc_core::testing::GetFileContents(kCaCertPath),
MakeIdentityKeyCertPairForTlsCreds());
@@ -859,8 +867,7 @@ XdsEnd2endTest::CreateXdsChannelCredentials() {
options.set_certificate_verifier(std::move(verifier));
options.set_verify_server_certs(true);
options.set_check_call_host(false);
- auto tls_creds = grpc::experimental::TlsCredentials(options);
- return XdsCredentials(tls_creds);
+ return grpc::experimental::TlsCredentials(options);
}
std::shared_ptr
diff --git a/test/cpp/end2end/xds/xds_end2end_test_lib.h b/test/cpp/end2end/xds/xds_end2end_test_lib.h
index 7bbddfd1217..68991fc881c 100644
--- a/test/cpp/end2end/xds/xds_end2end_test_lib.h
+++ b/test/cpp/end2end/xds/xds_end2end_test_lib.h
@@ -613,6 +613,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam,
absl::optional backend_metrics;
bool server_notify_client_when_started = false;
bool echo_host_from_authority_header = false;
+ bool echo_metadata_initially = false;
RpcOptions() {}
@@ -689,6 +690,11 @@ class XdsEnd2endTest : public ::testing::TestWithParam,
return *this;
}
+ RpcOptions& set_echo_metadata_initially(bool value) {
+ echo_metadata_initially = value;
+ return *this;
+ }
+
// Populates context and request.
void SetupRpc(ClientContext* context, EchoRequest* request) const;
};
@@ -970,6 +976,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam,
// Returns XdsCredentials with mTLS fallback creds.
static std::shared_ptr CreateXdsChannelCredentials();
+ static std::shared_ptr CreateTlsChannelCredentials();
// Creates various types of server credentials.
static std::shared_ptr CreateFakeServerCredentials();
diff --git a/test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc b/test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc
new file mode 100644
index 00000000000..d30c22e7605
--- /dev/null
+++ b/test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc
@@ -0,0 +1,231 @@
+//
+// Copyright 2024 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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include
+
+#include "src/core/client_channel/backup_poller.h"
+#include "src/core/lib/config/config_vars.h"
+#include "src/core/util/http_client/httpcli.h"
+#include "src/proto/grpc/testing/xds/v3/cluster.grpc.pb.h"
+#include "src/proto/grpc/testing/xds/v3/gcp_authn.grpc.pb.h"
+#include "src/proto/grpc/testing/xds/v3/http_connection_manager.grpc.pb.h"
+#include "src/proto/grpc/testing/xds/v3/router.grpc.pb.h"
+#include "test/core/test_util/scoped_env_var.h"
+#include "test/core/test_util/test_config.h"
+#include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
+
+namespace grpc {
+namespace testing {
+namespace {
+
+using ::envoy::extensions::filters::http::gcp_authn::v3::Audience;
+using ::envoy::extensions::filters::http::gcp_authn::v3::GcpAuthnFilterConfig;
+using ::envoy::extensions::filters::network::http_connection_manager::v3::
+ HttpFilter;
+
+constexpr absl::string_view kFilterInstanceName = "gcp_authn_instance";
+constexpr absl::string_view kAudience = "audience";
+
+class XdsGcpAuthnEnd2endTest : public XdsEnd2endTest {
+ public:
+ void SetUp() override {
+ g_audience = "";
+ g_token = nullptr;
+ grpc_core::HttpRequest::SetOverride(HttpGetOverride, nullptr, nullptr);
+ InitClient(MakeBootstrapBuilder(), /*lb_expected_authority=*/"",
+ /*xds_resource_does_not_exist_timeout_ms=*/0,
+ /*balancer_authority_override=*/"", /*args=*/nullptr,
+ CreateTlsChannelCredentials());
+ }
+
+ void TearDown() override {
+ XdsEnd2endTest::TearDown();
+ grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
+ }
+
+ static void ValidateHttpRequest(const grpc_http_request* request,
+ const grpc_core::URI& uri) {
+ EXPECT_THAT(
+ uri.query_parameter_map(),
+ ::testing::ElementsAre(::testing::Pair("audience", g_audience)));
+ ASSERT_EQ(request->hdr_count, 1);
+ EXPECT_EQ(absl::string_view(request->hdrs[0].key), "Metadata-Flavor");
+ EXPECT_EQ(absl::string_view(request->hdrs[0].value), "Google");
+ }
+
+ static int HttpGetOverride(const grpc_http_request* request,
+ const grpc_core::URI& uri,
+ grpc_core::Timestamp /*deadline*/,
+ grpc_closure* on_done,
+ grpc_http_response* response) {
+ // Intercept only requests for GCP service account identity tokens.
+ if (uri.authority() != "metadata.google.internal." ||
+ uri.path() !=
+ "/computeMetadata/v1/instance/service-accounts/default/identity") {
+ return 0;
+ }
+ // Validate request.
+ ValidateHttpRequest(request, uri);
+ // Generate response.
+ response->status = 200;
+ response->body = gpr_strdup(const_cast(g_token));
+ response->body_length = strlen(g_token);
+ grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
+ return 1;
+ }
+
+ // Constructs a synthetic JWT token that's just valid enough for the
+ // call creds to extract the expiration date.
+ static std::string MakeToken(grpc_core::Timestamp expiration) {
+ gpr_timespec ts = expiration.as_timespec(GPR_CLOCK_REALTIME);
+ std::string json = absl::StrCat("{\"exp\":", ts.tv_sec, "}");
+ return absl::StrCat("foo.", absl::WebSafeBase64Escape(json), ".bar");
+ }
+
+ Listener BuildListenerWithGcpAuthnFilter(bool optional = false) {
+ Listener listener = default_listener_;
+ HttpConnectionManager hcm = ClientHcmAccessor().Unpack(listener);
+ HttpFilter* filter0 = hcm.mutable_http_filters(0);
+ *hcm.add_http_filters() = *filter0;
+ filter0->set_name(kFilterInstanceName);
+ if (optional) filter0->set_is_optional(true);
+ filter0->mutable_typed_config()->PackFrom(GcpAuthnFilterConfig());
+ ClientHcmAccessor().Pack(hcm, &listener);
+ return listener;
+ }
+
+ Cluster BuildClusterWithAudience(absl::string_view audience) {
+ Audience audience_proto;
+ audience_proto.set_url(audience);
+ Cluster cluster = default_cluster_;
+ auto& filter_map =
+ *cluster.mutable_metadata()->mutable_typed_filter_metadata();
+ auto& entry = filter_map[kFilterInstanceName];
+ entry.PackFrom(audience_proto);
+ return cluster;
+ }
+
+ static absl::string_view g_audience;
+ static const char* g_token;
+};
+
+absl::string_view XdsGcpAuthnEnd2endTest::g_audience;
+const char* XdsGcpAuthnEnd2endTest::g_token;
+
+INSTANTIATE_TEST_SUITE_P(XdsTest, XdsGcpAuthnEnd2endTest,
+ ::testing::Values(XdsTestType()), &XdsTestType::Name);
+
+TEST_P(XdsGcpAuthnEnd2endTest, Basic) {
+ grpc_core::testing::ScopedExperimentalEnvVar env(
+ "GRPC_EXPERIMENTAL_XDS_GCP_AUTHENTICATION_FILTER");
+ // Construct auth token.
+ g_audience = kAudience;
+ std::string token = MakeToken(grpc_core::Timestamp::InfFuture());
+ g_token = token.c_str();
+ // Set xDS resources.
+ CreateAndStartBackends(1, /*xds_enabled=*/false,
+ CreateTlsServerCredentials());
+ SetListenerAndRouteConfiguration(balancer_.get(),
+ BuildListenerWithGcpAuthnFilter(),
+ default_route_config_);
+ balancer_->ads_service()->SetCdsResource(BuildClusterWithAudience(kAudience));
+ EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Send an RPC and check that it arrives with the right auth token.
+ std::multimap server_initial_metadata;
+ Status status = SendRpc(RpcOptions().set_echo_metadata_initially(true),
+ /*response=*/nullptr, &server_initial_metadata);
+ EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
+ << " message=" << status.error_message();
+ EXPECT_THAT(server_initial_metadata,
+ ::testing::Contains(::testing::Pair(
+ "authorization", absl::StrCat("Bearer ", g_token))));
+}
+
+TEST_P(XdsGcpAuthnEnd2endTest, NoOpWhenClusterHasNoAudience) {
+ grpc_core::testing::ScopedExperimentalEnvVar env(
+ "GRPC_EXPERIMENTAL_XDS_GCP_AUTHENTICATION_FILTER");
+ // Set xDS resources.
+ CreateAndStartBackends(1, /*xds_enabled=*/false,
+ CreateTlsServerCredentials());
+ SetListenerAndRouteConfiguration(balancer_.get(),
+ BuildListenerWithGcpAuthnFilter(),
+ default_route_config_);
+ EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Send an RPC and check that it does not have an auth token.
+ std::multimap server_initial_metadata;
+ Status status = SendRpc(RpcOptions().set_echo_metadata_initially(true),
+ /*response=*/nullptr, &server_initial_metadata);
+ EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
+ << " message=" << status.error_message();
+ EXPECT_THAT(
+ server_initial_metadata,
+ ::testing::Not(::testing::Contains(::testing::Key("authorization"))));
+}
+
+TEST_P(XdsGcpAuthnEnd2endTest, FilterIgnoredWhenEnvVarNotSet) {
+ // Construct auth token.
+ g_audience = kAudience;
+ std::string token = MakeToken(grpc_core::Timestamp::InfFuture());
+ g_token = token.c_str();
+ // Set xDS resources.
+ CreateAndStartBackends(1, /*xds_enabled=*/false,
+ CreateTlsServerCredentials());
+ SetListenerAndRouteConfiguration(
+ balancer_.get(), BuildListenerWithGcpAuthnFilter(/*optional=*/true),
+ default_route_config_);
+ balancer_->ads_service()->SetCdsResource(BuildClusterWithAudience(kAudience));
+ EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
+ balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
+ // Send an RPC and check that it does not have an auth token.
+ std::multimap server_initial_metadata;
+ Status status = SendRpc(RpcOptions().set_echo_metadata_initially(true),
+ /*response=*/nullptr, &server_initial_metadata);
+ EXPECT_TRUE(status.ok()) << "code=" << status.error_code()
+ << " message=" << status.error_message();
+ EXPECT_THAT(
+ server_initial_metadata,
+ ::testing::Not(::testing::Contains(::testing::Key("authorization"))));
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc::testing::TestEnvironment env(&argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ // Make the backup poller poll very frequently in order to pick up
+ // updates from all the subchannels's FDs.
+ grpc_core::ConfigVars::Overrides overrides;
+ overrides.client_channel_backup_poll_interval_ms = 1;
+ grpc_core::ConfigVars::SetOverrides(overrides);
+#if TARGET_OS_IPHONE
+ // Workaround Apple CFStream bug
+ grpc_core::SetEnv("grpc_cfstream", "0");
+#endif
+ grpc_init();
+ const auto result = RUN_ALL_TESTS();
+ grpc_shutdown();
+ return result;
+}
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index e000762b1bc..75cba764be5 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1150,6 +1150,10 @@ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.h \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h \
+src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc \
+src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h \
+src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc \
+src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \
src/core/ext/filters/http/client_authority_filter.cc \
@@ -2577,6 +2581,8 @@ src/core/lib/security/credentials/external/url_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.h \
src/core/lib/security/credentials/fake/fake_credentials.cc \
src/core/lib/security/credentials/fake/fake_credentials.h \
+src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc \
+src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h \
src/core/lib/security/credentials/google_default/credentials_generic.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.h \
@@ -2947,6 +2953,7 @@ src/core/util/latent_see.cc \
src/core/util/latent_see.h \
src/core/util/linux/cpu.cc \
src/core/util/log.cc \
+src/core/util/lru_cache.h \
src/core/util/msys/tmpfile.cc \
src/core/util/posix/cpu.cc \
src/core/util/posix/string.cc \
@@ -3006,6 +3013,8 @@ src/core/xds/grpc/xds_http_fault_filter.h \
src/core/xds/grpc/xds_http_filter.h \
src/core/xds/grpc/xds_http_filter_registry.cc \
src/core/xds/grpc/xds_http_filter_registry.h \
+src/core/xds/grpc/xds_http_gcp_authn_filter.cc \
+src/core/xds/grpc/xds_http_gcp_authn_filter.h \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_rbac_filter.h \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 1d1d04c9bd0..2c6b3e5be77 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -951,6 +951,10 @@ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.h \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h \
+src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc \
+src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h \
+src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc \
+src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \
src/core/ext/filters/http/client_authority_filter.cc \
@@ -2348,6 +2352,8 @@ src/core/lib/security/credentials/external/url_external_account_credentials.cc \
src/core/lib/security/credentials/external/url_external_account_credentials.h \
src/core/lib/security/credentials/fake/fake_credentials.cc \
src/core/lib/security/credentials/fake/fake_credentials.h \
+src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc \
+src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h \
src/core/lib/security/credentials/google_default/credentials_generic.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.cc \
src/core/lib/security/credentials/google_default/google_default_credentials.h \
@@ -2726,6 +2732,7 @@ src/core/util/latent_see.cc \
src/core/util/latent_see.h \
src/core/util/linux/cpu.cc \
src/core/util/log.cc \
+src/core/util/lru_cache.h \
src/core/util/msys/tmpfile.cc \
src/core/util/posix/cpu.cc \
src/core/util/posix/string.cc \
@@ -2784,6 +2791,8 @@ src/core/xds/grpc/xds_http_fault_filter.h \
src/core/xds/grpc/xds_http_filter.h \
src/core/xds/grpc/xds_http_filter_registry.cc \
src/core/xds/grpc/xds_http_filter_registry.h \
+src/core/xds/grpc/xds_http_gcp_authn_filter.cc \
+src/core/xds/grpc/xds_http_gcp_authn_filter.h \
src/core/xds/grpc/xds_http_rbac_filter.cc \
src/core/xds/grpc/xds_http_rbac_filter.h \
src/core/xds/grpc/xds_http_stateful_session_filter.cc \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index df179bbb3da..5152c4f42e5 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -3975,6 +3975,30 @@
],
"uses_polling": true
},
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "gcp_authentication_filter_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": false
+ },
{
"args": [],
"benchmark": false,
@@ -5777,6 +5801,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": "lru_cache_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": false
+ },
{
"args": [],
"benchmark": false,