SDK authorization policy translator. (#25361)

* SDK authorization policy translator.
pull/25637/head
Ashitha Santhosh 4 years ago committed by GitHub
parent 34c8a1f87a
commit bd86187f19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 65
      BUILD
  2. 15
      BUILD.gn
  3. 56
      CMakeLists.txt
  4. 8
      Makefile
  5. 56
      build_autogenerated.yaml
  6. 6
      config.m4
  7. 6
      config.w32
  8. 21
      gRPC-C++.podspec
  9. 25
      gRPC-Core.podspec
  10. 15
      grpc.gemspec
  11. 5
      grpc.gyp
  12. 15
      package.xml
  13. 2
      src/core/ext/xds/xds_api.h
  14. 16
      src/core/lib/matchers/matchers.cc
  15. 26
      src/core/lib/matchers/matchers.h
  16. 328
      src/core/lib/security/authorization/rbac_policy.cc
  17. 163
      src/core/lib/security/authorization/rbac_policy.h
  18. 354
      src/core/lib/security/authorization/rbac_translator.cc
  19. 39
      src/core/lib/security/authorization/rbac_translator.h
  20. 4
      src/python/grpcio/grpc_core_dependencies.py
  21. 16
      test/core/security/BUILD
  22. 2
      test/core/security/matchers_test.cc
  23. 804
      test/core/security/rbac_translator_test.cc
  24. 14
      tools/doxygen/Doxyfile.c++.internal
  25. 14
      tools/doxygen/Doxyfile.core.internal
  26. 24
      tools/run_tests/generated/tests.json

65
BUILD

@ -1422,9 +1422,9 @@ grpc_cc_library(
deps = [
"envoy_ads_upb",
"envoy_ads_upbdefs",
"grpc_authorization_engine",
"grpc_base",
"grpc_client_channel",
"grpc_matchers",
"grpc_secure",
"grpc_transport_chttp2_client_secure",
"udpa_type_upb",
@ -1984,21 +1984,70 @@ grpc_cc_library(
],
)
# This target depends on RE2 and should not be linked into grpc by default for binary-size reasons.
grpc_cc_library(
name = "grpc_authorization_engine",
name = "grpc_matchers",
srcs = [
"src/core/lib/matchers/matchers.cc",
],
hdrs = [
"src/core/lib/matchers/matchers.h",
],
external_deps = [
"re2",
],
language = "c++",
deps = [
"grpc_base",
],
)
# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
grpc_cc_library(
name = "grpc_rbac_engine",
srcs = [
"src/core/lib/security/authorization/authorization_engine.cc",
"src/core/lib/security/authorization/evaluate_args.cc",
"src/core/lib/security/authorization/matchers.cc",
"src/core/lib/security/authorization/rbac_policy.cc",
],
hdrs = [
"src/core/lib/security/authorization/authorization_engine.h",
"src/core/lib/security/authorization/evaluate_args.h",
"src/core/lib/security/authorization/matchers.h",
"src/core/lib/security/authorization/rbac_policy.h",
],
language = "c++",
deps = [
"grpc_base",
"grpc_matchers",
"grpc_secure",
],
)
# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
grpc_cc_library(
name = "grpc_authorization_provider",
srcs = [
"src/core/lib/security/authorization/rbac_translator.cc",
],
hdrs = [
"src/core/lib/security/authorization/rbac_translator.h",
],
language = "c++",
deps = [
"grpc_matchers",
"grpc_rbac_engine",
],
)
# This target pulls in a dependency on RE2 and should not be linked into grpc by default for binary-size reasons.
grpc_cc_library(
name = "grpc_cel_engine",
srcs = [
"src/core/lib/security/authorization/authorization_engine.cc",
],
hdrs = [
"src/core/lib/security/authorization/authorization_engine.h",
],
external_deps = [
"absl/container:flat_hash_set",
"re2",
],
language = "c++",
deps = [
@ -2006,7 +2055,7 @@ grpc_cc_library(
"google_api_upb",
"grpc_base",
"grpc_mock_cel",
"grpc_secure",
"grpc_rbac_engine",
],
)

@ -992,18 +992,8 @@ config("grpc_config") {
"src/core/lib/json/json_util.cc",
"src/core/lib/json/json_util.h",
"src/core/lib/json/json_writer.cc",
"src/core/lib/security/authorization/authorization_engine.cc",
"src/core/lib/security/authorization/authorization_engine.h",
"src/core/lib/security/authorization/evaluate_args.cc",
"src/core/lib/security/authorization/evaluate_args.h",
"src/core/lib/security/authorization/matchers.cc",
"src/core/lib/security/authorization/matchers.h",
"src/core/lib/security/authorization/mock_cel/activation.h",
"src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h",
"src/core/lib/security/authorization/mock_cel/cel_expression.h",
"src/core/lib/security/authorization/mock_cel/cel_value.h",
"src/core/lib/security/authorization/mock_cel/evaluator_core.h",
"src/core/lib/security/authorization/mock_cel/flat_expr_builder.h",
"src/core/lib/matchers/matchers.cc",
"src/core/lib/matchers/matchers.h",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.cc",
@ -1242,7 +1232,6 @@ config("grpc_config") {
":absl/status:status",
":absl/functional:bind_front",
":absl/container:inlined_vector",
":absl/container:flat_hash_set",
":absl/container:flat_hash_map",
"//third_party/cares",
":address_sorting",

@ -123,7 +123,6 @@ set(gRPC_ABSL_USED_TARGETS
absl_exponential_biased
absl_fixed_array
absl_flat_hash_map
absl_flat_hash_set
absl_function_ref
absl_graphcycles_internal
absl_hash
@ -887,6 +886,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx qps_json_driver)
add_dependencies(buildtests_cxx qps_worker)
add_dependencies(buildtests_cxx raw_end2end_test)
add_dependencies(buildtests_cxx rbac_translator_test)
add_dependencies(buildtests_cxx ref_counted_ptr_test)
add_dependencies(buildtests_cxx ref_counted_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -1864,9 +1864,7 @@ add_library(grpc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_util.cc
src/core/lib/json/json_writer.cc
src/core/lib/security/authorization/authorization_engine.cc
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/matchers/matchers.cc
src/core/lib/security/context/security_context.cc
src/core/lib/security/credentials/alts/alts_credentials.cc
src/core/lib/security/credentials/alts/check_gcp_environment.cc
@ -2036,7 +2034,6 @@ target_link_libraries(grpc
absl::status
absl::bind_front
absl::inlined_vector
absl::flat_hash_set
absl::flat_hash_map
)
if(_gRPC_PLATFORM_IOS OR _gRPC_PLATFORM_MAC)
@ -8555,6 +8552,9 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(authorization_engine_test
src/core/lib/security/authorization/authorization_engine.cc
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/rbac_policy.cc
test/core/security/authorization_engine_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -8587,6 +8587,7 @@ target_link_libraries(authorization_engine_test
address_sorting
upb
${_gRPC_SSL_LIBRARIES}
absl::flat_hash_set
)
@ -11089,6 +11090,8 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(evaluate_args_test
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/rbac_policy.cc
test/core/security/evaluate_args_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -13757,6 +13760,49 @@ target_link_libraries(raw_end2end_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(rbac_translator_test
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_translator.cc
test/core/security/rbac_translator_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(rbac_translator_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(rbac_translator_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
address_sorting
upb
${_gRPC_SSL_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)

@ -1443,9 +1443,7 @@ LIBGRPC_SRC = \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/security/authorization/authorization_engine.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/alts/alts_credentials.cc \
src/core/lib/security/credentials/alts/check_gcp_environment.cc \
@ -2830,9 +2828,7 @@ src/core/ext/xds/xds_client_stats.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_http_filters.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_server_config_fetcher.cc: $(OPENSSL_DEP)
src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/authorization_engine.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/evaluate_args.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/matchers.cc: $(OPENSSL_DEP)
src/core/lib/matchers/matchers.cc: $(OPENSSL_DEP)
src/core/lib/security/context/security_context.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/alts/alts_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/alts/check_gcp_environment.cc: $(OPENSSL_DEP)

@ -757,15 +757,7 @@ libs:
- src/core/lib/iomgr/work_serializer.h
- src/core/lib/json/json.h
- src/core/lib/json/json_util.h
- src/core/lib/security/authorization/authorization_engine.h
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/mock_cel/activation.h
- src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
- src/core/lib/security/authorization/mock_cel/cel_expression.h
- src/core/lib/security/authorization/mock_cel/cel_value.h
- src/core/lib/security/authorization/mock_cel/evaluator_core.h
- src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
- src/core/lib/matchers/matchers.h
- src/core/lib/security/context/security_context.h
- src/core/lib/security/credentials/alts/alts_credentials.h
- src/core/lib/security/credentials/alts/check_gcp_environment.h
@ -1280,9 +1272,7 @@ libs:
- src/core/lib/json/json_reader.cc
- src/core/lib/json/json_util.cc
- src/core/lib/json/json_writer.cc
- src/core/lib/security/authorization/authorization_engine.cc
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/matchers/matchers.cc
- src/core/lib/security/context/security_context.cc
- src/core/lib/security/credentials/alts/alts_credentials.cc
- src/core/lib/security/credentials/alts/check_gcp_environment.cc
@ -1415,7 +1405,6 @@ libs:
- absl/status:status
- absl/functional:bind_front
- absl/container:inlined_vector
- absl/container:flat_hash_set
- absl/container:flat_hash_map
baselib: true
generate_plugin_registry: true
@ -4965,8 +4954,20 @@ targets:
gtest: true
build: test
language: c++
headers: []
headers:
- src/core/lib/security/authorization/authorization_engine.h
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/mock_cel/activation.h
- src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h
- src/core/lib/security/authorization/mock_cel/cel_expression.h
- src/core/lib/security/authorization/mock_cel/cel_value.h
- src/core/lib/security/authorization/mock_cel/evaluator_core.h
- src/core/lib/security/authorization/mock_cel/flat_expr_builder.h
- src/core/lib/security/authorization/rbac_policy.h
src:
- src/core/lib/security/authorization/authorization_engine.cc
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/rbac_policy.cc
- test/core/security/authorization_engine_test.cc
deps:
- grpc_test_util
@ -4975,6 +4976,7 @@ targets:
- address_sorting
- upb
- libssl
- absl/container:flat_hash_set
- name: aws_request_signer_test
gtest: true
build: test
@ -6122,8 +6124,12 @@ targets:
gtest: true
build: test
language: c++
headers: []
headers:
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/rbac_policy.h
src:
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/rbac_policy.cc
- test/core/security/evaluate_args_test.cc
deps:
- grpc_test_util
@ -7333,6 +7339,26 @@ targets:
- address_sorting
- upb
- libssl
- name: rbac_translator_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/rbac_translator.h
src:
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/rbac_translator.cc
- test/core/security/rbac_translator_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- address_sorting
- upb
- libssl
- name: ref_counted_ptr_test
gtest: true
build: test

@ -493,11 +493,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
src/core/lib/security/authorization/authorization_engine.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/alts/alts_credentials.cc \
src/core/lib/security/credentials/alts/check_gcp_environment.cc \
@ -1125,8 +1123,8 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/executor)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/iomgr/poller)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/json)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/matchers)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/profiling)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/authorization)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/context)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/security/credentials/alts)

@ -460,11 +460,9 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\json\\json_reader.cc " +
"src\\core\\lib\\json\\json_util.cc " +
"src\\core\\lib\\json\\json_writer.cc " +
"src\\core\\lib\\matchers\\matchers.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +
"src\\core\\lib\\profiling\\stap_timers.cc " +
"src\\core\\lib\\security\\authorization\\authorization_engine.cc " +
"src\\core\\lib\\security\\authorization\\evaluate_args.cc " +
"src\\core\\lib\\security\\authorization\\matchers.cc " +
"src\\core\\lib\\security\\context\\security_context.cc " +
"src\\core\\lib\\security\\credentials\\alts\\alts_credentials.cc " +
"src\\core\\lib\\security\\credentials\\alts\\check_gcp_environment.cc " +
@ -1210,9 +1208,9 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\executor");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\iomgr\\poller");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\json");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\matchers");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\profiling");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\authorization");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\context");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\security\\credentials\\alts");

@ -189,7 +189,6 @@ Pod::Spec.new do |s|
abseil_version = '1.20200923.3'
ss.dependency 'abseil/base/base', abseil_version
ss.dependency 'abseil/container/flat_hash_map', abseil_version
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
ss.dependency 'abseil/functional/bind_front', abseil_version
ss.dependency 'abseil/memory/memory', abseil_version
@ -607,16 +606,8 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/json/json_util.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/mock_cel/activation.h',
'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
'src/core/lib/security/authorization/mock_cel/cel_expression.h',
'src/core/lib/security/authorization/mock_cel/cel_value.h',
'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',
@ -1233,16 +1224,8 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/json/json_util.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/mock_cel/activation.h',
'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
'src/core/lib/security/authorization/mock_cel/cel_expression.h',
'src/core/lib/security/authorization/mock_cel/cel_value.h',
'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',

@ -176,7 +176,6 @@ Pod::Spec.new do |s|
ss.dependency 'BoringSSL-GRPC', '0.0.17'
ss.dependency 'abseil/base/base', abseil_version
ss.dependency 'abseil/container/flat_hash_map', abseil_version
ss.dependency 'abseil/container/flat_hash_set', abseil_version
ss.dependency 'abseil/container/inlined_vector', abseil_version
ss.dependency 'abseil/functional/bind_front', abseil_version
ss.dependency 'abseil/memory/memory', abseil_version
@ -1049,21 +1048,11 @@ Pod::Spec.new do |s|
'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_util.h',
'src/core/lib/json/json_writer.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/matchers/matchers.h',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.cc',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/mock_cel/activation.h',
'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
'src/core/lib/security/authorization/mock_cel/cel_expression.h',
'src/core/lib/security/authorization/mock_cel/cel_value.h',
'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.cc',
@ -1773,16 +1762,8 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/json/json_util.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/mock_cel/activation.h',
'src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h',
'src/core/lib/security/authorization/mock_cel/cel_expression.h',
'src/core/lib/security/authorization/mock_cel/cel_value.h',
'src/core/lib/security/authorization/mock_cel/evaluator_core.h',
'src/core/lib/security/authorization/mock_cel/flat_expr_builder.h',
'src/core/lib/security/context/security_context.h',
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',

@ -964,21 +964,11 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/json/json_util.cc )
s.files += %w( src/core/lib/json/json_util.h )
s.files += %w( src/core/lib/json/json_writer.cc )
s.files += %w( src/core/lib/matchers/matchers.cc )
s.files += %w( src/core/lib/matchers/matchers.h )
s.files += %w( src/core/lib/profiling/basic_timers.cc )
s.files += %w( src/core/lib/profiling/stap_timers.cc )
s.files += %w( src/core/lib/profiling/timers.h )
s.files += %w( src/core/lib/security/authorization/authorization_engine.cc )
s.files += %w( src/core/lib/security/authorization/authorization_engine.h )
s.files += %w( src/core/lib/security/authorization/evaluate_args.cc )
s.files += %w( src/core/lib/security/authorization/evaluate_args.h )
s.files += %w( src/core/lib/security/authorization/matchers.cc )
s.files += %w( src/core/lib/security/authorization/matchers.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/activation.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/cel_expression.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/cel_value.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/evaluator_core.h )
s.files += %w( src/core/lib/security/authorization/mock_cel/flat_expr_builder.h )
s.files += %w( src/core/lib/security/context/security_context.cc )
s.files += %w( src/core/lib/security/context/security_context.h )
s.files += %w( src/core/lib/security/credentials/alts/alts_credentials.cc )
@ -1262,7 +1252,6 @@ Gem::Specification.new do |s|
s.files += %w( third_party/abseil-cpp/absl/base/thread_annotations.h )
s.files += %w( third_party/abseil-cpp/absl/container/fixed_array.h )
s.files += %w( third_party/abseil-cpp/absl/container/flat_hash_map.h )
s.files += %w( third_party/abseil-cpp/absl/container/flat_hash_set.h )
s.files += %w( third_party/abseil-cpp/absl/container/inlined_vector.h )
s.files += %w( third_party/abseil-cpp/absl/container/internal/common.h )
s.files += %w( third_party/abseil-cpp/absl/container/internal/compressed_tuple.h )

@ -449,7 +449,6 @@
'absl/status:status',
'absl/functional:bind_front',
'absl/container:inlined_vector',
'absl/container:flat_hash_set',
'absl/container:flat_hash_map',
],
'sources': [
@ -862,9 +861,7 @@
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/security/authorization/authorization_engine.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/alts/alts_credentials.cc',
'src/core/lib/security/credentials/alts/check_gcp_environment.cc',

@ -944,21 +944,11 @@
<file baseinstalldir="/" name="src/core/lib/json/json_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/matchers/matchers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/matchers/matchers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_engine.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_engine.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/evaluate_args.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/evaluate_args.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/matchers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/matchers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/activation.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_expression.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/cel_value.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/evaluator_core.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/mock_cel/flat_expr_builder.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/alts_credentials.cc" role="src" />
@ -1264,7 +1254,6 @@
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/base/thread_annotations.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/fixed_array.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/flat_hash_map.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/flat_hash_set.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/inlined_vector.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/internal/common.h" role="src" />
<file baseinstalldir="/" name="third_party/abseil-cpp/absl/container/internal/compressed_tuple.h" role="src" />

@ -37,7 +37,7 @@
#include "src/core/ext/xds/xds_bootstrap.h"
#include "src/core/ext/xds/xds_client_stats.h"
#include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/lib/security/authorization/matchers.h"
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {

@ -14,7 +14,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/authorization/matchers.h"
#include "src/core/lib/matchers/matchers.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
@ -29,12 +29,12 @@ namespace grpc_core {
//
absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
const std::string& matcher,
absl::string_view matcher,
bool case_sensitive) {
if (type == Type::SAFE_REGEX) {
RE2::Options options;
options.set_case_sensitive(case_sensitive);
auto regex_matcher = absl::make_unique<RE2>(matcher, options);
auto regex_matcher = absl::make_unique<RE2>(std::string(matcher), options);
if (!regex_matcher->ok()) {
return absl::InvalidArgumentError(
"Invalid regex string specified in matcher.");
@ -45,7 +45,7 @@ absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
}
}
StringMatcher::StringMatcher(Type type, const std::string& matcher,
StringMatcher::StringMatcher(Type type, absl::string_view matcher,
bool case_sensitive)
: type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {}
@ -164,7 +164,7 @@ std::string StringMatcher::ToString() const {
//
absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
const std::string& name, Type type, const std::string& matcher,
absl::string_view name, Type type, absl::string_view matcher,
int64_t range_start, int64_t range_end, bool present_match,
bool invert_match) {
if (static_cast<int>(type) < 5) {
@ -189,14 +189,14 @@ absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
}
}
HeaderMatcher::HeaderMatcher(const std::string& name, Type type,
HeaderMatcher::HeaderMatcher(absl::string_view name, Type type,
StringMatcher string_matcher, bool invert_match)
: name_(name),
type_(type),
matcher_(std::move(string_matcher)),
invert_match_(invert_match) {}
HeaderMatcher::HeaderMatcher(const std::string& name, int64_t range_start,
HeaderMatcher::HeaderMatcher(absl::string_view name, int64_t range_start,
int64_t range_end, bool invert_match)
: name_(name),
type_(Type::RANGE),
@ -204,7 +204,7 @@ HeaderMatcher::HeaderMatcher(const std::string& name, int64_t range_start,
range_end_(range_end),
invert_match_(invert_match) {}
HeaderMatcher::HeaderMatcher(const std::string& name, bool present_match,
HeaderMatcher::HeaderMatcher(absl::string_view name, bool present_match,
bool invert_match)
: name_(name),
type_(Type::PRESENT),

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
#ifndef GRPC_CORE_LIB_MATCHERS_MATCHERS_H
#define GRPC_CORE_LIB_MATCHERS_MATCHERS_H
#include <grpc/support/port_platform.h>
@ -40,7 +40,7 @@ class StringMatcher {
// Creates StringMatcher instance. Returns error status on failure.
static absl::StatusOr<StringMatcher> Create(Type type,
const std::string& matcher,
absl::string_view matcher,
bool case_sensitive = true);
StringMatcher() = default;
@ -65,7 +65,7 @@ class StringMatcher {
bool case_sensitive() const { return case_sensitive_; }
private:
StringMatcher(Type type, const std::string& matcher, bool case_sensitive);
StringMatcher(Type type, absl::string_view matcher, bool case_sensitive);
StringMatcher(std::unique_ptr<RE2> regex_matcher, bool case_sensitive);
Type type_ = Type::EXACT;
@ -106,10 +106,12 @@ class HeaderMatcher {
"");
// Creates HeaderMatcher instance. Returns error status on failure.
static absl::StatusOr<HeaderMatcher> Create(
const std::string& name, Type type, const std::string& matcher,
int64_t range_start = 0, int64_t range_end = 0,
bool present_match = false, bool invert_match = false);
static absl::StatusOr<HeaderMatcher> Create(absl::string_view name, Type type,
absl::string_view matcher,
int64_t range_start = 0,
int64_t range_end = 0,
bool present_match = false,
bool invert_match = false);
HeaderMatcher() = default;
HeaderMatcher(const HeaderMatcher& other);
@ -136,13 +138,13 @@ class HeaderMatcher {
private:
// For StringMatcher.
HeaderMatcher(const std::string& name, Type type, StringMatcher matcher,
HeaderMatcher(absl::string_view name, Type type, StringMatcher matcher,
bool invert_match);
// For RangeMatcher.
HeaderMatcher(const std::string& name, int64_t range_start, int64_t range_end,
HeaderMatcher(absl::string_view name, int64_t range_start, int64_t range_end,
bool invert_match);
// For PresentMatcher.
HeaderMatcher(const std::string& name, bool present_match, bool invert_match);
HeaderMatcher(absl::string_view name, bool present_match, bool invert_match);
std::string name_;
Type type_ = Type::EXACT;
@ -155,4 +157,4 @@ class HeaderMatcher {
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H */
#endif /* GRPC_CORE_LIB_MATCHERS_MATCHERS_H */

@ -0,0 +1,328 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/authorization/rbac_policy.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
namespace grpc_core {
//
// Rbac
//
Rbac::Rbac(Rbac::Action action, std::map<std::string, Policy> policies)
: action(action), policies(std::move(policies)) {}
Rbac::Rbac(Rbac&& other) noexcept
: action(other.action), policies(std::move(other.policies)) {}
Rbac& Rbac::operator=(Rbac&& other) noexcept {
action = other.action;
policies = std::move(other.policies);
return *this;
}
std::string Rbac::ToString() const {
std::vector<std::string> contents;
contents.push_back(absl::StrFormat(
"Rbac action=%s{", action == Rbac::Action::ALLOW ? "Allow" : "Deny"));
for (const auto& p : policies) {
contents.push_back(absl::StrFormat("{\n policy_name=%s\n%s\n}", p.first,
p.second.ToString()));
}
contents.push_back("}");
return absl::StrJoin(contents, "\n");
}
//
// CidrRange
//
Rbac::CidrRange::CidrRange(std::string address_prefix, uint32_t prefix_len)
: address_prefix(std::move(address_prefix)), prefix_len(prefix_len) {}
Rbac::CidrRange::CidrRange(Rbac::CidrRange&& other) noexcept
: address_prefix(std::move(other.address_prefix)),
prefix_len(other.prefix_len) {}
Rbac::CidrRange& Rbac::CidrRange::operator=(Rbac::CidrRange&& other) noexcept {
address_prefix = std::move(other.address_prefix);
prefix_len = other.prefix_len;
return *this;
}
std::string Rbac::CidrRange::ToString() const {
return absl::StrFormat("CidrRange{address_prefix=%s,prefix_len=%d}",
address_prefix, prefix_len);
}
//
// Permission
//
Rbac::Permission::Permission(
Permission::RuleType type,
std::vector<std::unique_ptr<Permission>> permissions, bool not_rule)
: type(type), permissions(std::move(permissions)), not_rule(not_rule) {}
Rbac::Permission::Permission(Permission::RuleType type, bool not_rule)
: type(type), not_rule(not_rule) {}
Rbac::Permission::Permission(Permission::RuleType type,
HeaderMatcher header_matcher, bool not_rule)
: type(type),
header_matcher(std::move(header_matcher)),
not_rule(not_rule) {}
Rbac::Permission::Permission(Permission::RuleType type,
StringMatcher string_matcher, bool not_rule)
: type(type),
string_matcher(std::move(string_matcher)),
not_rule(not_rule) {}
Rbac::Permission::Permission(Permission::RuleType type, CidrRange ip,
bool not_rule)
: type(type), ip(std::move(ip)), not_rule(not_rule) {}
Rbac::Permission::Permission(Permission::RuleType type, int port, bool not_rule)
: type(type), port(port), not_rule(not_rule) {}
Rbac::Permission::Permission(Rbac::Permission&& other) noexcept
: type(other.type), not_rule(other.not_rule) {
switch (type) {
case RuleType::AND:
case RuleType::OR:
permissions = std::move(other.permissions);
break;
case RuleType::ANY:
break;
case RuleType::HEADER:
header_matcher = std::move(other.header_matcher);
break;
case RuleType::PATH:
case RuleType::REQ_SERVER_NAME:
string_matcher = std::move(other.string_matcher);
break;
case RuleType::DEST_IP:
ip = std::move(other.ip);
break;
default:
port = other.port;
}
}
Rbac::Permission& Rbac::Permission::operator=(
Rbac::Permission&& other) noexcept {
type = other.type;
not_rule = other.not_rule;
switch (type) {
case RuleType::AND:
case RuleType::OR:
permissions = std::move(other.permissions);
break;
case RuleType::ANY:
break;
case RuleType::HEADER:
header_matcher = std::move(other.header_matcher);
break;
case RuleType::PATH:
case RuleType::REQ_SERVER_NAME:
string_matcher = std::move(other.string_matcher);
break;
case RuleType::DEST_IP:
ip = std::move(other.ip);
break;
default:
port = other.port;
}
return *this;
}
std::string Rbac::Permission::ToString() const {
switch (type) {
case RuleType::AND: {
std::vector<std::string> contents;
contents.reserve(permissions.size());
for (const auto& permission : permissions) {
contents.push_back(permission->ToString());
}
return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
absl::StrJoin(contents, ","));
}
case RuleType::OR: {
std::vector<std::string> contents;
contents.reserve(permissions.size());
for (const auto& permission : permissions) {
contents.push_back(permission->ToString());
}
return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
absl::StrJoin(contents, ","));
}
case RuleType::ANY:
return absl::StrFormat("%sany", not_rule ? "not " : "");
case RuleType::HEADER:
return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
header_matcher.ToString());
case RuleType::PATH:
return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
string_matcher.ToString());
case RuleType::DEST_IP:
return absl::StrFormat("%sdest_ip=%s", not_rule ? "not " : "",
ip.ToString());
case RuleType::DEST_PORT:
return absl::StrFormat("%sdest_port=%d", not_rule ? "not " : "", port);
case RuleType::REQ_SERVER_NAME:
return absl::StrFormat("%srequested_server_name=%s",
not_rule ? "not " : "", string_matcher.ToString());
default:
return "";
}
}
//
// Principal
//
Rbac::Principal::Principal(Principal::RuleType type,
std::vector<std::unique_ptr<Principal>> principals,
bool not_rule)
: type(type), principals(std::move(principals)), not_rule(not_rule) {}
Rbac::Principal::Principal(Principal::RuleType type, bool not_rule)
: type(type), not_rule(not_rule) {}
Rbac::Principal::Principal(Principal::RuleType type,
StringMatcher string_matcher, bool not_rule)
: type(type),
string_matcher(std::move(string_matcher)),
not_rule(not_rule) {}
Rbac::Principal::Principal(Principal::RuleType type, CidrRange ip,
bool not_rule)
: type(type), ip(std::move(ip)), not_rule(not_rule) {}
Rbac::Principal::Principal(Principal::RuleType type,
HeaderMatcher header_matcher, bool not_rule)
: type(type),
header_matcher(std::move(header_matcher)),
not_rule(not_rule) {}
Rbac::Principal::Principal(Rbac::Principal&& other) noexcept
: type(other.type), not_rule(other.not_rule) {
switch (type) {
case RuleType::AND:
case RuleType::OR:
principals = std::move(other.principals);
break;
case RuleType::ANY:
break;
case RuleType::HEADER:
header_matcher = std::move(other.header_matcher);
break;
case RuleType::PRINCIPAL_NAME:
case RuleType::PATH:
string_matcher = std::move(other.string_matcher);
break;
default:
ip = std::move(other.ip);
}
}
Rbac::Principal& Rbac::Principal::operator=(Rbac::Principal&& other) noexcept {
type = other.type;
not_rule = other.not_rule;
switch (type) {
case RuleType::AND:
case RuleType::OR:
principals = std::move(other.principals);
break;
case RuleType::ANY:
break;
case RuleType::HEADER:
header_matcher = std::move(other.header_matcher);
break;
case RuleType::PRINCIPAL_NAME:
case RuleType::PATH:
string_matcher = std::move(other.string_matcher);
break;
default:
ip = std::move(other.ip);
}
return *this;
}
std::string Rbac::Principal::ToString() const {
switch (type) {
case RuleType::AND: {
std::vector<std::string> contents;
contents.reserve(principals.size());
for (const auto& principal : principals) {
contents.push_back(principal->ToString());
}
return absl::StrFormat("%sand=[%s]", not_rule ? "not " : "",
absl::StrJoin(contents, ","));
}
case RuleType::OR: {
std::vector<std::string> contents;
contents.reserve(principals.size());
for (const auto& principal : principals) {
contents.push_back(principal->ToString());
}
return absl::StrFormat("%sor=[%s]", not_rule ? "not " : "",
absl::StrJoin(contents, ","));
}
case RuleType::ANY:
return absl::StrFormat("%sany", not_rule ? "not " : "");
case RuleType::PRINCIPAL_NAME:
return absl::StrFormat("%sprincipal_name=%s", not_rule ? "not " : "",
string_matcher.ToString());
case RuleType::SOURCE_IP:
return absl::StrFormat("%ssource_ip=%s", not_rule ? "not " : "",
ip.ToString());
case RuleType::DIRECT_REMOTE_IP:
return absl::StrFormat("%sdirect_remote_ip=%s", not_rule ? "not " : "",
ip.ToString());
case RuleType::REMOTE_IP:
return absl::StrFormat("%sremote_ip=%s", not_rule ? "not " : "",
ip.ToString());
case RuleType::HEADER:
return absl::StrFormat("%sheader=%s", not_rule ? "not " : "",
header_matcher.ToString());
case RuleType::PATH:
return absl::StrFormat("%spath=%s", not_rule ? "not " : "",
string_matcher.ToString());
default:
return "";
}
}
//
// Policy
//
Rbac::Policy::Policy(Permission permissions, Principal principals)
: permissions(std::move(permissions)), principals(std::move(principals)) {}
Rbac::Policy::Policy(Rbac::Policy&& other) noexcept
: permissions(std::move(other.permissions)),
principals(std::move(other.principals)) {}
Rbac::Policy& Rbac::Policy::operator=(Rbac::Policy&& other) noexcept {
permissions = std::move(other.permissions);
principals = std::move(other.principals);
return *this;
}
std::string Rbac::Policy::ToString() const {
return absl::StrFormat(
" Policy {\n Permissions{%s}\n Principals{%s}\n }",
permissions.ToString(), principals.ToString());
}
} // namespace grpc_core

@ -0,0 +1,163 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H
#include <grpc/support/port_platform.h>
#include <memory>
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {
// Represents Envoy RBAC Proto. [See
// https://github.com/envoyproxy/envoy/blob/release/v1.17/api/envoy/config/rbac/v3/rbac.proto]
struct Rbac {
enum class Action {
ALLOW,
DENY,
};
struct CidrRange {
CidrRange() = default;
CidrRange(std::string address_prefix, uint32_t prefix_len);
CidrRange(CidrRange&& other) noexcept;
CidrRange& operator=(CidrRange&& other) noexcept;
std::string ToString() const;
std::string address_prefix;
uint32_t prefix_len;
};
// TODO(ashithasantosh): Add metadata field to Permission and Principal.
struct Permission {
enum class RuleType {
AND,
OR,
ANY,
HEADER,
PATH,
DEST_IP,
DEST_PORT,
REQ_SERVER_NAME,
};
Permission() = default;
// For AND/OR RuleType.
Permission(Permission::RuleType type,
std::vector<std::unique_ptr<Permission>> permissions,
bool not_rule = false);
// For ANY RuleType.
explicit Permission(Permission::RuleType type, bool not_rule = false);
// For HEADER RuleType.
Permission(Permission::RuleType type, HeaderMatcher header_matcher,
bool not_rule = false);
// For PATH/REQ_SERVER_NAME RuleType.
Permission(Permission::RuleType type, StringMatcher string_matcher,
bool not_rule = false);
// For DEST_IP RuleType.
Permission(Permission::RuleType type, CidrRange ip, bool not_rule = false);
// For DEST_PORT RuleType.
Permission(Permission::RuleType type, int port, bool not_rule = false);
Permission(Permission&& other) noexcept;
Permission& operator=(Permission&& other) noexcept;
std::string ToString() const;
RuleType type;
HeaderMatcher header_matcher;
StringMatcher string_matcher;
CidrRange ip;
int port;
// For type AND/OR.
std::vector<std::unique_ptr<Permission>> permissions;
bool not_rule = false;
};
struct Principal {
enum class RuleType {
AND,
OR,
ANY,
PRINCIPAL_NAME,
SOURCE_IP,
DIRECT_REMOTE_IP,
REMOTE_IP,
HEADER,
PATH,
};
Principal() = default;
// For AND/OR RuleType.
Principal(Principal::RuleType type,
std::vector<std::unique_ptr<Principal>> principals,
bool not_rule = false);
// For ANY RuleType.
explicit Principal(Principal::RuleType type, bool not_rule = false);
// For PRINCIPAL_NAME/PATH RuleType.
Principal(Principal::RuleType type, StringMatcher string_matcher,
bool not_rule = false);
// For SOURCE_IP/DIRECT_REMOTE_IP/REMOTE_IP RuleType.
Principal(Principal::RuleType type, CidrRange ip, bool not_rule = false);
// For HEADER RuleType.
Principal(Principal::RuleType type, HeaderMatcher header_matcher,
bool not_rule = false);
Principal(Principal&& other) noexcept;
Principal& operator=(Principal&& other) noexcept;
std::string ToString() const;
RuleType type;
HeaderMatcher header_matcher;
StringMatcher string_matcher;
CidrRange ip;
// For type AND/OR.
std::vector<std::unique_ptr<Principal>> principals;
bool not_rule = false;
};
struct Policy {
Policy() = default;
Policy(Permission permissions, Principal principals);
Policy(Policy&& other) noexcept;
Policy& operator=(Policy&& other) noexcept;
std::string ToString() const;
Permission permissions;
Principal principals;
};
Rbac() = default;
Rbac(Rbac::Action action, std::map<std::string, Policy> policies);
Rbac(Rbac&& other) noexcept;
Rbac& operator=(Rbac&& other) noexcept;
std::string ToString() const;
Action action;
std::map<std::string, Policy> policies;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_POLICY_H */

@ -0,0 +1,354 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/authorization/rbac_translator.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/strip.h"
#include "src/core/lib/matchers/matchers.h"
namespace grpc_core {
namespace {
absl::string_view GetMatcherType(absl::string_view value,
StringMatcher::Type* type) {
if (value == "*") {
*type = StringMatcher::Type::PREFIX;
return "";
} else if (absl::StartsWith(value, "*")) {
*type = StringMatcher::Type::SUFFIX;
return absl::StripPrefix(value, "*");
} else if (absl::EndsWith(value, "*")) {
*type = StringMatcher::Type::PREFIX;
return absl::StripSuffix(value, "*");
}
*type = StringMatcher::Type::EXACT;
return value;
}
absl::StatusOr<StringMatcher> GetStringMatcher(absl::string_view value) {
StringMatcher::Type type;
absl::string_view matcher = GetMatcherType(value, &type);
return StringMatcher::Create(type, matcher);
}
absl::StatusOr<HeaderMatcher> GetHeaderMatcher(absl::string_view name,
absl::string_view value) {
StringMatcher::Type type;
absl::string_view matcher = GetMatcherType(value, &type);
return HeaderMatcher::Create(name, static_cast<HeaderMatcher::Type>(type),
matcher);
}
absl::StatusOr<Rbac::Principal> ParsePrincipalsArray(const Json& json) {
std::vector<std::unique_ptr<Rbac::Principal>> principal_names;
for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& child = json.array_value().at(i);
if (child.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
absl::StrCat("\"principals\" ", i, ": is not a string."));
}
auto matcher_or = GetStringMatcher(child.string_value());
if (!matcher_or.ok()) {
return absl::Status(matcher_or.status().code(),
absl::StrCat("\"principals\" ", i, ": ",
matcher_or.status().message()));
}
principal_names.push_back(absl::make_unique<Rbac::Principal>(
Rbac::Principal::RuleType::PRINCIPAL_NAME,
std::move(matcher_or.value())));
}
return Rbac::Principal(Rbac::Principal::RuleType::OR,
std::move(principal_names));
}
absl::StatusOr<Rbac::Principal> ParsePeer(const Json& json) {
std::vector<std::unique_ptr<Rbac::Principal>> peer;
auto it = json.object_value().find("principals");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"principals\" is not an array.");
}
auto principal_names_or = ParsePrincipalsArray(it->second);
if (!principal_names_or.ok()) return principal_names_or.status();
if (!principal_names_or.value().principals.empty()) {
peer.push_back(absl::make_unique<Rbac::Principal>(
std::move(principal_names_or.value())));
}
}
if (peer.empty()) {
return Rbac::Principal(Rbac::Principal::RuleType::ANY);
}
return Rbac::Principal(Rbac::Principal::RuleType::AND, std::move(peer));
}
absl::StatusOr<Rbac::Permission> ParseHeaderValues(
const Json& json, absl::string_view header_name) {
if (json.array_value().empty()) {
return absl::InvalidArgumentError("\"values\" list is empty.");
}
std::vector<std::unique_ptr<Rbac::Permission>> values;
for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& child = json.array_value().at(i);
if (child.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
absl::StrCat("\"values\" ", i, ": is not a string."));
}
auto matcher_or = GetHeaderMatcher(header_name, child.string_value());
if (!matcher_or.ok()) {
return absl::Status(
matcher_or.status().code(),
absl::StrCat("\"values\" ", i, ": ", matcher_or.status().message()));
}
values.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER, std::move(matcher_or.value())));
}
return Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(values));
}
absl::StatusOr<Rbac::Permission> ParseHeaders(const Json& json) {
auto it = json.object_value().find("key");
if (it == json.object_value().end()) {
return absl::InvalidArgumentError("\"key\" is not present.");
}
if (it->second.type() != Json::Type::STRING) {
return absl::InvalidArgumentError("\"key\" is not a string.");
}
absl::string_view header_name = it->second.string_value();
// TODO(ashithasantosh): Add connection headers below.
if (absl::StartsWith(header_name, ":") ||
absl::StartsWith(header_name, "grpc-") || header_name == "host" ||
header_name == "Host") {
return absl::InvalidArgumentError(
absl::StrFormat("Unsupported \"key\" %s.", header_name));
}
it = json.object_value().find("values");
if (it == json.object_value().end()) {
return absl::InvalidArgumentError("\"values\" is not present.");
}
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"values\" is not an array.");
}
return ParseHeaderValues(it->second, header_name);
}
absl::StatusOr<Rbac::Permission> ParseHeadersArray(const Json& json) {
std::vector<std::unique_ptr<Rbac::Permission>> headers;
for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& child = json.array_value().at(i);
if (child.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError(
absl::StrCat("\"headers\" ", i, ": is not an object."));
}
auto headers_or = ParseHeaders(child);
if (!headers_or.ok()) {
return absl::Status(
headers_or.status().code(),
absl::StrCat("\"headers\" ", i, ": ", headers_or.status().message()));
}
headers.push_back(
absl::make_unique<Rbac::Permission>(std::move(headers_or.value())));
}
return Rbac::Permission(Rbac::Permission::RuleType::AND, std::move(headers));
}
absl::StatusOr<Rbac::Permission> ParsePathsArray(const Json& json) {
std::vector<std::unique_ptr<Rbac::Permission>> paths;
for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& child = json.array_value().at(i);
if (child.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
absl::StrCat("\"paths\" ", i, ": is not a string."));
}
auto matcher_or = GetStringMatcher(child.string_value());
if (!matcher_or.ok()) {
return absl::Status(
matcher_or.status().code(),
absl::StrCat("\"paths\" ", i, ": ", matcher_or.status().message()));
}
paths.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::PATH, std::move(matcher_or.value())));
}
return Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(paths));
}
absl::StatusOr<Rbac::Permission> ParseRequest(const Json& json) {
std::vector<std::unique_ptr<Rbac::Permission>> request;
auto it = json.object_value().find("paths");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"paths\" is not an array.");
}
auto paths_or = ParsePathsArray(it->second);
if (!paths_or.ok()) return paths_or.status();
if (!paths_or.value().permissions.empty()) {
request.push_back(
absl::make_unique<Rbac::Permission>(std::move(paths_or.value())));
}
}
it = json.object_value().find("headers");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"headers\" is not an array.");
}
auto headers_or = ParseHeadersArray(it->second);
if (!headers_or.ok()) return headers_or.status();
if (!headers_or.value().permissions.empty()) {
request.push_back(
absl::make_unique<Rbac::Permission>(std::move(headers_or.value())));
}
}
if (request.empty()) {
return Rbac::Permission(Rbac::Permission::RuleType::ANY);
}
return Rbac::Permission(Rbac::Permission::RuleType::AND, std::move(request));
}
absl::StatusOr<Rbac::Policy> ParseRules(const Json& json) {
Rbac::Principal principals;
auto it = json.object_value().find("source");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError("\"source\" is not an object.");
}
auto peer_or = ParsePeer(it->second);
if (!peer_or.ok()) return peer_or.status();
principals = std::move(peer_or.value());
} else {
principals = Rbac::Principal(Rbac::Principal::RuleType::ANY);
}
Rbac::Permission permissions;
it = json.object_value().find("request");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError("\"request\" is not an object.");
}
auto request_or = ParseRequest(it->second);
if (!request_or.ok()) return request_or.status();
permissions = std::move(request_or.value());
} else {
permissions = Rbac::Permission(Rbac::Permission::RuleType::ANY);
}
return Rbac::Policy(std::move(permissions), std::move(principals));
}
absl::StatusOr<std::map<std::string, Rbac::Policy>> ParseRulesArray(
const Json& json, absl::string_view name) {
std::map<std::string, Rbac::Policy> policies;
for (size_t i = 0; i < json.array_value().size(); ++i) {
const Json& child = json.array_value().at(i);
if (child.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError(
absl::StrCat("rules ", i, ": is not an object."));
}
auto it = child.object_value().find("name");
if (it == child.object_value().end()) {
return absl::InvalidArgumentError(
absl::StrCat("rules ", i, ": \"name\" is not present."));
}
if (it->second.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
absl::StrCat("rules ", i, ": \"name\" is not a string."));
}
std::string policy_name =
std::string(name) + "_" + it->second.string_value();
auto policy_or = ParseRules(child);
if (!policy_or.ok()) {
return absl::Status(
policy_or.status().code(),
absl::StrCat("rules ", i, ": ", policy_or.status().message()));
}
policies[policy_name] = std::move(policy_or.value());
}
return std::move(policies);
}
absl::StatusOr<Rbac> ParseDenyRulesArray(const Json& json,
absl::string_view name) {
auto policies_or = ParseRulesArray(json, name);
if (!policies_or.ok()) return policies_or.status();
return Rbac(Rbac::Action::DENY, std::move(policies_or.value()));
}
absl::StatusOr<Rbac> ParseAllowRulesArray(const Json& json,
absl::string_view name) {
auto policies_or = ParseRulesArray(json, name);
if (!policies_or.ok()) return policies_or.status();
return Rbac(Rbac::Action::ALLOW, std::move(policies_or.value()));
}
} // namespace
absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
absl::string_view authz_policy) {
grpc_error* error = GRPC_ERROR_NONE;
Json json = Json::Parse(authz_policy, &error);
if (error != GRPC_ERROR_NONE) {
absl::Status status = absl::InvalidArgumentError(
absl::StrCat("Failed to parse SDK authorization policy. Error: ",
grpc_error_string(error)));
GRPC_ERROR_UNREF(error);
return status;
}
if (json.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError(
"SDK authorization policy is not an object.");
}
auto it = json.mutable_object()->find("name");
if (it == json.mutable_object()->end()) {
return absl::InvalidArgumentError("\"name\" field is not present.");
}
if (it->second.type() != Json::Type::STRING) {
return absl::InvalidArgumentError("\"name\" is not a string.");
}
absl::string_view name = it->second.string_value();
RbacPolicies rbac_policies;
it = json.mutable_object()->find("deny_rules");
if (it != json.mutable_object()->end()) {
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"deny_rules\" is not an array.");
}
auto deny_policy_or = ParseDenyRulesArray(it->second, name);
if (!deny_policy_or.ok()) {
return absl::Status(
deny_policy_or.status().code(),
absl::StrCat("deny_", deny_policy_or.status().message()));
}
rbac_policies.deny_policy = std::move(deny_policy_or.value());
} else {
rbac_policies.deny_policy.action = Rbac::Action::DENY;
}
it = json.mutable_object()->find("allow_rules");
if (it == json.mutable_object()->end()) {
return absl::InvalidArgumentError("\"allow_rules\" is not present.");
}
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("\"allow_rules\" is not an array.");
}
auto allow_policy_or = ParseAllowRulesArray(it->second, name);
if (!allow_policy_or.ok()) {
return absl::Status(
allow_policy_or.status().code(),
absl::StrCat("allow_", allow_policy_or.status().message()));
}
rbac_policies.allow_policy = std::move(allow_policy_or.value());
return std::move(rbac_policies);
}
} // namespace grpc_core

@ -0,0 +1,39 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H
#include <grpc/support/port_platform.h>
#include "absl/status/statusor.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/security/authorization/rbac_policy.h"
namespace grpc_core {
struct RbacPolicies {
Rbac deny_policy;
Rbac allow_policy;
};
// Translates SDK authorization policy to Envoy RBAC policies. Returns error on
// failure.
// authz_policy: Authorization Policy string in JSON format.
absl::StatusOr<RbacPolicies> GenerateRbacPolicies(
absl::string_view authz_policy);
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_RBAC_TRANSLATOR_H */

@ -469,11 +469,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/security/authorization/authorization_engine.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/alts/alts_credentials.cc',
'src/core/lib/security/credentials/alts/check_gcp_environment.cc',

@ -80,6 +80,7 @@ grpc_cc_test(
deps = [
"//:gpr",
"//:grpc",
"//:grpc_cel_engine",
"//test/core/util:grpc_test_util",
],
)
@ -116,6 +117,7 @@ grpc_cc_test(
deps = [
"//:gpr",
"//:grpc",
"//:grpc_rbac_engine",
"//test/core/util:grpc_test_util",
"//test/core/util:grpc_test_util_base",
],
@ -406,6 +408,20 @@ grpc_cc_test(
deps = [
"//:gpr",
"//:grpc",
"//:grpc_secure",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "rbac_translator_test",
srcs = ["rbac_translator_test.cc"],
external_deps = ["gtest"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc_authorization_provider",
"//test/core/util:grpc_test_util",
],
)

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/security/authorization/matchers.h"
#include "src/core/lib/matchers/matchers.h"
#include <gtest/gtest.h>

@ -0,0 +1,804 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/core/lib/security/authorization/rbac_translator.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace grpc_core {
namespace {
MATCHER_P2(EqualsPrincipalName, expected_matcher_type, expected_matcher_value,
"") {
return arg->type == Rbac::Principal::RuleType::PRINCIPAL_NAME &&
arg->string_matcher.type() == expected_matcher_type &&
arg->string_matcher.string_matcher() == expected_matcher_value;
}
MATCHER_P2(EqualsPath, expected_matcher_type, expected_matcher_value, "") {
return arg->type == Rbac::Permission::RuleType::PATH &&
arg->string_matcher.type() == expected_matcher_type &&
arg->string_matcher.string_matcher() == expected_matcher_value;
}
MATCHER_P3(EqualsHeader, expected_name, expected_matcher_type,
expected_matcher_value, "") {
return arg->type == Rbac::Permission::RuleType::HEADER &&
arg->header_matcher.name() == expected_name &&
arg->header_matcher.type() == expected_matcher_type &&
arg->header_matcher.string_matcher() == expected_matcher_value;
}
} // namespace
TEST(GenerateRbacPoliciesTest, InvalidPolicy) {
const char* authz_policy =
"{"
" \"name\": \"authz-policy\",,"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(rbac_policies.status().message()),
::testing::StartsWith("Failed to parse SDK authorization policy."));
}
TEST(GenerateRbacPoliciesTest, MissingAuthorizationPolicyName) {
const char* authz_policy = "{}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(), "\"name\" field is not present.");
}
TEST(GenerateRbacPoliciesTest, IncorrectAuthorizationPolicyNameType) {
const char* authz_policy =
"{"
" \"name\": [\"authz_policy\"]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(), "\"name\" is not a string.");
}
TEST(GenerateRbacPoliciesTest, MissingAllowRules) {
const char* authz_policy =
"{"
" \"name\": \"authz_policy\""
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"\"allow_rules\" is not present.");
}
TEST(GenerateRbacPoliciesTest, MissingDenyRules) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\""
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
}
TEST(GenerateRbacPoliciesTest, IncorrectAllowRulesType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": {}"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"\"allow_rules\" is not an array.");
}
TEST(GenerateRbacPoliciesTest, IncorrectDenyRulesType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": 123"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"\"deny_rules\" is not an array.");
}
TEST(GenerateRbacPoliciesTest, IncorrectRuleType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": [\"rule-a\"]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: is not an object.");
}
TEST(GenerateRbacPoliciesTest, MissingRuleNameField) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": [{}]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"name\" is not present.");
}
TEST(GenerateRbacPoliciesTest, IncorrectRuleNameType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": 123"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"name\" is not a string.");
}
TEST(GenerateRbacPoliciesTest, MissingSourceAndRequest) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\""
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_allow_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY))))));
}
TEST(GenerateRbacPoliciesTest, EmptySourceAndRequest) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"source\": {},"
" \"request\": {}"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_allow_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY))))));
}
TEST(GenerateRbacPoliciesTest, IncorrectSourceType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"source\": 111"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"source\" is not an object.");
}
TEST(GenerateRbacPoliciesTest, IncorrectPrincipalsType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"source\": {"
" \"principals\": ["
" \"*\","
" 123"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"principals\" 1: is not a string.");
}
TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"source\": {"
" \"principals\": ["
" \"spiffe://foo.abc\","
" \"spiffe://bar*\","
" \"*baz\","
" \"spiffe://abc.*.com\""
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_policy\","
" \"source\": {"
" \"principals\": ["
" \"*\""
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(
rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_allow_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::principals,
::testing::AllOf(
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::AND),
::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Principal::type,
Rbac::Principal::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(
EqualsPrincipalName(
StringMatcher::Type::EXACT,
"spiffe://foo.abc"),
EqualsPrincipalName(
StringMatcher::Type::PREFIX,
"spiffe://bar"),
EqualsPrincipalName(
StringMatcher::Type::SUFFIX, "baz"),
EqualsPrincipalName(
StringMatcher::Type::EXACT,
"spiffe://abc.*.com")))))))))))));
EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
EXPECT_THAT(
rbac_policies.value().deny_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_deny_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::principals,
::testing::AllOf(
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::AND),
::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Principal::type,
Rbac::Principal::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(EqualsPrincipalName(
StringMatcher::Type::PREFIX,
"")))))))))))));
}
TEST(GenerateRbacPoliciesTest, IncorrectRequestType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": ["
" {"
" \"name\": \"deny_policy\","
" \"request\": 111"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"deny_rules 0: \"request\" is not an object.");
}
TEST(GenerateRbacPoliciesTest, IncorrectPathType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"request\": {"
" \"paths\": ["
" \"path-a\","
" 123"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"deny_rules 0: \"paths\" 1: is not a string.");
}
TEST(GenerateRbacPoliciesTest, ParseRequestPathsSuccess) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"request\": {"
" \"paths\": ["
" \"*\""
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_policy\","
" \"request\": {"
" \"paths\": ["
" \"path-foo\","
" \"path-bar*\","
" \"*baz\""
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
EXPECT_THAT(
rbac_policies.value().deny_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_deny_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::permissions,
::testing::AllOf(
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::AND),
::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(
EqualsPath(StringMatcher::Type::EXACT,
"path-foo"),
EqualsPath(StringMatcher::Type::PREFIX,
"path-bar"),
EqualsPath(StringMatcher::Type::SUFFIX,
"baz")))))))))))));
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_allow_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::permissions,
::testing::AllOf(
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::AND),
::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(EqualsPath(
StringMatcher::Type::PREFIX,
"")))))))))))));
}
TEST(GenerateRbacPoliciesTest, IncorrectHeaderType) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"request\": {"
" \"headers\": ["
" \"header-a\""
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"deny_rules 0: \"headers\" 0: is not an object.");
}
TEST(GenerateRbacPoliciesTest, UnsupportedGrpcHeaders) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": ["
" {"
" \"name\": \"policy\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \"grpc-xxx\","
" \"values\": ["
" \"*\""
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"deny_rules 0: \"headers\" 0: Unsupported \"key\" grpc-xxx.");
}
TEST(GenerateRbacPoliciesTest, UnsupportedPseudoHeaders) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"policy\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \":method\","
" \"values\": ["
" \"*\""
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"headers\" 0: Unsupported \"key\" :method.");
}
TEST(GenerateRbacPoliciesTest, UnsupportedhostHeader) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"deny_rules\": ["
" {"
" \"name\": \"policy\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \"host\","
" \"values\": ["
" \"*\""
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"deny_rules 0: \"headers\" 0: Unsupported \"key\" host.");
}
TEST(GenerateRbacPoliciesTest, UnsupportedHostHeader) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"policy\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \"Host\","
" \"values\": ["
" \"*\""
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"headers\" 0: Unsupported \"key\" Host.");
}
TEST(GenerateRbacPoliciesTest, EmptyHeaderValuesList) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy_1\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \"key-a\","
" \"values\": ["
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(rbac_policies.status().message(),
"allow_rules 0: \"headers\" 0: \"values\" list is empty.");
}
TEST(GenerateRbacPoliciesTest, ParseRequestHeadersSuccess) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy\","
" \"request\": {"
" \"headers\": ["
" {"
" \"key\": \"key-1\","
" \"values\": ["
" \"*\""
" ]"
" },"
" {"
" \"key\": \"key-2\","
" \"values\": ["
" \"foo\","
" \"bar*\","
" \"*baz\""
" ]"
" }"
" ]"
" }"
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(
rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(::testing::Pair(
"authz_allow_policy",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::permissions,
::testing::AllOf(
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::AND),
::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::AND)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(
::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(
EqualsHeader("key-1",
HeaderMatcher::
Type::PREFIX,
""))))),
::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(
EqualsHeader("key-2",
HeaderMatcher::
Type::EXACT,
"foo"),
EqualsHeader("key-2",
HeaderMatcher::
Type::PREFIX,
"bar"),
EqualsHeader(
"key-2",
HeaderMatcher::Type::
SUFFIX,
"baz")))))))))))))))));
}
TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) {
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_policy_1\","
" \"source\": {"
" \"principals\": ["
" \"spiffe://foo.abc\""
" ]"
" },"
" \"request\": {"
" \"paths\": ["
" \"foo\""
" ]"
" }"
" },"
" {"
" \"name\": \"allow_policy_2\""
" }"
" ]"
"}";
auto rbac_policies = GenerateRbacPolicies(authz_policy);
ASSERT_TRUE(rbac_policies.ok());
EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::DENY);
EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty());
EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::ALLOW);
EXPECT_THAT(
rbac_policies.value().allow_policy.policies,
::testing::ElementsAre(
::testing::Pair(
"authz_allow_policy_1",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::AllOf(
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::AND),
::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Permission::type,
Rbac::Permission::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Permission::permissions,
::testing::ElementsAre(
EqualsPath(StringMatcher::Type::EXACT,
"foo"))))))))),
::testing::Field(
&Rbac::Policy::principals,
::testing::AllOf(
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::AND),
::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(::testing::AllOf(
::testing::Pointee(::testing::Field(
&Rbac::Principal::type,
Rbac::Principal::RuleType::OR)),
::testing::Pointee(::testing::Field(
&Rbac::Principal::principals,
::testing::ElementsAre(
EqualsPrincipalName(
StringMatcher::Type::EXACT,
"spiffe://foo.abc"))))))))))),
::testing::Pair(
"authz_allow_policy_2",
::testing::AllOf(
::testing::Field(
&Rbac::Policy::permissions,
::testing::Field(&Rbac::Permission::type,
Rbac::Permission::RuleType::ANY)),
::testing::Field(
&Rbac::Policy::principals,
::testing::Field(&Rbac::Principal::type,
Rbac::Principal::RuleType::ANY))))));
}
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1896,21 +1896,11 @@ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_util.cc \
src/core/lib/json/json_util.h \
src/core/lib/json/json_writer.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/matchers/matchers.h \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
src/core/lib/profiling/timers.h \
src/core/lib/security/authorization/authorization_engine.cc \
src/core/lib/security/authorization/authorization_engine.h \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/evaluate_args.h \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/matchers.h \
src/core/lib/security/authorization/mock_cel/activation.h \
src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h \
src/core/lib/security/authorization/mock_cel/cel_expression.h \
src/core/lib/security/authorization/mock_cel/cel_value.h \
src/core/lib/security/authorization/mock_cel/evaluator_core.h \
src/core/lib/security/authorization/mock_cel/flat_expr_builder.h \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/context/security_context.h \
src/core/lib/security/credentials/alts/alts_credentials.cc \

@ -1736,21 +1736,11 @@ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_util.cc \
src/core/lib/json/json_util.h \
src/core/lib/json/json_writer.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/matchers/matchers.h \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
src/core/lib/profiling/timers.h \
src/core/lib/security/authorization/authorization_engine.cc \
src/core/lib/security/authorization/authorization_engine.h \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/evaluate_args.h \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/matchers.h \
src/core/lib/security/authorization/mock_cel/activation.h \
src/core/lib/security/authorization/mock_cel/cel_expr_builder_factory.h \
src/core/lib/security/authorization/mock_cel/cel_expression.h \
src/core/lib/security/authorization/mock_cel/cel_value.h \
src/core/lib/security/authorization/mock_cel/evaluator_core.h \
src/core/lib/security/authorization/mock_cel/flat_expr_builder.h \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/context/security_context.h \
src/core/lib/security/credentials/alts/alts_credentials.cc \

@ -5367,6 +5367,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": "rbac_translator_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save