[xDS] implement GCP Auth filter (#37550)

Final piece of gRFC A83 (https://github.com/grpc/proposal/pull/438): the GCP authentication filter itself.

Infrastructure changes include:
- Added a general-purpose LRU cache library that can be reused elsewhere.
- Fixed the client channel code to use the channel args returned by the resolver for the dynamic filters.  This was necessary so that the GCP auth filter could access the `XdsConfig` object, which is passed via a channel arg.
- Unlike the other xDS HTTP filters we support, the GCP auth filter does not support config overrides, and its configuration includes a cache size parameter that we always need at the channel level, not per-call.  As a result, I had to change the xDS HTTP filter API to give it the ability to set top-level fields in the service config, not just per-method fields.  (We use the service config as a way of passing configuration down into xDS HTTP filters.)  Note that for now, this works only on the client side, because we don't have machinery for a top-level service config on the server side.
- The GCP auth filter is also the first case where the filter needs to know its instance name from the xDS config, so I changed the xDS HTTP filter API to plumb that through.
- Fixed a bug in the HTTP client library that prevented the override functions from declining to override a particular request.

Closes #37550

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/37550 from markdroth:xds_gcp_auth_filter 19eaefb52f
PiperOrigin-RevId: 669371249
pull/37613/head
Mark D. Roth 3 months ago committed by Copybara-Service
parent 24e341be62
commit c4117e4615
  1. 277
      CMakeLists.txt
  2. 4
      Makefile
  3. 9
      Package.swift
  4. 103
      build_autogenerated.yaml
  5. 6
      config.m4
  6. 6
      config.w32
  7. 10
      gRPC-C++.podspec
  8. 14
      gRPC-Core.podspec
  9. 9
      grpc.gemspec
  10. 9
      package.xml
  11. 62
      src/core/BUILD
  12. 17
      src/core/client_channel/client_channel.cc
  13. 2
      src/core/client_channel/client_channel.h
  14. 18
      src/core/client_channel/client_channel_filter.cc
  15. 2
      src/core/client_channel/client_channel_filter.h
  16. 167
      src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc
  17. 82
      src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h
  18. 81
      src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc
  19. 87
      src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h
  20. 2
      src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc
  21. 5
      src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h
  22. 3
      src/core/plugin_registry/grpc_plugin_registry_extra.cc
  23. 35
      src/core/resolver/xds/xds_resolver.cc
  24. 2
      src/core/server/xds_server_config_fetcher.cc
  25. 5
      src/core/service_config/service_config_call_data.h
  26. 25
      src/core/util/http_client/httpcli.cc
  27. 4
      src/core/util/http_client/httpcli.h
  28. 104
      src/core/util/lru_cache.h
  29. 13
      src/core/xds/grpc/xds_http_fault_filter.cc
  30. 6
      src/core/xds/grpc/xds_http_fault_filter.h
  31. 12
      src/core/xds/grpc/xds_http_filter.h
  32. 7
      src/core/xds/grpc/xds_http_filter_registry.cc
  33. 9
      src/core/xds/grpc/xds_http_filter_registry.h
  34. 142
      src/core/xds/grpc/xds_http_gcp_authn_filter.cc
  35. 61
      src/core/xds/grpc/xds_http_gcp_authn_filter.h
  36. 10
      src/core/xds/grpc/xds_http_rbac_filter.cc
  37. 6
      src/core/xds/grpc/xds_http_rbac_filter.h
  38. 10
      src/core/xds/grpc/xds_http_stateful_session_filter.cc
  39. 6
      src/core/xds/grpc/xds_http_stateful_session_filter.h
  40. 4
      src/core/xds/grpc/xds_listener_parser.cc
  41. 2
      src/core/xds/grpc/xds_route_config_parser.cc
  42. 78
      src/core/xds/grpc/xds_routing.cc
  43. 12
      src/core/xds/grpc/xds_routing.h
  44. 4
      src/python/grpcio/grpc_core_dependencies.py
  45. 21
      test/core/filters/BUILD
  46. 4
      test/core/filters/filter_test.cc
  47. 4
      test/core/filters/filter_test.h
  48. 386
      test/core/filters/gcp_authentication_filter_test.cc
  49. 12
      test/core/util/BUILD
  50. 74
      test/core/util/lru_cache_test.cc
  51. 1
      test/core/xds/BUILD
  52. 290
      test/core/xds/xds_http_filters_test.cc
  53. 37
      test/cpp/end2end/xds/BUILD
  54. 11
      test/cpp/end2end/xds/xds_end2end_test_lib.cc
  55. 7
      test/cpp/end2end/xds/xds_end2end_test_lib.h
  56. 231
      test/cpp/end2end/xds/xds_gcp_authn_end2end_test.cc
  57. 9
      tools/doxygen/Doxyfile.c++.internal
  58. 9
      tools/doxygen/Doxyfile.core.internal
  59. 48
      tools/run_tests/generated/tests.json

277
CMakeLists.txt generated

@ -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

4
Makefile generated

@ -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 \

9
Package.swift generated

@ -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",

@ -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

6
config.m4 generated

@ -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)

6
config.w32 generated

@ -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");

10
gRPC-C++.podspec generated

@ -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',

14
gRPC-Core.podspec generated

@ -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',

9
grpc.gemspec generated

@ -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 )

9
package.xml generated

@ -165,6 +165,10 @@
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" />
@ -1554,6 +1558,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/external/url_external_account_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/fake/fake_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/fake/fake_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/gcp_service_account_identity/gcp_service_account_identity_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/google_default/credentials_generic.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/google_default/google_default_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/google_default/google_default_credentials.h" role="src" />
@ -1924,6 +1930,7 @@
<file baseinstalldir="/" name="src/core/util/latent_see.h" role="src" />
<file baseinstalldir="/" name="src/core/util/linux/cpu.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/log.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/lru_cache.h" role="src" />
<file baseinstalldir="/" name="src/core/util/msys/tmpfile.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/posix/cpu.cc" role="src" />
<file baseinstalldir="/" name="src/core/util/posix/string.cc" role="src" />
@ -1982,6 +1989,8 @@
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_filter_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_filter_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_gcp_authn_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_gcp_authn_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_rbac_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_rbac_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/xds/grpc/xds_http_stateful_session_filter.cc" role="src" />

@ -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",

@ -1105,6 +1105,10 @@ void ClientChannel::OnResolverResultChangedLocked(Resolver::Result result) {
service_config = std::move(*result.service_config);
config_selector = result.args.GetObjectRef<ConfigSelector>();
}
// 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<DefaultConfigSelector>(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();

@ -149,7 +149,7 @@ class ClientChannel : public Channel {
RefCountedPtr<ConfigSelector> 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,

@ -1319,6 +1319,10 @@ void ClientChannelFilter::OnResolverResultChangedLocked(
service_config = std::move(*result.service_config);
config_selector = result.args.GetObjectRef<ConfigSelector>();
}
// 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<ServiceConfig> 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<DefaultConfigSelector>(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);

@ -247,7 +247,7 @@ class ClientChannelFilter final {
RefCountedPtr<ConfigSelector> 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_);

@ -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 <memory>
#include <string>
#include <utility>
#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<ServiceConfigCallData>();
auto cluster_attribute =
service_config_call_data->GetCallAttribute<XdsClusterAttribute>();
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<const XdsGcpAuthnAudienceMetadataValue*>(metadata_value)->url());
// Add the call creds instance to the call.
auto* arena = GetContext<Arena>();
auto* security_ctx = DownCast<grpc_client_security_context*>(
arena->GetContext<SecurityContext>());
if (security_ctx == nullptr) {
security_ctx = arena->New<grpc_client_security_context>(std::move(creds));
arena->SetContext<SecurityContext>(security_ctx);
} else {
security_ctx->creds = std::move(creds);
}
return absl::OkStatus();
}
const grpc_channel_filter GcpAuthenticationFilter::kFilter =
MakePromiseBasedFilter<GcpAuthenticationFilter, FilterEndpoint::kClient,
0>();
absl::StatusOr<std::unique_ptr<GcpAuthenticationFilter>>
GcpAuthenticationFilter::Create(const ChannelArgs& args,
ChannelFilter::Args filter_args) {
auto* service_config = args.GetObject<ServiceConfig>();
if (service_config == nullptr) {
return absl::InvalidArgumentError(
"gcp_auth: no service config in channel args");
}
auto* config = static_cast<const GcpAuthenticationParsedConfig*>(
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<XdsConfig>();
if (xds_config == nullptr) {
return absl::InvalidArgumentError(
"gcp_auth: xds config not found in channel args");
}
return std::make_unique<GcpAuthenticationFilter>(filter_config,
std::move(xds_config));
}
GcpAuthenticationFilter::GcpAuthenticationFilter(
const GcpAuthenticationParsedConfig::Config* filter_config,
RefCountedPtr<const XdsConfig> xds_config)
: filter_config_(filter_config),
xds_config_(std::move(xds_config)),
cache_(filter_config->cache_size) {}
RefCountedPtr<grpc_call_credentials>
GcpAuthenticationFilter::GetCallCredentials(const std::string& audience) {
MutexLock lock(&mu_);
return cache_.GetOrInsert(audience, [](const std::string& audience) {
return MakeRefCounted<GcpServiceAccountIdentityCallCredentials>(audience);
});
}
void GcpAuthenticationFilterRegister(CoreConfiguration::Builder* builder) {
GcpAuthenticationServiceConfigParser::Register(builder);
}
} // namespace grpc_core

@ -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 <memory>
#include <string>
#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<GcpAuthenticationFilter> {
public:
static const grpc_channel_filter kFilter;
static absl::string_view TypeName() { return "gcp_authentication_filter"; }
static absl::StatusOr<std::unique_ptr<GcpAuthenticationFilter>> Create(
const ChannelArgs& args, ChannelFilter::Args filter_args);
GcpAuthenticationFilter(
const GcpAuthenticationParsedConfig::Config* filter_config,
RefCountedPtr<const XdsConfig> 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<grpc_call_credentials> GetCallCredentials(
const std::string& audience);
const GcpAuthenticationParsedConfig::Config* filter_config_;
const RefCountedPtr<const XdsConfig> xds_config_;
Mutex mu_;
LruCache<std::string /*audience*/, RefCountedPtr<grpc_call_credentials>>
cache_ ABSL_GUARDED_BY(&mu_);
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_FILTERS_GCP_AUTHENTICATION_GCP_AUTHENTICATION_FILTER_H

@ -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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/gcp_authentication/gcp_authentication_service_config_parser.h"
#include <vector>
#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<Config>()
.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<GcpAuthenticationParsedConfig>()
.OptionalField("gcp_authentication",
&GcpAuthenticationParsedConfig::configs_)
.Finish();
return loader;
}
std::unique_ptr<ServiceConfigParser::ParsedConfig>
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<std::unique_ptr<GcpAuthenticationParsedConfig>>(
json, JsonArgs(), errors);
}
void GcpAuthenticationServiceConfigParser::Register(
CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<GcpAuthenticationServiceConfigParser>());
}
size_t GcpAuthenticationServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
} // namespace grpc_core

@ -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 <stddef.h>
#include <memory>
#include <string>
#include <vector>
#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<Config> configs_;
};
class GcpAuthenticationServiceConfigParser final
: public ServiceConfigParser::Parser {
public:
absl::string_view name() const override { return parser_name(); }
std::unique_ptr<ServiceConfigParser::ParsedConfig> 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

@ -161,7 +161,7 @@ std::string GcpServiceAccountIdentityCallCredentials::debug_string() {
")");
}
UniqueTypeName GcpServiceAccountIdentityCallCredentials::type() const {
UniqueTypeName GcpServiceAccountIdentityCallCredentials::Type() {
static UniqueTypeName::Factory kFactory("GcpServiceAccountIdentity");
return kFactory.Create();
}

@ -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_; }

@ -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);

@ -510,7 +510,7 @@ XdsResolver::RouteConfigData::CreateMethodConfig(
// Handle xDS HTTP filters.
const auto& hcm = absl::get<XdsListenerResource::HttpConnectionManager>(
resolver->current_config_->listener->listener);
auto result = XdsRouting::GeneratePerHTTPFilterConfigs(
auto result = XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
static_cast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap())
.http_filter_registry(),
hcm.http_filters, *resolver->current_config_->virtual_host, route,
@ -1041,18 +1041,27 @@ XdsResolver::CreateServiceConfig() {
}
std::vector<std::string> 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<XdsListenerResource::HttpConnectionManager>(
current_config_->listener->listener);
auto filter_configs =
XdsRouting::GeneratePerHTTPFilterConfigsForServiceConfig(
static_cast<const GrpcXdsBootstrap&>(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() {

@ -1176,7 +1176,7 @@ XdsServerConfigFetcher::ListenerWatcher::FilterChainMatchManager::
config_selector_route.unsupported_action =
absl::get_if<XdsRouteConfigResource::Route::NonForwardingAction>(
&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();

@ -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).

@ -70,14 +70,14 @@ OrphanablePtr<HttpRequest> HttpRequest::Get(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr<grpc_channel_credentials> channel_creds) {
absl::optional<std::function<void()>> test_only_generate_response;
absl::optional<std::function<bool()>> 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> HttpRequest::Post(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr<grpc_channel_credentials> channel_creds) {
absl::optional<std::function<void()>> test_only_generate_response;
absl::optional<std::function<bool()>> 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> HttpRequest::Put(
grpc_polling_entity* pollent, const grpc_http_request* request,
Timestamp deadline, grpc_closure* on_done, grpc_http_response* response,
RefCountedPtr<grpc_channel_credentials> channel_creds) {
absl::optional<std::function<void()>> test_only_generate_response;
absl::optional<std::function<bool()>> 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<std::function<void()>> test_only_generate_response,
absl::optional<std::function<bool()>> test_only_generate_response,
RefCountedPtr<grpc_channel_credentials> 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(

@ -165,7 +165,7 @@ class HttpRequest : public InternallyRefCounted<HttpRequest> {
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<std::function<void()>> test_only_generate_response,
absl::optional<std::function<bool()>> test_only_generate_response,
RefCountedPtr<grpc_channel_credentials> channel_creds);
~HttpRequest() override;
@ -250,7 +250,7 @@ class HttpRequest : public InternallyRefCounted<HttpRequest> {
ResourceQuotaRefPtr resource_quota_;
grpc_polling_entity* pollent_;
grpc_pollset_set* pollset_set_;
const absl::optional<std::function<void()>> test_only_generate_response_;
const absl::optional<std::function<bool()>> test_only_generate_response_;
Mutex mu_;
RefCountedPtr<HandshakeManager> handshake_mgr_ ABSL_GUARDED_BY(mu_);
bool cancelled_ ABSL_GUARDED_BY(mu_) = false;

@ -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 <list>
#include <tuple>
#include <utility>
#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 <typename Key, typename Value>
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<Value> 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<Value(const Key&)> create);
private:
struct CacheEntry {
Value value;
typename std::list<Key>::iterator lru_iterator;
explicit CacheEntry(Value v) : value(std::move(v)) {}
};
const size_t max_size_;
absl::flat_hash_map<Key, CacheEntry> cache_;
std::list<Key> lru_list_;
};
//
// implementation -- no user-serviceable parts below
//
template <typename Key, typename Value>
absl::optional<Value> LruCache<Key, Value>::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 <typename Key, typename Value>
Value LruCache<Key, Value>::GetOrInsert(
Key key, absl::AnyInvocable<Value(const Key&)> 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

@ -87,6 +87,7 @@ void XdsHttpFaultFilter::PopulateSymtab(upb_DefPool* symtab) const {
absl::optional<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
XdsHttpFaultFilter::GenerateServiceConfig(
const FilterConfig& /*hcm_filter_config*/) const {
return ServiceConfigJsonEntry{"", ""};
}
} // namespace grpc_core

@ -39,17 +39,21 @@ class XdsHttpFaultFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional<FilterConfig> GenerateFilterConfig(
absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional<FilterConfig> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
absl::StatusOr<ServiceConfigJsonEntry> GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return true; }
bool IsSupportedOnServers() const override { return false; }
};

@ -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<FilterConfig> 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<FilterConfig> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
virtual absl::StatusOr<ServiceConfigJsonEntry> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
const FilterConfig& hcm_filter_config) const = 0;
// Returns true if the filter is supported on clients; false otherwise
virtual bool IsSupportedOnClients() const = 0;

@ -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<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFaultFilter>());
RegisterFilter(std::make_unique<XdsHttpRbacFilter>());
RegisterFilter(std::make_unique<XdsHttpStatefulSessionFilter>());
if (XdsGcpAuthFilterEnabled()) {
RegisterFilter(std::make_unique<XdsHttpGcpAuthnFilter>());
}
}
}

@ -45,19 +45,26 @@ class XdsHttpRouterFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional<FilterConfig> GenerateFilterConfig(
absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional<FilterConfig> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
absl::StatusOr<ServiceConfigJsonEntry> 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<ServiceConfigJsonEntry> 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; }

@ -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 <string>
#include <utility>
#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 <grpc/support/json.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/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<XdsHttpFilterImpl::FilterConfig>
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<absl::string_view>(&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<XdsHttpFilterImpl::FilterConfig>
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<GcpAuthenticationFilter>();
}
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
XdsHttpGcpAuthnFilter::GenerateMethodConfig(
const FilterConfig& /*hcm_filter_config*/,
const FilterConfig* /*filter_config_override*/) const {
return ServiceConfigJsonEntry{"", ""};
}
absl::StatusOr<XdsHttpFilterImpl::ServiceConfigJsonEntry>
XdsHttpGcpAuthnFilter::GenerateServiceConfig(
const FilterConfig& hcm_filter_config) const {
return ServiceConfigJsonEntry{"gcp_authentication",
JsonDump(hcm_filter_config.config)};
}
} // namespace grpc_core

@ -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<FilterConfig> GenerateFilterConfig(
absl::string_view instance_name,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional<FilterConfig> 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<ServiceConfigJsonEntry> GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
absl::StatusOr<ServiceConfigJsonEntry> 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

@ -515,6 +515,7 @@ void XdsHttpRbacFilter::PopulateSymtab(upb_DefPool* symtab) const {
absl::optional<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
XdsHttpRbacFilter::GenerateServiceConfig(
const FilterConfig& /*hcm_filter_config*/) const {
return ServiceConfigJsonEntry{"", ""};
}
} // namespace grpc_core

@ -39,17 +39,21 @@ class XdsHttpRbacFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional<FilterConfig> GenerateFilterConfig(
absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional<FilterConfig> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
absl::StatusOr<ServiceConfigJsonEntry> GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return false; }
bool IsSupportedOnServers() const override { return true; }
};

@ -141,6 +141,7 @@ Json::Object ValidateStatefulSession(
absl::optional<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::FilterConfig>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
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<XdsHttpFilterImpl::ServiceConfigJsonEntry>
XdsHttpStatefulSessionFilter::GenerateServiceConfig(
const FilterConfig& /*hcm_filter_config*/) const {
return ServiceConfigJsonEntry{"", ""};
}
} // namespace grpc_core

@ -39,17 +39,21 @@ class XdsHttpStatefulSessionFilter final : public XdsHttpFilterImpl {
absl::string_view OverrideConfigProtoName() const override;
void PopulateSymtab(upb_DefPool* symtab) const override;
absl::optional<FilterConfig> GenerateFilterConfig(
absl::string_view /*instance_name*/,
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
absl::optional<FilterConfig> 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<ServiceConfigJsonEntry> GenerateServiceConfig(
absl::StatusOr<ServiceConfigJsonEntry> GenerateMethodConfig(
const FilterConfig& hcm_filter_config,
const FilterConfig* filter_config_override) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
const FilterConfig& hcm_filter_config) const override;
bool IsSupportedOnClients() const override { return true; }
bool IsSupportedOnServers() const override { return false; }
};

@ -268,8 +268,8 @@ XdsListenerResource::HttpConnectionManager HttpConnectionManagerParse(
continue;
}
absl::optional<XdsHttpFilterImpl::FilterConfig> 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{

@ -441,7 +441,7 @@ XdsRouteConfigResource::TypedPerFilterConfig ParseTypedPerFilterConfig(
}
absl::optional<XdsHttpFilterImpl::FilterConfig> 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);
}

@ -215,23 +215,21 @@ const XdsHttpFilterImpl::FilterConfig* FindFilterConfigOverride(
return nullptr;
}
} // namespace
absl::StatusOr<XdsRouting::GeneratePerHttpFilterConfigsResult>
XdsRouting::GeneratePerHTTPFilterConfigs(
GeneratePerHTTPFilterConfigs(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
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<absl::StatusOr<XdsHttpFilterImpl::ServiceConfigJsonEntry>(
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::GeneratePerHttpFilterConfigsResult>
XdsRouting::GeneratePerHTTPFilterConfigsForMethodConfig(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
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::GeneratePerHttpFilterConfigsResult>
XdsRouting::GeneratePerHTTPFilterConfigsForServiceConfig(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
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

@ -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<GeneratePerHttpFilterConfigsResult>
GeneratePerHTTPFilterConfigs(
GeneratePerHTTPFilterConfigsForMethodConfig(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
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<GeneratePerHttpFilterConfigsResult>
GeneratePerHTTPFilterConfigsForServiceConfig(
const XdsHttpFilterRegistry& http_filter_registry,
const std::vector<XdsListenerResource::HttpConnectionManager::HttpFilter>&
http_filters,
const ChannelArgs& args);
};
} // namespace grpc_core

@ -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',

@ -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"],

@ -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::Impl>& 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<std::pair<absl::string_view, absl::string_view>>

@ -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<Channel> 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);
}

@ -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 <memory>
#include <utility>
#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<GcpAuthenticationFilter> {
protected:
static RefCountedPtr<ServiceConfig> 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<const XdsConfig> MakeXdsConfig(
absl::string_view cluster, absl::string_view filter_instance_name,
std::unique_ptr<XdsMetadataValue> audience_metadata) {
auto xds_config = MakeRefCounted<XdsConfig>();
if (!cluster.empty()) {
auto cluster_resource = std::make_shared<XdsClusterResource>();
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<const XdsConfig> MakeXdsConfigWithCluster(
absl::string_view cluster,
absl::StatusOr<XdsConfig::ClusterConfig> cluster_config) {
auto xds_config = MakeRefCounted<XdsConfig>();
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<XdsMetadataValue> 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<grpc_call_credentials> GetCallCreds(const Call& call) {
auto* security_ctx = DownCast<grpc_client_security_context*>(
call.arena()->GetContext<SecurityContext>());
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<ServiceConfigCallData>(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<XdsGcpAuthnAudienceMetadataValue>(kAudience));
Call call(MakeChannel(channel_args).value());
auto* service_config_call_data =
call.arena()->New<ServiceConfigCallData>(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<ServiceConfigCallData>(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<ServiceConfigCallData>(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<ServiceConfigCallData>(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<ServiceConfigCallData>(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<XdsStructMetadataValue>(Json()));
Call call(MakeChannel(channel_args).value());
auto* service_config_call_data =
call.arena()->New<ServiceConfigCallData>(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<XdsGcpAuthnAudienceMetadataValue>(kAudience));
Call call(MakeChannel(channel_args).value());
auto* service_config_call_data =
call.arena()->New<ServiceConfigCallData>(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();
}

@ -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",
],
)

@ -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<int> 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<std::string, int> cache(5);
// Insert 5 values.
const std::array<int, 5> 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<int, 5> 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();
}

@ -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",

@ -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

@ -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",

@ -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<ChannelCredentials>
XdsEnd2endTest::CreateXdsChannelCredentials() {
return XdsCredentials(CreateTlsChannelCredentials());
}
std::shared_ptr<ChannelCredentials>
XdsEnd2endTest::CreateTlsChannelCredentials() {
auto certificate_provider = std::make_shared<StaticDataCertificateProvider>(
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<ServerCredentials>

@ -613,6 +613,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<XdsTestType>,
absl::optional<xds::data::orca::v3::OrcaLoadReport> 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<XdsTestType>,
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<XdsTestType>,
// Returns XdsCredentials with mTLS fallback creds.
static std::shared_ptr<ChannelCredentials> CreateXdsChannelCredentials();
static std::shared_ptr<ChannelCredentials> CreateTlsChannelCredentials();
// Creates various types of server credentials.
static std::shared_ptr<ServerCredentials> CreateFakeServerCredentials();

@ -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 <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <grpc/support/string_util.h>
#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<char*>(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<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> 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;
}

@ -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 \

@ -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 \

@ -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,

Loading…
Cancel
Save