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