xref: /aosp_15_r20/external/grpc-grpc/test/core/xds/xds_audit_logger_registry_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/ext/xds/xds_audit_logger_registry.h"
20 
21 #include <memory>
22 #include <string>
23 
24 #include <google/protobuf/any.pb.h>
25 
26 #include "absl/status/status.h"
27 #include "absl/status/statusor.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/string_view.h"
30 #include "envoy/config/rbac/v3/rbac.upb.h"
31 #include "google/protobuf/struct.pb.h"
32 #include "gtest/gtest.h"
33 #include "upb/mem/arena.hpp"
34 #include "upb/reflection/def.hpp"
35 
36 #include <grpc/grpc.h>
37 #include <grpc/grpc_audit_logging.h>
38 
39 #include "src/core/ext/xds/xds_bootstrap_grpc.h"
40 #include "src/core/lib/gprpp/crash.h"
41 #include "src/core/lib/json/json.h"
42 #include "src/core/lib/json/json_writer.h"
43 #include "src/core/lib/security/authorization/audit_logging.h"
44 #include "src/proto/grpc/testing/xds/v3/audit_logger_stream.pb.h"
45 #include "src/proto/grpc/testing/xds/v3/extension.pb.h"
46 #include "src/proto/grpc/testing/xds/v3/rbac.pb.h"
47 #include "src/proto/grpc/testing/xds/v3/typed_struct.pb.h"
48 #include "test/core/util/test_config.h"
49 
50 namespace grpc_core {
51 namespace testing {
52 namespace {
53 
54 using experimental::AuditLogger;
55 using experimental::AuditLoggerFactory;
56 using experimental::AuditLoggerRegistry;
57 using AuditLoggerConfigProto =
58     ::envoy::config::rbac::v3::RBAC::AuditLoggingOptions::AuditLoggerConfig;
59 using ::envoy::extensions::rbac::audit_loggers::stream::v3::StdoutAuditLog;
60 using ::xds::type::v3::TypedStruct;
61 
62 constexpr absl::string_view kName = "test_logger";
63 
ConvertAuditLoggerConfig(const AuditLoggerConfigProto & config)64 absl::StatusOr<std::string> ConvertAuditLoggerConfig(
65     const AuditLoggerConfigProto& config) {
66   std::string serialized_config = config.SerializeAsString();
67   upb::Arena arena;
68   upb::DefPool def_pool;
69   XdsResourceType::DecodeContext context = {
70       nullptr, GrpcXdsBootstrap::GrpcXdsServer(), nullptr, def_pool.ptr(),
71       arena.ptr()};
72   auto* upb_config =
73       envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig_parse(
74           serialized_config.data(), serialized_config.size(), arena.ptr());
75   ValidationErrors errors;
76   auto config_json = XdsAuditLoggerRegistry().ConvertXdsAuditLoggerConfig(
77       context, upb_config, &errors);
78   if (!errors.ok()) {
79     return errors.status(absl::StatusCode::kInvalidArgument,
80                          "validation errors");
81   }
82   return JsonDump(config_json);
83 }
84 
85 class TestAuditLoggerFactory : public AuditLoggerFactory {
86  public:
name() const87   absl::string_view name() const override { return kName; }
88   absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>>
ParseAuditLoggerConfig(const Json & json)89   ParseAuditLoggerConfig(const Json& json) override {
90     if (json.object().find("bad") != json.object().end()) {
91       return absl::InvalidArgumentError("invalid test_logger config");
92     }
93     return nullptr;
94   }
CreateAuditLogger(std::unique_ptr<AuditLoggerFactory::Config>)95   std::unique_ptr<AuditLogger> CreateAuditLogger(
96       std::unique_ptr<AuditLoggerFactory::Config>) override {
97     Crash("unreachable");
98     return nullptr;
99   }
100 };
101 
102 class XdsAuditLoggerRegistryTest : public ::testing::Test {
103  protected:
SetUp()104   void SetUp() override {
105     AuditLoggerRegistry::RegisterFactory(
106         std::make_unique<TestAuditLoggerFactory>());
107   }
108 
TearDown()109   void TearDown() override { AuditLoggerRegistry::TestOnlyResetRegistry(); }
110 };
111 
112 //
113 // StdoutLoggerTest
114 //
115 
TEST(StdoutLoggerTest,BasicStdoutLogger)116 TEST(StdoutLoggerTest, BasicStdoutLogger) {
117   AuditLoggerConfigProto config;
118   config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
119       StdoutAuditLog());
120   auto result = ConvertAuditLoggerConfig(config);
121   ASSERT_TRUE(result.ok()) << result.status();
122   EXPECT_EQ(*result, "{\"stdout_logger\":{}}");
123 }
124 
125 //
126 // ThirdPartyLoggerTest
127 //
128 
TEST_F(XdsAuditLoggerRegistryTest,ValidThirdPartyLogger)129 TEST_F(XdsAuditLoggerRegistryTest, ValidThirdPartyLogger) {
130   AuditLoggerConfigProto config;
131   TypedStruct logger;
132   logger.set_type_url(absl::StrFormat("myorg/foo/bar/%s", kName));
133   auto* fields = logger.mutable_value()->mutable_fields();
134   (*fields)["foo"].set_string_value("bar");
135   config.mutable_audit_logger()->mutable_typed_config()->PackFrom(logger);
136   auto result = ConvertAuditLoggerConfig(config);
137   ASSERT_TRUE(result.ok()) << result.status();
138   EXPECT_EQ(*result, "{\"test_logger\":{\"foo\":\"bar\"}}");
139 }
140 
TEST_F(XdsAuditLoggerRegistryTest,InvalidThirdPartyLoggerConfig)141 TEST_F(XdsAuditLoggerRegistryTest, InvalidThirdPartyLoggerConfig) {
142   AuditLoggerConfigProto config;
143   TypedStruct logger;
144   logger.set_type_url(absl::StrFormat("myorg/foo/bar/%s", kName));
145   auto* fields = logger.mutable_value()->mutable_fields();
146   (*fields)["bad"].set_string_value("true");
147   config.mutable_audit_logger()->mutable_typed_config()->PackFrom(logger);
148   auto result = ConvertAuditLoggerConfig(config);
149   EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
150   EXPECT_EQ(result.status().message(),
151             "validation errors: "
152             "[field:audit_logger.typed_config.value"
153             "[xds.type.v3.TypedStruct].value[test_logger] "
154             "error:invalid test_logger config]")
155       << result.status();
156 }
157 
158 //
159 // XdsAuditLoggerRegistryTest
160 //
161 
TEST_F(XdsAuditLoggerRegistryTest,EmptyAuditLoggerConfig)162 TEST_F(XdsAuditLoggerRegistryTest, EmptyAuditLoggerConfig) {
163   auto result = ConvertAuditLoggerConfig(AuditLoggerConfigProto());
164   EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
165   EXPECT_EQ(result.status().message(),
166             "validation errors: [field:audit_logger error:field not present]")
167       << result.status();
168 }
169 
TEST_F(XdsAuditLoggerRegistryTest,MissingTypedConfig)170 TEST_F(XdsAuditLoggerRegistryTest, MissingTypedConfig) {
171   AuditLoggerConfigProto config;
172   config.mutable_audit_logger();
173   auto result = ConvertAuditLoggerConfig(config);
174   EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
175   EXPECT_EQ(result.status().message(),
176             "validation errors: [field:audit_logger.typed_config error:field "
177             "not present]")
178       << result.status();
179 }
180 
TEST_F(XdsAuditLoggerRegistryTest,NoSupportedType)181 TEST_F(XdsAuditLoggerRegistryTest, NoSupportedType) {
182   AuditLoggerConfigProto config;
183   config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
184       AuditLoggerConfigProto());
185   auto result = ConvertAuditLoggerConfig(config);
186   EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
187   EXPECT_EQ(result.status().message(),
188             "validation errors: "
189             "[field:audit_logger.typed_config.value[envoy.config.rbac.v3.RBAC."
190             "AuditLoggingOptions.AuditLoggerConfig] error:unsupported audit "
191             "logger type]")
192       << result.status();
193 }
194 
TEST_F(XdsAuditLoggerRegistryTest,NoSupportedTypeButIsOptional)195 TEST_F(XdsAuditLoggerRegistryTest, NoSupportedTypeButIsOptional) {
196   AuditLoggerConfigProto config;
197   config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
198       AuditLoggerConfigProto());
199   config.set_is_optional(true);
200   auto result = ConvertAuditLoggerConfig(config);
201   EXPECT_EQ(result.status().code(), absl::StatusCode::kOk);
202   EXPECT_EQ(*result, "null");
203 }
204 
205 }  // namespace
206 }  // namespace testing
207 }  // namespace grpc_core
208 
main(int argc,char ** argv)209 int main(int argc, char** argv) {
210   ::testing::InitGoogleTest(&argc, argv);
211   grpc::testing::TestEnvironment env(&argc, argv);
212   grpc_init();
213   auto result = RUN_ALL_TESTS();
214   grpc_shutdown();
215   return result;
216 }
217