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