RBAC engine matchers implementation. (#25997)

pull/26012/head
Ashitha Santhosh 4 years ago committed by GitHub
parent d4f6cfd535
commit 628bf7fe08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      BUILD
  2. 56
      CMakeLists.txt
  3. 43
      build_autogenerated.yaml
  4. 12
      src/core/lib/security/authorization/cel_authorization_engine.cc
  5. 24
      src/core/lib/security/authorization/cel_authorization_engine.h
  6. 202
      src/core/lib/security/authorization/matchers.cc
  7. 206
      src/core/lib/security/authorization/matchers.h
  8. 17
      test/core/security/BUILD
  9. 420
      test/core/security/authorization_matchers_test.cc
  10. 44
      test/core/security/cel_authorization_engine_test.cc
  11. 26
      tools/run_tests/generated/tests.json

@ -2061,10 +2061,12 @@ grpc_cc_library(
name = "grpc_rbac_engine", name = "grpc_rbac_engine",
srcs = [ srcs = [
"src/core/lib/security/authorization/evaluate_args.cc", "src/core/lib/security/authorization/evaluate_args.cc",
"src/core/lib/security/authorization/matchers.cc",
"src/core/lib/security/authorization/rbac_policy.cc", "src/core/lib/security/authorization/rbac_policy.cc",
], ],
hdrs = [ hdrs = [
"src/core/lib/security/authorization/evaluate_args.h", "src/core/lib/security/authorization/evaluate_args.h",
"src/core/lib/security/authorization/matchers.h",
"src/core/lib/security/authorization/rbac_policy.h", "src/core/lib/security/authorization/rbac_policy.h",
], ],
language = "c++", language = "c++",
@ -2095,10 +2097,10 @@ grpc_cc_library(
grpc_cc_library( grpc_cc_library(
name = "grpc_cel_engine", name = "grpc_cel_engine",
srcs = [ srcs = [
"src/core/lib/security/authorization/authorization_engine.cc", "src/core/lib/security/authorization/cel_authorization_engine.cc",
], ],
hdrs = [ hdrs = [
"src/core/lib/security/authorization/authorization_engine.h", "src/core/lib/security/authorization/cel_authorization_engine.h",
], ],
external_deps = [ external_deps = [
"absl/container:flat_hash_set", "absl/container:flat_hash_set",

@ -737,7 +737,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx alts_util_test) add_dependencies(buildtests_cxx alts_util_test)
add_dependencies(buildtests_cxx async_end2end_test) add_dependencies(buildtests_cxx async_end2end_test)
add_dependencies(buildtests_cxx auth_property_iterator_test) add_dependencies(buildtests_cxx auth_property_iterator_test)
add_dependencies(buildtests_cxx authorization_engine_test) add_dependencies(buildtests_cxx authorization_matchers_test)
add_dependencies(buildtests_cxx aws_request_signer_test) add_dependencies(buildtests_cxx aws_request_signer_test)
add_dependencies(buildtests_cxx backoff_test) add_dependencies(buildtests_cxx backoff_test)
add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test) add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
@ -811,6 +811,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx byte_buffer_test) add_dependencies(buildtests_cxx byte_buffer_test)
add_dependencies(buildtests_cxx byte_stream_test) add_dependencies(buildtests_cxx byte_stream_test)
add_dependencies(buildtests_cxx cancel_ares_query_test) add_dependencies(buildtests_cxx cancel_ares_query_test)
add_dependencies(buildtests_cxx cel_authorization_engine_test)
add_dependencies(buildtests_cxx certificate_provider_registry_test) add_dependencies(buildtests_cxx certificate_provider_registry_test)
add_dependencies(buildtests_cxx certificate_provider_store_test) add_dependencies(buildtests_cxx certificate_provider_store_test)
add_dependencies(buildtests_cxx cfstream_test) add_dependencies(buildtests_cxx cfstream_test)
@ -8022,16 +8023,16 @@ target_link_libraries(auth_property_iterator_test
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
add_executable(authorization_engine_test add_executable(authorization_matchers_test
src/core/lib/security/authorization/authorization_engine.cc
src/core/lib/security/authorization/evaluate_args.cc src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc src/core/lib/security/authorization/rbac_policy.cc
test/core/security/authorization_engine_test.cc test/core/security/authorization_matchers_test.cc
third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc third_party/googletest/googlemock/src/gmock-all.cc
) )
target_include_directories(authorization_engine_test target_include_directories(authorization_matchers_test
PRIVATE PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include
@ -8050,10 +8051,9 @@ target_include_directories(authorization_engine_test
${_gRPC_PROTO_GENS_DIR} ${_gRPC_PROTO_GENS_DIR}
) )
target_link_libraries(authorization_engine_test target_link_libraries(authorization_matchers_test
${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES}
absl::flat_hash_set
grpc_test_util grpc_test_util
) )
@ -9133,6 +9133,46 @@ target_link_libraries(cancel_ares_query_test
) )
endif()
if(gRPC_BUILD_TESTS)
add_executable(cel_authorization_engine_test
src/core/lib/security/authorization/cel_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
test/core/security/cel_authorization_engine_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(cel_authorization_engine_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(cel_authorization_engine_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::flat_hash_set
grpc_test_util
)
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
@ -10282,6 +10322,7 @@ if(gRPC_BUILD_TESTS)
add_executable(evaluate_args_test add_executable(evaluate_args_test
src/core/lib/security/authorization/evaluate_args.cc src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc src/core/lib/security/authorization/rbac_policy.cc
test/core/security/evaluate_args_test.cc test/core/security/evaluate_args_test.cc
third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googletest/src/gtest-all.cc
@ -12724,6 +12765,7 @@ if(gRPC_BUILD_TESTS)
add_executable(rbac_translator_test add_executable(rbac_translator_test
src/core/lib/security/authorization/evaluate_args.cc src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_translator.cc src/core/lib/security/authorization/rbac_translator.cc
test/core/security/rbac_translator_test.cc test/core/security/rbac_translator_test.cc

@ -4246,27 +4246,20 @@ targets:
deps: deps:
- grpc++_test_util - grpc++_test_util
uses_polling: false uses_polling: false
- name: authorization_engine_test - name: authorization_matchers_test
gtest: true gtest: true
build: test build: test
language: c++ 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/evaluate_args.h
- src/core/lib/security/authorization/mock_cel/activation.h - src/core/lib/security/authorization/matchers.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/core/lib/security/authorization/rbac_policy.h
src: src:
- src/core/lib/security/authorization/authorization_engine.cc
- src/core/lib/security/authorization/evaluate_args.cc - src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc - src/core/lib/security/authorization/rbac_policy.cc
- test/core/security/authorization_engine_test.cc - test/core/security/authorization_matchers_test.cc
deps: deps:
- absl/container:flat_hash_set
- grpc_test_util - grpc_test_util
- name: aws_request_signer_test - name: aws_request_signer_test
gtest: true gtest: true
@ -4672,6 +4665,30 @@ targets:
deps: deps:
- grpc++_test_config - grpc++_test_config
- grpc++_test_util - grpc++_test_util
- name: cel_authorization_engine_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/security/authorization/cel_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/authorization/rbac_policy.h
src:
- src/core/lib/security/authorization/cel_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
- test/core/security/cel_authorization_engine_test.cc
deps:
- absl/container:flat_hash_set
- grpc_test_util
- name: certificate_provider_registry_test - name: certificate_provider_registry_test
gtest: true gtest: true
build: test build: test
@ -5055,9 +5072,11 @@ targets:
language: c++ language: c++
headers: headers:
- src/core/lib/security/authorization/evaluate_args.h - src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h - src/core/lib/security/authorization/rbac_policy.h
src: src:
- src/core/lib/security/authorization/evaluate_args.cc - src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc - src/core/lib/security/authorization/rbac_policy.cc
- test/core/security/evaluate_args_test.cc - test/core/security/evaluate_args_test.cc
deps: deps:
@ -5935,10 +5954,12 @@ targets:
language: c++ language: c++
headers: headers:
- src/core/lib/security/authorization/evaluate_args.h - src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h - src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/rbac_translator.h - src/core/lib/security/authorization/rbac_translator.h
src: src:
- src/core/lib/security/authorization/evaluate_args.cc - src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc - src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/rbac_translator.cc - src/core/lib/security/authorization/rbac_translator.cc
- test/core/security/rbac_translator_test.cc - test/core/security/rbac_translator_test.cc

@ -16,7 +16,7 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "src/core/lib/security/authorization/authorization_engine.h" #include "src/core/lib/security/authorization/cel_authorization_engine.h"
namespace grpc_core { namespace grpc_core {
@ -36,8 +36,8 @@ constexpr char kCertServerName[] = "cert_server_name";
} // namespace } // namespace
std::unique_ptr<AuthorizationEngine> std::unique_ptr<CelAuthorizationEngine>
AuthorizationEngine::CreateAuthorizationEngine( CelAuthorizationEngine::CreateCelAuthorizationEngine(
const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) { const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
if (rbac_policies.empty() || rbac_policies.size() > 2) { if (rbac_policies.empty() || rbac_policies.size() > 2) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
@ -52,11 +52,11 @@ AuthorizationEngine::CreateAuthorizationEngine(
policy and one allow policy, in that order."); policy and one allow policy, in that order.");
return nullptr; return nullptr;
} else { } else {
return absl::make_unique<AuthorizationEngine>(rbac_policies); return absl::make_unique<CelAuthorizationEngine>(rbac_policies);
} }
} }
AuthorizationEngine::AuthorizationEngine( CelAuthorizationEngine::CelAuthorizationEngine(
const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) { const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies) {
for (const auto& rbac_policy : rbac_policies) { for (const auto& rbac_policy : rbac_policies) {
// Extract array of policies and store their condition fields in either // Extract array of policies and store their condition fields in either
@ -90,7 +90,7 @@ AuthorizationEngine::AuthorizationEngine(
} }
} }
std::unique_ptr<mock_cel::Activation> AuthorizationEngine::CreateActivation( std::unique_ptr<mock_cel::Activation> CelAuthorizationEngine::CreateActivation(
const EvaluateArgs& args) { const EvaluateArgs& args) {
std::unique_ptr<mock_cel::Activation> activation; std::unique_ptr<mock_cel::Activation> activation;
for (const auto& elem : envoy_attributes_) { for (const auto& elem : envoy_attributes_) {

@ -13,8 +13,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H #ifndef GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H #define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
@ -34,7 +34,7 @@
namespace grpc_core { namespace grpc_core {
// AuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the // CelAuthorizationEngine makes an AuthorizationDecision to ALLOW or DENY the
// current action based on the condition fields in provided RBAC policies. // current action based on the condition fields in provided RBAC policies.
// The engine may be constructed with one or two policies. If two polcies, // The engine may be constructed with one or two policies. If two polcies,
// the first policy is deny-if-matched and the second is allow-if-matched. // the first policy is deny-if-matched and the second is allow-if-matched.
@ -44,19 +44,19 @@ namespace grpc_core {
// are compatible with this engine. // are compatible with this engine.
// //
// Example: // Example:
// AuthorizationEngine* // CelAuthorizationEngine* engine =
// auth_engine = AuthorizationEngine::CreateAuthorizationEngine(rbac_policies); // CelAuthorizationEngine::CreateCelAuthorizationEngine(rbac_policies);
// auth_engine->Evaluate(evaluate_args); // returns authorization decision. // engine->Evaluate(evaluate_args); // returns authorization decision.
class AuthorizationEngine { class CelAuthorizationEngine {
public: public:
// rbac_policies must be a vector containing either a single policy of any // rbac_policies must be a vector containing either a single policy of any
// kind, or one deny policy and one allow policy, in that order. // kind, or one deny policy and one allow policy, in that order.
static std::unique_ptr<AuthorizationEngine> CreateAuthorizationEngine( static std::unique_ptr<CelAuthorizationEngine> CreateCelAuthorizationEngine(
const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies); const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
// Users should use the CreateAuthorizationEngine factory function // Users should use the CreateCelAuthorizationEngine factory function
// instead of calling the AuthorizationEngine constructor directly. // instead of calling the CelAuthorizationEngine constructor directly.
explicit AuthorizationEngine( explicit CelAuthorizationEngine(
const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies); const std::vector<envoy_config_rbac_v3_RBAC*>& rbac_policies);
// TODO(mywang@google.com): add an Evaluate member function. // TODO(mywang@google.com): add an Evaluate member function.
@ -81,4 +81,4 @@ class AuthorizationEngine {
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H */ #endif /* GRPC_CORE_LIB_SECURITY_AUTHORIZATION_CEL_AUTHORIZATION_ENGINE_H */

@ -0,0 +1,202 @@
// 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/matchers.h"
namespace grpc_core {
namespace {
bool AuthenticatedMatchesHelper(const EvaluateArgs& args,
const StringMatcher& matcher) {
if (args.GetTransportSecurityType() != GRPC_SSL_TRANSPORT_SECURITY_TYPE) {
// Connection is not authenticated.
return false;
}
if (matcher.string_matcher().empty()) {
// Allows any authenticated user.
return true;
}
absl::string_view spiffe_id = args.GetSpiffeId();
if (!spiffe_id.empty()) {
return matcher.Match(spiffe_id);
}
// TODO(ashithasantosh): Check principal matches DNS SAN, followed by Subject
// field from certificate. This requires updating tsi_peer to expose these
// fields.
return false;
}
} // namespace
std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
Rbac::Permission permission) {
switch (permission.type) {
case Rbac::Permission::RuleType::AND:
return absl::make_unique<AndAuthorizationMatcher>(
std::move(permission.permissions), permission.not_rule);
case Rbac::Permission::RuleType::OR:
return absl::make_unique<OrAuthorizationMatcher>(
std::move(permission.permissions), permission.not_rule);
case Rbac::Permission::RuleType::ANY:
return absl::make_unique<AlwaysAuthorizationMatcher>(permission.not_rule);
case Rbac::Permission::RuleType::HEADER:
return absl::make_unique<HeaderAuthorizationMatcher>(
std::move(permission.header_matcher), permission.not_rule);
case Rbac::Permission::RuleType::PATH:
return absl::make_unique<PathAuthorizationMatcher>(
std::move(permission.string_matcher), permission.not_rule);
case Rbac::Permission::RuleType::DEST_IP:
return absl::make_unique<IpAuthorizationMatcher>(std::move(permission.ip),
permission.not_rule);
case Rbac::Permission::RuleType::DEST_PORT:
return absl::make_unique<PortAuthorizationMatcher>(permission.port,
permission.not_rule);
case Rbac::Permission::RuleType::REQ_SERVER_NAME:
return absl::make_unique<ReqServerNameAuthorizationMatcher>(
std::move(permission.string_matcher), permission.not_rule);
}
return nullptr;
}
std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
Rbac::Principal principal) {
switch (principal.type) {
case Rbac::Principal::RuleType::AND:
return absl::make_unique<AndAuthorizationMatcher>(
std::move(principal.principals), principal.not_rule);
case Rbac::Principal::RuleType::OR:
return absl::make_unique<OrAuthorizationMatcher>(
std::move(principal.principals), principal.not_rule);
case Rbac::Principal::RuleType::ANY:
return absl::make_unique<AlwaysAuthorizationMatcher>(principal.not_rule);
case Rbac::Principal::RuleType::PRINCIPAL_NAME:
return absl::make_unique<AuthenticatedAuthorizationMatcher>(
std::move(principal.string_matcher), principal.not_rule);
case Rbac::Principal::RuleType::SOURCE_IP:
case Rbac::Principal::RuleType::DIRECT_REMOTE_IP:
case Rbac::Principal::RuleType::REMOTE_IP:
return absl::make_unique<IpAuthorizationMatcher>(std::move(principal.ip),
principal.not_rule);
case Rbac::Principal::RuleType::HEADER:
return absl::make_unique<HeaderAuthorizationMatcher>(
std::move(principal.header_matcher), principal.not_rule);
case Rbac::Principal::RuleType::PATH:
return absl::make_unique<PathAuthorizationMatcher>(
std::move(principal.string_matcher), principal.not_rule);
}
return nullptr;
}
AndAuthorizationMatcher::AndAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
: not_rule_(not_rule) {
for (auto& rule : rules) {
matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
}
}
AndAuthorizationMatcher::AndAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
: not_rule_(not_rule) {
for (const auto& id : ids) {
matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
}
}
bool AndAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
bool matches = true;
for (const auto& matcher : matchers_) {
if (!matcher->Matches(args)) {
matches = false;
break;
}
}
return matches != not_rule_;
}
OrAuthorizationMatcher::OrAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Permission>> rules, bool not_rule)
: not_rule_(not_rule) {
for (const auto& rule : rules) {
matchers_.push_back(AuthorizationMatcher::Create(std::move(*rule)));
}
}
OrAuthorizationMatcher::OrAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule)
: not_rule_(not_rule) {
for (const auto& id : ids) {
matchers_.push_back(AuthorizationMatcher::Create(std::move(*id)));
}
}
bool OrAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
bool matches = false;
for (const auto& matcher : matchers_) {
if (matcher->Matches(args)) {
matches = true;
break;
}
}
return matches != not_rule_;
}
bool HeaderAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
std::string concatenated_value;
bool matches =
matcher_.Match(args.GetHeaderValue(matcher_.name(), &concatenated_value));
return matches != not_rule_;
}
// TODO(ashithasantosh): Implement IpAuthorizationMatcher::Matches.
bool IpAuthorizationMatcher::Matches(const EvaluateArgs&) const {
bool matches = false;
return matches != not_rule_;
}
bool PortAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
bool matches = (port_ == args.GetLocalPort());
return matches != not_rule_;
}
bool AuthenticatedAuthorizationMatcher::Matches(
const EvaluateArgs& args) const {
bool matches = AuthenticatedMatchesHelper(args, matcher_);
return matches != not_rule_;
}
bool ReqServerNameAuthorizationMatcher::Matches(const EvaluateArgs&) const {
// Currently we do not support matching rules containing
// "requested_server_name".
bool matches = false;
return matches != not_rule_;
}
bool PathAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
bool matches = false;
absl::string_view path = args.GetPath();
if (!path.empty()) {
matches = matcher_.Match(path);
}
return matches != not_rule_;
}
bool PolicyAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
return permissions_->Matches(args) && principals_->Matches(args);
}
} // namespace grpc_core

@ -0,0 +1,206 @@
// 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_MATCHERS_H
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H
#include <grpc/support/port_platform.h>
#include <memory>
#include "src/core/lib/matchers/matchers.h"
#include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/security/authorization/rbac_policy.h"
namespace grpc_core {
// Describes the rules for matching permission or principal.
class AuthorizationMatcher {
public:
virtual ~AuthorizationMatcher() = default;
// Returns whether or not the permission/principal matches the rules of the
// matcher.
virtual bool Matches(const EvaluateArgs& args) const = 0;
// Creates an instance of a matcher based off the rules defined in Permission
// config.
static std::unique_ptr<AuthorizationMatcher> Create(
Rbac::Permission permission);
// Creates an instance of a matcher based off the rules defined in Principal
// config.
static std::unique_ptr<AuthorizationMatcher> Create(
Rbac::Principal principal);
};
class AlwaysAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit AlwaysAuthorizationMatcher(bool not_rule = false)
: not_rule_(not_rule) {}
bool Matches(const EvaluateArgs&) const override { return !not_rule_; }
private:
// Negates matching the provided permission/principal.
const bool not_rule_;
};
class AndAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit AndAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Permission>> rules,
bool not_rule = false);
explicit AndAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
bool Matches(const EvaluateArgs& args) const override;
private:
std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
class OrAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit OrAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Permission>> rules,
bool not_rule = false);
explicit OrAuthorizationMatcher(
std::vector<std::unique_ptr<Rbac::Principal>> ids, bool not_rule = false);
bool Matches(const EvaluateArgs& args) const override;
private:
std::vector<std::unique_ptr<AuthorizationMatcher>> matchers_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// TODO(ashithasantosh): Add matcher implementation for metadata field.
// Perform a match against HTTP headers.
class HeaderAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit HeaderAuthorizationMatcher(HeaderMatcher matcher,
bool not_rule = false)
: matcher_(std::move(matcher)), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs& args) const override;
private:
const HeaderMatcher matcher_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Perform a match against IP Cidr Range.
// TODO(ashithasantosh): Handle type of Ip or use seperate matchers for each
// type. Implement Match functionality, this would require updating EvaluateArgs
// getters, to return format of IP as well.
class IpAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit IpAuthorizationMatcher(Rbac::CidrRange range, bool not_rule = false)
: range_(std::move(range)), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs&) const override;
private:
const Rbac::CidrRange range_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Perform a match against port number of the destination (local) address.
class PortAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit PortAuthorizationMatcher(int port, bool not_rule = false)
: port_(port), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs& args) const override;
private:
const int port_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Matches the principal name as described in the peer certificate. Uses URI SAN
// or DNS SAN in that order, otherwise uses subject field.
class AuthenticatedAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit AuthenticatedAuthorizationMatcher(StringMatcher auth,
bool not_rule = false)
: matcher_(std::move(auth)), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs& args) const override;
private:
const StringMatcher matcher_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Perform a match against the request server from the client's connection
// request. This is typically TLS SNI. Currently unsupported.
class ReqServerNameAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit ReqServerNameAuthorizationMatcher(
StringMatcher requested_server_name, bool not_rule = false)
: matcher_(std::move(requested_server_name)), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs&) const override;
private:
const StringMatcher matcher_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Perform a match against the path header of HTTP request.
class PathAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit PathAuthorizationMatcher(StringMatcher path, bool not_rule = false)
: matcher_(std::move(path)), not_rule_(not_rule) {}
bool Matches(const EvaluateArgs& args) const override;
private:
const StringMatcher matcher_;
// Negates matching the provided permission/principal.
const bool not_rule_;
};
// Performs a match for policy field in RBAC, which is a collection of
// permission and principal matchers. Policy matches iff, we find a match in one
// of its permissions and a match in one of its principals.
class PolicyAuthorizationMatcher : public AuthorizationMatcher {
public:
explicit PolicyAuthorizationMatcher(Rbac::Policy policy)
: permissions_(
AuthorizationMatcher::Create(std::move(policy.permissions))),
principals_(
AuthorizationMatcher::Create(std::move(policy.principals))) {}
bool Matches(const EvaluateArgs& args) const override;
private:
std::unique_ptr<AuthorizationMatcher> permissions_;
std::unique_ptr<AuthorizationMatcher> principals_;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_MATCHERS_H

@ -73,8 +73,8 @@ grpc_cc_test(
) )
grpc_cc_test( grpc_cc_test(
name = "authorization_engine_test", name = "cel_authorization_engine_test",
srcs = ["authorization_engine_test.cc"], srcs = ["cel_authorization_engine_test.cc"],
external_deps = ["gtest"], external_deps = ["gtest"],
language = "C++", language = "C++",
deps = [ deps = [
@ -425,3 +425,16 @@ grpc_cc_test(
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
], ],
) )
grpc_cc_test(
name = "authorization_matchers_test",
srcs = ["authorization_matchers_test.cc"],
external_deps = ["gtest"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//:grpc_rbac_engine",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,420 @@
// 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 <list>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/security/authorization/matchers.h"
#include "test/core/util/evaluate_args_test_util.h"
namespace grpc_core {
class AuthorizationMatchersTest : public ::testing::Test {
protected:
EvaluateArgsTestUtil args_;
};
TEST_F(AuthorizationMatchersTest, AlwaysAuthorizationMatcher) {
EvaluateArgs args = args_.MakeEvaluateArgs();
AlwaysAuthorizationMatcher matcher;
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotAlwaysAuthorizationMatcher) {
EvaluateArgs args = args_.MakeEvaluateArgs();
AlwaysAuthorizationMatcher matcher(/*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("foo", "bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::DEST_PORT, /*port=*/123));
AndAuthorizationMatcher matcher(std::move(rules));
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata("foo", "not_bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::DEST_PORT, /*port=*/123));
AndAuthorizationMatcher matcher(std::move(rules));
// Header rule fails. Expected value "bar", got "not_bar" for key "foo".
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotAndAuthorizationMatcher) {
args_.AddPairToMetadata(":path", "/expected/foo");
EvaluateArgs args = args_.MakeEvaluateArgs();
StringMatcher string_matcher =
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"/expected/foo",
/*case_sensitive=*/false)
.value();
std::vector<std::unique_ptr<Rbac::Permission>> ids;
ids.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::PATH, std::move(string_matcher)));
AndAuthorizationMatcher matcher(std::move(ids), /*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("foo", "bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderMatcher header_matcher =
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER, header_matcher));
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::DEST_PORT, /*port=*/456));
OrAuthorizationMatcher matcher(std::move(rules));
// Matches as header rule matches even though port rule fails.
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata("foo", "not_bar");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
OrAuthorizationMatcher matcher(std::move(rules));
// Header rule fails. Expected value "bar", got "not_bar" for key "foo".
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotOrAuthorizationMatcher) {
args_.AddPairToMetadata("foo", "not_bar");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
OrAuthorizationMatcher matcher(std::move(rules), /*not_rule=*/true);
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("foo", "bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::DEST_PORT, /*port=*/123));
std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::AND, std::move(sub_and_rules)));
and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::OR, std::move(std::move(sub_or_rules))));
AndAuthorizationMatcher matcher(std::move(and_rules));
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, HybridAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata("foo", "bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> sub_and_rules;
sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
sub_and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"absent_key", HeaderMatcher::Type::EXACT,
/*matcher=*/"some_value")
.value()));
std::vector<std::unique_ptr<Rbac::Permission>> sub_or_rules;
sub_or_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::DEST_PORT, /*port=*/123));
std::vector<std::unique_ptr<Rbac::Permission>> and_rules;
and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::AND, std::move(sub_and_rules)));
and_rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::OR, std::move(std::move(sub_or_rules))));
AndAuthorizationMatcher matcher(std::move(and_rules));
// Fails as "absent_key" header was not present.
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata(":path", "expected/path");
EvaluateArgs args = args_.MakeEvaluateArgs();
PathAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"expected/path",
/*case_sensitive=*/false)
.value());
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PathAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata(":path", "different/path");
EvaluateArgs args = args_.MakeEvaluateArgs();
PathAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"expected/path",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotPathAuthorizationMatcher) {
args_.AddPairToMetadata(":path", "expected/path");
EvaluateArgs args = args_.MakeEvaluateArgs();
PathAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT, "expected/path", false)
.value(),
/*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
PathAuthorizationMatcherFailedMatchMissingPath) {
EvaluateArgs args = args_.MakeEvaluateArgs();
PathAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"expected/path",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("key123", "foo_xxx");
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderAuthorizationMatcher matcher(
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::PREFIX,
/*matcher=*/"foo")
.value());
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, HeaderAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata("key123", "foo");
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderAuthorizationMatcher matcher(
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
HeaderAuthorizationMatcherFailedMatchMultivaluedHeader) {
args_.AddPairToMetadata("key123", "foo");
args_.AddPairToMetadata("key123", "bar");
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderAuthorizationMatcher matcher(
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::EXACT,
/*matcher=*/"foo")
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
HeaderAuthorizationMatcherFailedMatchMissingHeader) {
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderAuthorizationMatcher matcher(
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::SUFFIX,
/*matcher=*/"foo")
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotHeaderAuthorizationMatcher) {
args_.AddPairToMetadata("key123", "foo");
EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderAuthorizationMatcher matcher(
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value(),
/*not_rule=*/true);
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherSuccessfulMatch) {
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
PortAuthorizationMatcher matcher(/*port=*/123);
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherFailedMatch) {
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
PortAuthorizationMatcher matcher(/*port=*/456);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotPortAuthorizationMatcher) {
args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
PortAuthorizationMatcher matcher(/*port=*/123, /*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
AuthenticatedMatcherUnAuthenticatedConnection) {
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"foo.com",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
AuthenticatedMatcherAuthenticatedConnectionMatcherUnset) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"",
/*case_sensitive=*/false)
.value());
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
AuthenticatedMatcherSuccessfulSpiffeIdMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
"spiffe://foo.abc");
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"spiffe://foo.abc",
/*case_sensitive=*/false)
.value());
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedSpiffeIdMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
args_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME,
"spiffe://bar.abc");
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"spiffe://foo.abc",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedNothingMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT,
/*matcher=*/"foo",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotAuthenticatedMatcher) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::EXACT, /*matcher=*/"foo",
/*case_sensitive=*/false)
.value(),
/*not_rule=*/true);
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("key123", "foo");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::EXACT,
/*matcher=*/"foo")
.value()));
PolicyAuthorizationMatcher matcher(Rbac::Policy(
Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(rules)),
Rbac::Principal(Rbac::Principal::RuleType::ANY)));
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PolicyAuthorizationMatcherFailedMatch) {
args_.AddPairToMetadata("key123", "foo");
EvaluateArgs args = args_.MakeEvaluateArgs();
std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::HEADER,
HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::EXACT,
/*matcher=*/"bar")
.value()));
PolicyAuthorizationMatcher matcher(Rbac::Policy(
Rbac::Permission(Rbac::Permission::RuleType::OR, std::move(rules)),
Rbac::Principal(Rbac::Principal::RuleType::ANY)));
EXPECT_FALSE(matcher.Matches(args));
}
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_init();
int ret = RUN_ALL_TESTS();
grpc_shutdown();
return ret;
}

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "src/core/lib/security/authorization/authorization_engine.h" #include "src/core/lib/security/authorization/cel_authorization_engine.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace grpc_core { namespace grpc_core {
class AuthorizationEngineTest : public ::testing::Test { class CelAuthorizationEngineTest : public ::testing::Test {
protected: protected:
void SetUp() override { void SetUp() override {
deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr()); deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr());
@ -31,44 +31,44 @@ class AuthorizationEngineTest : public ::testing::Test {
envoy_config_rbac_v3_RBAC* allow_policy_; envoy_config_rbac_v3_RBAC* allow_policy_;
}; };
TEST_F(AuthorizationEngineTest, CreateEngineSuccessOnePolicy) { TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessOnePolicy) {
std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_}; std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_};
std::unique_ptr<AuthorizationEngine> engine = std::unique_ptr<CelAuthorizationEngine> engine =
AuthorizationEngine::CreateAuthorizationEngine(policies); CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
EXPECT_NE(engine, nullptr) EXPECT_NE(engine, nullptr)
<< "Error: Failed to create an AuthorizationEngine with one policy."; << "Error: Failed to create CelAuthorizationEngine with one policy.";
} }
TEST_F(AuthorizationEngineTest, CreateEngineSuccessTwoPolicies) { TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessTwoPolicies) {
std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_}; std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_};
std::unique_ptr<AuthorizationEngine> engine = std::unique_ptr<CelAuthorizationEngine> engine =
AuthorizationEngine::CreateAuthorizationEngine(policies); CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
EXPECT_NE(engine, nullptr) EXPECT_NE(engine, nullptr)
<< "Error: Failed to create an AuthorizationEngine with two policies."; << "Error: Failed to create CelAuthorizationEngine with two policies.";
} }
TEST_F(AuthorizationEngineTest, CreateEngineFailNoPolicies) { TEST_F(CelAuthorizationEngineTest, CreateEngineFailNoPolicies) {
std::vector<envoy_config_rbac_v3_RBAC*> policies{}; std::vector<envoy_config_rbac_v3_RBAC*> policies{};
std::unique_ptr<AuthorizationEngine> engine = std::unique_ptr<CelAuthorizationEngine> engine =
AuthorizationEngine::CreateAuthorizationEngine(policies); CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
EXPECT_EQ(engine, nullptr) EXPECT_EQ(engine, nullptr)
<< "Error: Created an AuthorizationEngine without policies."; << "Error: Created CelAuthorizationEngine without policies.";
} }
TEST_F(AuthorizationEngineTest, CreateEngineFailTooManyPolicies) { TEST_F(CelAuthorizationEngineTest, CreateEngineFailTooManyPolicies) {
std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_, std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_,
deny_policy_}; deny_policy_};
std::unique_ptr<AuthorizationEngine> engine = std::unique_ptr<CelAuthorizationEngine> engine =
AuthorizationEngine::CreateAuthorizationEngine(policies); CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
EXPECT_EQ(engine, nullptr) EXPECT_EQ(engine, nullptr)
<< "Error: Created an AuthorizationEngine with more than two policies."; << "Error: Created CelAuthorizationEngine with more than two policies.";
} }
TEST_F(AuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) { TEST_F(CelAuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) {
std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_}; std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_};
std::unique_ptr<AuthorizationEngine> engine = std::unique_ptr<CelAuthorizationEngine> engine =
AuthorizationEngine::CreateAuthorizationEngine(policies); CelAuthorizationEngine::CreateCelAuthorizationEngine(policies);
EXPECT_EQ(engine, nullptr) << "Error: Created an AuthorizationEngine with " EXPECT_EQ(engine, nullptr) << "Error: Created CelAuthorizationEngine with "
"policies in the wrong order."; "policies in the wrong order.";
} }

@ -3300,7 +3300,7 @@
"flaky": false, "flaky": false,
"gtest": true, "gtest": true,
"language": "c++", "language": "c++",
"name": "authorization_engine_test", "name": "authorization_matchers_test",
"platforms": [ "platforms": [
"linux", "linux",
"mac", "mac",
@ -3839,6 +3839,30 @@
], ],
"uses_polling": true "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": "cel_authorization_engine_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,

Loading…
Cancel
Save