IPMatcher implementation. (#26132)

pull/26219/head
Ashitha Santhosh 4 years ago committed by GitHub
parent a989179ace
commit c90fae35cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      src/core/lib/security/authorization/cel_authorization_engine.cc
  2. 79
      src/core/lib/security/authorization/evaluate_args.cc
  3. 23
      src/core/lib/security/authorization/evaluate_args.h
  4. 102
      src/core/lib/security/authorization/matchers.cc
  5. 21
      src/core/lib/security/authorization/matchers.h
  6. 26
      src/core/lib/security/authorization/rbac_policy.h
  7. 32
      src/core/lib/security/credentials/tls/tls_utils.cc
  8. 13
      src/core/lib/security/credentials/tls/tls_utils.h
  9. 106
      test/core/security/authorization_matchers_test.cc
  10. 41
      test/core/security/evaluate_args_test.cc

@ -16,6 +16,7 @@
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/security/authorization/cel_authorization_engine.h" #include "src/core/lib/security/authorization/cel_authorization_engine.h"
namespace grpc_core { namespace grpc_core {
@ -132,7 +133,7 @@ std::unique_ptr<mock_cel::Activation> CelAuthorizationEngine::CreateActivation(
activation->InsertValue(kHeaders, activation->InsertValue(kHeaders,
mock_cel::CelValue::CreateMap(headers_.get())); mock_cel::CelValue::CreateMap(headers_.get()));
} else if (elem == kSourceAddress) { } else if (elem == kSourceAddress) {
absl::string_view source_address(args.GetPeerAddress()); absl::string_view source_address(args.GetPeerAddressString());
if (!source_address.empty()) { if (!source_address.empty()) {
activation->InsertValue( activation->InsertValue(
kSourceAddress, kSourceAddress,
@ -142,7 +143,7 @@ std::unique_ptr<mock_cel::Activation> CelAuthorizationEngine::CreateActivation(
activation->InsertValue( activation->InsertValue(
kSourcePort, mock_cel::CelValue::CreateInt64(args.GetPeerPort())); kSourcePort, mock_cel::CelValue::CreateInt64(args.GetPeerPort()));
} else if (elem == kDestinationAddress) { } else if (elem == kDestinationAddress) {
absl::string_view destination_address(args.GetLocalAddress()); absl::string_view destination_address(args.GetLocalAddressString());
if (!destination_address.empty()) { if (!destination_address.empty()) {
activation->InsertValue( activation->InsertValue(
kDestinationAddress, kDestinationAddress,

@ -17,48 +17,43 @@
#include "src/core/lib/security/authorization/evaluate_args.h" #include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/address_utils/parse_address.h" #include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/gprpp/host_port.h" #include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/security/credentials/tls/tls_utils.h"
#include "src/core/lib/slice/slice_utils.h" #include "src/core/lib/slice/slice_utils.h"
namespace grpc_core { namespace grpc_core {
namespace { namespace {
absl::string_view GetAuthPropertyValue(grpc_auth_context* context, EvaluateArgs::PerChannelArgs::Address ParseEndpointUri(
const char* property_name) { absl::string_view uri_text) {
grpc_auth_property_iterator it = EvaluateArgs::PerChannelArgs::Address address;
grpc_auth_context_find_properties_by_name(context, property_name);
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
if (prop == nullptr) {
gpr_log(GPR_DEBUG, "No value found for %s property.", property_name);
return "";
}
if (grpc_auth_property_iterator_next(&it) != nullptr) {
gpr_log(GPR_DEBUG, "Multiple values found for %s property.", property_name);
return "";
}
return absl::string_view(prop->value, prop->value_length);
}
void ParseEndpointUri(absl::string_view uri_text, std::string* address,
int* port) {
absl::StatusOr<URI> uri = URI::Parse(uri_text); absl::StatusOr<URI> uri = URI::Parse(uri_text);
if (!uri.ok()) { if (!uri.ok()) {
gpr_log(GPR_DEBUG, "Failed to parse uri."); gpr_log(GPR_DEBUG, "Failed to parse uri.");
return; return address;
} }
absl::string_view host_view; absl::string_view host_view;
absl::string_view port_view; absl::string_view port_view;
if (!SplitHostPort(uri->path(), &host_view, &port_view)) { if (!SplitHostPort(uri->path(), &host_view, &port_view)) {
gpr_log(GPR_DEBUG, "Failed to split %s into host and port.", gpr_log(GPR_DEBUG, "Failed to split %s into host and port.",
uri->path().c_str()); uri->path().c_str());
return; return address;
} }
*address = std::string(host_view); if (!absl::SimpleAtoi(port_view, &address.port)) {
if (!absl::SimpleAtoi(port_view, port)) {
gpr_log(GPR_DEBUG, "Port %s is out of range or null.", gpr_log(GPR_DEBUG, "Port %s is out of range or null.",
std::string(port_view).c_str()); std::string(port_view).c_str());
} }
address.address_str = std::string(host_view);
grpc_error_handle error = grpc_string_to_sockaddr(
&address.address, address.address_str.c_str(), address.port);
if (error != GRPC_ERROR_NONE) {
gpr_log(GPR_DEBUG, "Address %s is not IPv4/IPv6. Error: %s",
address.address_str.c_str(), grpc_error_std_string(error).c_str());
}
GRPC_ERROR_UNREF(error);
return address;
} }
} // namespace } // namespace
@ -70,14 +65,13 @@ EvaluateArgs::PerChannelArgs::PerChannelArgs(grpc_auth_context* auth_context,
auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME); auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME);
spiffe_id = spiffe_id =
GetAuthPropertyValue(auth_context, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME); GetAuthPropertyValue(auth_context, GRPC_PEER_SPIFFE_ID_PROPERTY_NAME);
dns_sans = GetAuthPropertyArray(auth_context, GRPC_PEER_DNS_PROPERTY_NAME);
common_name = common_name =
GetAuthPropertyValue(auth_context, GRPC_X509_CN_PROPERTY_NAME); GetAuthPropertyValue(auth_context, GRPC_X509_CN_PROPERTY_NAME);
} }
if (endpoint != nullptr) { if (endpoint != nullptr) {
ParseEndpointUri(grpc_endpoint_get_local_address(endpoint), &local_address, local_address = ParseEndpointUri(grpc_endpoint_get_local_address(endpoint));
&local_port); peer_address = ParseEndpointUri(grpc_endpoint_get_peer(endpoint));
ParseEndpointUri(grpc_endpoint_get_peer(endpoint), &peer_address,
&peer_port);
} }
} }
@ -134,32 +128,46 @@ absl::optional<absl::string_view> EvaluateArgs::GetHeaderValue(
return grpc_metadata_batch_get_value(metadata_, key, concatenated_value); return grpc_metadata_batch_get_value(metadata_, key, concatenated_value);
} }
absl::string_view EvaluateArgs::GetLocalAddress() const { grpc_resolved_address EvaluateArgs::GetLocalAddress() const {
if (channel_args_ == nullptr) {
return {};
}
return channel_args_->local_address.address;
}
absl::string_view EvaluateArgs::GetLocalAddressString() const {
if (channel_args_ == nullptr) { if (channel_args_ == nullptr) {
return ""; return "";
} }
return channel_args_->local_address; return channel_args_->local_address.address_str;
} }
int EvaluateArgs::GetLocalPort() const { int EvaluateArgs::GetLocalPort() const {
if (channel_args_ == nullptr) { if (channel_args_ == nullptr) {
return 0; return 0;
} }
return channel_args_->local_port; return channel_args_->local_address.port;
}
grpc_resolved_address EvaluateArgs::GetPeerAddress() const {
if (channel_args_ == nullptr) {
return {};
}
return channel_args_->peer_address.address;
} }
absl::string_view EvaluateArgs::GetPeerAddress() const { absl::string_view EvaluateArgs::GetPeerAddressString() const {
if (channel_args_ == nullptr) { if (channel_args_ == nullptr) {
return ""; return "";
} }
return channel_args_->peer_address; return channel_args_->peer_address.address_str;
} }
int EvaluateArgs::GetPeerPort() const { int EvaluateArgs::GetPeerPort() const {
if (channel_args_ == nullptr) { if (channel_args_ == nullptr) {
return 0; return 0;
} }
return channel_args_->peer_port; return channel_args_->peer_address.port;
} }
absl::string_view EvaluateArgs::GetTransportSecurityType() const { absl::string_view EvaluateArgs::GetTransportSecurityType() const {
@ -176,6 +184,13 @@ absl::string_view EvaluateArgs::GetSpiffeId() const {
return channel_args_->spiffe_id; return channel_args_->spiffe_id;
} }
std::vector<absl::string_view> EvaluateArgs::GetDnsSans() const {
if (channel_args_ == nullptr) {
return {};
}
return channel_args_->dns_sans;
}
absl::string_view EvaluateArgs::GetCommonName() const { absl::string_view EvaluateArgs::GetCommonName() const {
if (channel_args_ == nullptr) { if (channel_args_ == nullptr) {
return ""; return "";

@ -22,6 +22,7 @@
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/transport/metadata_batch.h" #include "src/core/lib/transport/metadata_batch.h"
@ -32,15 +33,22 @@ class EvaluateArgs {
// Caller is responsible for ensuring auth_context outlives PerChannelArgs // Caller is responsible for ensuring auth_context outlives PerChannelArgs
// struct. // struct.
struct PerChannelArgs { struct PerChannelArgs {
struct Address {
// The address in sockaddr form.
grpc_resolved_address address;
// The same address with only the host part.
std::string address_str;
int port = 0;
};
PerChannelArgs(grpc_auth_context* auth_context, grpc_endpoint* endpoint); PerChannelArgs(grpc_auth_context* auth_context, grpc_endpoint* endpoint);
absl::string_view transport_security_type; absl::string_view transport_security_type;
absl::string_view spiffe_id; absl::string_view spiffe_id;
std::vector<absl::string_view> dns_sans;
absl::string_view common_name; absl::string_view common_name;
std::string local_address; Address local_address;
int local_port = 0; Address peer_address;
std::string peer_address;
int peer_port = 0;
}; };
EvaluateArgs(grpc_metadata_batch* metadata, PerChannelArgs* channel_args) EvaluateArgs(grpc_metadata_batch* metadata, PerChannelArgs* channel_args)
@ -60,12 +68,15 @@ class EvaluateArgs {
absl::optional<absl::string_view> GetHeaderValue( absl::optional<absl::string_view> GetHeaderValue(
absl::string_view key, std::string* concatenated_value) const; absl::string_view key, std::string* concatenated_value) const;
absl::string_view GetLocalAddress() const; grpc_resolved_address GetLocalAddress() const;
absl::string_view GetLocalAddressString() const;
int GetLocalPort() const; int GetLocalPort() const;
absl::string_view GetPeerAddress() const; grpc_resolved_address GetPeerAddress() const;
absl::string_view GetPeerAddressString() const;
int GetPeerPort() const; int GetPeerPort() const;
absl::string_view GetTransportSecurityType() const; absl::string_view GetTransportSecurityType() const;
absl::string_view GetSpiffeId() const; absl::string_view GetSpiffeId() const;
std::vector<absl::string_view> GetDnsSans() const;
absl::string_view GetCommonName() const; absl::string_view GetCommonName() const;
private: private:

@ -14,34 +14,11 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/security/authorization/matchers.h" #include "src/core/lib/security/authorization/matchers.h"
namespace grpc_core { 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( std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
Rbac::Permission permission) { Rbac::Permission permission) {
switch (permission.type) { switch (permission.type) {
@ -60,8 +37,9 @@ std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
return absl::make_unique<PathAuthorizationMatcher>( return absl::make_unique<PathAuthorizationMatcher>(
std::move(permission.string_matcher), permission.not_rule); std::move(permission.string_matcher), permission.not_rule);
case Rbac::Permission::RuleType::kDestIp: case Rbac::Permission::RuleType::kDestIp:
return absl::make_unique<IpAuthorizationMatcher>(std::move(permission.ip), return absl::make_unique<IpAuthorizationMatcher>(
permission.not_rule); IpAuthorizationMatcher::Type::kDestIp, std::move(permission.ip),
permission.not_rule);
case Rbac::Permission::RuleType::kDestPort: case Rbac::Permission::RuleType::kDestPort:
return absl::make_unique<PortAuthorizationMatcher>(permission.port, return absl::make_unique<PortAuthorizationMatcher>(permission.port,
permission.not_rule); permission.not_rule);
@ -87,10 +65,17 @@ std::unique_ptr<AuthorizationMatcher> AuthorizationMatcher::Create(
return absl::make_unique<AuthenticatedAuthorizationMatcher>( return absl::make_unique<AuthenticatedAuthorizationMatcher>(
std::move(principal.string_matcher), principal.not_rule); std::move(principal.string_matcher), principal.not_rule);
case Rbac::Principal::RuleType::kSourceIp: case Rbac::Principal::RuleType::kSourceIp:
return absl::make_unique<IpAuthorizationMatcher>(
IpAuthorizationMatcher::Type::kSourceIp, std::move(principal.ip),
principal.not_rule);
case Rbac::Principal::RuleType::kDirectRemoteIp: case Rbac::Principal::RuleType::kDirectRemoteIp:
return absl::make_unique<IpAuthorizationMatcher>(
IpAuthorizationMatcher::Type::kDirectRemoteIp,
std::move(principal.ip), principal.not_rule);
case Rbac::Principal::RuleType::kRemoteIp: case Rbac::Principal::RuleType::kRemoteIp:
return absl::make_unique<IpAuthorizationMatcher>(std::move(principal.ip), return absl::make_unique<IpAuthorizationMatcher>(
principal.not_rule); IpAuthorizationMatcher::Type::kRemoteIp, std::move(principal.ip),
principal.not_rule);
case Rbac::Principal::RuleType::kHeader: case Rbac::Principal::RuleType::kHeader:
return absl::make_unique<HeaderAuthorizationMatcher>( return absl::make_unique<HeaderAuthorizationMatcher>(
std::move(principal.header_matcher), principal.not_rule); std::move(principal.header_matcher), principal.not_rule);
@ -162,9 +147,40 @@ bool HeaderAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
return matches != not_rule_; return matches != not_rule_;
} }
// TODO(ashithasantosh): Implement IpAuthorizationMatcher::Matches. IpAuthorizationMatcher::IpAuthorizationMatcher(Type type, Rbac::CidrRange range,
bool IpAuthorizationMatcher::Matches(const EvaluateArgs&) const { bool not_rule)
bool matches = false; : type_(type), prefix_len_(range.prefix_len), not_rule_(not_rule) {
grpc_error_handle error =
grpc_string_to_sockaddr(&subnet_address_, range.address_prefix.c_str(),
/*port does not matter here*/ 0);
if (error == GRPC_ERROR_NONE) {
grpc_sockaddr_mask_bits(&subnet_address_, prefix_len_);
} else {
gpr_log(GPR_DEBUG, "CidrRange address %s is not IPv4/IPv6. Error: %s",
range.address_prefix.c_str(), grpc_error_std_string(error).c_str());
}
GRPC_ERROR_UNREF(error);
}
bool IpAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
grpc_resolved_address address;
switch (type_) {
case Type::kDestIp: {
address = args.GetLocalAddress();
break;
}
case Type::kSourceIp:
case Type::kDirectRemoteIp: {
address = args.GetPeerAddress();
break;
}
default: {
// Currently we do not support matching rules containing "remote_ip".
return not_rule_;
}
}
bool matches =
grpc_sockaddr_match_subnet(&address, &subnet_address_, prefix_len_);
return matches != not_rule_; return matches != not_rule_;
} }
@ -175,8 +191,28 @@ bool PortAuthorizationMatcher::Matches(const EvaluateArgs& args) const {
bool AuthenticatedAuthorizationMatcher::Matches( bool AuthenticatedAuthorizationMatcher::Matches(
const EvaluateArgs& args) const { const EvaluateArgs& args) const {
bool matches = AuthenticatedMatchesHelper(args, matcher_); if (args.GetTransportSecurityType() != GRPC_SSL_TRANSPORT_SECURITY_TYPE) {
return matches != not_rule_; // Connection is not authenticated.
return not_rule_;
}
if (matcher_.string_matcher().empty()) {
// Allows any authenticated user.
return !not_rule_;
}
absl::string_view spiffe_id = args.GetSpiffeId();
if (!spiffe_id.empty()) {
return matcher_.Match(spiffe_id) != not_rule_;
}
std::vector<absl::string_view> dns_sans = args.GetDnsSans();
if (!dns_sans.empty()) {
for (const auto& dns : dns_sans) {
if (matcher_.Match(dns)) {
return !not_rule_;
}
}
}
// TODO(ashithasantosh): Check Subject field from certificate.
return not_rule_;
} }
bool ReqServerNameAuthorizationMatcher::Matches(const EvaluateArgs&) const { bool ReqServerNameAuthorizationMatcher::Matches(const EvaluateArgs&) const {

@ -107,18 +107,25 @@ class HeaderAuthorizationMatcher : public AuthorizationMatcher {
}; };
// Perform a match against IP Cidr Range. // 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 { class IpAuthorizationMatcher : public AuthorizationMatcher {
public: public:
explicit IpAuthorizationMatcher(Rbac::CidrRange range, bool not_rule = false) enum class Type {
: range_(std::move(range)), not_rule_(not_rule) {} kDestIp,
kSourceIp,
kDirectRemoteIp,
kRemoteIp,
};
bool Matches(const EvaluateArgs&) const override; IpAuthorizationMatcher(Type type, Rbac::CidrRange range,
bool not_rule = false);
bool Matches(const EvaluateArgs& args) const override;
private: private:
const Rbac::CidrRange range_; const Type type_;
// Subnet masked address.
grpc_resolved_address subnet_address_;
const uint32_t prefix_len_;
// Negates matching the provided permission/principal. // Negates matching the provided permission/principal.
const bool not_rule_; const bool not_rule_;
}; };

@ -58,21 +58,21 @@ struct Rbac {
}; };
Permission() = default; Permission() = default;
// For AND/OR RuleType. // For kAnd/kOr RuleType.
Permission(Permission::RuleType type, Permission(Permission::RuleType type,
std::vector<std::unique_ptr<Permission>> permissions, std::vector<std::unique_ptr<Permission>> permissions,
bool not_rule = false); bool not_rule = false);
// For ANY RuleType. // For kAny RuleType.
explicit Permission(Permission::RuleType type, bool not_rule = false); explicit Permission(Permission::RuleType type, bool not_rule = false);
// For HEADER RuleType. // For kHeader RuleType.
Permission(Permission::RuleType type, HeaderMatcher header_matcher, Permission(Permission::RuleType type, HeaderMatcher header_matcher,
bool not_rule = false); bool not_rule = false);
// For PATH/REQ_SERVER_NAME RuleType. // For kPath/kReqServerName RuleType.
Permission(Permission::RuleType type, StringMatcher string_matcher, Permission(Permission::RuleType type, StringMatcher string_matcher,
bool not_rule = false); bool not_rule = false);
// For DEST_IP RuleType. // For kDestIp RuleType.
Permission(Permission::RuleType type, CidrRange ip, bool not_rule = false); Permission(Permission::RuleType type, CidrRange ip, bool not_rule = false);
// For DEST_PORT RuleType. // For kDestPort RuleType.
Permission(Permission::RuleType type, int port, bool not_rule = false); Permission(Permission::RuleType type, int port, bool not_rule = false);
Permission(Permission&& other) noexcept; Permission(Permission&& other) noexcept;
@ -85,7 +85,7 @@ struct Rbac {
StringMatcher string_matcher; StringMatcher string_matcher;
CidrRange ip; CidrRange ip;
int port; int port;
// For type AND/OR. // For type kAnd/kOr.
std::vector<std::unique_ptr<Permission>> permissions; std::vector<std::unique_ptr<Permission>> permissions;
bool not_rule = false; bool not_rule = false;
}; };
@ -104,18 +104,18 @@ struct Rbac {
}; };
Principal() = default; Principal() = default;
// For AND/OR RuleType. // For kAnd/kOr RuleType.
Principal(Principal::RuleType type, Principal(Principal::RuleType type,
std::vector<std::unique_ptr<Principal>> principals, std::vector<std::unique_ptr<Principal>> principals,
bool not_rule = false); bool not_rule = false);
// For ANY RuleType. // For kAny RuleType.
explicit Principal(Principal::RuleType type, bool not_rule = false); explicit Principal(Principal::RuleType type, bool not_rule = false);
// For PRINCIPAL_NAME/PATH RuleType. // For kPrincipalName/kPath RuleType.
Principal(Principal::RuleType type, StringMatcher string_matcher, Principal(Principal::RuleType type, StringMatcher string_matcher,
bool not_rule = false); bool not_rule = false);
// For SOURCE_IP/DIRECT_REMOTE_IP/REMOTE_IP RuleType. // For kSourceIp/kDirectRemoteIp/kRemoteIp RuleType.
Principal(Principal::RuleType type, CidrRange ip, bool not_rule = false); Principal(Principal::RuleType type, CidrRange ip, bool not_rule = false);
// For HEADER RuleType. // For kHeader RuleType.
Principal(Principal::RuleType type, HeaderMatcher header_matcher, Principal(Principal::RuleType type, HeaderMatcher header_matcher,
bool not_rule = false); bool not_rule = false);
@ -128,7 +128,7 @@ struct Rbac {
HeaderMatcher header_matcher; HeaderMatcher header_matcher;
StringMatcher string_matcher; StringMatcher string_matcher;
CidrRange ip; CidrRange ip;
// For type AND/OR. // For type kAnd/kOr.
std::vector<std::unique_ptr<Principal>> principals; std::vector<std::unique_ptr<Principal>> principals;
bool not_rule = false; bool not_rule = false;
}; };

@ -88,4 +88,36 @@ bool VerifySubjectAlternativeName(absl::string_view subject_alternative_name,
std::string::npos; std::string::npos;
} }
absl::string_view GetAuthPropertyValue(grpc_auth_context* context,
const char* property_name) {
grpc_auth_property_iterator it =
grpc_auth_context_find_properties_by_name(context, property_name);
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
if (prop == nullptr) {
gpr_log(GPR_DEBUG, "No value found for %s property.", property_name);
return "";
}
if (grpc_auth_property_iterator_next(&it) != nullptr) {
gpr_log(GPR_DEBUG, "Multiple values found for %s property.", property_name);
return "";
}
return absl::string_view(prop->value, prop->value_length);
}
std::vector<absl::string_view> GetAuthPropertyArray(grpc_auth_context* context,
const char* property_name) {
std::vector<absl::string_view> values;
grpc_auth_property_iterator it =
grpc_auth_context_find_properties_by_name(context, property_name);
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
while (prop != nullptr) {
values.emplace_back(prop->value, prop->value_length);
prop = grpc_auth_property_iterator_next(&it);
}
if (values.empty()) {
gpr_log(GPR_DEBUG, "No value found for %s property.", property_name);
}
return values;
}
} // namespace grpc_core } // namespace grpc_core

@ -26,6 +26,8 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "src/core/lib/security/context/security_context.h"
namespace grpc_core { namespace grpc_core {
// Matches \a subject_alternative_name with \a matcher. Returns true if there // Matches \a subject_alternative_name with \a matcher. Returns true if there
@ -33,6 +35,17 @@ namespace grpc_core {
bool VerifySubjectAlternativeName(absl::string_view subject_alternative_name, bool VerifySubjectAlternativeName(absl::string_view subject_alternative_name,
const std::string& matcher); const std::string& matcher);
// Returns value for the specified property_name from auth context. Here the
// property is expected to have a single value. Returns empty if multiple values
// are found.
absl::string_view GetAuthPropertyValue(grpc_auth_context* context,
const char* property_name);
// Returns values for the specified property_name from auth context. Here the
// property can have any number of values.
std::vector<absl::string_view> GetAuthPropertyArray(grpc_auth_context* context,
const char* property_name);
} // namespace grpc_core } // namespace grpc_core
#endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_TLS_UTILS_H #endif // GRPC_CORE_LIB_SECURITY_CREDENTIALS_TLS_TLS_UTILS_H

@ -78,14 +78,13 @@ TEST_F(AuthorizationMatchersTest, AndAuthorizationMatcherFailedMatch) {
TEST_F(AuthorizationMatchersTest, NotAndAuthorizationMatcher) { TEST_F(AuthorizationMatchersTest, NotAndAuthorizationMatcher) {
args_.AddPairToMetadata(":path", "/expected/foo"); args_.AddPairToMetadata(":path", "/expected/foo");
EvaluateArgs args = args_.MakeEvaluateArgs(); EvaluateArgs args = args_.MakeEvaluateArgs();
StringMatcher string_matcher = std::vector<std::unique_ptr<Rbac::Permission>> ids;
ids.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::kPath,
StringMatcher::Create(StringMatcher::Type::kExact, StringMatcher::Create(StringMatcher::Type::kExact,
/*matcher=*/"/expected/foo", /*matcher=*/"/expected/foo",
/*case_sensitive=*/false) /*case_sensitive=*/false)
.value(); .value()));
std::vector<std::unique_ptr<Rbac::Permission>> ids;
ids.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::kPath, std::move(string_matcher)));
AndAuthorizationMatcher matcher(std::move(ids), /*not_rule=*/true); AndAuthorizationMatcher matcher(std::move(ids), /*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args)); EXPECT_FALSE(matcher.Matches(args));
} }
@ -94,13 +93,12 @@ TEST_F(AuthorizationMatchersTest, OrAuthorizationMatcherSuccessfulMatch) {
args_.AddPairToMetadata("foo", "bar"); args_.AddPairToMetadata("foo", "bar");
args_.SetLocalEndpoint("ipv4:255.255.255.255:123"); args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs(); EvaluateArgs args = args_.MakeEvaluateArgs();
HeaderMatcher header_matcher =
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
/*matcher=*/"bar")
.value();
std::vector<std::unique_ptr<Rbac::Permission>> rules; std::vector<std::unique_ptr<Rbac::Permission>> rules;
rules.push_back(absl::make_unique<Rbac::Permission>( rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::kHeader, header_matcher)); Rbac::Permission::RuleType::kHeader,
HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact,
/*matcher=*/"bar")
.value()));
rules.push_back(absl::make_unique<Rbac::Permission>( rules.push_back(absl::make_unique<Rbac::Permission>(
Rbac::Permission::RuleType::kDestPort, /*port=*/456)); Rbac::Permission::RuleType::kDestPort, /*port=*/456));
OrAuthorizationMatcher matcher(std::move(rules)); OrAuthorizationMatcher matcher(std::move(rules));
@ -211,7 +209,9 @@ TEST_F(AuthorizationMatchersTest, NotPathAuthorizationMatcher) {
args_.AddPairToMetadata(":path", "expected/path"); args_.AddPairToMetadata(":path", "expected/path");
EvaluateArgs args = args_.MakeEvaluateArgs(); EvaluateArgs args = args_.MakeEvaluateArgs();
PathAuthorizationMatcher matcher( PathAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::kExact, "expected/path", false) StringMatcher::Create(StringMatcher::Type::kExact,
/*matcher=*/"expected/path",
/*case_sensitive=*/false)
.value(), .value(),
/*not_rule=*/true); /*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args)); EXPECT_FALSE(matcher.Matches(args));
@ -281,6 +281,60 @@ TEST_F(AuthorizationMatchersTest, NotHeaderAuthorizationMatcher) {
EXPECT_TRUE(matcher.Matches(args)); EXPECT_TRUE(matcher.Matches(args));
} }
TEST_F(AuthorizationMatchersTest,
IpAuthorizationMatcherLocalIpSuccessfulMatch) {
args_.SetLocalEndpoint("ipv4:1.2.3.4:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(
IpAuthorizationMatcher::Type::kDestIp,
Rbac::CidrRange(/*address_prefix=*/"1.7.8.9", /*prefix_len=*/8));
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, IpAuthorizationMatcherLocalIpFailedMatch) {
args_.SetLocalEndpoint("ipv4:1.2.3.4:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(
IpAuthorizationMatcher::Type::kDestIp,
Rbac::CidrRange(/*address_prefix=*/"1.2.3.9", /*prefix_len=*/32));
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, IpAuthorizationMatcherPeerIpSuccessfulMatch) {
args_.SetPeerEndpoint("ipv6:[1:2:3::]:456");
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(
IpAuthorizationMatcher::Type::kSourceIp,
Rbac::CidrRange(/*address_prefix=*/"1:2:4::", /*prefix_len=*/32));
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, IpAuthorizationMatcherPeerIpFailedMatch) {
args_.SetPeerEndpoint("ipv6:[1:2::]:456");
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(
IpAuthorizationMatcher::Type::kSourceIp,
Rbac::CidrRange(/*address_prefix=*/"1:3::", /*prefix_len=*/32));
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest,
IpAuthorizationMatcherUnsupportedIpFailedMatch) {
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(IpAuthorizationMatcher::Type::kRemoteIp, {});
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, NotIpAuthorizationMatcherSuccessfulMatch) {
args_.SetLocalEndpoint("ipv4:1.2.3.4:123");
EvaluateArgs args = args_.MakeEvaluateArgs();
IpAuthorizationMatcher matcher(
IpAuthorizationMatcher::Type::kDestIp,
Rbac::CidrRange(/*address_prefix=*/"1.7.8.9", /*prefix_len=*/8),
/*not_rule=*/true);
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherSuccessfulMatch) { TEST_F(AuthorizationMatchersTest, PortAuthorizationMatcherSuccessfulMatch) {
args_.SetLocalEndpoint("ipv4:255.255.255.255:123"); args_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = args_.MakeEvaluateArgs(); EvaluateArgs args = args_.MakeEvaluateArgs();
@ -355,6 +409,36 @@ TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedSpiffeIdMatches) {
EXPECT_FALSE(matcher.Matches(args)); EXPECT_FALSE(matcher.Matches(args));
} }
TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherSuccessfulDnsSanMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
args_.AddPropertyToAuthContext(GRPC_PEER_DNS_PROPERTY_NAME,
"foo.test.domain.com");
args_.AddPropertyToAuthContext(GRPC_PEER_DNS_PROPERTY_NAME,
"bar.test.domain.com");
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::kExact,
/*matcher=*/"bar.test.domain.com",
/*case_sensitive=*/false)
.value());
EXPECT_TRUE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedDnsSanMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE);
args_.AddPropertyToAuthContext(GRPC_PEER_DNS_PROPERTY_NAME,
"foo.test.domain.com");
EvaluateArgs args = args_.MakeEvaluateArgs();
AuthenticatedAuthorizationMatcher matcher(
StringMatcher::Create(StringMatcher::Type::kExact,
/*matcher=*/"bar.test.domain.com",
/*case_sensitive=*/false)
.value());
EXPECT_FALSE(matcher.Matches(args));
}
TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedNothingMatches) { TEST_F(AuthorizationMatchersTest, AuthenticatedMatcherFailedNothingMatches) {
args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, args_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_SSL_TRANSPORT_SECURITY_TYPE); GRPC_SSL_TRANSPORT_SECURITY_TYPE);

@ -17,6 +17,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/security/authorization/evaluate_args.h" #include "src/core/lib/security/authorization/evaluate_args.h"
#include "test/core/util/evaluate_args_test_util.h" #include "test/core/util/evaluate_args_test_util.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
@ -75,38 +76,31 @@ TEST_F(EvaluateArgsTest, GetHeaderValueSuccess) {
EXPECT_EQ(value.value(), "value123"); EXPECT_EQ(value.value(), "value123");
} }
TEST_F(EvaluateArgsTest, TestIpv4LocalAddressAndPort) { TEST_F(EvaluateArgsTest, TestLocalAddressAndPort) {
util_.SetLocalEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_EQ(args.GetLocalAddress(), "255.255.255.255");
EXPECT_EQ(args.GetLocalPort(), 123);
}
TEST_F(EvaluateArgsTest, TestIpv4PeerAddressAndPort) {
util_.SetPeerEndpoint("ipv4:128.128.128.128:321");
EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_EQ(args.GetPeerAddress(), "128.128.128.128");
EXPECT_EQ(args.GetPeerPort(), 321);
}
TEST_F(EvaluateArgsTest, TestIpv6LocalAddressAndPort) {
util_.SetLocalEndpoint("ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456"); util_.SetLocalEndpoint("ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456");
EvaluateArgs args = util_.MakeEvaluateArgs(); EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_EQ(args.GetLocalAddress(), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); grpc_resolved_address local_address = args.GetLocalAddress();
EXPECT_EQ(grpc_sockaddr_to_uri(&local_address),
"ipv6:[2001:db8:85a3::8a2e:370:7334]:456");
EXPECT_EQ(args.GetLocalAddressString(),
"2001:0db8:85a3:0000:0000:8a2e:0370:7334");
EXPECT_EQ(args.GetLocalPort(), 456); EXPECT_EQ(args.GetLocalPort(), 456);
} }
TEST_F(EvaluateArgsTest, TestIpv6PeerAddressAndPort) { TEST_F(EvaluateArgsTest, TestPeerAddressAndPort) {
util_.SetPeerEndpoint("ipv6:[2001:db8::1]:654"); util_.SetPeerEndpoint("ipv4:255.255.255.255:123");
EvaluateArgs args = util_.MakeEvaluateArgs(); EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_EQ(args.GetPeerAddress(), "2001:db8::1"); grpc_resolved_address peer_address = args.GetPeerAddress();
EXPECT_EQ(args.GetPeerPort(), 654); EXPECT_EQ(grpc_sockaddr_to_uri(&peer_address), "ipv4:255.255.255.255:123");
EXPECT_EQ(args.GetPeerAddressString(), "255.255.255.255");
EXPECT_EQ(args.GetPeerPort(), 123);
} }
TEST_F(EvaluateArgsTest, EmptyAuthContext) { TEST_F(EvaluateArgsTest, EmptyAuthContext) {
EvaluateArgs args = util_.MakeEvaluateArgs(); EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_TRUE(args.GetTransportSecurityType().empty()); EXPECT_TRUE(args.GetTransportSecurityType().empty());
EXPECT_TRUE(args.GetSpiffeId().empty()); EXPECT_TRUE(args.GetSpiffeId().empty());
EXPECT_TRUE(args.GetDnsSans().empty());
EXPECT_TRUE(args.GetCommonName().empty()); EXPECT_TRUE(args.GetCommonName().empty());
} }
@ -139,6 +133,13 @@ TEST_F(EvaluateArgsTest, GetSpiffeIdFailDuplicateProperty) {
EXPECT_TRUE(args.GetSpiffeId().empty()); EXPECT_TRUE(args.GetSpiffeId().empty());
} }
TEST_F(EvaluateArgsTest, GetDnsSanSuccessMultipleProperties) {
util_.AddPropertyToAuthContext(GRPC_PEER_DNS_PROPERTY_NAME, "foo");
util_.AddPropertyToAuthContext(GRPC_PEER_DNS_PROPERTY_NAME, "bar");
EvaluateArgs args = util_.MakeEvaluateArgs();
EXPECT_THAT(args.GetDnsSans(), ::testing::ElementsAre("foo", "bar"));
}
TEST_F(EvaluateArgsTest, GetCommonNameSuccessOneProperty) { TEST_F(EvaluateArgsTest, GetCommonNameSuccessOneProperty) {
util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123"); util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123");
EvaluateArgs args = util_.MakeEvaluateArgs(); EvaluateArgs args = util_.MakeEvaluateArgs();

Loading…
Cancel
Save