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