SDK authorization filter. (#26468)

* SDK authorization filter.
pull/27139/head
Ashitha Santhosh 4 years ago committed by GitHub
parent 2d1ca227a6
commit 1ff1f8fd83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      BUILD
  2. 62
      CMakeLists.txt
  3. 2
      Makefile
  4. 38
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 1
      doc/environment_variables.md
  8. 2
      gRPC-C++.podspec
  9. 16
      gRPC-Core.podspec
  10. 2
      grpc.gemspec
  11. 7
      grpc.gyp
  12. 2
      package.xml
  13. 9
      src/core/lib/security/authorization/authorization_policy_provider.h
  14. 7
      src/core/lib/security/authorization/grpc_authorization_policy_provider.h
  15. 159
      src/core/lib/security/authorization/sdk_server_authz_filter.cc
  16. 67
      src/core/lib/security/authorization/sdk_server_authz_filter.h
  17. 22
      src/core/lib/surface/init_secure.cc
  18. 1
      src/python/grpcio/grpc_core_dependencies.py
  19. 8
      test/core/end2end/end2end_tests.cc
  20. 2
      test/core/end2end/generate_tests.bzl
  21. 439
      test/core/end2end/tests/sdk_authz.cc
  22. 17
      test/core/security/grpc_authorization_policy_provider_test.cc
  23. 19
      test/cpp/end2end/BUILD
  24. 360
      test/cpp/end2end/sdk_authz_end2end_test.cc
  25. 2
      tools/doxygen/Doxyfile.c++.internal
  26. 2
      tools/doxygen/Doxyfile.core.internal
  27. 24
      tools/run_tests/generated/tests.json

@ -2513,6 +2513,7 @@ grpc_cc_library(
"src/core/lib/http/httpcli_security_connector.cc",
"src/core/lib/security/authorization/authorization_policy_provider_vtable.cc",
"src/core/lib/security/authorization/evaluate_args.cc",
"src/core/lib/security/authorization/sdk_server_authz_filter.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/credentials/alts/alts_credentials.cc",
"src/core/lib/security/credentials/composite/composite_credentials.cc",
@ -2565,6 +2566,7 @@ grpc_cc_library(
"src/core/lib/security/authorization/authorization_engine.h",
"src/core/lib/security/authorization/authorization_policy_provider.h",
"src/core/lib/security/authorization/evaluate_args.h",
"src/core/lib/security/authorization/sdk_server_authz_filter.h",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",

62
CMakeLists.txt generated

@ -939,6 +939,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx remove_stream_from_stalled_lists_test)
endif()
add_dependencies(buildtests_cxx retry_throttle_test)
add_dependencies(buildtests_cxx sdk_authz_end2end_test)
add_dependencies(buildtests_cxx secure_auth_context_test)
add_dependencies(buildtests_cxx seq_test)
add_dependencies(buildtests_cxx server_builder_plugin_test)
@ -1226,6 +1227,11 @@ endif()
if(gRPC_BUILD_TESTS)
add_library(end2end_tests
src/core/lib/security/authorization/grpc_authorization_engine.cc
src/core/lib/security/authorization/grpc_authorization_policy_provider.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_translator.cc
test/core/end2end/cq_verifier.cc
test/core/end2end/data/client_certs.cc
test/core/end2end/data/server1_cert.cc
@ -1309,6 +1315,7 @@ add_library(end2end_tests
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
test/core/end2end/tests/retry_throttled.cc
test/core/end2end/tests/retry_too_many_attempts.cc
test/core/end2end/tests/sdk_authz.cc
test/core/end2end/tests/server_finishes_request.cc
test/core/end2end/tests/server_streaming.cc
test/core/end2end/tests/shutdown_finishes_calls.cc
@ -1983,6 +1990,7 @@ add_library(grpc
src/core/lib/matchers/matchers.cc
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/sdk_server_authz_filter.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
@ -13914,6 +13922,60 @@ target_link_libraries(retry_throttle_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(sdk_authz_end2end_test
${_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
src/core/lib/security/authorization/grpc_authorization_engine.cc
src/core/lib/security/authorization/grpc_authorization_policy_provider.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_translator.cc
src/cpp/server/authorization_policy_provider.cc
test/cpp/end2end/sdk_authz_end2end_test.cc
test/cpp/end2end/test_service_impl.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(sdk_authz_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(sdk_authz_end2end_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_util
)
endif()
if(gRPC_BUILD_TESTS)

2
Makefile generated

@ -1493,6 +1493,7 @@ LIBGRPC_SRC = \
src/core/lib/matchers/matchers.cc \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/sdk_server_authz_filter.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 \
@ -2911,6 +2912,7 @@ src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/matchers/matchers.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/evaluate_args.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/sdk_server_authz_filter.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)

@ -132,6 +132,11 @@ libs:
language: c
public_headers: []
headers:
- src/core/lib/security/authorization/grpc_authorization_engine.h
- src/core/lib/security/authorization/grpc_authorization_policy_provider.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/rbac_translator.h
- test/core/end2end/cq_verifier.h
- test/core/end2end/data/ssl_test_data.h
- test/core/end2end/end2end_tests.h
@ -141,6 +146,11 @@ libs:
- test/core/end2end/tests/cancel_test_helpers.h
- test/core/util/test_lb_policies.h
src:
- src/core/lib/security/authorization/grpc_authorization_engine.cc
- src/core/lib/security/authorization/grpc_authorization_policy_provider.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/rbac_translator.cc
- test/core/end2end/cq_verifier.cc
- test/core/end2end/data/client_certs.cc
- test/core/end2end/data/server1_cert.cc
@ -224,6 +234,7 @@ libs:
- test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
- test/core/end2end/tests/retry_throttled.cc
- test/core/end2end/tests/retry_too_many_attempts.cc
- test/core/end2end/tests/sdk_authz.cc
- test/core/end2end/tests/server_finishes_request.cc
- test/core/end2end/tests/server_streaming.cc
- test/core/end2end/tests/shutdown_finishes_calls.cc
@ -835,6 +846,7 @@ libs:
- src/core/lib/security/authorization/authorization_engine.h
- src/core/lib/security/authorization/authorization_policy_provider.h
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/sdk_server_authz_filter.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
@ -1389,6 +1401,7 @@ libs:
- src/core/lib/matchers/matchers.cc
- src/core/lib/security/authorization/authorization_policy_provider_vtable.cc
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/sdk_server_authz_filter.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
@ -6526,6 +6539,31 @@ targets:
deps:
- grpc_test_util
uses_polling: false
- name: sdk_authz_end2end_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/security/authorization/grpc_authorization_engine.h
- src/core/lib/security/authorization/grpc_authorization_policy_provider.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/rbac_translator.h
- test/cpp/end2end/test_service_impl.h
src:
- src/proto/grpc/testing/echo.proto
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/simple_messages.proto
- src/core/lib/security/authorization/grpc_authorization_engine.cc
- src/core/lib/security/authorization/grpc_authorization_policy_provider.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/rbac_translator.cc
- src/cpp/server/authorization_policy_provider.cc
- test/cpp/end2end/sdk_authz_end2end_test.cc
- test/cpp/end2end/test_service_impl.cc
deps:
- grpc++_test_util
- name: secure_auth_context_test
gtest: true
build: test

1
config.m4 generated

@ -546,6 +546,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/profiling/stap_timers.cc \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/sdk_server_authz_filter.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 \

1
config.w32 generated

@ -512,6 +512,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\profiling\\stap_timers.cc " +
"src\\core\\lib\\security\\authorization\\authorization_policy_provider_vtable.cc " +
"src\\core\\lib\\security\\authorization\\evaluate_args.cc " +
"src\\core\\lib\\security\\authorization\\sdk_server_authz_filter.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 " +

@ -78,6 +78,7 @@ some configuration as environment variables that can be set.
- ring_hash_lb - traces the ring hash load balancing policy
- round_robin - traces the round_robin load balancing policy
- queue_pluck
- sdk_authz - traces sdk authorization
- server_channel - lightweight trace of significant server channel events
- secure_endpoint - traces bytes flowing through encrypted channels
- subchannel - traces the connectivity state of subchannel

2
gRPC-C++.podspec generated

@ -660,6 +660,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',
@ -1326,6 +1327,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',

16
gRPC-Core.podspec generated

@ -1157,6 +1157,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/sdk_server_authz_filter.cc',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',
@ -1914,6 +1916,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',
'src/core/lib/security/authorization/evaluate_args.h',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',
@ -2099,7 +2102,17 @@ Pod::Spec.new do |s|
ss.dependency 'abseil/debugging/stacktrace', abseil_version
ss.dependency 'abseil/debugging/symbolize', abseil_version
ss.source_files = 'test/core/end2end/cq_verifier.cc',
ss.source_files = 'src/core/lib/security/authorization/grpc_authorization_engine.cc',
'src/core/lib/security/authorization/grpc_authorization_engine.h',
'src/core/lib/security/authorization/grpc_authorization_policy_provider.cc',
'src/core/lib/security/authorization/grpc_authorization_policy_provider.h',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/rbac_policy.h',
'src/core/lib/security/authorization/rbac_translator.cc',
'src/core/lib/security/authorization/rbac_translator.h',
'test/core/end2end/cq_verifier.cc',
'test/core/end2end/cq_verifier.h',
'test/core/end2end/data/client_certs.cc',
'test/core/end2end/data/server1_cert.cc',
@ -2189,6 +2202,7 @@ Pod::Spec.new do |s|
'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
'test/core/end2end/tests/retry_throttled.cc',
'test/core/end2end/tests/retry_too_many_attempts.cc',
'test/core/end2end/tests/sdk_authz.cc',
'test/core/end2end/tests/server_finishes_request.cc',
'test/core/end2end/tests/server_streaming.cc',
'test/core/end2end/tests/shutdown_finishes_calls.cc',

2
grpc.gemspec generated

@ -1070,6 +1070,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/authorization/authorization_policy_provider_vtable.cc )
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/sdk_server_authz_filter.cc )
s.files += %w( src/core/lib/security/authorization/sdk_server_authz_filter.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 )

7
grpc.gyp generated

@ -288,6 +288,11 @@
'grpc_test_util',
],
'sources': [
'src/core/lib/security/authorization/grpc_authorization_engine.cc',
'src/core/lib/security/authorization/grpc_authorization_policy_provider.cc',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/rbac_translator.cc',
'test/core/end2end/cq_verifier.cc',
'test/core/end2end/data/client_certs.cc',
'test/core/end2end/data/server1_cert.cc',
@ -371,6 +376,7 @@
'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
'test/core/end2end/tests/retry_throttled.cc',
'test/core/end2end/tests/retry_too_many_attempts.cc',
'test/core/end2end/tests/sdk_authz.cc',
'test/core/end2end/tests/server_finishes_request.cc',
'test/core/end2end/tests/server_streaming.cc',
'test/core/end2end/tests/shutdown_finishes_calls.cc',
@ -926,6 +932,7 @@
'src/core/lib/matchers/matchers.cc',
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',

2
package.xml generated

@ -1050,6 +1050,8 @@
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_policy_provider_vtable.cc" 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/sdk_server_authz_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/sdk_server_authz_filter.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" />

@ -23,10 +23,11 @@
struct grpc_authorization_policy_provider
: public grpc_core::DualRefCounted<grpc_authorization_policy_provider> {
public:
virtual grpc_core::RefCountedPtr<grpc_core::AuthorizationEngine>
allow_engine() const = 0;
virtual grpc_core::RefCountedPtr<grpc_core::AuthorizationEngine> deny_engine()
const = 0;
struct AuthorizationEngines {
grpc_core::RefCountedPtr<grpc_core::AuthorizationEngine> allow_engine;
grpc_core::RefCountedPtr<grpc_core::AuthorizationEngine> deny_engine;
};
virtual AuthorizationEngines engines() const = 0;
};
#endif // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_POLICY_PROVIDER_H

@ -38,11 +38,8 @@ class StaticDataAuthorizationPolicyProvider
explicit StaticDataAuthorizationPolicyProvider(RbacPolicies policies);
RefCountedPtr<AuthorizationEngine> allow_engine() const override {
return allow_engine_;
}
RefCountedPtr<AuthorizationEngine> deny_engine() const override {
return deny_engine_;
AuthorizationEngines engines() const override {
return {allow_engine_, deny_engine_};
}
void Orphan() override {}

@ -0,0 +1,159 @@
// 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/sdk_server_authz_filter.h"
#include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/transport/transport.h"
namespace grpc_core {
TraceFlag grpc_sdk_authz_trace(false, "sdk_authz");
SdkServerAuthzFilter::SdkServerAuthzFilter(
RefCountedPtr<grpc_auth_context> auth_context, grpc_endpoint* endpoint,
RefCountedPtr<grpc_authorization_policy_provider> provider)
: auth_context_(std::move(auth_context)),
per_channel_evaluate_args_(auth_context_.get(), endpoint),
provider_(std::move(provider)) {}
grpc_error_handle SdkServerAuthzFilter::Init(grpc_channel_element* elem,
grpc_channel_element_args* args) {
GPR_ASSERT(!args->is_last);
grpc_auth_context* auth_context =
grpc_find_auth_context_in_args(args->channel_args);
grpc_authorization_policy_provider* provider =
grpc_channel_args_find_pointer<grpc_authorization_policy_provider>(
args->channel_args, GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER);
if (provider == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Failed to get authorization provider.");
}
// grpc_endpoint isn't needed because the current SDK authorization policy
// does not support any rules that requires looking for source or destination
// addresses.
new (elem->channel_data) SdkServerAuthzFilter(
auth_context != nullptr ? auth_context->Ref() : nullptr,
/*endpoint=*/nullptr, provider->Ref());
return GRPC_ERROR_NONE;
}
void SdkServerAuthzFilter::Destroy(grpc_channel_element* elem) {
auto* chand = static_cast<SdkServerAuthzFilter*>(elem->channel_data);
chand->~SdkServerAuthzFilter();
}
SdkServerAuthzFilter::CallData::CallData(grpc_call_element* elem) {
GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady,
elem, grpc_schedule_on_exec_ctx);
}
void SdkServerAuthzFilter::CallData::StartTransportStreamOpBatch(
grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
auto* calld = static_cast<CallData*>(elem->call_data);
if (batch->recv_initial_metadata) {
// Inject our callback.
calld->recv_initial_metadata_batch_ =
batch->payload->recv_initial_metadata.recv_initial_metadata;
calld->original_recv_initial_metadata_ready_ =
batch->payload->recv_initial_metadata.recv_initial_metadata_ready;
batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
&calld->recv_initial_metadata_ready_;
}
grpc_call_next_op(elem, batch);
}
grpc_error_handle SdkServerAuthzFilter::CallData::Init(
grpc_call_element* elem, const grpc_call_element_args*) {
new (elem->call_data) CallData(elem);
return GRPC_ERROR_NONE;
}
void SdkServerAuthzFilter::CallData::Destroy(
grpc_call_element* elem, const grpc_call_final_info* /*final_info*/,
grpc_closure* /*ignored*/) {
CallData* calld = static_cast<CallData*>(elem->call_data);
calld->~CallData();
}
bool SdkServerAuthzFilter::CallData::IsAuthorized(SdkServerAuthzFilter* chand) {
EvaluateArgs args(recv_initial_metadata_batch_,
&chand->per_channel_evaluate_args_);
grpc_authorization_policy_provider::AuthorizationEngines engines =
chand->provider_->engines();
if (engines.deny_engine != nullptr) {
AuthorizationEngine::Decision decision =
engines.deny_engine->Evaluate(args);
if (decision.type == AuthorizationEngine::Decision::Type::kDeny) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_sdk_authz_trace)) {
gpr_log(GPR_INFO, "chand=%p calld=%p: request denied by policy %s.",
chand, this, decision.matching_policy_name.c_str());
}
return false;
}
}
if (engines.allow_engine != nullptr) {
AuthorizationEngine::Decision decision =
engines.allow_engine->Evaluate(args);
if (decision.type == AuthorizationEngine::Decision::Type::kAllow) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_sdk_authz_trace)) {
gpr_log(GPR_INFO, "chand=%p calld=%p: request allowed by policy %s.",
chand, this, decision.matching_policy_name.c_str());
}
return true;
}
}
if (GRPC_TRACE_FLAG_ENABLED(grpc_sdk_authz_trace)) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: request denied, no matching policy found.",
chand, this);
}
return false;
}
void SdkServerAuthzFilter::CallData::RecvInitialMetadataReady(
void* arg, grpc_error_handle error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
auto* chand = static_cast<SdkServerAuthzFilter*>(elem->channel_data);
auto* calld = static_cast<CallData*>(elem->call_data);
if (error == GRPC_ERROR_NONE) {
if (!calld->IsAuthorized(chand)) {
error = grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Unauthorized RPC request rejected."),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_PERMISSION_DENIED);
}
} else {
GRPC_ERROR_REF(error);
}
Closure::Run(DEBUG_LOCATION, calld->original_recv_initial_metadata_ready_,
error);
}
const grpc_channel_filter SdkServerAuthzFilter::kFilterVtable = {
SdkServerAuthzFilter::CallData::StartTransportStreamOpBatch,
grpc_channel_next_op,
sizeof(SdkServerAuthzFilter::CallData),
SdkServerAuthzFilter::CallData::Init,
grpc_call_stack_ignore_set_pollset_or_pollset_set,
SdkServerAuthzFilter::CallData::Destroy,
sizeof(SdkServerAuthzFilter),
SdkServerAuthzFilter::Init,
SdkServerAuthzFilter::Destroy,
grpc_channel_next_get_info,
"sdk-server-authz"};
} // namespace grpc_core

@ -0,0 +1,67 @@
// 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_SDK_SERVER_AUTHZ_FILTER_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_SDK_SERVER_AUTHZ_FILTER_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/security/authorization/authorization_policy_provider.h"
namespace grpc_core {
class SdkServerAuthzFilter {
public:
static const grpc_channel_filter kFilterVtable;
private:
class CallData {
public:
static void StartTransportStreamOpBatch(
grpc_call_element* elem, grpc_transport_stream_op_batch* batch);
static grpc_error_handle Init(grpc_call_element* elem,
const grpc_call_element_args*);
static void Destroy(grpc_call_element* elem,
const grpc_call_final_info* /*final_info*/,
grpc_closure* /*ignored*/);
private:
explicit CallData(grpc_call_element* elem);
bool IsAuthorized(SdkServerAuthzFilter* chand);
static void RecvInitialMetadataReady(void* arg, grpc_error_handle error);
grpc_metadata_batch* recv_initial_metadata_batch_;
grpc_closure* original_recv_initial_metadata_ready_;
grpc_closure recv_initial_metadata_ready_;
};
SdkServerAuthzFilter(
RefCountedPtr<grpc_auth_context> auth_context, grpc_endpoint* endpoint,
RefCountedPtr<grpc_authorization_policy_provider> provider);
static grpc_error_handle Init(grpc_channel_element* elem,
grpc_channel_element_args* args);
static void Destroy(grpc_channel_element* elem);
RefCountedPtr<grpc_auth_context> auth_context_;
EvaluateArgs::PerChannelArgs per_channel_evaluate_args_;
RefCountedPtr<grpc_authorization_policy_provider> provider_;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_SDK_SERVER_AUTHZ_FILTER_H

@ -24,6 +24,7 @@
#include <string.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/security/authorization/sdk_server_authz_filter.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
@ -66,6 +67,21 @@ static bool maybe_prepend_server_auth_filter(
return true;
}
static bool maybe_prepend_sdk_server_authz_filter(
grpc_channel_stack_builder* builder, void* /*arg*/) {
const grpc_channel_args* args =
grpc_channel_stack_builder_get_channel_arguments(builder);
const auto* provider =
grpc_channel_args_find_pointer<grpc_authorization_policy_provider>(
args, GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER);
if (provider != nullptr) {
return grpc_channel_stack_builder_prepend_filter(
builder, &grpc_core::SdkServerAuthzFilter::kFilterVtable, nullptr,
nullptr);
}
return true;
}
void grpc_register_security_filters(void) {
// Register the auth client with a priority < INT_MAX to allow the authority
// filter -on which the auth filter depends- to be higher on the channel
@ -76,6 +92,12 @@ void grpc_register_security_filters(void) {
maybe_prepend_client_auth_filter, nullptr);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX - 1,
maybe_prepend_server_auth_filter, nullptr);
// Register the SdkServerAuthzFilter with a priority less than
// server_auth_filter to allow server_auth_filter on which the sdk filter
// depends on to be higher on the channel stack.
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX - 2,
maybe_prepend_sdk_server_authz_filter,
nullptr);
}
void grpc_security_init() { grpc_core::SecurityRegisterHandshakerFactories(); }

@ -521,6 +521,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/sdk_server_authz_filter.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',

@ -175,6 +175,8 @@ extern void retry_throttled(grpc_end2end_test_config config);
extern void retry_throttled_pre_init(void);
extern void retry_too_many_attempts(grpc_end2end_test_config config);
extern void retry_too_many_attempts_pre_init(void);
extern void sdk_authz(grpc_end2end_test_config config);
extern void sdk_authz_pre_init(void);
extern void server_finishes_request(grpc_end2end_test_config config);
extern void server_finishes_request_pre_init(void);
extern void server_streaming(grpc_end2end_test_config config);
@ -284,6 +286,7 @@ void grpc_end2end_tests_pre_init(void) {
retry_streaming_succeeds_before_replay_finished_pre_init();
retry_throttled_pre_init();
retry_too_many_attempts_pre_init();
sdk_authz_pre_init();
server_finishes_request_pre_init();
server_streaming_pre_init();
shutdown_finishes_calls_pre_init();
@ -383,6 +386,7 @@ void grpc_end2end_tests(int argc, char **argv,
retry_streaming_succeeds_before_replay_finished(config);
retry_throttled(config);
retry_too_many_attempts(config);
sdk_authz(config);
server_finishes_request(config);
server_streaming(config);
shutdown_finishes_calls(config);
@ -695,6 +699,10 @@ void grpc_end2end_tests(int argc, char **argv,
retry_too_many_attempts(config);
continue;
}
if (0 == strcmp("sdk_authz", argv[i])) {
sdk_authz(config);
continue;
}
if (0 == strcmp("server_finishes_request", argv[i])) {
server_finishes_request(config);
continue;

@ -333,6 +333,7 @@ END2END_TESTS = {
),
"retry_throttled": _test_options(needs_client_channel = True),
"retry_too_many_attempts": _test_options(needs_client_channel = True),
"sdk_authz": _test_options(secure = True),
"server_finishes_request": _test_options(),
"server_streaming": _test_options(needs_http2 = True),
"shutdown_finishes_calls": _test_options(),
@ -420,6 +421,7 @@ def grpc_end2end_tests():
":proxy",
":local_util",
"//test/core/util:test_lb_policies",
"//:grpc_authorization_provider",
],
)

@ -0,0 +1,439 @@
// 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 "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/security/authorization/grpc_authorization_policy_provider.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "test/core/end2end/cq_verifier.h"
static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
static void test_allow_authorized_request(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_status_code status;
const char* error_string = nullptr;
grpc_call_error error;
grpc_slice details = grpc_empty_slice();
int was_cancelled = 2;
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_foo\","
" \"request\": {"
" \"paths\": ["
" \"*/foo\""
" ]"
" }"
" }"
" ]"
"}";
grpc_status_code code;
const char* error_details;
grpc_authorization_policy_provider* provider =
grpc_authorization_policy_provider_static_data_create(authz_policy, &code,
&error_details);
GPR_ASSERT(GRPC_STATUS_OK == code);
grpc_arg args[] = {
grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER), provider,
grpc_authorization_policy_provider_arg_vtable()),
};
grpc_channel_args server_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f = begin_test(
config, "test_allow_authorized_request", nullptr, &server_args);
grpc_authorization_policy_provider_release(provider);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"), nullptr,
deadline, nullptr);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->data.recv_status_on_client.error_string = &error_string;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
cq_verify(cqv);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_OK;
grpc_slice status_details = grpc_slice_from_static_string("xyz");
op->data.send_status_from_server.status_details = &status_details;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(GRPC_STATUS_OK == status);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
grpc_slice_unref(details);
gpr_free(const_cast<char*>(error_string));
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
static void test_deny_unauthorized_request(grpc_end2end_test_config config) {
grpc_call* c;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_status_code status;
const char* error_string = nullptr;
grpc_call_error error;
grpc_slice details = grpc_empty_slice();
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_foo\","
" \"request\": {"
" \"paths\": ["
" \"*/foo\""
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_bar\","
" \"request\": {"
" \"paths\": ["
" \"*/bar\""
" ]"
" }"
" }"
" ]"
"}";
grpc_status_code code;
const char* error_details;
grpc_authorization_policy_provider* provider =
grpc_authorization_policy_provider_static_data_create(authz_policy, &code,
&error_details);
GPR_ASSERT(GRPC_STATUS_OK == code);
grpc_arg args[] = {
grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER), provider,
grpc_authorization_policy_provider_arg_vtable()),
};
grpc_channel_args server_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f = begin_test(
config, "test_deny_unauthorized_request", nullptr, &server_args);
grpc_authorization_policy_provider_release(provider);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/bar"), nullptr,
deadline, nullptr);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->data.recv_status_on_client.error_string = &error_string;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(GRPC_STATUS_PERMISSION_DENIED == status);
GPR_ASSERT(0 ==
grpc_slice_str_cmp(details, "Unauthorized RPC request rejected."));
grpc_slice_unref(details);
gpr_free(const_cast<char*>(error_string));
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_call_unref(c);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
static void test_deny_request_no_match_in_policy(
grpc_end2end_test_config config) {
grpc_call* c;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_status_code status;
const char* error_string = nullptr;
grpc_call_error error;
grpc_slice details = grpc_empty_slice();
const char* authz_policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_foo\","
" \"request\": {"
" \"paths\": ["
" \"*/foo\""
" ]"
" }"
" }"
" ]"
"}";
grpc_status_code code;
const char* error_details;
grpc_authorization_policy_provider* provider =
grpc_authorization_policy_provider_static_data_create(authz_policy, &code,
&error_details);
GPR_ASSERT(GRPC_STATUS_OK == code);
grpc_arg args[] = {
grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_AUTHORIZATION_POLICY_PROVIDER), provider,
grpc_authorization_policy_provider_arg_vtable()),
};
grpc_channel_args server_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f = begin_test(
config, "test_deny_request_no_match_in_policy", nullptr, &server_args);
grpc_authorization_policy_provider_release(provider);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/bar"), nullptr,
deadline, nullptr);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->data.recv_status_on_client.error_string = &error_string;
op->flags = 0;
op->reserved = nullptr;
op++;
error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(GRPC_STATUS_PERMISSION_DENIED == status);
GPR_ASSERT(0 ==
grpc_slice_str_cmp(details, "Unauthorized RPC request rejected."));
grpc_slice_unref(details);
gpr_free(const_cast<char*>(error_string));
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_call_unref(c);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void sdk_authz(grpc_end2end_test_config config) {
test_allow_authorized_request(config);
test_deny_unauthorized_request(config);
test_deny_request_no_match_in_policy(config);
}
void sdk_authz_pre_init(void) {}

@ -36,14 +36,15 @@ TEST(AuthorizationPolicyProviderTest, StaticDataInitializationSuccessful) {
"}";
auto provider = StaticDataAuthorizationPolicyProvider::Create(authz_policy);
ASSERT_TRUE(provider.ok());
auto* allow_engine =
dynamic_cast<GrpcAuthorizationEngine*>((*provider)->allow_engine().get());
ASSERT_NE(allow_engine, nullptr);
EXPECT_EQ(allow_engine->action(), Rbac::Action::kAllow);
auto* deny_engine =
dynamic_cast<GrpcAuthorizationEngine*>((*provider)->deny_engine().get());
ASSERT_NE(deny_engine, nullptr);
EXPECT_EQ(deny_engine->action(), Rbac::Action::kDeny);
auto engines = (*provider)->engines();
ASSERT_NE(engines.allow_engine, nullptr);
EXPECT_EQ(dynamic_cast<GrpcAuthorizationEngine*>(engines.allow_engine.get())
->action(),
Rbac::Action::kAllow);
ASSERT_NE(engines.deny_engine, nullptr);
EXPECT_EQ(dynamic_cast<GrpcAuthorizationEngine*>(engines.deny_engine.get())
->action(),
Rbac::Action::kDeny);
}
TEST(AuthorizationPolicyProviderTest,

@ -891,3 +891,22 @@ grpc_cc_test(
"//test/cpp/util:test_util",
],
)
grpc_cc_test(
name = "sdk_authz_end2end_test",
srcs = ["sdk_authz_end2end_test.cc"],
external_deps = [
"gtest",
],
deps = [
":test_service_impl",
"//:gpr",
"//:grpc",
"//:grpc++",
"//:grpc++_authorization_provider",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],
)

@ -0,0 +1,360 @@
// 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/authorization_policy_provider.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/server/secure_server_credentials.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/end2end/test_service_impl.h"
namespace grpc {
namespace testing {
namespace {
constexpr char kMessage[] = "Hello";
class SdkAuthzEnd2EndTest : public ::testing::Test {
protected:
SdkAuthzEnd2EndTest()
: server_address_(
absl::StrCat("localhost:", grpc_pick_unused_port_or_die())),
server_creds_(
std::shared_ptr<ServerCredentials>(new SecureServerCredentials(
grpc_fake_transport_security_server_credentials_create()))),
channel_creds_(
std::shared_ptr<ChannelCredentials>(new SecureChannelCredentials(
grpc_fake_transport_security_credentials_create()))) {}
~SdkAuthzEnd2EndTest() override { server_->Shutdown(); }
// Replaces existing credentials with insecure credentials.
void UseInsecureCredentials() {
server_creds_ = InsecureServerCredentials();
channel_creds_ = InsecureChannelCredentials();
}
// Creates server with sdk authorization enabled when provider is not null.
void InitServer(
std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
provider) {
ServerBuilder builder;
builder.AddListeningPort(server_address_, std::move(server_creds_));
builder.experimental().SetAuthorizationPolicyProvider(std::move(provider));
builder.RegisterService(&service_);
server_ = builder.BuildAndStart();
}
std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
CreateStaticAuthzPolicyProvider(const std::string& policy) {
grpc::Status status;
auto provider = experimental::StaticDataAuthorizationPolicyProvider::Create(
policy, &status);
EXPECT_TRUE(status.ok());
return provider;
}
std::shared_ptr<Channel> BuildChannel() {
ChannelArguments args;
return ::grpc::CreateCustomChannel(server_address_, channel_creds_, args);
}
grpc::Status SendRpc(const std::shared_ptr<Channel>& channel,
ClientContext* context,
grpc::testing::EchoResponse* response = nullptr) {
auto stub = grpc::testing::EchoTestService::NewStub(channel);
grpc::testing::EchoRequest request;
request.set_message(kMessage);
return stub->Echo(context, request, response);
}
std::string server_address_;
TestServiceImpl service_;
std::unique_ptr<Server> server_;
std::shared_ptr<ServerCredentials> server_creds_;
std::shared_ptr<ChannelCredentials> channel_creds_;
};
TEST_F(SdkAuthzEnd2EndTest,
StaticInitAllowsRpcRequestNoMatchInDenyMatchInAllow) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_echo\","
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ],"
" \"headers\": ["
" {"
" \"key\": \"key-foo\","
" \"values\": [\"foo1\", \"foo2\"]"
" },"
" {"
" \"key\": \"key-bar\","
" \"values\": [\"bar1\"]"
" }"
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_clientstreamingecho\","
" \"request\": {"
" \"paths\": ["
" \"*/ClientStreamingEcho\""
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
context.AddMetadata("key-foo", "foo2");
context.AddMetadata("key-bar", "bar1");
context.AddMetadata("key-baz", "baz1");
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_TRUE(status.ok());
EXPECT_EQ(resp.message(), kMessage);
}
TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestNoMatchInAllowAndDeny) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_foo\","
" \"request\": {"
" \"paths\": ["
" \"*/foo\""
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_bar\","
" \"source\": {"
" \"principals\": ["
" \"bar\""
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
EXPECT_TRUE(resp.message().empty());
}
TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestMatchInDenyMatchInAllow) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_all\""
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_echo\","
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
EXPECT_TRUE(resp.message().empty());
}
TEST_F(SdkAuthzEnd2EndTest,
StaticInitDeniesRpcRequestMatchInDenyNoMatchInAllow) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_clientstreamingecho\","
" \"request\": {"
" \"paths\": ["
" \"*/ClientStreamingEcho\""
" ]"
" }"
" }"
" ],"
" \"deny_rules\": ["
" {"
" \"name\": \"deny_echo\","
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
EXPECT_TRUE(resp.message().empty());
}
TEST_F(SdkAuthzEnd2EndTest, StaticInitAllowsRpcRequestEmptyDenyMatchInAllow) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_echo\","
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ],"
" \"headers\": ["
" {"
" \"key\": \"key-foo\","
" \"values\": [\"foo1\", \"foo2\"]"
" },"
" {"
" \"key\": \"key-bar\","
" \"values\": [\"bar1\"]"
" }"
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
context.AddMetadata("key-foo", "foo2");
context.AddMetadata("key-bar", "bar1");
context.AddMetadata("key-baz", "baz1");
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_TRUE(status.ok());
EXPECT_EQ(resp.message(), kMessage);
}
TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestEmptyDenyNoMatchInAllow) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_echo\","
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ],"
" \"headers\": ["
" {"
" \"key\": \"key-foo\","
" \"values\": [\"foo1\"]"
" }"
" ]"
" }"
" }"
" ]"
"}";
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
context.AddMetadata("key-bar", "bar1");
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
EXPECT_TRUE(resp.message().empty());
}
TEST_F(
SdkAuthzEnd2EndTest,
StaticInitDeniesRpcRequestWithPrincipalsFieldOnUnauthenticatedConnection) {
std::string policy =
"{"
" \"name\": \"authz\","
" \"allow_rules\": ["
" {"
" \"name\": \"allow_echo\","
" \"source\": {"
" \"principals\": ["
" \"foo\""
" ]"
" },"
" \"request\": {"
" \"paths\": ["
" \"*/Echo\""
" ]"
" }"
" }"
" ]"
"}";
UseInsecureCredentials();
InitServer(CreateStaticAuthzPolicyProvider(policy));
auto channel = BuildChannel();
ClientContext context;
grpc::testing::EchoResponse resp;
grpc::Status status = SendRpc(channel, &context, &resp);
EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
EXPECT_TRUE(resp.message().empty());
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
const auto result = RUN_ALL_TESTS();
return result;
}

@ -2003,6 +2003,8 @@ src/core/lib/security/authorization/authorization_policy_provider.h \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/evaluate_args.h \
src/core/lib/security/authorization/sdk_server_authz_filter.cc \
src/core/lib/security/authorization/sdk_server_authz_filter.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 \

@ -1843,6 +1843,8 @@ src/core/lib/security/authorization/authorization_policy_provider.h \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/evaluate_args.h \
src/core/lib/security/authorization/sdk_server_authz_filter.cc \
src/core/lib/security/authorization/sdk_server_authz_filter.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 \

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

Loading…
Cancel
Save