mirror of https://github.com/grpc/grpc.git
[Audit Logging] Logger and factory APIs in C-Core and C++. (#32750)
Audit logging APIs for both built-in loggers and third-party logger implementations. C++ uses using decls referring to C-Core APIs. --------- Co-authored-by: rockspore <rockspore@users.noreply.github.com>pull/32947/head
parent
da5dbc068d
commit
dcfc5d6904
22 changed files with 586 additions and 0 deletions
@ -0,0 +1,96 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2023 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_GRPC_AUDIT_LOGGING_H |
||||||
|
#define GRPC_GRPC_AUDIT_LOGGING_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
// TODO(lwge): Switch to public header when it's ready.
|
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
// The class containing the context for an audited RPC.
|
||||||
|
class AuditContext { |
||||||
|
public: |
||||||
|
AuditContext(absl::string_view rpc_method, absl::string_view principal, |
||||||
|
absl::string_view policy_name, absl::string_view matched_rule, |
||||||
|
bool authorized) |
||||||
|
: rpc_method_(rpc_method), |
||||||
|
principal_(principal), |
||||||
|
policy_name_(policy_name), |
||||||
|
matched_rule_(matched_rule), |
||||||
|
authorized_(authorized) {} |
||||||
|
|
||||||
|
absl::string_view rpc_method() const { return rpc_method_; } |
||||||
|
absl::string_view principal() const { return principal_; } |
||||||
|
absl::string_view policy_name() const { return policy_name_; } |
||||||
|
absl::string_view matched_rule() const { return matched_rule_; } |
||||||
|
bool authorized() const { return authorized_; } |
||||||
|
|
||||||
|
private: |
||||||
|
absl::string_view rpc_method_; |
||||||
|
absl::string_view principal_; |
||||||
|
absl::string_view policy_name_; |
||||||
|
absl::string_view matched_rule_; |
||||||
|
bool authorized_; |
||||||
|
}; |
||||||
|
|
||||||
|
// This base class for audit logger implementations.
|
||||||
|
class AuditLogger { |
||||||
|
public: |
||||||
|
virtual ~AuditLogger() = default; |
||||||
|
virtual void Log(const AuditContext& audit_context) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// This is the base class for audit logger factory implementations.
|
||||||
|
class AuditLoggerFactory { |
||||||
|
public: |
||||||
|
class Config { |
||||||
|
public: |
||||||
|
virtual ~Config() = default; |
||||||
|
virtual absl::string_view name() const = 0; |
||||||
|
virtual std::string ToString() const = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
virtual ~AuditLoggerFactory() = default; |
||||||
|
virtual absl::string_view name() const = 0; |
||||||
|
|
||||||
|
virtual absl::StatusOr<std::unique_ptr<Config>> ParseAuditLoggerConfig( |
||||||
|
const Json& json) = 0; |
||||||
|
|
||||||
|
virtual std::unique_ptr<AuditLogger> CreateAuditLogger( |
||||||
|
std::unique_ptr<AuditLoggerFactory::Config>) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// Registers an audit logger factory. This should only be called during
|
||||||
|
// initialization.
|
||||||
|
void RegisterAuditLoggerFactory(std::unique_ptr<AuditLoggerFactory> factory); |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif /* GRPC_GRPC_AUDIT_LOGGING_H */ |
@ -0,0 +1,44 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2023 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPCPP_SECURITY_AUDIT_LOGGING_H |
||||||
|
#define GRPCPP_SECURITY_AUDIT_LOGGING_H |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
#include "absl/status/statusor.h" |
||||||
|
|
||||||
|
#include <grpc/grpc_audit_logging.h> |
||||||
|
#include <grpcpp/support/string_ref.h> |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
using grpc_core::experimental::AuditContext; // NOLINT(misc-unused-using-decls)
|
||||||
|
using grpc_core::experimental::AuditLogger; // NOLINT(misc-unused-using-decls)
|
||||||
|
using grpc_core::experimental:: |
||||||
|
AuditLoggerFactory; // NOLINT(misc-unused-using-decls)
|
||||||
|
using grpc_core::experimental:: |
||||||
|
RegisterAuditLoggerFactory; // NOLINT(misc-unused-using-decls)
|
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
#endif // GRPCPP_SECURITY_AUDIT_LOGGING_H
|
@ -0,0 +1,91 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2023 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/security/authorization/audit_logging.h" |
||||||
|
|
||||||
|
#include <initializer_list> |
||||||
|
#include <map> |
||||||
|
#include <memory> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
#include "absl/status/status.h" |
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "absl/strings/str_format.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include <grpc/grpc_audit_logging.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/sync.h" |
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
Mutex* AuditLoggerRegistry::mu = new Mutex(); |
||||||
|
|
||||||
|
AuditLoggerRegistry* AuditLoggerRegistry::registry = new AuditLoggerRegistry(); |
||||||
|
|
||||||
|
void AuditLoggerRegistry::RegisterFactory( |
||||||
|
std::unique_ptr<AuditLoggerFactory> factory) { |
||||||
|
GPR_ASSERT(factory != nullptr); |
||||||
|
MutexLock lock(mu); |
||||||
|
absl::string_view name = factory->name(); |
||||||
|
GPR_ASSERT( |
||||||
|
registry->logger_factories_map_.emplace(name, std::move(factory)).second); |
||||||
|
} |
||||||
|
|
||||||
|
bool AuditLoggerRegistry::FactoryExists(absl::string_view name) { |
||||||
|
MutexLock lock(mu); |
||||||
|
return registry->logger_factories_map_.find(name) != |
||||||
|
registry->logger_factories_map_.end(); |
||||||
|
} |
||||||
|
|
||||||
|
absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>> |
||||||
|
AuditLoggerRegistry::ParseConfig(absl::string_view name, const Json& json) { |
||||||
|
MutexLock lock(mu); |
||||||
|
auto it = registry->logger_factories_map_.find(name); |
||||||
|
if (it == registry->logger_factories_map_.end()) { |
||||||
|
return absl::NotFoundError( |
||||||
|
absl::StrFormat("audit logger factory for %s does not exist", name)); |
||||||
|
} |
||||||
|
return it->second->ParseAuditLoggerConfig(json); |
||||||
|
} |
||||||
|
|
||||||
|
std::unique_ptr<AuditLogger> AuditLoggerRegistry::CreateAuditLogger( |
||||||
|
std::unique_ptr<AuditLoggerFactory::Config> config) { |
||||||
|
MutexLock lock(mu); |
||||||
|
auto it = registry->logger_factories_map_.find(config->name()); |
||||||
|
GPR_ASSERT(it != registry->logger_factories_map_.end()); |
||||||
|
return it->second->CreateAuditLogger(std::move(config)); |
||||||
|
} |
||||||
|
|
||||||
|
void AuditLoggerRegistry::TestOnlyResetRegistry() { |
||||||
|
MutexLock lock(mu); |
||||||
|
delete registry; |
||||||
|
registry = new AuditLoggerRegistry(); |
||||||
|
} |
||||||
|
|
||||||
|
void RegisterAuditLoggerFactory(std::unique_ptr<AuditLoggerFactory> factory) { |
||||||
|
AuditLoggerRegistry::RegisterFactory(std::move(factory)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,74 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2023 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_AUDIT_LOGGING_H |
||||||
|
#define GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_AUDIT_LOGGING_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <map> |
||||||
|
#include <memory> |
||||||
|
|
||||||
|
#include "absl/base/thread_annotations.h" |
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include <grpc/grpc_audit_logging.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/sync.h" |
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
class AuditLoggerRegistry { |
||||||
|
public: |
||||||
|
static void RegisterFactory(std::unique_ptr<AuditLoggerFactory>); |
||||||
|
|
||||||
|
static bool FactoryExists(absl::string_view name); |
||||||
|
|
||||||
|
static absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>> |
||||||
|
ParseConfig(absl::string_view name, const Json& json); |
||||||
|
|
||||||
|
// This assume the given config is parsed and validated already.
|
||||||
|
// Therefore, it should always succeed in creating a logger.
|
||||||
|
static std::unique_ptr<AuditLogger> CreateAuditLogger( |
||||||
|
std::unique_ptr<AuditLoggerFactory::Config>); |
||||||
|
|
||||||
|
// Factories are registered during initialization. They should never be
|
||||||
|
// unregistered since they will be looked up at any time till the program
|
||||||
|
// exits. This function should only be used in tests to clear the registry.
|
||||||
|
static void TestOnlyResetRegistry(); |
||||||
|
|
||||||
|
private: |
||||||
|
// TODO(lwge): Add built-in logger registrations once avaialble.
|
||||||
|
AuditLoggerRegistry() = default; |
||||||
|
|
||||||
|
static Mutex* mu; |
||||||
|
|
||||||
|
static AuditLoggerRegistry* registry ABSL_GUARDED_BY(mu); |
||||||
|
|
||||||
|
// The key is owned by the factory.
|
||||||
|
std::map<absl::string_view, std::unique_ptr<AuditLoggerFactory>> |
||||||
|
logger_factories_map_ ABSL_GUARDED_BY(mu); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_AUDIT_LOGGING_H
|
@ -0,0 +1,114 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2023 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
#include "absl/status/status.h" |
||||||
|
#include "absl/status/statusor.h" |
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include <grpc/grpc_audit_logging.h> |
||||||
|
|
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
#include "src/core/lib/security/authorization/audit_logging.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
#include "test/core/util/tls_utils.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace testing { |
||||||
|
|
||||||
|
constexpr absl::string_view kName = "test_logger"; |
||||||
|
|
||||||
|
using experimental::AuditContext; |
||||||
|
using experimental::AuditLogger; |
||||||
|
using experimental::AuditLoggerFactory; |
||||||
|
using experimental::AuditLoggerRegistry; |
||||||
|
using experimental::RegisterAuditLoggerFactory; |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
class TestAuditLogger : public AuditLogger { |
||||||
|
public: |
||||||
|
void Log(const AuditContext&) override {} |
||||||
|
}; |
||||||
|
|
||||||
|
class TestAuditLoggerFactory : public AuditLoggerFactory { |
||||||
|
public: |
||||||
|
class TestConfig : public Config { |
||||||
|
public: |
||||||
|
absl::string_view name() const override { return kName; } |
||||||
|
std::string ToString() const override { return "test_config"; } |
||||||
|
}; |
||||||
|
|
||||||
|
absl::string_view name() const override { return kName; } |
||||||
|
std::unique_ptr<AuditLogger> CreateAuditLogger( |
||||||
|
std::unique_ptr<AuditLoggerFactory::Config>) override { |
||||||
|
return std::make_unique<TestAuditLogger>(); |
||||||
|
} |
||||||
|
absl::StatusOr<std::unique_ptr<Config>> ParseAuditLoggerConfig( |
||||||
|
const Json&) override { |
||||||
|
return std::make_unique<TestConfig>(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
class AuditLoggingTest : public ::testing::Test { |
||||||
|
protected: |
||||||
|
void SetUp() override { |
||||||
|
RegisterAuditLoggerFactory(std::make_unique<TestAuditLoggerFactory>()); |
||||||
|
} |
||||||
|
void TearDown() override { AuditLoggerRegistry::TestOnlyResetRegistry(); } |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_F(AuditLoggingTest, SuccessfulLoggerCreation) { |
||||||
|
auto result = AuditLoggerRegistry::ParseConfig(kName, Json()); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_NE(AuditLoggerRegistry::CreateAuditLogger(std::move(result.value())), |
||||||
|
nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(AuditLoggingTest, UnknownLogger) { |
||||||
|
auto result = AuditLoggerRegistry::ParseConfig("unknown_logger", Json()); |
||||||
|
EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound); |
||||||
|
EXPECT_EQ(result.status().message(), |
||||||
|
"audit logger factory for unknown_logger does not exist") |
||||||
|
<< result.status(); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(AuditLoggingTest, AuditLoggerFactoryExistenceChecks) { |
||||||
|
EXPECT_TRUE(AuditLoggerRegistry::FactoryExists(kName)); |
||||||
|
EXPECT_FALSE(AuditLoggerRegistry::FactoryExists("unknown_logger")); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
grpc::testing::TestEnvironment env(&argc, argv); |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
grpc_init(); |
||||||
|
int ret = RUN_ALL_TESTS(); |
||||||
|
grpc_shutdown(); |
||||||
|
return ret; |
||||||
|
} |
Loading…
Reference in new issue