diff --git a/src/datastore/rbac-policies.cpp b/src/datastore/rbac-policies.cpp index 883fa11f..072b489b 100644 --- a/src/datastore/rbac-policies.cpp +++ b/src/datastore/rbac-policies.cpp @@ -212,4 +212,23 @@ std::vector RbacPolicy::Record::check() const { return policies; } + +RbacPolicy RetrieveRbacPolicy(const std::string &id) { + std::string_view qry = R"( + select + _id, + _rev, + name + from "rbac-policies" + where + _id = $1::text; + )"; + + auto res = pg::exec(qry, id); + if (res.empty()) { + throw err::DatastoreRbacPolicyNotFound(); + } + + return RbacPolicy(res[0]); +} } // namespace datastore diff --git a/src/datastore/rbac-policies.h b/src/datastore/rbac-policies.h index 68ed5374..1edfdbe3 100644 --- a/src/datastore/rbac-policies.h +++ b/src/datastore/rbac-policies.h @@ -76,4 +76,6 @@ class RbacPolicy { }; using RbacPolicies = std::vector; + +RbacPolicy RetrieveRbacPolicy(const std::string &id); } // namespace datastore diff --git a/src/service/grpc.cpp b/src/service/grpc.cpp index 817a3cbb..66bdca79 100644 --- a/src/service/grpc.cpp +++ b/src/service/grpc.cpp @@ -389,6 +389,21 @@ grpc::ServerUnaryReactor *Grpc::CreateRbacPolicy( gk::v1::RbacPolicy *response) { auto *reactor = context->DefaultReactor(); + if (request->has_id()) { + try { + auto policy = datastore::RetrieveRbacPolicy(request->id()); + reactor->Finish(grpc::Status(grpc::StatusCode::ALREADY_EXISTS, "Duplicate policy id")); + return reactor; + } catch (const err::DatastoreRbacPolicyNotFound &) { + // Policy with an `id` matching the request `id` doesn't exist, we can continue with + // creating a new one. + } catch (const std::exception &e) { + std::cout << "Y " << e.what() << std::endl; + reactor->Finish(grpc::Status(grpc::StatusCode::UNAVAILABLE, "Failed to retrieve data")); + return reactor; + } + } + auto policy = map(request); try { // Store the policy @@ -444,8 +459,7 @@ grpc::ServerUnaryReactor *Grpc::CreateRbacPolicy( } } } - - } catch (...) { + } catch (std::exception &e) { reactor->Finish(grpc::Status(grpc::StatusCode::UNAVAILABLE, "Failed to store data")); return reactor; } diff --git a/src/service/grpc_test.cpp b/src/service/grpc_test.cpp index 2fd0784a..2583fbca 100644 --- a/src/service/grpc_test.cpp +++ b/src/service/grpc_test.cpp @@ -908,8 +908,44 @@ TEST_F(GrpcTest, UpdateIndentity) { } // RBAC -TEST_F(GrpcTest, CreateRbacRbacPolicy) { +TEST_F(GrpcTest, CreateRbacPolicy) { service::Grpc service; + // Success: create rbac policy with `id` + { + grpc::CallbackServerContext ctx; + grpc::testing::DefaultReactorTestPeer peer(&ctx); + gk::v1::RbacPolicy response; + + gk::v1::CreateRbacPolicyRequest request; + request.set_id("id:GrpcTest.CreateRbacPolicy-id"); + request.set_name("name:GrpcTest.CreateRbacPolicy-id"); + + auto reactor = service.CreateRbacPolicy(&ctx, &request, &response); + EXPECT_TRUE(peer.test_status_set()); + EXPECT_TRUE(peer.test_status().ok()); + EXPECT_EQ(peer.reactor(), reactor); + EXPECT_EQ(request.id(), response.id()); + EXPECT_EQ(request.name(), response.name()); + } + + // Error: duplicate `id` + { + const datastore::RbacPolicy policy({.name = "name:GrpcTest.CreateRbacPolicy-duplicate"}); + EXPECT_NO_THROW(policy.store()); + + grpc::CallbackServerContext ctx; + grpc::testing::DefaultReactorTestPeer peer(&ctx); + gk::v1::RbacPolicy response; + + gk::v1::CreateRbacPolicyRequest request; + request.set_id(policy.id()); + request.set_name("name:GrpcTest.CreateRbacPolicy-duplicate"); + + auto reactor = service.CreateRbacPolicy(&ctx, &request, &response); + EXPECT_TRUE(peer.test_status_set()); + EXPECT_EQ(grpc::StatusCode::ALREADY_EXISTS, peer.test_status().error_code()); + EXPECT_EQ("Duplicate policy id", peer.test_status().error_message()); + } // Success: create rbac policy {