xref: /aosp_15_r20/external/grpc-grpc/test/cpp/end2end/grpc_authz_end2end_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <memory>
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 #include <grpcpp/channel.h>
21 #include <grpcpp/client_context.h>
22 #include <grpcpp/create_channel.h>
23 #include <grpcpp/security/audit_logging.h>
24 #include <grpcpp/security/authorization_policy_provider.h>
25 #include <grpcpp/server.h>
26 #include <grpcpp/server_builder.h>
27 
28 #include "src/core/lib/security/authorization/audit_logging.h"
29 #include "src/core/lib/security/authorization/grpc_authorization_policy_provider.h"
30 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
31 #include "src/cpp/client/secure_credentials.h"
32 #include "src/cpp/server/secure_server_credentials.h"
33 #include "src/proto/grpc/testing/echo.grpc.pb.h"
34 #include "test/core/util/audit_logging_utils.h"
35 #include "test/core/util/port.h"
36 #include "test/core/util/test_config.h"
37 #include "test/core/util/tls_utils.h"
38 #include "test/cpp/end2end/test_service_impl.h"
39 
40 namespace grpc {
41 namespace testing {
42 namespace {
43 
44 constexpr char kCaCertPath[] = "src/core/tsi/test_creds/ca.pem";
45 constexpr char kServerCertPath[] = "src/core/tsi/test_creds/server1.pem";
46 constexpr char kServerKeyPath[] = "src/core/tsi/test_creds/server1.key";
47 constexpr char kClientCertPath[] =
48     "src/core/tsi/test_creds/client-with-spiffe.pem";
49 constexpr char kClientKeyPath[] =
50     "src/core/tsi/test_creds/client-with-spiffe.key";
51 
52 constexpr char kMessage[] = "Hello";
53 
54 using experimental::RegisterAuditLoggerFactory;
55 using grpc_core::experimental::AuditLoggerRegistry;
56 using grpc_core::testing::TestAuditLoggerFactory;
57 
58 class GrpcAuthzEnd2EndTest : public ::testing::Test {
59  protected:
GrpcAuthzEnd2EndTest()60   GrpcAuthzEnd2EndTest()
61       : server_address_(
62             absl::StrCat("localhost:", grpc_pick_unused_port_or_die())) {
63     std::string root_cert = grpc_core::testing::GetFileContents(kCaCertPath);
64     std::string identity_cert =
65         grpc_core::testing::GetFileContents(kServerCertPath);
66     std::string private_key =
67         grpc_core::testing::GetFileContents(kServerKeyPath);
68     std::vector<experimental::IdentityKeyCertPair>
69         server_identity_key_cert_pairs = {{private_key, identity_cert}};
70     grpc::experimental::TlsServerCredentialsOptions server_options(
71         std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
72             root_cert, server_identity_key_cert_pairs));
73     server_options.watch_root_certs();
74     server_options.watch_identity_key_cert_pairs();
75     server_options.set_cert_request_type(
76         GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
77     server_creds_ = grpc::experimental::TlsServerCredentials(server_options);
78     std::vector<experimental::IdentityKeyCertPair>
79         channel_identity_key_cert_pairs = {
80             {grpc_core::testing::GetFileContents(kClientKeyPath),
81              grpc_core::testing::GetFileContents(kClientCertPath)}};
82     grpc::experimental::TlsChannelCredentialsOptions channel_options;
83     channel_options.set_certificate_provider(
84         std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
85             grpc_core::testing::GetFileContents(kCaCertPath),
86             channel_identity_key_cert_pairs));
87     channel_options.watch_identity_key_cert_pairs();
88     channel_options.watch_root_certs();
89     channel_creds_ = grpc::experimental::TlsCredentials(channel_options);
90     RegisterAuditLoggerFactory(
91         std::make_unique<TestAuditLoggerFactory>(&audit_logs_));
92   }
93 
~GrpcAuthzEnd2EndTest()94   ~GrpcAuthzEnd2EndTest() override {
95     AuditLoggerRegistry::TestOnlyResetRegistry();
96     server_->Shutdown();
97   }
98 
99   // Replaces existing credentials with insecure credentials.
UseInsecureCredentials()100   void UseInsecureCredentials() {
101     server_creds_ = InsecureServerCredentials();
102     channel_creds_ = InsecureChannelCredentials();
103   }
104 
105   // Creates server with gRPC authorization enabled when provider is not null.
InitServer(std::shared_ptr<experimental::AuthorizationPolicyProviderInterface> provider)106   void InitServer(
107       std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
108           provider) {
109     ServerBuilder builder;
110     builder.AddListeningPort(server_address_, std::move(server_creds_));
111     builder.experimental().SetAuthorizationPolicyProvider(std::move(provider));
112     builder.RegisterService(&service_);
113     server_ = builder.BuildAndStart();
114   }
115 
116   std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
CreateStaticAuthzPolicyProvider(const std::string & policy)117   CreateStaticAuthzPolicyProvider(const std::string& policy) {
118     grpc::Status status;
119     auto provider = experimental::StaticDataAuthorizationPolicyProvider::Create(
120         policy, &status);
121     EXPECT_TRUE(status.ok());
122     return provider;
123   }
124 
125   std::shared_ptr<experimental::AuthorizationPolicyProviderInterface>
CreateFileWatcherAuthzPolicyProvider(const std::string & policy_path,unsigned int refresh_interval_sec)126   CreateFileWatcherAuthzPolicyProvider(const std::string& policy_path,
127                                        unsigned int refresh_interval_sec) {
128     grpc::Status status;
129     auto provider =
130         experimental::FileWatcherAuthorizationPolicyProvider::Create(
131             policy_path, refresh_interval_sec, &status);
132     EXPECT_TRUE(status.ok());
133     return provider;
134   }
135 
BuildChannel()136   std::shared_ptr<Channel> BuildChannel() {
137     ChannelArguments args;
138     // Override target name for host name check
139     args.SetSslTargetNameOverride("foo.test.google.fr");
140     return grpc::CreateCustomChannel(server_address_, channel_creds_, args);
141   }
142 
SendRpc(const std::shared_ptr<Channel> & channel,ClientContext * context,grpc::testing::EchoResponse * response=nullptr)143   grpc::Status SendRpc(const std::shared_ptr<Channel>& channel,
144                        ClientContext* context,
145                        grpc::testing::EchoResponse* response = nullptr) {
146     auto stub = grpc::testing::EchoTestService::NewStub(channel);
147     grpc::testing::EchoRequest request;
148     request.set_message(kMessage);
149     return stub->Echo(context, request, response);
150   }
151 
152   std::string server_address_;
153   TestServiceImpl service_;
154   std::unique_ptr<Server> server_;
155   std::shared_ptr<ServerCredentials> server_creds_;
156   std::shared_ptr<ChannelCredentials> channel_creds_;
157   std::vector<std::string> audit_logs_;
158 };
159 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitAllowsRpcRequestNoMatchInDenyMatchInAllow)160 TEST_F(GrpcAuthzEnd2EndTest,
161        StaticInitAllowsRpcRequestNoMatchInDenyMatchInAllow) {
162   std::string policy =
163       "{"
164       "  \"name\": \"authz\","
165       "  \"allow_rules\": ["
166       "    {"
167       "      \"name\": \"allow_echo\","
168       "      \"request\": {"
169       "        \"paths\": ["
170       "          \"*/Echo\""
171       "        ],"
172       "        \"headers\": ["
173       "          {"
174       "            \"key\": \"key-foo\","
175       "            \"values\": [\"foo1\", \"foo2\"]"
176       "          },"
177       "          {"
178       "            \"key\": \"key-bar\","
179       "            \"values\": [\"bar1\"]"
180       "          }"
181       "        ]"
182       "      }"
183       "    }"
184       "  ],"
185       "  \"deny_rules\": ["
186       "    {"
187       "      \"name\": \"deny_clientstreamingecho\","
188       "      \"request\": {"
189       "        \"paths\": ["
190       "          \"*/ClientStreamingEcho\""
191       "        ]"
192       "      }"
193       "    }"
194       "  ]"
195       "}";
196   InitServer(CreateStaticAuthzPolicyProvider(policy));
197   auto channel = BuildChannel();
198   ClientContext context;
199   context.AddMetadata("key-foo", "foo2");
200   context.AddMetadata("key-bar", "bar1");
201   context.AddMetadata("key-baz", "baz1");
202   grpc::testing::EchoResponse resp;
203   grpc::Status status = SendRpc(channel, &context, &resp);
204   EXPECT_TRUE(status.ok());
205   EXPECT_EQ(resp.message(), kMessage);
206 }
207 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitDeniesRpcRequestNoMatchInAllowAndDeny)208 TEST_F(GrpcAuthzEnd2EndTest, StaticInitDeniesRpcRequestNoMatchInAllowAndDeny) {
209   std::string policy =
210       "{"
211       "  \"name\": \"authz\","
212       "  \"allow_rules\": ["
213       "    {"
214       "      \"name\": \"allow_foo\","
215       "      \"request\": {"
216       "        \"paths\": ["
217       "          \"*/foo\""
218       "        ]"
219       "      }"
220       "    }"
221       "  ],"
222       "  \"deny_rules\": ["
223       "    {"
224       "      \"name\": \"deny_bar\","
225       "      \"source\": {"
226       "        \"principals\": ["
227       "          \"bar\""
228       "        ]"
229       "      }"
230       "    }"
231       "  ]"
232       "}";
233   InitServer(CreateStaticAuthzPolicyProvider(policy));
234   auto channel = BuildChannel();
235   ClientContext context;
236   grpc::testing::EchoResponse resp;
237   grpc::Status status = SendRpc(channel, &context, &resp);
238   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
239   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
240   EXPECT_TRUE(resp.message().empty());
241 }
242 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitDeniesRpcRequestMatchInDenyMatchInAllow)243 TEST_F(GrpcAuthzEnd2EndTest,
244        StaticInitDeniesRpcRequestMatchInDenyMatchInAllow) {
245   std::string policy =
246       "{"
247       "  \"name\": \"authz\","
248       "  \"allow_rules\": ["
249       "    {"
250       "      \"name\": \"allow_all\""
251       "    }"
252       "  ],"
253       "  \"deny_rules\": ["
254       "    {"
255       "      \"name\": \"deny_echo\","
256       "      \"request\": {"
257       "        \"paths\": ["
258       "          \"*/Echo\""
259       "        ]"
260       "      }"
261       "    }"
262       "  ]"
263       "}";
264   InitServer(CreateStaticAuthzPolicyProvider(policy));
265   auto channel = BuildChannel();
266   ClientContext context;
267   grpc::testing::EchoResponse resp;
268   grpc::Status status = SendRpc(channel, &context, &resp);
269   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
270   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
271   EXPECT_TRUE(resp.message().empty());
272 }
273 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitDeniesRpcRequestMatchInDenyNoMatchInAllow)274 TEST_F(GrpcAuthzEnd2EndTest,
275        StaticInitDeniesRpcRequestMatchInDenyNoMatchInAllow) {
276   std::string policy =
277       "{"
278       "  \"name\": \"authz\","
279       "  \"allow_rules\": ["
280       "    {"
281       "      \"name\": \"allow_clientstreamingecho\","
282       "      \"request\": {"
283       "        \"paths\": ["
284       "          \"*/ClientStreamingEcho\""
285       "        ]"
286       "      }"
287       "    }"
288       "  ],"
289       "  \"deny_rules\": ["
290       "    {"
291       "      \"name\": \"deny_echo\","
292       "      \"request\": {"
293       "        \"paths\": ["
294       "          \"*/Echo\""
295       "        ]"
296       "      }"
297       "    }"
298       "  ]"
299       "}";
300   InitServer(CreateStaticAuthzPolicyProvider(policy));
301   auto channel = BuildChannel();
302   ClientContext context;
303   grpc::testing::EchoResponse resp;
304   grpc::Status status = SendRpc(channel, &context, &resp);
305   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
306   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
307   EXPECT_TRUE(resp.message().empty());
308 }
309 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitAllowsRpcRequestEmptyDenyMatchInAllow)310 TEST_F(GrpcAuthzEnd2EndTest, StaticInitAllowsRpcRequestEmptyDenyMatchInAllow) {
311   std::string policy =
312       "{"
313       "  \"name\": \"authz\","
314       "  \"allow_rules\": ["
315       "    {"
316       "      \"name\": \"allow_echo\","
317       "      \"request\": {"
318       "        \"paths\": ["
319       "          \"*\""
320       "        ],"
321       "        \"headers\": ["
322       "          {"
323       "            \"key\": \"key-foo\","
324       "            \"values\": [\"foo1\", \"foo2\"]"
325       "          },"
326       "          {"
327       "            \"key\": \"key-bar\","
328       "            \"values\": [\"bar1\"]"
329       "          }"
330       "        ]"
331       "      }"
332       "    }"
333       "  ]"
334       "}";
335   InitServer(CreateStaticAuthzPolicyProvider(policy));
336   auto channel = BuildChannel();
337   ClientContext context;
338   context.AddMetadata("key-foo", "foo2");
339   context.AddMetadata("key-bar", "bar1");
340   context.AddMetadata("key-baz", "baz1");
341   grpc::testing::EchoResponse resp;
342   grpc::Status status = SendRpc(channel, &context, &resp);
343   EXPECT_TRUE(status.ok());
344   EXPECT_EQ(resp.message(), kMessage);
345 }
346 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitDeniesRpcRequestEmptyDenyNoMatchInAllow)347 TEST_F(GrpcAuthzEnd2EndTest,
348        StaticInitDeniesRpcRequestEmptyDenyNoMatchInAllow) {
349   std::string policy =
350       "{"
351       "  \"name\": \"authz\","
352       "  \"allow_rules\": ["
353       "    {"
354       "      \"name\": \"allow_echo\","
355       "      \"request\": {"
356       "        \"paths\": ["
357       "          \"*/Echo\""
358       "        ],"
359       "        \"headers\": ["
360       "          {"
361       "            \"key\": \"key-foo\","
362       "            \"values\": [\"foo1\"]"
363       "          }"
364       "        ]"
365       "      }"
366       "    }"
367       "  ]"
368       "}";
369   InitServer(CreateStaticAuthzPolicyProvider(policy));
370   auto channel = BuildChannel();
371   ClientContext context;
372   context.AddMetadata("key-bar", "bar1");
373   grpc::testing::EchoResponse resp;
374   grpc::Status status = SendRpc(channel, &context, &resp);
375   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
376   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
377   EXPECT_TRUE(resp.message().empty());
378 }
379 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitDeniesRpcRequestWithPrincipalsFieldOnUnauthenticatedConnection)380 TEST_F(
381     GrpcAuthzEnd2EndTest,
382     StaticInitDeniesRpcRequestWithPrincipalsFieldOnUnauthenticatedConnection) {
383   std::string policy =
384       "{"
385       "  \"name\": \"authz\","
386       "  \"allow_rules\": ["
387       "    {"
388       "      \"name\": \"allow_mtls\","
389       "      \"source\": {"
390       "        \"principals\": [\"*\"]"
391       "      }"
392       "    }"
393       "  ]"
394       "}";
395   UseInsecureCredentials();
396   InitServer(CreateStaticAuthzPolicyProvider(policy));
397   auto channel = BuildChannel();
398   ClientContext context;
399   grpc::testing::EchoResponse resp;
400   grpc::Status status = SendRpc(channel, &context, &resp);
401   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
402   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
403   EXPECT_TRUE(resp.message().empty());
404 }
405 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitAllowsRpcRequestWithPrincipalsFieldOnAuthenticatedConnection)406 TEST_F(GrpcAuthzEnd2EndTest,
407        StaticInitAllowsRpcRequestWithPrincipalsFieldOnAuthenticatedConnection) {
408   std::string policy =
409       "{"
410       "  \"name\": \"authz\","
411       "  \"allow_rules\": ["
412       "    {"
413       "      \"name\": \"allow_mtls\","
414       "      \"source\": {"
415       "        \"principals\": [\"*\"]"
416       "      }"
417       "    }"
418       "  ]"
419       "}";
420   InitServer(CreateStaticAuthzPolicyProvider(policy));
421   auto channel = BuildChannel();
422   ClientContext context;
423   grpc::testing::EchoResponse resp;
424   grpc::Status status = SendRpc(channel, &context, &resp);
425   EXPECT_TRUE(status.ok());
426   EXPECT_EQ(resp.message(), kMessage);
427 }
428 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInAllowWithAuditLoggingNone)429 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInAllowWithAuditLoggingNone) {
430   std::string policy =
431       "{"
432       "  \"name\": \"authz\","
433       "  \"allow_rules\": ["
434       "    {"
435       "      \"name\": \"allow_foo\","
436       "      \"request\": {"
437       "        \"headers\": ["
438       "          {"
439       "            \"key\": \"key-foo\","
440       "            \"values\": [\"foo\"]"
441       "          }"
442       "        ]"
443       "      }"
444       "    }"
445       "  ],"
446       "  \"deny_rules\": ["
447       "    {"
448       "      \"name\": \"deny_bar\","
449       "      \"request\": {"
450       "        \"headers\": ["
451       "          {"
452       "            \"key\": \"key-bar\","
453       "            \"values\": [\"bar\"]"
454       "          }"
455       "        ]"
456       "      }"
457       "    }"
458       "  ],"
459       "  \"audit_logging_options\": {"
460       "    \"audit_condition\": \"NONE\","
461       "    \"audit_loggers\": ["
462       "      {"
463       "        \"name\": \"test_logger\""
464       "      }"
465       "    ]"
466       "  }"
467       "}";
468   InitServer(CreateStaticAuthzPolicyProvider(policy));
469   auto channel = BuildChannel();
470   grpc::testing::EchoResponse resp;
471   grpc::Status status;
472   ClientContext context;
473   // Matches the allow rule.
474   context.AddMetadata("key-foo", "foo");
475   status = SendRpc(channel, &context, &resp);
476   EXPECT_TRUE(status.ok());
477   EXPECT_EQ(audit_logs_.size(), 0);
478 }
479 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitNoMatchWithAuditLoggingNone)480 TEST_F(GrpcAuthzEnd2EndTest, StaticInitNoMatchWithAuditLoggingNone) {
481   std::string policy =
482       "{"
483       "  \"name\": \"authz\","
484       "  \"allow_rules\": ["
485       "    {"
486       "      \"name\": \"allow_foo\","
487       "      \"request\": {"
488       "        \"headers\": ["
489       "          {"
490       "            \"key\": \"key-foo\","
491       "            \"values\": [\"foo\"]"
492       "          }"
493       "        ]"
494       "      }"
495       "    }"
496       "  ],"
497       "  \"deny_rules\": ["
498       "    {"
499       "      \"name\": \"deny_bar\","
500       "      \"request\": {"
501       "        \"headers\": ["
502       "          {"
503       "            \"key\": \"key-bar\","
504       "            \"values\": [\"bar\"]"
505       "          }"
506       "        ]"
507       "      }"
508       "    }"
509       "  ],"
510       "  \"audit_logging_options\": {"
511       "    \"audit_condition\": \"NONE\","
512       "    \"audit_loggers\": ["
513       "      {"
514       "        \"name\": \"test_logger\""
515       "      }"
516       "    ]"
517       "  }"
518       "}";
519   InitServer(CreateStaticAuthzPolicyProvider(policy));
520   auto channel = BuildChannel();
521   grpc::testing::EchoResponse resp;
522   grpc::Status status;
523   ClientContext context;
524   // Does not match the allow rule or deny rule.
525   context.AddMetadata("key-foo", "bar");
526   status = SendRpc(channel, &context, &resp);
527   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
528   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
529   EXPECT_EQ(audit_logs_.size(), 0);
530 }
531 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInDenyWithAuditLoggingNone)532 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInDenyWithAuditLoggingNone) {
533   std::string policy =
534       "{"
535       "  \"name\": \"authz\","
536       "  \"allow_rules\": ["
537       "    {"
538       "      \"name\": \"allow_foo\","
539       "      \"request\": {"
540       "        \"headers\": ["
541       "          {"
542       "            \"key\": \"key-foo\","
543       "            \"values\": [\"foo\"]"
544       "          }"
545       "        ]"
546       "      }"
547       "    }"
548       "  ],"
549       "  \"deny_rules\": ["
550       "    {"
551       "      \"name\": \"deny_bar\","
552       "      \"request\": {"
553       "        \"headers\": ["
554       "          {"
555       "            \"key\": \"key-bar\","
556       "            \"values\": [\"bar\"]"
557       "          }"
558       "        ]"
559       "      }"
560       "    }"
561       "  ],"
562       "  \"audit_logging_options\": {"
563       "    \"audit_condition\": \"NONE\","
564       "    \"audit_loggers\": ["
565       "      {"
566       "        \"name\": \"test_logger\""
567       "      }"
568       "    ]"
569       "  }"
570       "}";
571   InitServer(CreateStaticAuthzPolicyProvider(policy));
572   auto channel = BuildChannel();
573   grpc::testing::EchoResponse resp;
574   grpc::Status status;
575   ClientContext context;
576   // Matches the deny rule.
577   context.AddMetadata("key-bar", "bar");
578   status = SendRpc(channel, &context, &resp);
579   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
580   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
581   EXPECT_EQ(audit_logs_.size(), 0);
582 }
583 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInAllowWithAuditLoggingOnDeny)584 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInAllowWithAuditLoggingOnDeny) {
585   std::string policy =
586       "{"
587       "  \"name\": \"authz\","
588       "  \"allow_rules\": ["
589       "    {"
590       "      \"name\": \"allow_foo\","
591       "      \"request\": {"
592       "        \"headers\": ["
593       "          {"
594       "            \"key\": \"key-foo\","
595       "            \"values\": [\"foo\"]"
596       "          }"
597       "        ]"
598       "      }"
599       "    }"
600       "  ],"
601       "  \"deny_rules\": ["
602       "    {"
603       "      \"name\": \"deny_bar\","
604       "      \"request\": {"
605       "        \"headers\": ["
606       "          {"
607       "            \"key\": \"key-bar\","
608       "            \"values\": [\"bar\"]"
609       "          }"
610       "        ]"
611       "      }"
612       "    }"
613       "  ],"
614       "  \"audit_logging_options\": {"
615       "    \"audit_condition\": \"ON_DENY\","
616       "    \"audit_loggers\": ["
617       "      {"
618       "        \"name\": \"test_logger\""
619       "      }"
620       "    ]"
621       "  }"
622       "}";
623   InitServer(CreateStaticAuthzPolicyProvider(policy));
624   auto channel = BuildChannel();
625   grpc::testing::EchoResponse resp;
626   grpc::Status status;
627   ClientContext context;
628   // Matches the allow rule.
629   context.AddMetadata("key-foo", "foo");
630   status = SendRpc(channel, &context, &resp);
631   EXPECT_TRUE(status.ok());
632   EXPECT_EQ(audit_logs_.size(), 0);
633 }
634 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitNoMatchWithAuditLoggingOnDeny)635 TEST_F(GrpcAuthzEnd2EndTest, StaticInitNoMatchWithAuditLoggingOnDeny) {
636   std::string policy =
637       "{"
638       "  \"name\": \"authz\","
639       "  \"allow_rules\": ["
640       "    {"
641       "      \"name\": \"allow_foo\","
642       "      \"request\": {"
643       "        \"headers\": ["
644       "          {"
645       "            \"key\": \"key-foo\","
646       "            \"values\": [\"foo\"]"
647       "          }"
648       "        ]"
649       "      }"
650       "    }"
651       "  ],"
652       "  \"deny_rules\": ["
653       "    {"
654       "      \"name\": \"deny_bar\","
655       "      \"request\": {"
656       "        \"headers\": ["
657       "          {"
658       "            \"key\": \"key-bar\","
659       "            \"values\": [\"bar\"]"
660       "          }"
661       "        ]"
662       "      }"
663       "    }"
664       "  ],"
665       "  \"audit_logging_options\": {"
666       "    \"audit_condition\": \"ON_DENY\","
667       "    \"audit_loggers\": ["
668       "      {"
669       "        \"name\": \"test_logger\""
670       "      }"
671       "    ]"
672       "  }"
673       "}";
674   InitServer(CreateStaticAuthzPolicyProvider(policy));
675   auto channel = BuildChannel();
676   grpc::testing::EchoResponse resp;
677   grpc::Status status;
678   ClientContext context;
679   // Does not match the allow rule or deny rule.
680   context.AddMetadata("key-foo", "bar");
681   status = SendRpc(channel, &context, &resp);
682   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
683   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
684   EXPECT_THAT(
685       audit_logs_,
686       ::testing::ElementsAre(
687           "{\"authorized\":false,\"matched_rule\":\"\",\"policy_name\":"
688           "\"authz\",\"principal\":\"spiffe://foo.com/bar/"
689           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
690 }
691 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInDenyWithAuditLoggingOnDeny)692 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInDenyWithAuditLoggingOnDeny) {
693   std::string policy =
694       "{"
695       "  \"name\": \"authz\","
696       "  \"allow_rules\": ["
697       "    {"
698       "      \"name\": \"allow_foo\","
699       "      \"request\": {"
700       "        \"headers\": ["
701       "          {"
702       "            \"key\": \"key-foo\","
703       "            \"values\": [\"foo\"]"
704       "          }"
705       "        ]"
706       "      }"
707       "    }"
708       "  ],"
709       "  \"deny_rules\": ["
710       "    {"
711       "      \"name\": \"deny_bar\","
712       "      \"request\": {"
713       "        \"headers\": ["
714       "          {"
715       "            \"key\": \"key-bar\","
716       "            \"values\": [\"bar\"]"
717       "          }"
718       "        ]"
719       "      }"
720       "    }"
721       "  ],"
722       "  \"audit_logging_options\": {"
723       "    \"audit_condition\": \"ON_DENY\","
724       "    \"audit_loggers\": ["
725       "      {"
726       "        \"name\": \"test_logger\""
727       "      }"
728       "    ]"
729       "  }"
730       "}";
731   InitServer(CreateStaticAuthzPolicyProvider(policy));
732   auto channel = BuildChannel();
733   grpc::testing::EchoResponse resp;
734   grpc::Status status;
735   ClientContext context;
736   // Matches the deny rule.
737   context.AddMetadata("key-bar", "bar");
738   status = SendRpc(channel, &context, &resp);
739   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
740   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
741   EXPECT_THAT(
742       audit_logs_,
743       ::testing::ElementsAre(
744           "{\"authorized\":false,\"matched_rule\":\"deny_bar\",\"policy_name\":"
745           "\"authz\",\"principal\":\"spiffe://foo.com/bar/"
746           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
747 }
748 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInAllowWithAuditLoggingOnAllow)749 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInAllowWithAuditLoggingOnAllow) {
750   std::string policy =
751       "{"
752       "  \"name\": \"authz\","
753       "  \"allow_rules\": ["
754       "    {"
755       "      \"name\": \"allow_foo\","
756       "      \"request\": {"
757       "        \"headers\": ["
758       "          {"
759       "            \"key\": \"key-foo\","
760       "            \"values\": [\"foo\"]"
761       "          }"
762       "        ]"
763       "      }"
764       "    }"
765       "  ],"
766       "  \"deny_rules\": ["
767       "    {"
768       "      \"name\": \"deny_bar\","
769       "      \"request\": {"
770       "        \"headers\": ["
771       "          {"
772       "            \"key\": \"key-bar\","
773       "            \"values\": [\"bar\"]"
774       "          }"
775       "        ]"
776       "      }"
777       "    }"
778       "  ],"
779       "  \"audit_logging_options\": {"
780       "    \"audit_condition\": \"ON_ALLOW\","
781       "    \"audit_loggers\": ["
782       "      {"
783       "        \"name\": \"test_logger\""
784       "      }"
785       "    ]"
786       "  }"
787       "}";
788   InitServer(CreateStaticAuthzPolicyProvider(policy));
789   auto channel = BuildChannel();
790   grpc::testing::EchoResponse resp;
791   grpc::Status status;
792   ClientContext context;
793   // Matches the allow rule.
794   context.AddMetadata("key-foo", "foo");
795   status = SendRpc(channel, &context, &resp);
796   EXPECT_TRUE(status.ok());
797   EXPECT_THAT(
798       audit_logs_,
799       ::testing::ElementsAre(
800           "{\"authorized\":true,\"matched_rule\":\"allow_foo\",\"policy_"
801           "name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
802           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
803 }
804 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitNoMatchWithAuditLoggingOnAllow)805 TEST_F(GrpcAuthzEnd2EndTest, StaticInitNoMatchWithAuditLoggingOnAllow) {
806   std::string policy =
807       "{"
808       "  \"name\": \"authz\","
809       "  \"allow_rules\": ["
810       "    {"
811       "      \"name\": \"allow_foo\","
812       "      \"request\": {"
813       "        \"headers\": ["
814       "          {"
815       "            \"key\": \"key-foo\","
816       "            \"values\": [\"foo\"]"
817       "          }"
818       "        ]"
819       "      }"
820       "    }"
821       "  ],"
822       "  \"deny_rules\": ["
823       "    {"
824       "      \"name\": \"deny_bar\","
825       "      \"request\": {"
826       "        \"headers\": ["
827       "          {"
828       "            \"key\": \"key-bar\","
829       "            \"values\": [\"bar\"]"
830       "          }"
831       "        ]"
832       "      }"
833       "    }"
834       "  ],"
835       "  \"audit_logging_options\": {"
836       "    \"audit_condition\": \"ON_ALLOW\","
837       "    \"audit_loggers\": ["
838       "      {"
839       "        \"name\": \"test_logger\""
840       "      }"
841       "    ]"
842       "  }"
843       "}";
844   InitServer(CreateStaticAuthzPolicyProvider(policy));
845   auto channel = BuildChannel();
846   grpc::testing::EchoResponse resp;
847   grpc::Status status;
848   ClientContext context;
849   // Does not match the allow rule. No audit log emitted.
850   context.AddMetadata("key-foo", "bar");
851   status = SendRpc(channel, &context, &resp);
852   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
853   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
854   EXPECT_EQ(audit_logs_.size(), 0);
855 }
856 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInDenyWithAuditLoggingOnAllow)857 TEST_F(GrpcAuthzEnd2EndTest, StaticInitMatchInDenyWithAuditLoggingOnAllow) {
858   std::string policy =
859       "{"
860       "  \"name\": \"authz\","
861       "  \"allow_rules\": ["
862       "    {"
863       "      \"name\": \"allow_foo\","
864       "      \"request\": {"
865       "        \"headers\": ["
866       "          {"
867       "            \"key\": \"key-foo\","
868       "            \"values\": [\"foo\"]"
869       "          }"
870       "        ]"
871       "      }"
872       "    }"
873       "  ],"
874       "  \"deny_rules\": ["
875       "    {"
876       "      \"name\": \"deny_bar\","
877       "      \"request\": {"
878       "        \"headers\": ["
879       "          {"
880       "            \"key\": \"key-bar\","
881       "            \"values\": [\"bar\"]"
882       "          }"
883       "        ]"
884       "      }"
885       "    }"
886       "  ],"
887       "  \"audit_logging_options\": {"
888       "    \"audit_condition\": \"ON_ALLOW\","
889       "    \"audit_loggers\": ["
890       "      {"
891       "        \"name\": \"test_logger\""
892       "      }"
893       "    ]"
894       "  }"
895       "}";
896   InitServer(CreateStaticAuthzPolicyProvider(policy));
897   auto channel = BuildChannel();
898   grpc::testing::EchoResponse resp;
899   grpc::Status status;
900   ClientContext context;
901   // Matches the deny rule. No audit log emitted.
902   context.AddMetadata("key-bar", "bar");
903   status = SendRpc(channel, &context, &resp);
904   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
905   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
906   EXPECT_EQ(audit_logs_.size(), 0);
907 }
908 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInAllowWithAuditLoggingOnDenyAndAllow)909 TEST_F(GrpcAuthzEnd2EndTest,
910        StaticInitMatchInAllowWithAuditLoggingOnDenyAndAllow) {
911   std::string policy =
912       "{"
913       "  \"name\": \"authz\","
914       "  \"allow_rules\": ["
915       "    {"
916       "      \"name\": \"allow_foo\","
917       "      \"request\": {"
918       "        \"headers\": ["
919       "          {"
920       "            \"key\": \"key-foo\","
921       "            \"values\": [\"foo\"]"
922       "          }"
923       "        ]"
924       "      }"
925       "    }"
926       "  ],"
927       "  \"deny_rules\": ["
928       "    {"
929       "      \"name\": \"deny_bar\","
930       "      \"request\": {"
931       "        \"headers\": ["
932       "          {"
933       "            \"key\": \"key-bar\","
934       "            \"values\": [\"bar\"]"
935       "          }"
936       "        ]"
937       "      }"
938       "    }"
939       "  ],"
940       "  \"audit_logging_options\": {"
941       "    \"audit_condition\": \"ON_DENY_AND_ALLOW\","
942       "    \"audit_loggers\": ["
943       "      {"
944       "        \"name\": \"test_logger\""
945       "      }"
946       "    ]"
947       "  }"
948       "}";
949   InitServer(CreateStaticAuthzPolicyProvider(policy));
950   auto channel = BuildChannel();
951   grpc::testing::EchoResponse resp;
952   grpc::Status status;
953   ClientContext context;
954   // Matches the allow rule.
955   context.AddMetadata("key-foo", "foo");
956   status = SendRpc(channel, &context, &resp);
957   EXPECT_TRUE(status.ok());
958   EXPECT_THAT(
959       audit_logs_,
960       ::testing::ElementsAre(
961           "{\"authorized\":true,\"matched_rule\":\"allow_foo\",\"policy_"
962           "name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
963           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
964 }
965 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitNoMatchWithAuditLoggingOnDenyAndAllow)966 TEST_F(GrpcAuthzEnd2EndTest, StaticInitNoMatchWithAuditLoggingOnDenyAndAllow) {
967   std::string policy =
968       "{"
969       "  \"name\": \"authz\","
970       "  \"allow_rules\": ["
971       "    {"
972       "      \"name\": \"allow_foo\","
973       "      \"request\": {"
974       "        \"headers\": ["
975       "          {"
976       "            \"key\": \"key-foo\","
977       "            \"values\": [\"foo\"]"
978       "          }"
979       "        ]"
980       "      }"
981       "    }"
982       "  ],"
983       "  \"deny_rules\": ["
984       "    {"
985       "      \"name\": \"deny_bar\","
986       "      \"request\": {"
987       "        \"headers\": ["
988       "          {"
989       "            \"key\": \"key-bar\","
990       "            \"values\": [\"bar\"]"
991       "          }"
992       "        ]"
993       "      }"
994       "    }"
995       "  ],"
996       "  \"audit_logging_options\": {"
997       "    \"audit_condition\": \"ON_DENY_AND_ALLOW\","
998       "    \"audit_loggers\": ["
999       "      {"
1000       "        \"name\": \"test_logger\""
1001       "      }"
1002       "    ]"
1003       "  }"
1004       "}";
1005   InitServer(CreateStaticAuthzPolicyProvider(policy));
1006   auto channel = BuildChannel();
1007   grpc::testing::EchoResponse resp;
1008   grpc::Status status;
1009   ClientContext context;
1010   // Does not match the allow rule.
1011   context.AddMetadata("key-foo", "bar");
1012   status = SendRpc(channel, &context, &resp);
1013   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1014   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1015   EXPECT_THAT(
1016       audit_logs_,
1017       ::testing::ElementsAre(
1018           "{\"authorized\":false,\"matched_rule\":\"\",\"policy_"
1019           "name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
1020           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
1021 }
1022 
TEST_F(GrpcAuthzEnd2EndTest,StaticInitMatchInDenyWithAuditLoggingOnDenyAndAllow)1023 TEST_F(GrpcAuthzEnd2EndTest,
1024        StaticInitMatchInDenyWithAuditLoggingOnDenyAndAllow) {
1025   std::string policy =
1026       "{"
1027       "  \"name\": \"authz\","
1028       "  \"allow_rules\": ["
1029       "    {"
1030       "      \"name\": \"allow_foo\","
1031       "      \"request\": {"
1032       "        \"headers\": ["
1033       "          {"
1034       "            \"key\": \"key-foo\","
1035       "            \"values\": [\"foo\"]"
1036       "          }"
1037       "        ]"
1038       "      }"
1039       "    }"
1040       "  ],"
1041       "  \"deny_rules\": ["
1042       "    {"
1043       "      \"name\": \"deny_bar\","
1044       "      \"request\": {"
1045       "        \"headers\": ["
1046       "          {"
1047       "            \"key\": \"key-bar\","
1048       "            \"values\": [\"bar\"]"
1049       "          }"
1050       "        ]"
1051       "      }"
1052       "    }"
1053       "  ],"
1054       "  \"audit_logging_options\": {"
1055       "    \"audit_condition\": \"ON_DENY_AND_ALLOW\","
1056       "    \"audit_loggers\": ["
1057       "      {"
1058       "        \"name\": \"test_logger\""
1059       "      }"
1060       "    ]"
1061       "  }"
1062       "}";
1063   InitServer(CreateStaticAuthzPolicyProvider(policy));
1064   auto channel = BuildChannel();
1065   grpc::testing::EchoResponse resp;
1066   grpc::Status status;
1067   ClientContext context;
1068   // Matches the deny rule.
1069   context.AddMetadata("key-bar", "bar");
1070   status = SendRpc(channel, &context, &resp);
1071   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1072   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1073   EXPECT_THAT(
1074       audit_logs_,
1075       ::testing::ElementsAre(
1076           "{\"authorized\":false,\"matched_rule\":\"deny_bar\",\"policy_"
1077           "name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
1078           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
1079 }
1080 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitAllowsRpcRequestNoMatchInDenyMatchInAllow)1081 TEST_F(GrpcAuthzEnd2EndTest,
1082        FileWatcherInitAllowsRpcRequestNoMatchInDenyMatchInAllow) {
1083   std::string policy =
1084       "{"
1085       "  \"name\": \"authz\","
1086       "  \"allow_rules\": ["
1087       "    {"
1088       "      \"name\": \"allow_echo\","
1089       "      \"request\": {"
1090       "        \"paths\": ["
1091       "          \"*/Echo\""
1092       "        ],"
1093       "        \"headers\": ["
1094       "          {"
1095       "            \"key\": \"key-foo\","
1096       "            \"values\": [\"foo1\", \"foo2\"]"
1097       "          },"
1098       "          {"
1099       "            \"key\": \"key-bar\","
1100       "            \"values\": [\"bar1\"]"
1101       "          }"
1102       "        ]"
1103       "      }"
1104       "    }"
1105       "  ],"
1106       "  \"deny_rules\": ["
1107       "    {"
1108       "      \"name\": \"deny_clientstreamingecho\","
1109       "      \"request\": {"
1110       "        \"paths\": ["
1111       "          \"*/ClientStreamingEcho\""
1112       "        ]"
1113       "      }"
1114       "    }"
1115       "  ]"
1116       "}";
1117   grpc_core::testing::TmpFile tmp_policy(policy);
1118   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1119   auto channel = BuildChannel();
1120   ClientContext context;
1121   context.AddMetadata("key-foo", "foo2");
1122   context.AddMetadata("key-bar", "bar1");
1123   context.AddMetadata("key-baz", "baz1");
1124   grpc::testing::EchoResponse resp;
1125   grpc::Status status = SendRpc(channel, &context, &resp);
1126   EXPECT_TRUE(status.ok());
1127   EXPECT_EQ(resp.message(), kMessage);
1128 }
1129 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitDeniesRpcRequestNoMatchInAllowAndDeny)1130 TEST_F(GrpcAuthzEnd2EndTest,
1131        FileWatcherInitDeniesRpcRequestNoMatchInAllowAndDeny) {
1132   std::string policy =
1133       "{"
1134       "  \"name\": \"authz\","
1135       "  \"allow_rules\": ["
1136       "    {"
1137       "      \"name\": \"allow_foo\","
1138       "      \"request\": {"
1139       "        \"paths\": ["
1140       "          \"*/foo\""
1141       "        ]"
1142       "      }"
1143       "    }"
1144       "  ],"
1145       "  \"deny_rules\": ["
1146       "    {"
1147       "      \"name\": \"deny_bar\","
1148       "      \"source\": {"
1149       "        \"principals\": ["
1150       "          \"bar\""
1151       "        ]"
1152       "      }"
1153       "    }"
1154       "  ]"
1155       "}";
1156   grpc_core::testing::TmpFile tmp_policy(policy);
1157   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1158   auto channel = BuildChannel();
1159   ClientContext context;
1160   grpc::testing::EchoResponse resp;
1161   grpc::Status status = SendRpc(channel, &context, &resp);
1162   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1163   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1164   EXPECT_TRUE(resp.message().empty());
1165 }
1166 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitDeniesRpcRequestMatchInDenyMatchInAllow)1167 TEST_F(GrpcAuthzEnd2EndTest,
1168        FileWatcherInitDeniesRpcRequestMatchInDenyMatchInAllow) {
1169   std::string policy =
1170       "{"
1171       "  \"name\": \"authz\","
1172       "  \"allow_rules\": ["
1173       "    {"
1174       "      \"name\": \"allow_all\""
1175       "    }"
1176       "  ],"
1177       "  \"deny_rules\": ["
1178       "    {"
1179       "      \"name\": \"deny_echo\","
1180       "      \"request\": {"
1181       "        \"paths\": ["
1182       "          \"*/Echo\""
1183       "        ]"
1184       "      }"
1185       "    }"
1186       "  ]"
1187       "}";
1188   grpc_core::testing::TmpFile tmp_policy(policy);
1189   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1190   auto channel = BuildChannel();
1191   ClientContext context;
1192   grpc::testing::EchoResponse resp;
1193   grpc::Status status = SendRpc(channel, &context, &resp);
1194   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1195   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1196   EXPECT_TRUE(resp.message().empty());
1197 }
1198 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitDeniesRpcRequestMatchInDenyNoMatchInAllow)1199 TEST_F(GrpcAuthzEnd2EndTest,
1200        FileWatcherInitDeniesRpcRequestMatchInDenyNoMatchInAllow) {
1201   std::string policy =
1202       "{"
1203       "  \"name\": \"authz\","
1204       "  \"allow_rules\": ["
1205       "    {"
1206       "      \"name\": \"allow_clientstreamingecho\","
1207       "      \"request\": {"
1208       "        \"paths\": ["
1209       "          \"*/ClientStreamingEcho\""
1210       "        ]"
1211       "      }"
1212       "    }"
1213       "  ],"
1214       "  \"deny_rules\": ["
1215       "    {"
1216       "      \"name\": \"deny_echo\","
1217       "      \"request\": {"
1218       "        \"paths\": ["
1219       "          \"*/Echo\""
1220       "        ]"
1221       "      }"
1222       "    }"
1223       "  ]"
1224       "}";
1225   grpc_core::testing::TmpFile tmp_policy(policy);
1226   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1227   auto channel = BuildChannel();
1228   ClientContext context;
1229   grpc::testing::EchoResponse resp;
1230   grpc::Status status = SendRpc(channel, &context, &resp);
1231   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1232   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1233   EXPECT_TRUE(resp.message().empty());
1234 }
1235 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitAllowsRpcRequestEmptyDenyMatchInAllow)1236 TEST_F(GrpcAuthzEnd2EndTest,
1237        FileWatcherInitAllowsRpcRequestEmptyDenyMatchInAllow) {
1238   std::string policy =
1239       "{"
1240       "  \"name\": \"authz\","
1241       "  \"allow_rules\": ["
1242       "    {"
1243       "      \"name\": \"allow_echo\","
1244       "      \"request\": {"
1245       "        \"paths\": ["
1246       "          \"*/Echo\""
1247       "        ],"
1248       "        \"headers\": ["
1249       "          {"
1250       "            \"key\": \"key-foo\","
1251       "            \"values\": [\"foo1\", \"foo2\"]"
1252       "          },"
1253       "          {"
1254       "            \"key\": \"key-bar\","
1255       "            \"values\": [\"bar1\"]"
1256       "          }"
1257       "        ]"
1258       "      }"
1259       "    }"
1260       "  ]"
1261       "}";
1262   grpc_core::testing::TmpFile tmp_policy(policy);
1263   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1264   auto channel = BuildChannel();
1265   ClientContext context;
1266   context.AddMetadata("key-foo", "foo2");
1267   context.AddMetadata("key-bar", "bar1");
1268   context.AddMetadata("key-baz", "baz1");
1269   grpc::testing::EchoResponse resp;
1270   grpc::Status status = SendRpc(channel, &context, &resp);
1271   EXPECT_TRUE(status.ok());
1272   EXPECT_EQ(resp.message(), kMessage);
1273 }
1274 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInitDeniesRpcRequestEmptyDenyNoMatchInAllow)1275 TEST_F(GrpcAuthzEnd2EndTest,
1276        FileWatcherInitDeniesRpcRequestEmptyDenyNoMatchInAllow) {
1277   std::string policy =
1278       "{"
1279       "  \"name\": \"authz\","
1280       "  \"allow_rules\": ["
1281       "    {"
1282       "      \"name\": \"allow_echo\","
1283       "      \"request\": {"
1284       "        \"paths\": ["
1285       "          \"*/Echo\""
1286       "        ],"
1287       "        \"headers\": ["
1288       "          {"
1289       "            \"key\": \"key-foo\","
1290       "            \"values\": [\"foo1\"]"
1291       "          }"
1292       "        ]"
1293       "      }"
1294       "    }"
1295       "  ]"
1296       "}";
1297   grpc_core::testing::TmpFile tmp_policy(policy);
1298   InitServer(CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 5));
1299   auto channel = BuildChannel();
1300   ClientContext context;
1301   context.AddMetadata("key-bar", "bar1");
1302   grpc::testing::EchoResponse resp;
1303   grpc::Status status = SendRpc(channel, &context, &resp);
1304   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1305   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1306   EXPECT_TRUE(resp.message().empty());
1307 }
1308 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherValidPolicyRefresh)1309 TEST_F(GrpcAuthzEnd2EndTest, FileWatcherValidPolicyRefresh) {
1310   std::string policy =
1311       "{"
1312       "  \"name\": \"authz\","
1313       "  \"allow_rules\": ["
1314       "    {"
1315       "      \"name\": \"allow_echo\","
1316       "      \"request\": {"
1317       "        \"paths\": ["
1318       "          \"*/Echo\""
1319       "        ]"
1320       "      }"
1321       "    }"
1322       "  ]"
1323       "}";
1324   grpc_core::testing::TmpFile tmp_policy(policy);
1325   auto provider = CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 1);
1326   InitServer(provider);
1327   auto channel = BuildChannel();
1328   ClientContext context1;
1329   grpc::testing::EchoResponse resp1;
1330   grpc::Status status = SendRpc(channel, &context1, &resp1);
1331   EXPECT_TRUE(status.ok());
1332   EXPECT_EQ(resp1.message(), kMessage);
1333   gpr_event on_reload_done;
1334   gpr_event_init(&on_reload_done);
1335   std::function<void(bool contents_changed, absl::Status status)> callback =
1336       [&on_reload_done](bool contents_changed, absl::Status status) {
1337         if (contents_changed) {
1338           EXPECT_TRUE(status.ok());
1339           gpr_event_set(&on_reload_done, reinterpret_cast<void*>(1));
1340         }
1341       };
1342   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1343       provider->c_provider())
1344       ->SetCallbackForTesting(std::move(callback));
1345   // Replace the existing policy with a new authorization policy.
1346   policy =
1347       "{"
1348       "  \"name\": \"authz\","
1349       "  \"allow_rules\": ["
1350       "    {"
1351       "      \"name\": \"allow_foo\","
1352       "      \"request\": {"
1353       "        \"paths\": ["
1354       "          \"*/foo\""
1355       "        ]"
1356       "      }"
1357       "    }"
1358       "  ],"
1359       "  \"deny_rules\": ["
1360       "    {"
1361       "      \"name\": \"deny_echo\","
1362       "      \"request\": {"
1363       "        \"paths\": ["
1364       "          \"*/Echo\""
1365       "        ]"
1366       "      }"
1367       "    }"
1368       "  ]"
1369       "}";
1370   tmp_policy.RewriteFile(policy);
1371   // Wait for the provider's refresh thread to read the updated files.
1372   ASSERT_EQ(
1373       gpr_event_wait(&on_reload_done, gpr_inf_future(GPR_CLOCK_MONOTONIC)),
1374       reinterpret_cast<void*>(1));
1375   ClientContext context2;
1376   grpc::testing::EchoResponse resp2;
1377   status = SendRpc(channel, &context2, &resp2);
1378   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1379   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1380   EXPECT_TRUE(resp2.message().empty());
1381   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1382       provider->c_provider())
1383       ->SetCallbackForTesting(nullptr);
1384 }
1385 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherInvalidPolicyRefreshSkipsReload)1386 TEST_F(GrpcAuthzEnd2EndTest, FileWatcherInvalidPolicyRefreshSkipsReload) {
1387   std::string policy =
1388       "{"
1389       "  \"name\": \"authz\","
1390       "  \"allow_rules\": ["
1391       "    {"
1392       "      \"name\": \"allow_echo\","
1393       "      \"request\": {"
1394       "        \"paths\": ["
1395       "          \"*/Echo\""
1396       "        ]"
1397       "      }"
1398       "    }"
1399       "  ]"
1400       "}";
1401   grpc_core::testing::TmpFile tmp_policy(policy);
1402   auto provider = CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 1);
1403   InitServer(provider);
1404   auto channel = BuildChannel();
1405   ClientContext context1;
1406   grpc::testing::EchoResponse resp1;
1407   grpc::Status status = SendRpc(channel, &context1, &resp1);
1408   EXPECT_TRUE(status.ok());
1409   EXPECT_EQ(resp1.message(), kMessage);
1410   gpr_event on_reload_done;
1411   gpr_event_init(&on_reload_done);
1412   std::function<void(bool contents_changed, absl::Status status)> callback =
1413       [&on_reload_done](bool contents_changed, absl::Status status) {
1414         if (contents_changed) {
1415           EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
1416           EXPECT_EQ(status.message(), "\"name\" field is not present.");
1417           gpr_event_set(&on_reload_done, reinterpret_cast<void*>(1));
1418         }
1419       };
1420   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1421       provider->c_provider())
1422       ->SetCallbackForTesting(std::move(callback));
1423   // Replaces existing policy with an invalid authorization policy.
1424   policy = "{}";
1425   tmp_policy.RewriteFile(policy);
1426   // Wait for the provider's refresh thread to read the updated files.
1427   ASSERT_EQ(
1428       gpr_event_wait(&on_reload_done, gpr_inf_future(GPR_CLOCK_MONOTONIC)),
1429       reinterpret_cast<void*>(1));
1430   ClientContext context2;
1431   grpc::testing::EchoResponse resp2;
1432   status = SendRpc(channel, &context2, &resp2);
1433   EXPECT_TRUE(status.ok());
1434   EXPECT_EQ(resp2.message(), kMessage);
1435   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1436       provider->c_provider())
1437       ->SetCallbackForTesting(nullptr);
1438 }
1439 
TEST_F(GrpcAuthzEnd2EndTest,FileWatcherWithAuditLoggingRecoversFromFailure)1440 TEST_F(GrpcAuthzEnd2EndTest, FileWatcherWithAuditLoggingRecoversFromFailure) {
1441   std::string policy =
1442       "{"
1443       "  \"name\": \"authz\","
1444       "  \"allow_rules\": ["
1445       "    {"
1446       "      \"name\": \"allow_echo\","
1447       "      \"request\": {"
1448       "        \"paths\": ["
1449       "          \"*/Echo\""
1450       "        ]"
1451       "      }"
1452       "    }"
1453       "  ],"
1454       "  \"audit_logging_options\": {"
1455       "    \"audit_condition\": \"ON_ALLOW\","
1456       "    \"audit_loggers\": ["
1457       "      {"
1458       "        \"name\": \"test_logger\""
1459       "      }"
1460       "    ]"
1461       "  }"
1462       "}";
1463   grpc_core::testing::TmpFile tmp_policy(policy);
1464   auto provider = CreateFileWatcherAuthzPolicyProvider(tmp_policy.name(), 1);
1465   InitServer(provider);
1466   auto channel = BuildChannel();
1467   ClientContext context1;
1468   grpc::testing::EchoResponse resp1;
1469   grpc::Status status = SendRpc(channel, &context1, &resp1);
1470   EXPECT_TRUE(status.ok());
1471   EXPECT_EQ(resp1.message(), kMessage);
1472   EXPECT_THAT(
1473       audit_logs_,
1474       ::testing::ElementsAre(
1475           "{\"authorized\":true,\"matched_rule\":\"allow_echo\","
1476           "\"policy_name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
1477           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
1478   audit_logs_.clear();
1479   gpr_event on_first_reload_done;
1480   gpr_event_init(&on_first_reload_done);
1481   std::function<void(bool contents_changed, absl::Status status)> callback1 =
1482       [&on_first_reload_done](bool contents_changed, absl::Status status) {
1483         if (contents_changed) {
1484           EXPECT_EQ(status.code(), absl::StatusCode::kInvalidArgument);
1485           EXPECT_EQ(status.message(), "\"name\" field is not present.");
1486           gpr_event_set(&on_first_reload_done, reinterpret_cast<void*>(1));
1487         }
1488       };
1489   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1490       provider->c_provider())
1491       ->SetCallbackForTesting(std::move(callback1));
1492   // Replaces existing policy with an invalid authorization policy.
1493   policy = "{}";
1494   tmp_policy.RewriteFile(policy);
1495   // Wait for the provider's refresh thread to read the updated files.
1496   ASSERT_EQ(gpr_event_wait(&on_first_reload_done,
1497                            gpr_inf_future(GPR_CLOCK_MONOTONIC)),
1498             reinterpret_cast<void*>(1));
1499   ClientContext context2;
1500   grpc::testing::EchoResponse resp2;
1501   status = SendRpc(channel, &context2, &resp2);
1502   EXPECT_TRUE(status.ok());
1503   EXPECT_EQ(resp2.message(), kMessage);
1504   EXPECT_THAT(
1505       audit_logs_,
1506       ::testing::ElementsAre(
1507           "{\"authorized\":true,\"matched_rule\":\"allow_echo\","
1508           "\"policy_name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
1509           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
1510   audit_logs_.clear();
1511   gpr_event on_second_reload_done;
1512   gpr_event_init(&on_second_reload_done);
1513   std::function<void(bool contents_changed, absl::Status status)> callback2 =
1514       [&on_second_reload_done](bool contents_changed, absl::Status status) {
1515         if (contents_changed) {
1516           EXPECT_TRUE(status.ok());
1517           gpr_event_set(&on_second_reload_done, reinterpret_cast<void*>(1));
1518         }
1519       };
1520   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1521       provider->c_provider())
1522       ->SetCallbackForTesting(std::move(callback2));
1523   // Replace the existing invalid policy with a valid authorization
1524   // policy.
1525   policy =
1526       "{"
1527       "  \"name\": \"authz\","
1528       "  \"allow_rules\": ["
1529       "    {"
1530       "      \"name\": \"allow_foo\","
1531       "      \"request\": {"
1532       "        \"paths\": ["
1533       "          \"*/foo\""
1534       "        ]"
1535       "      }"
1536       "    }"
1537       "  ],"
1538       "  \"deny_rules\": ["
1539       "    {"
1540       "      \"name\": \"deny_echo\","
1541       "      \"request\": {"
1542       "        \"paths\": ["
1543       "          \"*/Echo\""
1544       "        ]"
1545       "      }"
1546       "    }"
1547       "  ],"
1548       "  \"audit_logging_options\": {"
1549       "    \"audit_condition\": \"ON_DENY\","
1550       "    \"audit_loggers\": ["
1551       "      {"
1552       "        \"name\": \"test_logger\""
1553       "      }"
1554       "    ]"
1555       "  }"
1556       "}";
1557   tmp_policy.RewriteFile(policy);
1558   // Wait for the provider's refresh thread to read the updated files.
1559   ASSERT_EQ(gpr_event_wait(&on_second_reload_done,
1560                            gpr_inf_future(GPR_CLOCK_MONOTONIC)),
1561             reinterpret_cast<void*>(1));
1562   ClientContext context3;
1563   grpc::testing::EchoResponse resp3;
1564   status = SendRpc(channel, &context3, &resp3);
1565   EXPECT_EQ(status.error_code(), grpc::StatusCode::PERMISSION_DENIED);
1566   EXPECT_EQ(status.error_message(), "Unauthorized RPC request rejected.");
1567   EXPECT_TRUE(resp3.message().empty());
1568   EXPECT_THAT(
1569       audit_logs_,
1570       ::testing::ElementsAre(
1571           "{\"authorized\":false,\"matched_rule\":\"deny_echo\","
1572           "\"policy_name\":\"authz\",\"principal\":\"spiffe://foo.com/bar/"
1573           "baz\",\"rpc_method\":\"/grpc.testing.EchoTestService/Echo\"}"));
1574   dynamic_cast<grpc_core::FileWatcherAuthorizationPolicyProvider*>(
1575       provider->c_provider())
1576       ->SetCallbackForTesting(nullptr);
1577 }
1578 
1579 }  // namespace
1580 }  // namespace testing
1581 }  // namespace grpc
1582 
main(int argc,char ** argv)1583 int main(int argc, char** argv) {
1584   ::testing::InitGoogleTest(&argc, argv);
1585   grpc::testing::TestEnvironment env(&argc, argv);
1586   const auto result = RUN_ALL_TESTS();
1587   return result;
1588 }
1589