// 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 #include #include #include #include #include #include #include #include "src/core/lib/security/credentials/fake/fake_credentials.h" #include "src/cpp/client/secure_credentials.h" #include "src/cpp/server/secure_server_credentials.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/end2end/test_service_impl.h" namespace grpc { namespace testing { namespace { constexpr char kMessage[] = "Hello"; class SdkAuthzEnd2EndTest : public ::testing::Test { protected: SdkAuthzEnd2EndTest() : server_address_( absl::StrCat("localhost:", grpc_pick_unused_port_or_die())), server_creds_( std::shared_ptr(new SecureServerCredentials( grpc_fake_transport_security_server_credentials_create()))), channel_creds_( std::shared_ptr(new SecureChannelCredentials( grpc_fake_transport_security_credentials_create()))) {} ~SdkAuthzEnd2EndTest() override { server_->Shutdown(); } // Replaces existing credentials with insecure credentials. void UseInsecureCredentials() { server_creds_ = InsecureServerCredentials(); channel_creds_ = InsecureChannelCredentials(); } // Creates server with sdk authorization enabled when provider is not null. void InitServer( std::shared_ptr provider) { ServerBuilder builder; builder.AddListeningPort(server_address_, std::move(server_creds_)); builder.experimental().SetAuthorizationPolicyProvider(std::move(provider)); builder.RegisterService(&service_); server_ = builder.BuildAndStart(); } std::shared_ptr CreateStaticAuthzPolicyProvider(const std::string& policy) { grpc::Status status; auto provider = experimental::StaticDataAuthorizationPolicyProvider::Create( policy, &status); EXPECT_TRUE(status.ok()); return provider; } std::shared_ptr BuildChannel() { ChannelArguments args; return ::grpc::CreateCustomChannel(server_address_, channel_creds_, args); } grpc::Status SendRpc(const std::shared_ptr& channel, ClientContext* context, grpc::testing::EchoResponse* response = nullptr) { auto stub = grpc::testing::EchoTestService::NewStub(channel); grpc::testing::EchoRequest request; request.set_message(kMessage); return stub->Echo(context, request, response); } std::string server_address_; TestServiceImpl service_; std::unique_ptr server_; std::shared_ptr server_creds_; std::shared_ptr channel_creds_; }; TEST_F(SdkAuthzEnd2EndTest, StaticInitAllowsRpcRequestNoMatchInDenyMatchInAllow) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_echo\"," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]," " \"headers\": [" " {" " \"key\": \"key-foo\"," " \"values\": [\"foo1\", \"foo2\"]" " }," " {" " \"key\": \"key-bar\"," " \"values\": [\"bar1\"]" " }" " ]" " }" " }" " ]," " \"deny_rules\": [" " {" " \"name\": \"deny_clientstreamingecho\"," " \"request\": {" " \"paths\": [" " \"*/ClientStreamingEcho\"" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; context.AddMetadata("key-foo", "foo2"); context.AddMetadata("key-bar", "bar1"); context.AddMetadata("key-baz", "baz1"); grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_TRUE(status.ok()); EXPECT_EQ(resp.message(), kMessage); } TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestNoMatchInAllowAndDeny) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_foo\"," " \"request\": {" " \"paths\": [" " \"*/foo\"" " ]" " }" " }" " ]," " \"deny_rules\": [" " {" " \"name\": \"deny_bar\"," " \"source\": {" " \"principals\": [" " \"bar\"" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED); EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected."); EXPECT_TRUE(resp.message().empty()); } TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestMatchInDenyMatchInAllow) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_all\"" " }" " ]," " \"deny_rules\": [" " {" " \"name\": \"deny_echo\"," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED); EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected."); EXPECT_TRUE(resp.message().empty()); } TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestMatchInDenyNoMatchInAllow) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_clientstreamingecho\"," " \"request\": {" " \"paths\": [" " \"*/ClientStreamingEcho\"" " ]" " }" " }" " ]," " \"deny_rules\": [" " {" " \"name\": \"deny_echo\"," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED); EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected."); EXPECT_TRUE(resp.message().empty()); } TEST_F(SdkAuthzEnd2EndTest, StaticInitAllowsRpcRequestEmptyDenyMatchInAllow) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_echo\"," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]," " \"headers\": [" " {" " \"key\": \"key-foo\"," " \"values\": [\"foo1\", \"foo2\"]" " }," " {" " \"key\": \"key-bar\"," " \"values\": [\"bar1\"]" " }" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; context.AddMetadata("key-foo", "foo2"); context.AddMetadata("key-bar", "bar1"); context.AddMetadata("key-baz", "baz1"); grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_TRUE(status.ok()); EXPECT_EQ(resp.message(), kMessage); } TEST_F(SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestEmptyDenyNoMatchInAllow) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_echo\"," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]," " \"headers\": [" " {" " \"key\": \"key-foo\"," " \"values\": [\"foo1\"]" " }" " ]" " }" " }" " ]" "}"; InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; context.AddMetadata("key-bar", "bar1"); grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED); EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected."); EXPECT_TRUE(resp.message().empty()); } TEST_F( SdkAuthzEnd2EndTest, StaticInitDeniesRpcRequestWithPrincipalsFieldOnUnauthenticatedConnection) { std::string policy = "{" " \"name\": \"authz\"," " \"allow_rules\": [" " {" " \"name\": \"allow_echo\"," " \"source\": {" " \"principals\": [" " \"foo\"" " ]" " }," " \"request\": {" " \"paths\": [" " \"*/Echo\"" " ]" " }" " }" " ]" "}"; UseInsecureCredentials(); InitServer(CreateStaticAuthzPolicyProvider(policy)); auto channel = BuildChannel(); ClientContext context; grpc::testing::EchoResponse resp; grpc::Status status = SendRpc(channel, &context, &resp); EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED); EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected."); EXPECT_TRUE(resp.message().empty()); } } // namespace } // namespace testing } // namespace grpc int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); grpc::testing::TestEnvironment env(argc, argv); const auto result = RUN_ALL_TESTS(); return result; }