diff options
Diffstat (limited to 'grpc/test/core/security')
20 files changed, 2193 insertions, 335 deletions
diff --git a/grpc/test/core/security/authorization_matchers_test.cc b/grpc/test/core/security/authorization_matchers_test.cc new file mode 100644 index 00000000..36b38621 --- /dev/null +++ b/grpc/test/core/security/authorization_matchers_test.cc @@ -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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*matcher=*/"bar") + .value())); + rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kDestPort, /*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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*matcher=*/"bar") + .value())); + rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kDestPort, /*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::kExact, + /*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::kPath, 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::kExact, + /*matcher=*/"bar") + .value(); + std::vector<std::unique_ptr<Rbac::Permission>> rules; + rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kHeader, header_matcher)); + rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kDestPort, /*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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*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::kDestPort, /*port=*/123)); + std::vector<std::unique_ptr<Rbac::Permission>> and_rules; + and_rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules))); + and_rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kOr, 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::kHeader, + HeaderMatcher::Create(/*name=*/"foo", HeaderMatcher::Type::kExact, + /*matcher=*/"bar") + .value())); + sub_and_rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kHeader, + HeaderMatcher::Create(/*name=*/"absent_key", HeaderMatcher::Type::kExact, + /*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::kDestPort, /*port=*/123)); + std::vector<std::unique_ptr<Rbac::Permission>> and_rules; + and_rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kAnd, std::move(sub_and_rules))); + and_rules.push_back(absl::make_unique<Rbac::Permission>( + Rbac::Permission::RuleType::kOr, 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::kExact, + /*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::kExact, + /*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::kExact, "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::kExact, + /*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::kPrefix, + /*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::kExact, + /*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::kExact, + /*matcher=*/"foo") + .value()); + EXPECT_FALSE(matcher.Matches(args)); +} + +TEST_F(AuthorizationMatchersTest, + HeaderAuthorizationMatcherFailedMatchMissingHeader) { + EvaluateArgs args = args_.MakeEvaluateArgs(); + HeaderAuthorizationMatcher matcher( + HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kSuffix, + /*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::kExact, + /*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::kExact, + /*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::kExact, + /*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::kExact, + /*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::kExact, + /*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::kExact, + /*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::kExact, /*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::kHeader, + HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact, + /*matcher=*/"foo") + .value())); + PolicyAuthorizationMatcher matcher(Rbac::Policy( + Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)), + Rbac::Principal(Rbac::Principal::RuleType::kAny))); + 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::kHeader, + HeaderMatcher::Create(/*name=*/"key123", HeaderMatcher::Type::kExact, + /*matcher=*/"bar") + .value())); + PolicyAuthorizationMatcher matcher(Rbac::Policy( + Rbac::Permission(Rbac::Permission::RuleType::kOr, std::move(rules)), + Rbac::Principal(Rbac::Principal::RuleType::kAny))); + 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; +} diff --git a/grpc/test/core/security/aws_request_signer_test.cc b/grpc/test/core/security/aws_request_signer_test.cc index e384183c..bc5780fa 100644 --- a/grpc/test/core/security/aws_request_signer_test.cc +++ b/grpc/test/core/security/aws_request_signer_test.cc @@ -65,7 +65,7 @@ const char* kBotoTestDate = "Mon, 09 Sep 2011 23:36:00 GMT"; // AWS official example from the developer doc. // https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( "AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", "", "GET", "https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08", @@ -83,7 +83,7 @@ TEST(GrpcAwsRequestSignerTest, AWSOfficialExample) { } TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "GET", "https://" @@ -100,7 +100,7 @@ TEST(GrpcAwsRequestSignerTest, GetDescribeRegions) { } TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kAmzTestAccessKeyId, kAmzTestSecretAccessKey, kAmzTestToken, "POST", "https://" @@ -117,7 +117,7 @@ TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentity) { } TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kAmzTestAccessKeyId, kAmzTestSecretAccessKey, "", "POST", "https://" @@ -134,7 +134,7 @@ TEST(GrpcAwsRequestSignerTest, PostGetCallerIdentityNoToken) { } TEST(GrpcAwsRequestSignerTest, GetHost) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer(kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "GET", "https://host.foo.com", "us-east-1", @@ -149,7 +149,7 @@ TEST(GrpcAwsRequestSignerTest, GetHost) { } TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "GET", "https://host.foo.com/?foo=Zoo&foo=aha", "us-east-1", "", @@ -164,7 +164,7 @@ TEST(GrpcAwsRequestSignerTest, GetHostDuplicateQueryParam) { } TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST", "https://host.foo.com/", "us-east-1", "", @@ -179,7 +179,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderKey) { } TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST", "https://host.foo.com/", "us-east-1", "", @@ -194,7 +194,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithUpperCaseHeaderValue) { } TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST", "https://host.foo.com/", "us-east-1", "", @@ -209,7 +209,7 @@ TEST(GrpcAwsRequestSignerTest, SignPostWithHeader) { } TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST", "https://host.foo.com/", "us-east-1", "foo=bar", @@ -226,7 +226,7 @@ TEST(GrpcAwsRequestSignerTest, PostWithBodyNoCustomHeaders) { } TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( kBotoTestAccessKeyId, kBotoTestSecretAccessKey, kBotoTestToken, "POST", "https://host.foo.com/?foo=bar", "us-east-1", "", @@ -241,7 +241,7 @@ TEST(GrpcAwsRequestSignerTest, SignPostWithQueryString) { } TEST(GrpcAwsRequestSignerTest, InvalidUrl) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer("access_key_id", "secret_access_key", "token", "POST", "invalid_url", "us-east-1", "", {}, &error); @@ -256,7 +256,7 @@ TEST(GrpcAwsRequestSignerTest, InvalidUrl) { } TEST(GrpcAwsRequestSignerTest, DuplicateRequestDate) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::AwsRequestSigner signer( "access_key_id", "secret_access_key", "token", "POST", "invalid_url", "us-east-1", "", {{"date", kBotoTestDate}, {"x-amz-date", kAmzTestDate}}, diff --git a/grpc/test/core/security/authorization_engine_test.cc b/grpc/test/core/security/cel_authorization_engine_test.cc index 4b456a93..4c94a87d 100644 --- a/grpc/test/core/security/authorization_engine_test.cc +++ b/grpc/test/core/security/cel_authorization_engine_test.cc @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/core/lib/security/authorization/authorization_engine.h" +#include "src/core/lib/security/authorization/cel_authorization_engine.h" #include <gtest/gtest.h> namespace grpc_core { -class AuthorizationEngineTest : public ::testing::Test { +class CelAuthorizationEngineTest : public ::testing::Test { protected: void SetUp() override { deny_policy_ = envoy_config_rbac_v3_RBAC_new(arena_.ptr()); @@ -31,44 +31,44 @@ class AuthorizationEngineTest : public ::testing::Test { envoy_config_rbac_v3_RBAC* allow_policy_; }; -TEST_F(AuthorizationEngineTest, CreateEngineSuccessOnePolicy) { +TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessOnePolicy) { std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_}; - std::unique_ptr<AuthorizationEngine> engine = - AuthorizationEngine::CreateAuthorizationEngine(policies); + std::unique_ptr<CelAuthorizationEngine> engine = + CelAuthorizationEngine::CreateCelAuthorizationEngine(policies); EXPECT_NE(engine, nullptr) - << "Error: Failed to create an AuthorizationEngine with one policy."; + << "Error: Failed to create CelAuthorizationEngine with one policy."; } -TEST_F(AuthorizationEngineTest, CreateEngineSuccessTwoPolicies) { +TEST_F(CelAuthorizationEngineTest, CreateEngineSuccessTwoPolicies) { std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_}; - std::unique_ptr<AuthorizationEngine> engine = - AuthorizationEngine::CreateAuthorizationEngine(policies); + std::unique_ptr<CelAuthorizationEngine> engine = + CelAuthorizationEngine::CreateCelAuthorizationEngine(policies); EXPECT_NE(engine, nullptr) - << "Error: Failed to create an AuthorizationEngine with two policies."; + << "Error: Failed to create CelAuthorizationEngine with two policies."; } -TEST_F(AuthorizationEngineTest, CreateEngineFailNoPolicies) { +TEST_F(CelAuthorizationEngineTest, CreateEngineFailNoPolicies) { std::vector<envoy_config_rbac_v3_RBAC*> policies{}; - std::unique_ptr<AuthorizationEngine> engine = - AuthorizationEngine::CreateAuthorizationEngine(policies); + std::unique_ptr<CelAuthorizationEngine> engine = + CelAuthorizationEngine::CreateCelAuthorizationEngine(policies); EXPECT_EQ(engine, nullptr) - << "Error: Created an AuthorizationEngine without policies."; + << "Error: Created CelAuthorizationEngine without policies."; } -TEST_F(AuthorizationEngineTest, CreateEngineFailTooManyPolicies) { +TEST_F(CelAuthorizationEngineTest, CreateEngineFailTooManyPolicies) { std::vector<envoy_config_rbac_v3_RBAC*> policies{deny_policy_, allow_policy_, deny_policy_}; - std::unique_ptr<AuthorizationEngine> engine = - AuthorizationEngine::CreateAuthorizationEngine(policies); + std::unique_ptr<CelAuthorizationEngine> engine = + CelAuthorizationEngine::CreateCelAuthorizationEngine(policies); EXPECT_EQ(engine, nullptr) - << "Error: Created an AuthorizationEngine with more than two policies."; + << "Error: Created CelAuthorizationEngine with more than two policies."; } -TEST_F(AuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) { +TEST_F(CelAuthorizationEngineTest, CreateEngineFailWrongPolicyOrder) { std::vector<envoy_config_rbac_v3_RBAC*> policies{allow_policy_, deny_policy_}; - std::unique_ptr<AuthorizationEngine> engine = - AuthorizationEngine::CreateAuthorizationEngine(policies); - EXPECT_EQ(engine, nullptr) << "Error: Created an AuthorizationEngine with " + std::unique_ptr<CelAuthorizationEngine> engine = + CelAuthorizationEngine::CreateCelAuthorizationEngine(policies); + EXPECT_EQ(engine, nullptr) << "Error: Created CelAuthorizationEngine with " "policies in the wrong order."; } diff --git a/grpc/test/core/security/credentials_test.cc b/grpc/test/core/security/credentials_test.cc index 6106f6d4..0533247a 100644 --- a/grpc/test/core/security/credentials_test.cc +++ b/grpc/test/core/security/credentials_test.cc @@ -415,7 +415,7 @@ typedef struct { } expected_md; typedef struct { - grpc_error* expected_error; + grpc_error_handle expected_error; const expected_md* expected; size_t expected_size; grpc_credentials_mdelem_array md_array; @@ -443,11 +443,11 @@ static void check_metadata(const expected_md* expected, } } -static void check_request_metadata(void* arg, grpc_error* error) { +static void check_request_metadata(void* arg, grpc_error_handle error) { request_metadata_state* state = static_cast<request_metadata_state*>(arg); gpr_log(GPR_INFO, "expected_error: %s", - grpc_error_string(state->expected_error)); - gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error)); + grpc_error_std_string(state->expected_error).c_str()); + gpr_log(GPR_INFO, "actual_error: %s", grpc_error_std_string(error).c_str()); if (state->expected_error == GRPC_ERROR_NONE) { GPR_ASSERT(error == GRPC_ERROR_NONE); } else { @@ -470,7 +470,7 @@ static void check_request_metadata(void* arg, grpc_error* error) { } static request_metadata_state* make_request_metadata_state( - grpc_error* expected_error, const expected_md* expected, + grpc_error_handle expected_error, const expected_md* expected, size_t expected_size) { request_metadata_state* state = static_cast<request_metadata_state*>(gpr_zalloc(sizeof(*state))); @@ -487,7 +487,7 @@ static request_metadata_state* make_request_metadata_state( static void run_request_metadata_test(grpc_call_credentials* creds, grpc_auth_metadata_context auth_md_ctx, request_metadata_state* state) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; if (creds->get_request_metadata(&state->pollent, auth_md_ctx, &state->md_array, &state->on_request_metadata, &error)) { @@ -1663,27 +1663,27 @@ struct fake_call_creds : public grpc_call_credentials { explicit fake_call_creds() : grpc_call_credentials("fake") { grpc_slice key = grpc_slice_from_static_string("foo"); grpc_slice value = grpc_slice_from_static_string("oof"); - dummy_md_ = grpc_mdelem_from_slices(key, value); + phony_md_ = grpc_mdelem_from_slices(key, value); grpc_slice_unref(key); grpc_slice_unref(value); } - ~fake_call_creds() override { GRPC_MDELEM_UNREF(dummy_md_); } + ~fake_call_creds() override { GRPC_MDELEM_UNREF(phony_md_); } - bool get_request_metadata(grpc_polling_entity* pollent, - grpc_auth_metadata_context context, + bool get_request_metadata(grpc_polling_entity* /*pollent*/, + grpc_auth_metadata_context /*context*/, grpc_credentials_mdelem_array* md_array, - grpc_closure* on_request_metadata, - grpc_error** error) override { - grpc_credentials_mdelem_array_add(md_array, dummy_md_); + grpc_closure* /*on_request_metadata*/, + grpc_error_handle* /*error*/) override { + grpc_credentials_mdelem_array_add(md_array, phony_md_); return true; } - void cancel_get_request_metadata(grpc_credentials_mdelem_array* md_array, - grpc_error* error) override {} + void cancel_get_request_metadata(grpc_credentials_mdelem_array* /*md_array*/, + grpc_error_handle /*error*/) override {} private: - grpc_mdelem dummy_md_; + grpc_mdelem phony_md_; }; static void test_google_default_creds_not_default(void) { @@ -1983,7 +1983,7 @@ static void test_auth_metadata_context(void) { static void validate_external_account_creds_token_exchage_request( const grpc_httpcli_request* request, const char* body, size_t body_size, - bool expect_actor_token) { + bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); @@ -2021,7 +2021,7 @@ static void validate_external_account_creds_token_exchage_request( static void validate_external_account_creds_token_exchage_request_with_url_encode( const grpc_httpcli_request* request, const char* body, size_t body_size, - bool expect_actor_token) { + bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); @@ -2051,7 +2051,7 @@ validate_external_account_creds_token_exchage_request_with_url_encode( static void validate_external_account_creds_service_account_impersonation_request( const grpc_httpcli_request* request, const char* body, size_t body_size, - bool expect_actor_token) { + bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); @@ -2097,8 +2097,8 @@ static int external_account_creds_httpcli_post_success( static int external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token( - const grpc_httpcli_request* request, const char* body, size_t body_size, - grpc_millis /*deadline*/, grpc_closure* on_done, + const grpc_httpcli_request* request, const char* /*body*/, + size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* on_done, grpc_httpcli_response* response) { if (strcmp(request->http.path, "/token") == 0) { *response = http_response(200, @@ -2139,10 +2139,13 @@ static int url_external_account_creds_httpcli_get_success( static void validate_aws_external_account_creds_token_exchage_request( const grpc_httpcli_request* request, const char* body, size_t body_size, - bool expect_actor_token) { + bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); + // Check that the regional_cred_verification_url got constructed + // with the correct AWS Region ("test_regionz" or "test_region"). + GPR_ASSERT(strstr(body, "regional_cred_verification_url_test_region")); GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); std::string get_url_equivalent = absl::StrFormat("%s?%s", "https://foo.com:5555/token", body); @@ -2212,8 +2215,8 @@ class TestExternalAccountCredentials final protected: void RetrieveSubjectToken( - HTTPRequestContext* ctx, const Options& options, - std::function<void(std::string, grpc_error*)> cb) override { + HTTPRequestContext* /*ctx*/, const Options& /*options*/, + std::function<void(std::string, grpc_error_handle)> cb) override { cb("test_subject_token", GRPC_ERROR_NONE); } }; @@ -2337,10 +2340,11 @@ static void test_external_account_creds_failure_invalid_token_url(void) { TestExternalAccountCredentials creds(options, {}); grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); - grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid token url: invalid_token_url."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); run_request_metadata_test(&creds, auth_md_ctx, state); @@ -2371,11 +2375,12 @@ test_external_account_creds_failure_invalid_service_account_impersonation_url( TestExternalAccountCredentials creds(options, {}); grpc_httpcli_set_override(httpcli_get_should_not_be_called, external_account_creds_httpcli_post_success); - grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid service account impersonation url: " "invalid_service_account_impersonation_url."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); run_request_metadata_test(&creds, auth_md_ctx, state); @@ -2407,12 +2412,13 @@ test_external_account_creds_failure_token_exchange_response_missing_access_token grpc_httpcli_set_override( httpcli_get_should_not_be_called, external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token); - grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Missing or invalid access_token in " "{\"not_access_token\":\"not_access_token\",\"expires_in\":3599,\"token_" "type\":\"Bearer\"}."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); run_request_metadata_test(&creds, auth_md_ctx, state); @@ -2426,7 +2432,7 @@ static void test_url_external_account_creds_success_format_text(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_url_external_account_creds_options_credential_source_format_text, &error); @@ -2463,7 +2469,7 @@ test_url_external_account_creds_success_with_qurey_params_format_text(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text, &error); @@ -2499,7 +2505,7 @@ static void test_url_external_account_creds_success_format_json(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_url_external_account_creds_options_credential_source_format_json, &error); @@ -2532,7 +2538,7 @@ static void test_url_external_account_creds_success_format_json(void) { static void test_url_external_account_creds_failure_invalid_credential_source_url(void) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_url_external_account_creds_options_credential_source, &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2565,7 +2571,7 @@ static void test_file_external_account_creds_success_format_text(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; char* subject_token_path = write_tmp_jwt_file("test_subject_token"); grpc_core::Json credential_source = grpc_core::Json::Parse( absl::StrFormat( @@ -2606,7 +2612,7 @@ static void test_file_external_account_creds_success_format_json(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; char* subject_token_path = write_tmp_jwt_file("{\"access_token\":\"test_subject_token\"}"); grpc_core::Json credential_source = grpc_core::Json::Parse( @@ -2654,7 +2660,7 @@ static void test_file_external_account_creds_failure_file_not_found(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse("{\"file\":\"non_exisiting_file\"}", &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2677,8 +2683,9 @@ static void test_file_external_account_creds_failure_file_not_found(void) { grpc_httpcli_set_override(httpcli_get_should_not_be_called, httpcli_post_should_not_be_called); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to load file"); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); run_request_metadata_test(creds.get(), auth_md_ctx, state); @@ -2692,7 +2699,7 @@ static void test_file_external_account_creds_failure_invalid_json_content( grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; char* subject_token_path = write_tmp_jwt_file("not_a_valid_json_file"); grpc_core::Json credential_source = grpc_core::Json::Parse( absl::StrFormat( @@ -2727,8 +2734,9 @@ static void test_file_external_account_creds_failure_invalid_json_content( httpcli_post_should_not_be_called); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "The content of the file is not a valid json object."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); run_request_metadata_test(creds.get(), auth_md_ctx, state); @@ -2743,7 +2751,7 @@ static void test_aws_external_account_creds_success(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_aws_external_account_creds_options_credential_source, &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2780,7 +2788,86 @@ static void test_aws_external_account_creds_success_path_region_env_keys_url( grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; gpr_setenv("AWS_REGION", "test_regionz"); - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; + grpc_core::Json credential_source = grpc_core::Json::Parse( + valid_aws_external_account_creds_options_credential_source, &error); + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_core::ExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "", // service_account_impersonation_url; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + }; + auto creds = + grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error); + GPR_ASSERT(creds != nullptr); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); + request_metadata_state* state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); + grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); + run_request_metadata_test(creds.get(), auth_md_ctx, state); + grpc_core::ExecCtx::Get()->Flush(); + grpc_httpcli_set_override(nullptr, nullptr); + gpr_unsetenv("AWS_REGION"); +} + +static void +test_aws_external_account_creds_success_path_default_region_env_keys_url(void) { + expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}}; + grpc_core::ExecCtx exec_ctx; + grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, + nullptr, nullptr}; + gpr_setenv("AWS_DEFAULT_REGION", "test_regionz"); + grpc_error_handle error = GRPC_ERROR_NONE; + grpc_core::Json credential_source = grpc_core::Json::Parse( + valid_aws_external_account_creds_options_credential_source, &error); + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_core::ExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "", // service_account_impersonation_url; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + }; + auto creds = + grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error); + GPR_ASSERT(creds != nullptr); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); + request_metadata_state* state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); + grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); + run_request_metadata_test(creds.get(), auth_md_ctx, state); + grpc_core::ExecCtx::Get()->Flush(); + grpc_httpcli_set_override(nullptr, nullptr); + gpr_unsetenv("AWS_DEFAULT_REGION"); +} + +static void +test_aws_external_account_creds_success_path_duplicate_region_env_keys_url( + void) { + expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}}; + grpc_core::ExecCtx exec_ctx; + grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, + nullptr, nullptr}; + // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION + gpr_setenv("AWS_REGION", "test_regionz"); + gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION"); + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_aws_external_account_creds_options_credential_source, &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2809,6 +2896,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_url( grpc_core::ExecCtx::Get()->Flush(); grpc_httpcli_set_override(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); + gpr_unsetenv("AWS_DEFAULT_REGION"); } static void test_aws_external_account_creds_success_path_region_url_keys_env( @@ -2820,7 +2908,7 @@ static void test_aws_external_account_creds_success_path_region_url_keys_env( gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id"); gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key"); gpr_setenv("AWS_SESSION_TOKEN", "test_token"); - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_aws_external_account_creds_options_credential_source, &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2863,7 +2951,98 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env( gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id"); gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key"); gpr_setenv("AWS_SESSION_TOKEN", "test_token"); - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; + grpc_core::Json credential_source = grpc_core::Json::Parse( + valid_aws_external_account_creds_options_credential_source, &error); + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_core::ExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "", // service_account_impersonation_url; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + }; + auto creds = + grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error); + GPR_ASSERT(creds != nullptr); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); + request_metadata_state* state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); + grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); + run_request_metadata_test(creds.get(), auth_md_ctx, state); + grpc_core::ExecCtx::Get()->Flush(); + grpc_httpcli_set_override(nullptr, nullptr); + gpr_unsetenv("AWS_REGION"); + gpr_unsetenv("AWS_ACCESS_KEY_ID"); + gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); + gpr_unsetenv("AWS_SESSION_TOKEN"); +} + +static void +test_aws_external_account_creds_success_path_default_region_env_keys_env(void) { + expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}}; + grpc_core::ExecCtx exec_ctx; + grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, + nullptr, nullptr}; + gpr_setenv("AWS_DEFAULT_REGION", "test_regionz"); + gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id"); + gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key"); + gpr_setenv("AWS_SESSION_TOKEN", "test_token"); + grpc_error_handle error = GRPC_ERROR_NONE; + grpc_core::Json credential_source = grpc_core::Json::Parse( + valid_aws_external_account_creds_options_credential_source, &error); + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_core::ExternalAccountCredentials::Options options = { + "external_account", // type; + "audience", // audience; + "subject_token_type", // subject_token_type; + "", // service_account_impersonation_url; + "https://foo.com:5555/token", // token_url; + "https://foo.com:5555/token_info", // token_info_url; + credential_source, // credential_source; + "quota_project_id", // quota_project_id; + "client_id", // client_id; + "client_secret", // client_secret; + }; + auto creds = + grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error); + GPR_ASSERT(creds != nullptr); + GPR_ASSERT(error == GRPC_ERROR_NONE); + GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); + request_metadata_state* state = + make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd)); + grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); + run_request_metadata_test(creds.get(), auth_md_ctx, state); + grpc_core::ExecCtx::Get()->Flush(); + grpc_httpcli_set_override(nullptr, nullptr); + gpr_unsetenv("AWS_DEFAULT_REGION"); + gpr_unsetenv("AWS_ACCESS_KEY_ID"); + gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); + gpr_unsetenv("AWS_SESSION_TOKEN"); +} + +static void +test_aws_external_account_creds_success_path_duplicate_region_env_keys_env( + void) { + expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}}; + grpc_core::ExecCtx exec_ctx; + grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, + nullptr, nullptr}; + // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION + gpr_setenv("AWS_REGION", "test_regionz"); + gpr_setenv("AWS_DEFAULT_REGION", "ERROR_REGION"); + gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id"); + gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key"); + gpr_setenv("AWS_SESSION_TOKEN", "test_token"); + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( valid_aws_external_account_creds_options_credential_source, &error); GPR_ASSERT(error == GRPC_ERROR_NONE); @@ -2892,6 +3071,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env( grpc_core::ExecCtx::Get()->Flush(); grpc_httpcli_set_override(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); + gpr_unsetenv("AWS_DEFAULT_REGION"); gpr_unsetenv("AWS_ACCESS_KEY_ID"); gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); gpr_unsetenv("AWS_SESSION_TOKEN"); @@ -2899,7 +3079,7 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env( static void test_aws_external_account_creds_failure_unmatched_environment_id( void) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id, &error); @@ -2932,7 +3112,7 @@ static void test_aws_external_account_creds_failure_invalid_region_url(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_aws_external_account_creds_options_credential_source_invalid_region_url, &error); @@ -2956,8 +3136,9 @@ static void test_aws_external_account_creds_failure_invalid_region_url(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid region url: invalid_region_url."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, @@ -2972,7 +3153,7 @@ static void test_aws_external_account_creds_failure_invalid_url(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_aws_external_account_creds_options_credential_source_invalid_url, &error); @@ -2995,8 +3176,9 @@ static void test_aws_external_account_creds_failure_invalid_url(void) { GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid url: invalid_url."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, @@ -3011,7 +3193,7 @@ static void test_aws_external_account_creds_failure_missing_role_name(void) { grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_aws_external_account_creds_options_credential_source_missing_role_name, &error); @@ -3035,8 +3217,9 @@ static void test_aws_external_account_creds_failure_missing_role_name(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Missing role name when retrieving signing keys."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, @@ -3053,7 +3236,7 @@ test_aws_external_account_creds_failure_invalid_regional_cred_verification_url( grpc_core::ExecCtx exec_ctx; grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method, nullptr, nullptr}; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; grpc_core::Json credential_source = grpc_core::Json::Parse( invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url, &error); @@ -3077,8 +3260,9 @@ test_aws_external_account_creds_failure_invalid_regional_cred_verification_url( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Creating aws request signer failed."); - grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Error occurred when fetching oauth2 token.", &error, 1); + grpc_error_handle expected_error = + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Error occurred when fetching oauth2 token.", &error, 1); request_metadata_state* state = make_request_metadata_state(expected_error, nullptr, 0); grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, @@ -3235,8 +3419,12 @@ int main(int argc, char** argv) { test_file_external_account_creds_failure_invalid_json_content(); test_aws_external_account_creds_success(); test_aws_external_account_creds_success_path_region_env_keys_url(); + test_aws_external_account_creds_success_path_default_region_env_keys_url(); + test_aws_external_account_creds_success_path_duplicate_region_env_keys_url(); test_aws_external_account_creds_success_path_region_url_keys_env(); test_aws_external_account_creds_success_path_region_env_keys_env(); + test_aws_external_account_creds_success_path_default_region_env_keys_env(); + test_aws_external_account_creds_success_path_duplicate_region_env_keys_env(); test_aws_external_account_creds_failure_unmatched_environment_id(); test_aws_external_account_creds_failure_invalid_region_url(); test_aws_external_account_creds_failure_invalid_url(); diff --git a/grpc/test/core/security/evaluate_args_test.cc b/grpc/test/core/security/evaluate_args_test.cc index aa1b4361..de98537d 100644 --- a/grpc/test/core/security/evaluate_args_test.cc +++ b/grpc/test/core/security/evaluate_args_test.cc @@ -1,4 +1,4 @@ -// Copyright 2020 gRPC authors. +// 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. @@ -17,203 +17,139 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> -#include "absl/strings/string_view.h" - #include "src/core/lib/security/authorization/evaluate_args.h" -#include "test/core/util/eval_args_mock_endpoint.h" +#include "test/core/util/evaluate_args_test_util.h" #include "test/core/util/test_config.h" namespace grpc_core { class EvaluateArgsTest : public ::testing::Test { protected: - void SetUp() override { - local_address_ = "255.255.255.255"; - peer_address_ = "128.128.128.128"; - local_port_ = 413; - peer_port_ = 314; - endpoint_ = CreateEvalArgsMockEndpoint(local_address_.c_str(), local_port_, - peer_address_.c_str(), peer_port_); - evaluate_args_ = - absl::make_unique<EvaluateArgs>(nullptr, nullptr, endpoint_); - } - void TearDown() override { grpc_endpoint_destroy(endpoint_); } - grpc_endpoint* endpoint_; - std::unique_ptr<EvaluateArgs> evaluate_args_; - std::string local_address_; - std::string peer_address_; - int local_port_; - int peer_port_; + EvaluateArgsTestUtil util_; }; -TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalAddress) { - absl::string_view src_address = evaluate_args_->GetLocalAddress(); - EXPECT_EQ(src_address, local_address_); +TEST_F(EvaluateArgsTest, EmptyMetadata) { + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetPath(), nullptr); + EXPECT_EQ(args.GetMethod(), nullptr); + EXPECT_EQ(args.GetHost(), nullptr); + EXPECT_THAT(args.GetHeaders(), ::testing::ElementsAre()); + EXPECT_EQ(args.GetHeaderValue("some_key", nullptr), absl::nullopt); } -TEST_F(EvaluateArgsTest, TestEvaluateArgsLocalPort) { - int src_port = evaluate_args_->GetLocalPort(); - EXPECT_EQ(src_port, local_port_); +TEST_F(EvaluateArgsTest, GetPathSuccess) { + util_.AddPairToMetadata(":path", "/expected/path"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetPath(), "/expected/path"); } -TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerAddress) { - absl::string_view dest_address = evaluate_args_->GetPeerAddress(); - EXPECT_EQ(dest_address, peer_address_); +TEST_F(EvaluateArgsTest, GetHostSuccess) { + util_.AddPairToMetadata("host", "host123"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetHost(), "host123"); } -TEST_F(EvaluateArgsTest, TestEvaluateArgsPeerPort) { - int dest_port = evaluate_args_->GetPeerPort(); - EXPECT_EQ(dest_port, peer_port_); +TEST_F(EvaluateArgsTest, GetMethodSuccess) { + util_.AddPairToMetadata(":method", "GET"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetMethod(), "GET"); } -TEST(EvaluateArgsMetadataTest, HandlesNullMetadata) { - EvaluateArgs eval_args(nullptr, nullptr, nullptr); - EXPECT_EQ(eval_args.GetPath(), nullptr); - EXPECT_EQ(eval_args.GetMethod(), nullptr); - EXPECT_EQ(eval_args.GetHost(), nullptr); - EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre()); +TEST_F(EvaluateArgsTest, GetHeadersSuccess) { + util_.AddPairToMetadata("host", "host123"); + util_.AddPairToMetadata(":path", "/expected/path"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_THAT(args.GetHeaders(), + ::testing::UnorderedElementsAre( + ::testing::Pair("host", "host123"), + ::testing::Pair(":path", "/expected/path"))); } -TEST(EvaluateArgsMetadataTest, HandlesEmptyMetadata) { - grpc_metadata_batch metadata; - grpc_metadata_batch_init(&metadata); - EvaluateArgs eval_args(&metadata, nullptr, nullptr); - EXPECT_EQ(eval_args.GetPath(), nullptr); - EXPECT_EQ(eval_args.GetMethod(), nullptr); - EXPECT_EQ(eval_args.GetHost(), nullptr); - EXPECT_THAT(eval_args.GetHeaders(), ::testing::ElementsAre()); - grpc_metadata_batch_destroy(&metadata); +TEST_F(EvaluateArgsTest, GetHeaderValueSuccess) { + util_.AddPairToMetadata("key123", "value123"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + std::string concatenated_value; + absl::optional<absl::string_view> value = + args.GetHeaderValue("key123", &concatenated_value); + ASSERT_TRUE(value.has_value()); + EXPECT_EQ(value.value(), "value123"); } -TEST(EvaluateArgsMetadataTest, GetPathSuccess) { - grpc_init(); - const char* kPath = "/some/path"; - grpc_metadata_batch metadata; - grpc_metadata_batch_init(&metadata); - grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kPath)); - grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_val); - grpc_linked_mdelem storage; - storage.md = fake_val_md; - ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage), - GRPC_ERROR_NONE); - EvaluateArgs eval_args(&metadata, nullptr, nullptr); - EXPECT_EQ(eval_args.GetPath(), kPath); - grpc_metadata_batch_destroy(&metadata); - grpc_shutdown(); +TEST_F(EvaluateArgsTest, TestIpv4LocalAddressAndPort) { + 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(EvaluateArgsMetadataTest, GetHostSuccess) { - grpc_init(); - const char* kHost = "host"; - grpc_metadata_batch metadata; - grpc_metadata_batch_init(&metadata); - grpc_slice fake_val = grpc_slice_intern(grpc_slice_from_static_string(kHost)); - grpc_mdelem fake_val_md = grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_val); - grpc_linked_mdelem storage; - storage.md = fake_val_md; - ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage), - GRPC_ERROR_NONE); - EvaluateArgs eval_args(&metadata, nullptr, nullptr); - EXPECT_EQ(eval_args.GetHost(), kHost); - grpc_metadata_batch_destroy(&metadata); - grpc_shutdown(); +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(EvaluateArgsMetadataTest, GetMethodSuccess) { - grpc_init(); - const char* kMethod = "GET"; - grpc_metadata_batch metadata; - grpc_metadata_batch_init(&metadata); - grpc_slice fake_val = - grpc_slice_intern(grpc_slice_from_static_string(kMethod)); - grpc_mdelem fake_val_md = - grpc_mdelem_from_slices(GRPC_MDSTR_METHOD, fake_val); - grpc_linked_mdelem storage; - storage.md = fake_val_md; - ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage), - GRPC_ERROR_NONE); - EvaluateArgs eval_args(&metadata, nullptr, nullptr); - EXPECT_EQ(eval_args.GetMethod(), kMethod); - grpc_metadata_batch_destroy(&metadata); - grpc_shutdown(); +TEST_F(EvaluateArgsTest, TestIpv6LocalAddressAndPort) { + util_.SetLocalEndpoint("ipv6:[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:456"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetLocalAddress(), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + EXPECT_EQ(args.GetLocalPort(), 456); } -TEST(EvaluateArgsMetadataTest, GetHeadersSuccess) { - grpc_init(); - const char* kPath = "/some/path"; - const char* kHost = "host"; - grpc_metadata_batch metadata; - grpc_metadata_batch_init(&metadata); - grpc_slice fake_path = - grpc_slice_intern(grpc_slice_from_static_string(kPath)); - grpc_mdelem fake_path_md = - grpc_mdelem_from_slices(GRPC_MDSTR_PATH, fake_path); - grpc_linked_mdelem storage; - storage.md = fake_path_md; - ASSERT_EQ(grpc_metadata_batch_link_head(&metadata, &storage, GRPC_BATCH_PATH), - GRPC_ERROR_NONE); - grpc_slice fake_host = - grpc_slice_intern(grpc_slice_from_static_string(kHost)); - grpc_mdelem fake_host_md = - grpc_mdelem_from_slices(GRPC_MDSTR_HOST, fake_host); - grpc_linked_mdelem storage2; - storage2.md = fake_host_md; - ASSERT_EQ( - grpc_metadata_batch_link_tail(&metadata, &storage2, GRPC_BATCH_HOST), - GRPC_ERROR_NONE); - EvaluateArgs eval_args(&metadata, nullptr, nullptr); - EXPECT_THAT( - eval_args.GetHeaders(), - ::testing::UnorderedElementsAre( - ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_HOST), kHost), - ::testing::Pair(StringViewFromSlice(GRPC_MDSTR_PATH), kPath))); - grpc_metadata_batch_destroy(&metadata); - grpc_shutdown(); +TEST_F(EvaluateArgsTest, TestIpv6PeerAddressAndPort) { + util_.SetPeerEndpoint("ipv6:[2001:db8::1]:654"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetPeerAddress(), "2001:db8::1"); + EXPECT_EQ(args.GetPeerPort(), 654); +} + +TEST_F(EvaluateArgsTest, EmptyAuthContext) { + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_TRUE(args.GetTransportSecurityType().empty()); + EXPECT_TRUE(args.GetSpiffeId().empty()); + EXPECT_TRUE(args.GetCommonName().empty()); } -TEST(EvaluateArgsAuthContextTest, HandlesNullAuthContext) { - EvaluateArgs eval_args(nullptr, nullptr, nullptr); - EXPECT_EQ(eval_args.GetSpiffeId(), nullptr); - EXPECT_EQ(eval_args.GetCertServerName(), nullptr); +TEST_F(EvaluateArgsTest, GetTransportSecurityTypeSuccessOneProperty) { + util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + "ssl"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetTransportSecurityType(), "ssl"); } -TEST(EvaluateArgsAuthContextTest, HandlesEmptyAuthCtx) { - grpc_auth_context auth_context(nullptr); - EvaluateArgs eval_args(nullptr, &auth_context, nullptr); - EXPECT_EQ(eval_args.GetSpiffeId(), nullptr); - EXPECT_EQ(eval_args.GetCertServerName(), nullptr); +TEST_F(EvaluateArgsTest, GetTransportSecurityTypeFailDuplicateProperty) { + util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + "type1"); + util_.AddPropertyToAuthContext(GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + "type2"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_TRUE(args.GetTransportSecurityType().empty()); } -TEST(EvaluateArgsAuthContextTest, GetSpiffeIdSuccessOneProperty) { - grpc_auth_context auth_context(nullptr); - const char* kId = "spiffeid"; - auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, kId); - EvaluateArgs eval_args(nullptr, &auth_context, nullptr); - EXPECT_EQ(eval_args.GetSpiffeId(), kId); +TEST_F(EvaluateArgsTest, GetSpiffeIdSuccessOneProperty) { + util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetSpiffeId(), "id123"); } -TEST(EvaluateArgsAuthContextTest, GetSpiffeIdFailDuplicateProperty) { - grpc_auth_context auth_context(nullptr); - auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id1"); - auth_context.add_cstring_property(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id2"); - EvaluateArgs eval_args(nullptr, &auth_context, nullptr); - EXPECT_EQ(eval_args.GetSpiffeId(), nullptr); +TEST_F(EvaluateArgsTest, GetSpiffeIdFailDuplicateProperty) { + util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id123"); + util_.AddPropertyToAuthContext(GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, "id456"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_TRUE(args.GetSpiffeId().empty()); } -TEST(EvaluateArgsAuthContextTest, GetCertServerNameSuccessOneProperty) { - grpc_auth_context auth_context(nullptr); - const char* kServer = "server"; - auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, kServer); - EvaluateArgs eval_args(nullptr, &auth_context, nullptr); - EXPECT_EQ(eval_args.GetCertServerName(), kServer); +TEST_F(EvaluateArgsTest, GetCommonNameSuccessOneProperty) { + util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_EQ(args.GetCommonName(), "server123"); } -TEST(EvaluateArgsAuthContextTest, GetCertServerNameFailDuplicateProperty) { - grpc_auth_context auth_context(nullptr); - auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server1"); - auth_context.add_cstring_property(GRPC_X509_CN_PROPERTY_NAME, "server2"); - EvaluateArgs eval_args(nullptr, &auth_context, nullptr); - EXPECT_EQ(eval_args.GetCertServerName(), nullptr); +TEST_F(EvaluateArgsTest, GetCommonNameFailDuplicateProperty) { + util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server123"); + util_.AddPropertyToAuthContext(GRPC_X509_CN_PROPERTY_NAME, "server456"); + EvaluateArgs args = util_.MakeEvaluateArgs(); + EXPECT_TRUE(args.GetCommonName().empty()); } } // namespace grpc_core @@ -221,5 +157,8 @@ TEST(EvaluateArgsAuthContextTest, GetCertServerNameFailDuplicateProperty) { int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + grpc_init(); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; } diff --git a/grpc/test/core/security/grpc_authorization_engine_test.cc b/grpc/test/core/security/grpc_authorization_engine_test.cc new file mode 100644 index 00000000..a2b5e114 --- /dev/null +++ b/grpc/test/core/security/grpc_authorization_engine_test.cc @@ -0,0 +1,107 @@ +// 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 <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "src/core/lib/security/authorization/grpc_authorization_engine.h" + +namespace grpc_core { + +TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) { + Rbac::Policy policy1( + Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), + Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); + Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)), + (Rbac::Principal(Rbac::Principal::RuleType::kAny))); + std::map<std::string, Rbac::Policy> policies; + policies["policy1"] = std::move(policy1); + policies["policy2"] = std::move(policy2); + Rbac rbac(Rbac::Action::kAllow, std::move(policies)); + GrpcAuthorizationEngine engine(std::move(rbac)); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); + EXPECT_EQ(decision.matching_policy_name, "policy2"); +} + +TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) { + Rbac::Policy policy1( + Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), + Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); + std::map<std::string, Rbac::Policy> policies; + policies["policy1"] = std::move(policy1); + Rbac rbac(Rbac::Action::kAllow, std::move(policies)); + GrpcAuthorizationEngine engine(std::move(rbac)); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); + EXPECT_TRUE(decision.matching_policy_name.empty()); +} + +TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) { + GrpcAuthorizationEngine engine(Rbac::Action::kAllow); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); + EXPECT_TRUE(decision.matching_policy_name.empty()); +} + +TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) { + Rbac::Policy policy1( + Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), + Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); + Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)), + (Rbac::Principal(Rbac::Principal::RuleType::kAny))); + std::map<std::string, Rbac::Policy> policies; + policies["policy1"] = std::move(policy1); + policies["policy2"] = std::move(policy2); + Rbac rbac(Rbac::Action::kDeny, std::move(policies)); + GrpcAuthorizationEngine engine(std::move(rbac)); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); + EXPECT_EQ(decision.matching_policy_name, "policy2"); +} + +TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) { + Rbac::Policy policy1( + Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), + Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); + std::map<std::string, Rbac::Policy> policies; + policies["policy1"] = std::move(policy1); + Rbac rbac(Rbac::Action::kDeny, std::move(policies)); + GrpcAuthorizationEngine engine(std::move(rbac)); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); + EXPECT_TRUE(decision.matching_policy_name.empty()); +} + +TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) { + GrpcAuthorizationEngine engine(Rbac::Action::kDeny); + AuthorizationEngine::Decision decision = + engine.Evaluate(EvaluateArgs(nullptr, nullptr)); + EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); + EXPECT_TRUE(decision.matching_policy_name.empty()); +} + +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc b/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc index 9e8efcc4..92123a18 100644 --- a/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc +++ b/grpc/test/core/security/grpc_tls_certificate_distributor_test.cc @@ -129,8 +129,8 @@ class GrpcTlsCertificateDistributorTest : public ::testing::Test { std::move(updated_identity)); } - void OnError(grpc_error* root_cert_error, - grpc_error* identity_cert_error) override { + void OnError(grpc_error_handle root_cert_error, + grpc_error_handle identity_cert_error) override { GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE || identity_cert_error != GRPC_ERROR_NONE); std::string root_error_str; @@ -562,8 +562,8 @@ TEST_F(GrpcTlsCertificateDistributorTest, ResetCallbackToNull) { TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) { distributor_.SetWatchStatusCallback([this](std::string cert_name, - bool root_being_watched, - bool identity_being_watched) { + bool /*root_being_watched*/, + bool /*identity_being_watched*/) { distributor_.SetKeyMaterials( cert_name, kRootCert1Contents, MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents)); @@ -913,8 +913,8 @@ TEST_F(GrpcTlsCertificateDistributorTest, WatchErroredCertInfoBySetError) { TEST_F(GrpcTlsCertificateDistributorTest, SetErrorForCertInCallback) { distributor_.SetWatchStatusCallback([this](std::string cert_name, - bool root_being_watched, - bool identity_being_watched) { + bool /*root_being_watched*/, + bool /*identity_being_watched*/) { this->distributor_.SetErrorForCert( cert_name, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage), GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage)); diff --git a/grpc/test/core/security/grpc_tls_certificate_provider_test.cc b/grpc/test/core/security/grpc_tls_certificate_provider_test.cc index 50553577..9d675569 100644 --- a/grpc/test/core/security/grpc_tls_certificate_provider_test.cc +++ b/grpc/test/core/security/grpc_tls_certificate_provider_test.cc @@ -131,8 +131,8 @@ class GrpcTlsCertificateProviderTest : public ::testing::Test { std::move(updated_identity)); } - void OnError(grpc_error* root_cert_error, - grpc_error* identity_cert_error) override { + void OnError(grpc_error_handle root_cert_error, + grpc_error_handle identity_cert_error) override { MutexLock lock(&state_->mu); GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE || identity_cert_error != GRPC_ERROR_NONE); diff --git a/grpc/test/core/security/grpc_tls_credentials_options_test.cc b/grpc/test/core/security/grpc_tls_credentials_options_test.cc index 5e9a4e31..c5736ca1 100644 --- a/grpc/test/core/security/grpc_tls_credentials_options_test.cc +++ b/grpc/test/core/security/grpc_tls_credentials_options_test.cc @@ -69,6 +69,21 @@ TEST_F(GrpcTlsCredentialsOptionsTest, ErrorDetails) { EXPECT_STREQ(error_details.error_details().c_str(), "test error details"); } +TEST_F(GrpcTlsCredentialsOptionsTest, ClientOptionsOnDefaultRootCerts) { + auto options = MakeRefCounted<grpc_tls_credentials_options>(); + options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION); + auto credentials = MakeRefCounted<TlsCredentials>(options); + ASSERT_NE(credentials, nullptr); + grpc_channel_args* new_args = nullptr; + auto connector = credentials->create_security_connector( + nullptr, "random targets", nullptr, &new_args); + grpc_channel_args_destroy(new_args); + ASSERT_NE(connector, nullptr); + TlsChannelSecurityConnector* tls_connector = + static_cast<TlsChannelSecurityConnector*>(connector.get()); + EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr); +} + // Tests for StaticDataCertificateProvider. TEST_F(GrpcTlsCredentialsOptionsTest, ClientOptionsWithStaticDataProviderOnBothCerts) { @@ -136,6 +151,26 @@ TEST_F(GrpcTlsCredentialsOptionsTest, } TEST_F(GrpcTlsCredentialsOptionsTest, + ClientOptionsWithDefaultRootAndStaticDataProviderOnIdentityCerts) { + auto options = MakeRefCounted<grpc_tls_credentials_options>(); + auto provider = MakeRefCounted<StaticDataCertificateProvider>( + "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str())); + options->set_certificate_provider(std::move(provider)); + options->set_watch_identity_pair(true); + options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION); + auto credentials = MakeRefCounted<TlsCredentials>(options); + ASSERT_NE(credentials, nullptr); + grpc_channel_args* new_args = nullptr; + auto connector = credentials->create_security_connector( + nullptr, "random targets", nullptr, &new_args); + grpc_channel_args_destroy(new_args); + ASSERT_NE(connector, nullptr); + TlsChannelSecurityConnector* tls_connector = + static_cast<TlsChannelSecurityConnector*>(connector.get()); + EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr); +} + +TEST_F(GrpcTlsCredentialsOptionsTest, ServerOptionsWithStaticDataProviderOnBothCerts) { auto options = MakeRefCounted<grpc_tls_credentials_options>(); auto provider = MakeRefCounted<StaticDataCertificateProvider>( @@ -147,7 +182,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -166,7 +201,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -185,14 +220,14 @@ TEST_F(GrpcTlsCredentialsOptionsTest, options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr); } -//// Tests for FileWatcherCertificateProvider. +// Tests for FileWatcherCertificateProvider. TEST_F(GrpcTlsCredentialsOptionsTest, ClientOptionsWithCertWatcherProviderOnBothCerts) { auto options = MakeRefCounted<grpc_tls_credentials_options>(); @@ -290,7 +325,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -309,7 +344,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -328,7 +363,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -345,7 +380,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE); auto credentials = MakeRefCounted<TlsServerCredentials>(options); ASSERT_NE(credentials, nullptr); - auto connector = credentials->create_security_connector(); + auto connector = credentials->create_security_connector(nullptr); ASSERT_NE(connector, nullptr); TlsServerSecurityConnector* tls_connector = static_cast<TlsServerSecurityConnector*>(connector.get()); @@ -460,6 +495,7 @@ TEST_F(GrpcTlsCredentialsOptionsTest, int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, CA_CERT_PATH); ::testing::InitGoogleTest(&argc, argv); grpc_init(); int ret = RUN_ALL_TESTS(); diff --git a/grpc/test/core/security/json_token_test.cc b/grpc/test/core/security/json_token_test.cc index 6b032bb7..1ded259b 100644 --- a/grpc/test/core/security/json_token_test.cc +++ b/grpc/test/core/security/json_token_test.cc @@ -215,11 +215,12 @@ static Json parse_json_part_from_jwt(const char* str, size_t len) { grpc_slice slice = grpc_base64_decode(b64, 1); gpr_free(b64); GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice)); - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; absl::string_view string = grpc_core::StringViewFromSlice(slice); Json json = Json::Parse(string, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); GRPC_ERROR_UNREF(error); } grpc_slice_unref(slice); diff --git a/grpc/test/core/security/jwt_verifier_test.cc b/grpc/test/core/security/jwt_verifier_test.cc index 71178cb6..21ed63fc 100644 --- a/grpc/test/core/security/jwt_verifier_test.cc +++ b/grpc/test/core/security/jwt_verifier_test.cc @@ -207,10 +207,11 @@ static void test_jwt_issuer_email_domain(void) { static void test_claims_success(void) { grpc_jwt_claims* claims; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; Json json = Json::Parse(claims_without_time_constraint, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); } GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(json.type() == Json::Type::OBJECT); @@ -229,10 +230,11 @@ static void test_claims_success(void) { static void test_expired_claims_failure(void) { grpc_jwt_claims* claims; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; Json json = Json::Parse(expired_claims, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); } GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(json.type() == Json::Type::OBJECT); @@ -257,10 +259,11 @@ static void test_expired_claims_failure(void) { } static void test_invalid_claims_failure(void) { - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; Json json = Json::Parse(invalid_claims, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); } GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(json.type() == Json::Type::OBJECT); @@ -270,10 +273,11 @@ static void test_invalid_claims_failure(void) { static void test_bad_audience_claims_failure(void) { grpc_jwt_claims* claims; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; Json json = Json::Parse(claims_without_time_constraint, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); } GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(json.type() == Json::Type::OBJECT); @@ -287,10 +291,11 @@ static void test_bad_audience_claims_failure(void) { static void test_bad_subject_claims_failure(void) { grpc_jwt_claims* claims; - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; Json json = Json::Parse(claims_with_bad_subject, &error); if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "JSON parse error: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "JSON parse error: %s", + grpc_error_std_string(error).c_str()); } GPR_ASSERT(error == GRPC_ERROR_NONE); GPR_ASSERT(json.type() == Json::Type::OBJECT); diff --git a/grpc/test/core/security/matchers_test.cc b/grpc/test/core/security/matchers_test.cc new file mode 100644 index 00000000..0bacd167 --- /dev/null +++ b/grpc/test/core/security/matchers_test.cc @@ -0,0 +1,218 @@ +// 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 "src/core/lib/matchers/matchers.h" + +#include <gtest/gtest.h> + +namespace grpc_core { + +TEST(StringMatcherTest, ExactMatchCaseSensitive) { + auto string_matcher = + StringMatcher::Create(StringMatcher::Type::kExact, + /*matcher=*/"exact", /*case_sensitive=*/true); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("exact")); + EXPECT_FALSE(string_matcher->Match("Exact")); + EXPECT_FALSE(string_matcher->Match("exacz")); +} + +TEST(StringMatcherTest, ExactMatchCaseInsensitive) { + auto string_matcher = + StringMatcher::Create(StringMatcher::Type::kExact, + /*matcher=*/"exact", /*case_sensitive=*/false); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("Exact")); + EXPECT_FALSE(string_matcher->Match("Exacz")); +} + +TEST(StringMatcherTest, PrefixMatchCaseSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix, + /*matcher=*/"prefix", + /*case_sensitive=*/true); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("prefix-test")); + EXPECT_FALSE(string_matcher->Match("xx-prefix-test")); + EXPECT_FALSE(string_matcher->Match("Prefix-test")); + EXPECT_FALSE(string_matcher->Match("pre-test")); +} + +TEST(StringMatcherTest, PrefixMatchCaseInsensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kPrefix, + /*matcher=*/"prefix", + /*case_sensitive=*/false); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("PREfix-test")); + EXPECT_FALSE(string_matcher->Match("xx-PREfix-test")); + EXPECT_FALSE(string_matcher->Match("PRE-test")); +} + +TEST(StringMatcherTest, SuffixMatchCaseSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix, + /*matcher=*/"suffix", + /*case_sensitive=*/true); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("test-suffix")); + EXPECT_FALSE(string_matcher->Match("test-Suffix")); + EXPECT_FALSE(string_matcher->Match("test-suffix-xx")); + EXPECT_FALSE(string_matcher->Match("test-suffiz")); +} + +TEST(StringMatcherTest, SuffixMatchCaseInSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSuffix, + /*matcher=*/"suffix", + /*case_sensitive=*/false); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("Test-SUFFIX")); + EXPECT_FALSE(string_matcher->Match("Test-SUFFIX-xx")); + EXPECT_FALSE(string_matcher->Match("Test-SUFFIZ")); +} + +TEST(StringMatcherTest, InvalidRegex) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex, + /*matcher=*/"a[b-a]", + /*case_sensitive=*/true); + EXPECT_FALSE(string_matcher.ok()); + EXPECT_EQ(string_matcher.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(string_matcher.status().message(), + "Invalid regex string specified in matcher."); +} + +TEST(StringMatcherTest, SafeRegexMatchCaseSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex, + /*matcher=*/"regex.*", + /*case_sensitive=*/true); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("regex-test")); + EXPECT_FALSE(string_matcher->Match("xx-regex-test")); + EXPECT_FALSE(string_matcher->Match("Regex-test")); + EXPECT_FALSE(string_matcher->Match("test-regex")); +} + +TEST(StringMatcherTest, SafeRegexMatchCaseInSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kSafeRegex, + /*matcher=*/"regex.*", + /*case_sensitive=*/false); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("regex-test")); + EXPECT_TRUE(string_matcher->Match("Regex-test")); + EXPECT_FALSE(string_matcher->Match("xx-Regex-test")); + EXPECT_FALSE(string_matcher->Match("test-regex")); +} + +TEST(StringMatcherTest, ContainsMatchCaseSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains, + /*matcher=*/"contains", + /*case_sensitive=*/true); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("test-contains")); + EXPECT_TRUE(string_matcher->Match("test-contains-test")); + EXPECT_FALSE(string_matcher->Match("test-Contains")); + EXPECT_FALSE(string_matcher->Match("test-containz")); +} + +TEST(StringMatcherTest, ContainsMatchCaseInSensitive) { + auto string_matcher = StringMatcher::Create(StringMatcher::Type::kContains, + /*matcher=*/"contains", + /*case_sensitive=*/false); + ASSERT_TRUE(string_matcher.ok()); + EXPECT_TRUE(string_matcher->Match("Test-Contains")); + EXPECT_TRUE(string_matcher->Match("Test-Contains-Test")); + EXPECT_FALSE(string_matcher->Match("Test-Containz")); +} + +TEST(HeaderMatcherTest, StringMatcher) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact, + /*matcher=*/"exact"); + ASSERT_TRUE(header_matcher.ok()); + EXPECT_TRUE(header_matcher->Match("exact")); + EXPECT_FALSE(header_matcher->Match("Exact")); + EXPECT_FALSE(header_matcher->Match("exacz")); +} + +TEST(HeaderMatcherTest, StringMatcherWithInvertMatch) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kExact, + /*matcher=*/"exact", + /*range_start=*/0, /*range_end=*/0, + /*present_match=*/false, /*invert_match=*/true); + ASSERT_TRUE(header_matcher.ok()); + EXPECT_FALSE(header_matcher->Match("exact")); + EXPECT_TRUE(header_matcher->Match("Exact")); + EXPECT_TRUE(header_matcher->Match("exacz")); +} + +TEST(HeaderMatcherTest, InvalidRegex) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kSafeRegex, + /*matcher=*/"a[b-a]", + /*range_start=*/0, /*range_end=*/0, + /*present_match=*/false, /*invert_match=*/true); + EXPECT_FALSE(header_matcher.ok()); + EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(header_matcher.status().message(), + "Invalid regex string specified in matcher."); +} + +TEST(HeaderMatcherTest, RangeMatcherValidRange) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange, + /*matcher=*/"", /*range_start=*/10, + /*range_end*/ 20); + ASSERT_TRUE(header_matcher.ok()); + EXPECT_TRUE(header_matcher->Match("16")); + EXPECT_TRUE(header_matcher->Match("10")); + EXPECT_FALSE(header_matcher->Match("3")); + EXPECT_FALSE(header_matcher->Match("20")); +} + +TEST(HeaderMatcherTest, RangeMatcherInvalidRange) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kRange, + /*matcher=*/"", /*range_start=*/20, + /*range_end*/ 10); + EXPECT_FALSE(header_matcher.ok()); + EXPECT_EQ(header_matcher.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ( + header_matcher.status().message(), + "Invalid range specifier specified: end cannot be smaller than start."); +} + +TEST(HeaderMatcherTest, PresentMatcherTrue) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent, + /*matcher=*/"", /*range_start=*/0, + /*range_end=*/0, /*present_match=*/true); + ASSERT_TRUE(header_matcher.ok()); + EXPECT_TRUE(header_matcher->Match("any_value")); + EXPECT_FALSE(header_matcher->Match(absl::nullopt)); +} + +TEST(HeaderMatcherTest, PresentMatcherFalse) { + auto header_matcher = + HeaderMatcher::Create(/*name=*/"key", HeaderMatcher::Type::kPresent, + /*matcher=*/"", /*range_start=*/0, + /*range_end=*/0, /*present_match=*/false); + ASSERT_TRUE(header_matcher.ok()); + EXPECT_FALSE(header_matcher->Match("any_value")); + EXPECT_TRUE(header_matcher->Match(absl::nullopt)); +} + +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/grpc/test/core/security/oauth2_utils.cc b/grpc/test/core/security/oauth2_utils.cc index 0885a1ac..536696b4 100644 --- a/grpc/test/core/security/oauth2_utils.cc +++ b/grpc/test/core/security/oauth2_utils.cc @@ -40,12 +40,13 @@ typedef struct { grpc_closure closure; } oauth2_request; -static void on_oauth2_response(void* arg, grpc_error* error) { +static void on_oauth2_response(void* arg, grpc_error_handle error) { oauth2_request* request = static_cast<oauth2_request*>(arg); char* token = nullptr; grpc_slice token_slice; if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "Fetching token failed: %s", grpc_error_string(error)); + gpr_log(GPR_ERROR, "Fetching token failed: %s", + grpc_error_std_string(error).c_str()); } else { GPR_ASSERT(request->md_array.size == 1); token_slice = GRPC_MDVALUE(request->md_array.md[0]); @@ -64,7 +65,7 @@ static void on_oauth2_response(void* arg, grpc_error* error) { gpr_mu_unlock(request->mu); } -static void do_nothing(void* /*arg*/, grpc_error* /*error*/) {} +static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {} char* grpc_test_fetch_oauth2_token_with_credentials( grpc_call_credentials* creds) { @@ -86,7 +87,7 @@ char* grpc_test_fetch_oauth2_token_with_credentials( GRPC_CLOSURE_INIT(&request.closure, on_oauth2_response, &request, grpc_schedule_on_exec_ctx); - grpc_error* error = GRPC_ERROR_NONE; + grpc_error_handle error = GRPC_ERROR_NONE; if (creds->get_request_metadata(&request.pops, null_ctx, &request.md_array, &request.closure, &error)) { // Synchronous result; invoke callback directly. diff --git a/grpc/test/core/security/print_google_default_creds_token.cc b/grpc/test/core/security/print_google_default_creds_token.cc index 398c58c6..0d6c7b79 100644 --- a/grpc/test/core/security/print_google_default_creds_token.cc +++ b/grpc/test/core/security/print_google_default_creds_token.cc @@ -41,10 +41,11 @@ typedef struct { grpc_closure on_request_metadata; } synchronizer; -static void on_metadata_response(void* arg, grpc_error* error) { +static void on_metadata_response(void* arg, grpc_error_handle error) { synchronizer* sync = static_cast<synchronizer*>(arg); if (error != GRPC_ERROR_NONE) { - fprintf(stderr, "Fetching token failed: %s\n", grpc_error_string(error)); + fprintf(stderr, "Fetching token failed: %s\n", + grpc_error_std_string(error).c_str()); fflush(stderr); } else { char* token; @@ -70,7 +71,7 @@ int main(int argc, char** argv) { grpc_auth_metadata_context context; gpr_cmdline* cl = gpr_cmdline_create("print_google_default_creds_token"); grpc_pollset* pollset = nullptr; - grpc_error* error = nullptr; + grpc_error_handle error = GRPC_ERROR_NONE; gpr_cmdline_add_string(cl, "service_url", "Service URL for the token request.", &service_url); gpr_cmdline_parse(cl, argc, argv); diff --git a/grpc/test/core/security/rbac_translator_test.cc b/grpc/test/core/security/rbac_translator_test.cc new file mode 100644 index 00000000..337f4715 --- /dev/null +++ b/grpc/test/core/security/rbac_translator_test.cc @@ -0,0 +1,809 @@ +// 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 "src/core/lib/security/authorization/rbac_translator.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace grpc_core { + +namespace { + +MATCHER_P2(EqualsPrincipalName, expected_matcher_type, expected_matcher_value, + "") { + return arg->type == Rbac::Principal::RuleType::kPrincipalName && + arg->string_matcher.type() == expected_matcher_type && + arg->string_matcher.string_matcher() == expected_matcher_value; +} + +MATCHER_P2(EqualsPath, expected_matcher_type, expected_matcher_value, "") { + return arg->type == Rbac::Permission::RuleType::kPath && + arg->string_matcher.type() == expected_matcher_type && + arg->string_matcher.string_matcher() == expected_matcher_value; +} + +MATCHER_P3(EqualsHeader, expected_name, expected_matcher_type, + expected_matcher_value, "") { + return arg->type == Rbac::Permission::RuleType::kHeader && + arg->header_matcher.name() == expected_name && + arg->header_matcher.type() == expected_matcher_type && + arg->header_matcher.string_matcher() == expected_matcher_value; +} + +} // namespace + +TEST(GenerateRbacPoliciesTest, InvalidPolicy) { + const char* authz_policy = + "{" + " \"name\": \"authz-policy\",," + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_THAT( + std::string(rbac_policies.status().message()), + ::testing::StartsWith("Failed to parse SDK authorization policy.")); +} + +TEST(GenerateRbacPoliciesTest, MissingAuthorizationPolicyName) { + const char* authz_policy = "{}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), "\"name\" field is not present."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectAuthorizationPolicyNameType) { + const char* authz_policy = + "{" + " \"name\": [\"authz_policy\"]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), "\"name\" is not a string."); +} + +TEST(GenerateRbacPoliciesTest, MissingAllowRules) { + const char* authz_policy = + "{" + " \"name\": \"authz_policy\"" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "\"allow_rules\" is not present."); +} + +TEST(GenerateRbacPoliciesTest, MissingDenyRules) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny); + EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty()); +} + +TEST(GenerateRbacPoliciesTest, IncorrectAllowRulesType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": {}" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "\"allow_rules\" is not an array."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectDenyRulesType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": 123" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "\"deny_rules\" is not an array."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectRuleType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [\"rule-a\"]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: is not an object."); +} + +TEST(GenerateRbacPoliciesTest, MissingRuleNameField) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [{}]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"name\" is not present."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectRuleNameType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": 123" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"name\" is not a string."); +} + +TEST(GenerateRbacPoliciesTest, MissingSourceAndRequest) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_allow_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)))))); +} + +TEST(GenerateRbacPoliciesTest, EmptySourceAndRequest) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"source\": {}," + " \"request\": {}" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_allow_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)))))); +} + +TEST(GenerateRbacPoliciesTest, IncorrectSourceType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"source\": 111" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"source\" is not an object."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectPrincipalsType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"source\": {" + " \"principals\": [" + " \"*\"," + " 123" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"principals\" 1: is not a string."); +} + +TEST(GenerateRbacPoliciesTest, ParseSourceSuccess) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"source\": {" + " \"principals\": [" + " \"spiffe://foo.abc\"," + " \"spiffe://bar*\"," + " \"*baz\"," + " \"spiffe://abc.*.com\"" + " ]" + " }" + " }" + " ]," + " \"deny_rules\": [" + " {" + " \"name\": \"deny_policy\"," + " \"source\": {" + " \"principals\": [" + " \"*\"" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_allow_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::AllOf( + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAnd), + ::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Principal::type, + Rbac::Principal::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre( + EqualsPrincipalName( + StringMatcher::Type::kExact, + "spiffe://foo.abc"), + EqualsPrincipalName( + StringMatcher::Type::kPrefix, + "spiffe://bar"), + EqualsPrincipalName( + StringMatcher::Type::kSuffix, "baz"), + EqualsPrincipalName( + StringMatcher::Type::kExact, + "spiffe://abc.*.com"))))))))))))); + EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny); + EXPECT_THAT( + rbac_policies.value().deny_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_deny_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::AllOf( + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAnd), + ::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Principal::type, + Rbac::Principal::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre(EqualsPrincipalName( + StringMatcher::Type::kPrefix, + ""))))))))))))); +} + +TEST(GenerateRbacPoliciesTest, IncorrectRequestType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": [" + " {" + " \"name\": \"deny_policy\"," + " \"request\": 111" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "deny_rules 0: \"request\" is not an object."); +} + +TEST(GenerateRbacPoliciesTest, IncorrectPathType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"request\": {" + " \"paths\": [" + " \"path-a\"," + " 123" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "deny_rules 0: \"paths\" 1: is not a string."); +} + +TEST(GenerateRbacPoliciesTest, ParseRequestPathsSuccess) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"request\": {" + " \"paths\": [" + " \"*\"" + " ]" + " }" + " }" + " ]," + " \"deny_rules\": [" + " {" + " \"name\": \"deny_policy\"," + " \"request\": {" + " \"paths\": [" + " \"path-foo\"," + " \"path-bar*\"," + " \"*baz\"" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny); + EXPECT_THAT( + rbac_policies.value().deny_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_deny_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::AllOf( + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAnd), + ::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre( + EqualsPath(StringMatcher::Type::kExact, + "path-foo"), + EqualsPath(StringMatcher::Type::kPrefix, + "path-bar"), + EqualsPath(StringMatcher::Type::kSuffix, + "baz"))))))))))))); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_allow_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::AllOf( + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAnd), + ::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre( + EqualsPath(StringMatcher::Type::kPrefix, + ""))))))))))))); +} + +TEST(GenerateRbacPoliciesTest, IncorrectHeaderType) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"request\": {" + " \"headers\": [" + " \"header-a\"" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "deny_rules 0: \"headers\" 0: is not an object."); +} + +TEST(GenerateRbacPoliciesTest, UnsupportedGrpcHeaders) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": [" + " {" + " \"name\": \"policy\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \"grpc-xxx\"," + " \"values\": [" + " \"*\"" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "deny_rules 0: \"headers\" 0: Unsupported \"key\" grpc-xxx."); +} + +TEST(GenerateRbacPoliciesTest, UnsupportedPseudoHeaders) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"policy\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \":method\"," + " \"values\": [" + " \"*\"" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"headers\" 0: Unsupported \"key\" :method."); +} + +TEST(GenerateRbacPoliciesTest, UnsupportedhostHeader) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"deny_rules\": [" + " {" + " \"name\": \"policy\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \"host\"," + " \"values\": [" + " \"*\"" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "deny_rules 0: \"headers\" 0: Unsupported \"key\" host."); +} + +TEST(GenerateRbacPoliciesTest, UnsupportedHostHeader) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"policy\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \"Host\"," + " \"values\": [" + " \"*\"" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"headers\" 0: Unsupported \"key\" Host."); +} + +TEST(GenerateRbacPoliciesTest, EmptyHeaderValuesList) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy_1\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \"key-a\"," + " \"values\": [" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + EXPECT_EQ(rbac_policies.status().code(), absl::StatusCode::kInvalidArgument); + EXPECT_EQ(rbac_policies.status().message(), + "allow_rules 0: \"headers\" 0: \"values\" list is empty."); +} + +TEST(GenerateRbacPoliciesTest, ParseRequestHeadersSuccess) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy\"," + " \"request\": {" + " \"headers\": [" + " {" + " \"key\": \"key-1\"," + " \"values\": [" + " \"*\"" + " ]" + " }," + " {" + " \"key\": \"key-2\"," + " \"values\": [" + " \"foo\"," + " \"bar*\"," + " \"*baz\"" + " ]" + " }" + " ]" + " }" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny); + EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty()); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre(::testing::Pair( + "authz_allow_policy", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::AllOf( + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAnd), + ::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kAnd)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre( + ::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre( + EqualsHeader( + "key-1", + HeaderMatcher::Type:: + kPrefix, + ""))))), + ::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre( + EqualsHeader("key-2", + HeaderMatcher:: + Type::kExact, + "foo"), + EqualsHeader( + "key-2", + HeaderMatcher::Type:: + kPrefix, + "bar"), + EqualsHeader( + "key-2", + HeaderMatcher::Type:: + kSuffix, + "baz"))))))))))))))))); +} + +TEST(GenerateRbacPoliciesTest, ParseRulesArraySuccess) { + const char* authz_policy = + "{" + " \"name\": \"authz\"," + " \"allow_rules\": [" + " {" + " \"name\": \"allow_policy_1\"," + " \"source\": {" + " \"principals\": [" + " \"spiffe://foo.abc\"" + " ]" + " }," + " \"request\": {" + " \"paths\": [" + " \"foo\"" + " ]" + " }" + " }," + " {" + " \"name\": \"allow_policy_2\"" + " }" + " ]" + "}"; + auto rbac_policies = GenerateRbacPolicies(authz_policy); + ASSERT_TRUE(rbac_policies.ok()); + EXPECT_EQ(rbac_policies.value().deny_policy.action, Rbac::Action::kDeny); + EXPECT_TRUE(rbac_policies.value().deny_policy.policies.empty()); + EXPECT_EQ(rbac_policies.value().allow_policy.action, Rbac::Action::kAllow); + EXPECT_THAT( + rbac_policies.value().allow_policy.policies, + ::testing::ElementsAre( + ::testing::Pair( + "authz_allow_policy_1", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::AllOf( + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAnd), + ::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Permission::type, + Rbac::Permission::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Permission::permissions, + ::testing::ElementsAre(EqualsPath( + StringMatcher::Type::kExact, + "foo"))))))))), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::AllOf( + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAnd), + ::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre(::testing::AllOf( + ::testing::Pointee(::testing::Field( + &Rbac::Principal::type, + Rbac::Principal::RuleType::kOr)), + ::testing::Pointee(::testing::Field( + &Rbac::Principal::principals, + ::testing::ElementsAre( + EqualsPrincipalName( + StringMatcher::Type::kExact, + "spiffe://foo.abc"))))))))))), + ::testing::Pair( + "authz_allow_policy_2", + ::testing::AllOf( + ::testing::Field( + &Rbac::Policy::permissions, + ::testing::Field(&Rbac::Permission::type, + Rbac::Permission::RuleType::kAny)), + ::testing::Field( + &Rbac::Policy::principals, + ::testing::Field(&Rbac::Principal::type, + Rbac::Principal::RuleType::kAny)))))); +} + +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/grpc/test/core/security/secure_endpoint_test.cc b/grpc/test/core/security/secure_endpoint_test.cc index 50c3694d..c5621d92 100644 --- a/grpc/test/core/security/secure_endpoint_test.cc +++ b/grpc/test/core/security/secure_endpoint_test.cc @@ -166,7 +166,7 @@ static grpc_endpoint_test_config configs[] = { clean_up}, }; -static void inc_call_ctr(void* arg, grpc_error* /*error*/) { +static void inc_call_ctr(void* arg, grpc_error_handle /*error*/) { ++*static_cast<int*>(arg); } @@ -202,7 +202,7 @@ static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) { clean_up(); } -static void destroy_pollset(void* p, grpc_error* /*error*/) { +static void destroy_pollset(void* p, grpc_error_handle /*error*/) { grpc_pollset_destroy(static_cast<grpc_pollset*>(p)); } diff --git a/grpc/test/core/security/security_connector_test.cc b/grpc/test/core/security/security_connector_test.cc index 2049832b..da7f2f0c 100644 --- a/grpc/test/core/security/security_connector_test.cc +++ b/grpc/test/core/security/security_connector_test.cc @@ -222,6 +222,32 @@ static int check_x509_pem_cert_chain(const grpc_auth_context* ctx, return 1; } +static int check_sans( + const grpc_auth_context* ctx, const char* expected_property_name, + const std::vector<std::string>& expected_property_values) { + grpc_auth_property_iterator it = + grpc_auth_context_find_properties_by_name(ctx, expected_property_name); + for (const auto& property_value : expected_property_values) { + const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it); + if (prop == nullptr) { + gpr_log(GPR_ERROR, "Expected value %s not found.", + property_value.c_str()); + return 0; + } + if (strncmp(prop->value, property_value.c_str(), prop->value_length) != 0) { + gpr_log(GPR_ERROR, "Expected peer %s and got %s.", property_value.c_str(), + prop->value); + return 0; + } + } + if (grpc_auth_property_iterator_next(&it) != nullptr) { + gpr_log(GPR_ERROR, "Expected only %zu property values.", + expected_property_values.size()); + return 0; + } + return 1; +} + static int check_spiffe_id(const grpc_auth_context* ctx, const char* expected_spiffe_id, bool expect_spiffe_id) { @@ -444,6 +470,59 @@ static void test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context( ctx.reset(DEBUG_LOCATION, "test"); } +static void test_dns_peer_to_auth_context(void) { + tsi_peer peer; + const std::vector<std::string> expected_dns = {"dns1", "dns2", "dns3"}; + GPR_ASSERT(tsi_construct_peer(expected_dns.size(), &peer) == TSI_OK); + for (size_t i = 0; i < expected_dns.size(); ++i) { + GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( + TSI_X509_DNS_PEER_PROPERTY, expected_dns[i].c_str(), + &peer.properties[i]) == TSI_OK); + } + grpc_core::RefCountedPtr<grpc_auth_context> ctx = + grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); + GPR_ASSERT(ctx != nullptr); + GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_DNS_PROPERTY_NAME, expected_dns)); + tsi_peer_destruct(&peer); + ctx.reset(DEBUG_LOCATION, "test"); +} + +static void test_email_peer_to_auth_context(void) { + tsi_peer peer; + const std::vector<std::string> expected_emails = {"email1", "email2"}; + GPR_ASSERT(tsi_construct_peer(expected_emails.size(), &peer) == TSI_OK); + for (size_t i = 0; i < expected_emails.size(); ++i) { + GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( + TSI_X509_EMAIL_PEER_PROPERTY, expected_emails[i].c_str(), + &peer.properties[i]) == TSI_OK); + } + grpc_core::RefCountedPtr<grpc_auth_context> ctx = + grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); + GPR_ASSERT(ctx != nullptr); + GPR_ASSERT( + check_sans(ctx.get(), GRPC_PEER_EMAIL_PROPERTY_NAME, expected_emails)); + tsi_peer_destruct(&peer); + ctx.reset(DEBUG_LOCATION, "test"); +} + +static void test_ip_peer_to_auth_context(void) { + tsi_peer peer; + const std::vector<std::string> expected_ips = {"128.128.128.128", + "255.255.255.255"}; + GPR_ASSERT(tsi_construct_peer(expected_ips.size(), &peer) == TSI_OK); + for (size_t i = 0; i < expected_ips.size(); ++i) { + GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( + TSI_X509_IP_PEER_PROPERTY, expected_ips[i].c_str(), + &peer.properties[i]) == TSI_OK); + } + grpc_core::RefCountedPtr<grpc_auth_context> ctx = + grpc_ssl_peer_to_auth_context(&peer, GRPC_SSL_TRANSPORT_SECURITY_TYPE); + GPR_ASSERT(ctx != nullptr); + GPR_ASSERT(check_sans(ctx.get(), GRPC_PEER_IP_PROPERTY_NAME, expected_ips)); + tsi_peer_destruct(&peer); + ctx.reset(DEBUG_LOCATION, "test"); +} + static void test_spiffe_id_peer_to_auth_context(void) { // Invalid SPIFFE IDs should not be plumbed. std::string long_id(2050, 'x'); @@ -558,6 +637,7 @@ static void test_ipv6_address_san(void) { } tsi_peer_destruct(&peer); } + namespace grpc_core { namespace { @@ -637,7 +717,7 @@ static void test_peer_alpn_check(void) { GPR_ASSERT(tsi_construct_string_peer_property("wrong peer property name", alpn, strlen(alpn), &peer.properties[0]) == TSI_OK); - grpc_error* error = grpc_ssl_check_alpn(&peer); + grpc_error_handle error = grpc_ssl_check_alpn(&peer); GPR_ASSERT(error != GRPC_ERROR_NONE); tsi_peer_destruct(&peer); GRPC_ERROR_UNREF(error); @@ -672,6 +752,9 @@ int main(int argc, char** argv) { test_cn_and_one_san_ssl_peer_to_auth_context(); test_cn_and_multiple_sans_ssl_peer_to_auth_context(); test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context(); + test_dns_peer_to_auth_context(); + test_email_peer_to_auth_context(); + test_ip_peer_to_auth_context(); test_spiffe_id_peer_to_auth_context(); test_ipv6_address_san(); test_default_ssl_roots(); diff --git a/grpc/test/core/security/ssl_server_fuzzer.cc b/grpc/test/core/security/ssl_server_fuzzer.cc index bb5ca722..6401f8e2 100644 --- a/grpc/test/core/security/ssl_server_fuzzer.cc +++ b/grpc/test/core/security/ssl_server_fuzzer.cc @@ -42,7 +42,7 @@ struct handshake_state { bool done_callback_called; }; -static void on_handshake_done(void* arg, grpc_error* error) { +static void on_handshake_done(void* arg, grpc_error_handle error) { grpc_core::HandshakerArgs* args = static_cast<grpc_core::HandshakerArgs*>(arg); struct handshake_state* state = @@ -91,7 +91,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Create security connector grpc_core::RefCountedPtr<grpc_server_security_connector> sc = - creds->create_security_connector(); + creds->create_security_connector(nullptr); GPR_ASSERT(sc != nullptr); grpc_millis deadline = GPR_MS_PER_SEC + grpc_core::ExecCtx::Get()->Now(); diff --git a/grpc/test/core/security/tls_security_connector_test.cc b/grpc/test/core/security/tls_security_connector_test.cc index c6f744da..c041fd92 100644 --- a/grpc/test/core/security/tls_security_connector_test.cc +++ b/grpc/test/core/security/tls_security_connector_test.cc @@ -146,10 +146,59 @@ TEST_F(TlsSecurityConnectorTest, grpc_channel_args_destroy(new_args); } -// Note that on client side, we don't have tests watching identity certs only, -// because in TLS, the trust certs should always be presented. If we don't -// provide, it will try to load certs from some default system locations, and -// will hence fail on some systems. +TEST_F(TlsSecurityConnectorTest, + SystemRootsWhenCreateChannelSecurityConnector) { + // Create options watching for no certificates. + grpc_core::RefCountedPtr<grpc_tls_credentials_options> root_options = + grpc_core::MakeRefCounted<grpc_tls_credentials_options>(); + grpc_core::RefCountedPtr<TlsCredentials> root_credential = + grpc_core::MakeRefCounted<TlsCredentials>(root_options); + grpc_channel_args* root_new_args = nullptr; + grpc_core::RefCountedPtr<grpc_channel_security_connector> root_connector = + root_credential->create_security_connector(nullptr, "some_target", + nullptr, &root_new_args); + EXPECT_NE(root_connector, nullptr); + grpc_core::TlsChannelSecurityConnector* tls_root_connector = + static_cast<grpc_core::TlsChannelSecurityConnector*>( + root_connector.get()); + EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr); + grpc_channel_args_destroy(root_new_args); +} + +TEST_F(TlsSecurityConnectorTest, + SystemRootsAndIdentityCertsObtainedWhenCreateChannelSecurityConnector) { + grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor = + grpc_core::MakeRefCounted<grpc_tls_certificate_distributor>(); + distributor->SetKeyMaterials(kIdentityCertName, absl::nullopt, + identity_pairs_0_); + grpc_core::RefCountedPtr<::grpc_tls_certificate_provider> provider = + grpc_core::MakeRefCounted<TlsTestCertificateProvider>(distributor); + // Create options only watching for identity certificates. + grpc_core::RefCountedPtr<grpc_tls_credentials_options> root_options = + grpc_core::MakeRefCounted<grpc_tls_credentials_options>(); + root_options->set_certificate_provider(provider); + root_options->set_watch_identity_pair(true); + root_options->set_identity_cert_name(kIdentityCertName); + grpc_core::RefCountedPtr<TlsCredentials> root_credential = + grpc_core::MakeRefCounted<TlsCredentials>(root_options); + grpc_channel_args* root_new_args = nullptr; + grpc_core::RefCountedPtr<grpc_channel_security_connector> root_connector = + root_credential->create_security_connector(nullptr, "some_target", + nullptr, &root_new_args); + EXPECT_NE(root_connector, nullptr); + grpc_core::TlsChannelSecurityConnector* tls_root_connector = + static_cast<grpc_core::TlsChannelSecurityConnector*>( + root_connector.get()); + EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr); + EXPECT_EQ(tls_root_connector->KeyCertPairListForTesting(), identity_pairs_0_); + // If we have a root update, we shouldn't receive them in security connector, + // since we claimed to use default system roots. + distributor->SetKeyMaterials(kRootCertName, root_cert_1_, absl::nullopt); + EXPECT_NE(tls_root_connector->ClientHandshakerFactoryForTesting(), nullptr); + EXPECT_NE(tls_root_connector->RootCertsForTesting(), root_cert_1_); + grpc_channel_args_destroy(root_new_args); +} + TEST_F(TlsSecurityConnectorTest, RootCertsObtainedWhenCreateChannelSecurityConnector) { grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor = @@ -303,7 +352,8 @@ TEST_F(TlsSecurityConnectorTest, TlsCheckHostNameSuccess) { GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, target_name, &peer.properties[0]) == TSI_OK); - grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer); + grpc_error_handle error = + grpc_core::internal::TlsCheckHostName(target_name, &peer); tsi_peer_destruct(&peer); EXPECT_EQ(error, GRPC_ERROR_NONE); GRPC_ERROR_UNREF(error); @@ -317,7 +367,8 @@ TEST_F(TlsSecurityConnectorTest, TlsCheckHostNameFail) { GPR_ASSERT(tsi_construct_string_peer_property_from_cstring( TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, another_name, &peer.properties[0]) == TSI_OK); - grpc_error* error = grpc_core::internal::TlsCheckHostName(target_name, &peer); + grpc_error_handle error = + grpc_core::internal::TlsCheckHostName(target_name, &peer); tsi_peer_destruct(&peer); EXPECT_NE(error, GRPC_ERROR_NONE); GRPC_ERROR_UNREF(error); @@ -343,7 +394,7 @@ TEST_F(TlsSecurityConnectorTest, grpc_core::RefCountedPtr<TlsServerCredentials> credential = grpc_core::MakeRefCounted<TlsServerCredentials>(options); grpc_core::RefCountedPtr<grpc_server_security_connector> connector = - credential->create_security_connector(); + credential->create_security_connector(nullptr); EXPECT_NE(connector, nullptr); grpc_core::TlsServerSecurityConnector* tls_connector = static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get()); @@ -380,7 +431,7 @@ TEST_F(TlsSecurityConnectorTest, grpc_core::RefCountedPtr<TlsServerCredentials> identity_credential = grpc_core::MakeRefCounted<TlsServerCredentials>(identity_options); grpc_core::RefCountedPtr<grpc_server_security_connector> identity_connector = - identity_credential->create_security_connector(); + identity_credential->create_security_connector(nullptr); EXPECT_NE(identity_connector, nullptr); grpc_core::TlsServerSecurityConnector* tls_identity_connector = static_cast<grpc_core::TlsServerSecurityConnector*>( @@ -417,7 +468,7 @@ TEST_F(TlsSecurityConnectorTest, grpc_core::RefCountedPtr<TlsServerCredentials> credential = grpc_core::MakeRefCounted<TlsServerCredentials>(options); grpc_core::RefCountedPtr<grpc_server_security_connector> connector = - credential->create_security_connector(); + credential->create_security_connector(nullptr); EXPECT_NE(connector, nullptr); grpc_core::TlsServerSecurityConnector* tls_connector = static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get()); @@ -451,7 +502,7 @@ TEST_F(TlsSecurityConnectorTest, grpc_core::RefCountedPtr<TlsServerCredentials> credential = grpc_core::MakeRefCounted<TlsServerCredentials>(options); grpc_core::RefCountedPtr<grpc_server_security_connector> connector = - credential->create_security_connector(); + credential->create_security_connector(nullptr); EXPECT_NE(connector, nullptr); grpc_core::TlsServerSecurityConnector* tls_connector = static_cast<grpc_core::TlsServerSecurityConnector*>(connector.get()); @@ -495,6 +546,7 @@ TEST_F(TlsSecurityConnectorTest, CreateServerSecurityConnectorFailNoOptions) { int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, CA_CERT_PATH); ::testing::InitGoogleTest(&argc, argv); grpc_init(); int ret = RUN_ALL_TESTS(); diff --git a/grpc/test/core/security/xds_credentials_test.cc b/grpc/test/core/security/xds_credentials_test.cc index 373e905f..c055972a 100644 --- a/grpc/test/core/security/xds_credentials_test.cc +++ b/grpc/test/core/security/xds_credentials_test.cc @@ -29,32 +29,30 @@ namespace testing { namespace { -XdsApi::StringMatcher ExactMatcher(const char* string) { - return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::EXACT, - string); +StringMatcher ExactMatcher(const char* string) { + return StringMatcher::Create(StringMatcher::Type::kExact, string).value(); } -XdsApi::StringMatcher PrefixMatcher(const char* string, - bool ignore_case = false) { - return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::PREFIX, - string, ignore_case); +StringMatcher PrefixMatcher(const char* string, bool case_sensitive = true) { + return StringMatcher::Create(StringMatcher::Type::kPrefix, string, + case_sensitive) + .value(); } -XdsApi::StringMatcher SuffixMatcher(const char* string, - bool ignore_case = false) { - return XdsApi::StringMatcher(XdsApi::StringMatcher::StringMatcherType::SUFFIX, - string, ignore_case); +StringMatcher SuffixMatcher(const char* string, bool case_sensitive = true) { + return StringMatcher::Create(StringMatcher::Type::kSuffix, string, + case_sensitive) + .value(); } -XdsApi::StringMatcher ContainsMatcher(const char* string, - bool ignore_case = false) { - return XdsApi::StringMatcher( - XdsApi::StringMatcher::StringMatcherType::CONTAINS, string, ignore_case); +StringMatcher ContainsMatcher(const char* string, bool case_sensitive = true) { + return StringMatcher::Create(StringMatcher::Type::kContains, string, + case_sensitive) + .value(); } -XdsApi::StringMatcher SafeRegexMatcher(const char* string) { - return XdsApi::StringMatcher( - XdsApi::StringMatcher::StringMatcherType::SAFE_REGEX, string); +StringMatcher SafeRegexMatcher(const char* string) { + return StringMatcher::Create(StringMatcher::Type::kSafeRegex, string).value(); } TEST(XdsSanMatchingTest, EmptySansList) { @@ -210,15 +208,15 @@ TEST(XdsSanMatchingTest, PrefixMatchIgnoreCase) { std::vector<const char*> sans = {"aBc.cOm"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {PrefixMatcher("AbC", true /* ignore_case */)})); + {PrefixMatcher("AbC", false /* case_sensitive */)})); sans = {"abc.com"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {PrefixMatcher("AbC", true /* ignore_case */)})); + {PrefixMatcher("AbC", false /* case_sensitive */)})); sans = {"xyz.com"}; EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {PrefixMatcher("AbC", true /* ignore_case */)})); + {PrefixMatcher("AbC", false /* case_sensitive */)})); } TEST(XdsSanMatchingTest, SuffixMatch) { @@ -237,15 +235,15 @@ TEST(XdsSanMatchingTest, SuffixMatchIgnoreCase) { std::vector<const char*> sans = {"abc.com"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {SuffixMatcher(".CoM", true /* ignore_case */)})); + {SuffixMatcher(".CoM", false /* case_sensitive */)})); sans = {"AbC.cOm"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {SuffixMatcher(".CoM", true /* ignore_case */)})); + {SuffixMatcher(".CoM", false /* case_sensitive */)})); sans = {"abc.xyz"}; EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {SuffixMatcher(".CoM", true /* ignore_case */)})); + {SuffixMatcher(".CoM", false /* case_sensitive */)})); } TEST(XdsSanMatchingTest, ContainsMatch) { @@ -264,19 +262,19 @@ TEST(XdsSanMatchingTest, ContainsMatchIgnoresCase) { std::vector<const char*> sans = {"abc.com"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {ContainsMatcher("AbC", true /* ignore_case */)})); + {ContainsMatcher("AbC", false /* case_sensitive */)})); sans = {"xyz.abc.com"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {ContainsMatcher("AbC", true /* ignore_case */)})); + {ContainsMatcher("AbC", false /* case_sensitive */)})); sans = {"foo.aBc.com"}; EXPECT_TRUE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {ContainsMatcher("AbC", true /* ignore_case */)})); + {ContainsMatcher("AbC", false /* case_sensitive */)})); sans = {"foo.Ab.com"}; EXPECT_FALSE(TestOnlyXdsVerifySubjectAlternativeNames( sans.data(), sans.size(), - {ContainsMatcher("AbC", true /* ignore_case */)})); + {ContainsMatcher("AbC", false /* case_sensitive */)})); } TEST(XdsSanMatchingTest, RegexMatch) { |