mirror of https://github.com/grpc/grpc.git
RBAC engine matchers implementation. (#25997)
parent
d4f6cfd535
commit
628bf7fe08
11 changed files with 993 additions and 63 deletions
@ -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
|
@ -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; |
||||
} |
Loading…
Reference in new issue