mirror of https://github.com/grpc/grpc.git
RBAC Engine implementation. (#25948)
parent
c3a91f8c82
commit
457fd3d41c
11 changed files with 371 additions and 4 deletions
@ -0,0 +1,44 @@ |
||||
// Copyright 2021 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_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H |
||||
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <string> |
||||
|
||||
#include "src/core/lib/security/authorization/evaluate_args.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// Interface for gRPC Authorization Engine.
|
||||
class AuthorizationEngine { |
||||
public: |
||||
struct Decision { |
||||
enum class Type { |
||||
kAllow, |
||||
kDeny, |
||||
}; |
||||
Type type; |
||||
std::string matching_policy_name; |
||||
}; |
||||
|
||||
virtual ~AuthorizationEngine() = default; |
||||
virtual Decision Evaluate(const EvaluateArgs& args) const = 0; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_AUTHORIZATION_ENGINE_H
|
@ -0,0 +1,49 @@ |
||||
// Copyright 2021 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/grpc_authorization_engine.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
GrpcAuthorizationEngine::GrpcAuthorizationEngine(Rbac policy) |
||||
: action_(policy.action) { |
||||
for (auto& sub_policy : policy.policies) { |
||||
Policy policy; |
||||
policy.name = sub_policy.first; |
||||
policy.matcher = absl::make_unique<PolicyAuthorizationMatcher>( |
||||
std::move(sub_policy.second)); |
||||
policies_.push_back(std::move(policy)); |
||||
} |
||||
} |
||||
|
||||
AuthorizationEngine::Decision GrpcAuthorizationEngine::Evaluate( |
||||
const EvaluateArgs& args) const { |
||||
Decision decision; |
||||
bool matches = false; |
||||
for (const auto& policy : policies_) { |
||||
if (policy.matcher->Matches(args)) { |
||||
matches = true; |
||||
decision.matching_policy_name = policy.name; |
||||
break; |
||||
} |
||||
} |
||||
decision.type = (matches == (action_ == Rbac::Action::kAllow)) |
||||
? Decision::Type::kAllow |
||||
: Decision::Type::kDeny; |
||||
return decision; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,55 @@ |
||||
// Copyright 2021 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_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H |
||||
#define GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/security/authorization/authorization_engine.h" |
||||
#include "src/core/lib/security/authorization/matchers.h" |
||||
#include "src/core/lib/security/authorization/rbac_policy.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// GrpcAuthorizationEngine can be either an Allow engine or Deny engine. This
|
||||
// engine makes authorization decisions to Allow or Deny incoming RPC request
|
||||
// based on permission and principal configs in the provided RBAC policy and the
|
||||
// engine type. This engine ignores condition field in RBAC config. It is the
|
||||
// caller's responsibility to provide RBAC policies that are compatible with
|
||||
// this engine.
|
||||
class GrpcAuthorizationEngine : public AuthorizationEngine { |
||||
public: |
||||
// Builds GrpcAuthorizationEngine without any policies.
|
||||
explicit GrpcAuthorizationEngine(Rbac::Action action) : action_(action) {} |
||||
// Builds GrpcAuthorizationEngine with allow/deny RBAC policy.
|
||||
explicit GrpcAuthorizationEngine(Rbac policy); |
||||
|
||||
// Evaluates incoming request against RBAC policy and makes a decision to
|
||||
// whether allow/deny this request.
|
||||
Decision Evaluate(const EvaluateArgs& args) const override; |
||||
|
||||
private: |
||||
struct Policy { |
||||
std::string name; |
||||
std::unique_ptr<AuthorizationMatcher> matcher; |
||||
}; |
||||
|
||||
Rbac::Action action_; |
||||
std::vector<Policy> policies_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_SECURITY_AUTHORIZATION_GRPC_AUTHORIZATION_ENGINE_H
|
@ -0,0 +1,107 @@ |
||||
// Copyright 2021 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 <gmock/gmock.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
#include "src/core/lib/security/authorization/grpc_authorization_engine.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) { |
||||
Rbac::Policy policy1( |
||||
Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), |
||||
Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); |
||||
Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)), |
||||
(Rbac::Principal(Rbac::Principal::RuleType::kAny))); |
||||
std::map<std::string, Rbac::Policy> policies; |
||||
policies["policy1"] = std::move(policy1); |
||||
policies["policy2"] = std::move(policy2); |
||||
Rbac rbac(Rbac::Action::kAllow, std::move(policies)); |
||||
GrpcAuthorizationEngine engine(std::move(rbac)); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); |
||||
EXPECT_EQ(decision.matching_policy_name, "policy2"); |
||||
} |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) { |
||||
Rbac::Policy policy1( |
||||
Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), |
||||
Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); |
||||
std::map<std::string, Rbac::Policy> policies; |
||||
policies["policy1"] = std::move(policy1); |
||||
Rbac rbac(Rbac::Action::kAllow, std::move(policies)); |
||||
GrpcAuthorizationEngine engine(std::move(rbac)); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); |
||||
EXPECT_TRUE(decision.matching_policy_name.empty()); |
||||
} |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) { |
||||
GrpcAuthorizationEngine engine(Rbac::Action::kAllow); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); |
||||
EXPECT_TRUE(decision.matching_policy_name.empty()); |
||||
} |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) { |
||||
Rbac::Policy policy1( |
||||
Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), |
||||
Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); |
||||
Rbac::Policy policy2((Rbac::Permission(Rbac::Permission::RuleType::kAny)), |
||||
(Rbac::Principal(Rbac::Principal::RuleType::kAny))); |
||||
std::map<std::string, Rbac::Policy> policies; |
||||
policies["policy1"] = std::move(policy1); |
||||
policies["policy2"] = std::move(policy2); |
||||
Rbac rbac(Rbac::Action::kDeny, std::move(policies)); |
||||
GrpcAuthorizationEngine engine(std::move(rbac)); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny); |
||||
EXPECT_EQ(decision.matching_policy_name, "policy2"); |
||||
} |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) { |
||||
Rbac::Policy policy1( |
||||
Rbac::Permission(Rbac::Permission::RuleType::kAny, /*not_rule=*/true), |
||||
Rbac::Principal(Rbac::Principal::RuleType::kAny, /*not_rule=*/true)); |
||||
std::map<std::string, Rbac::Policy> policies; |
||||
policies["policy1"] = std::move(policy1); |
||||
Rbac rbac(Rbac::Action::kDeny, std::move(policies)); |
||||
GrpcAuthorizationEngine engine(std::move(rbac)); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); |
||||
EXPECT_TRUE(decision.matching_policy_name.empty()); |
||||
} |
||||
|
||||
TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) { |
||||
GrpcAuthorizationEngine engine(Rbac::Action::kDeny); |
||||
AuthorizationEngine::Decision decision = |
||||
engine.Evaluate(EvaluateArgs(nullptr, nullptr)); |
||||
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow); |
||||
EXPECT_TRUE(decision.matching_policy_name.empty()); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
Loading…
Reference in new issue