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