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