From dc8dad97944ec969c35f6f270670274f252adfbf Mon Sep 17 00:00:00 2001
From: niko4299 <51059248+niko4299@users.noreply.github.com>
Date: Tue, 13 Sep 2022 17:14:23 +0200
Subject: [PATCH] Add authorization in SetLabels, RemoveLabels, Allshortestpath
 cursor (#537)

---
 src/query/plan/operator.cpp                   |  37 +++-
 .../create_delete_filtering_tests.py          |  43 ++++
 .../path_filtering_tests.py                   | 188 ++++++++++++++++++
 .../query_plan_create_set_remove_delete.cpp   | 154 ++++++++++++++
 tests/unit/query_plan_match_filter_return.cpp | 157 +++++++++++----
 5 files changed, 543 insertions(+), 36 deletions(-)

diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp
index 1b92cae51..c86b427fc 100644
--- a/src/query/plan/operator.cpp
+++ b/src/query/plan/operator.cpp
@@ -1870,17 +1870,29 @@ class ExpandAllShortestPathsCursor : public query::plan::Cursor {
     // Populates the priority queue structure with expansions
     // from the given vertex. skips expansions that don't satisfy
     // the "where" condition.
-    auto expand_from_vertex = [this, &expand_vertex](const VertexAccessor &vertex, const TypedValue &weight,
-                                                     int64_t depth) {
+    auto expand_from_vertex = [this, &expand_vertex, &context](const VertexAccessor &vertex, const TypedValue &weight,
+                                                               int64_t depth) {
       if (self_.common_.direction != EdgeAtom::Direction::IN) {
         auto out_edges = UnwrapEdgesResult(vertex.OutEdges(storage::View::OLD, self_.common_.edge_types));
         for (const auto &edge : out_edges) {
+          if (context.auth_checker &&
+              !(context.auth_checker->Has(edge.To(), storage::View::OLD,
+                                          memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
+                context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
+            continue;
+          }
           expand_vertex(edge, EdgeAtom::Direction::OUT, weight, depth);
         }
       }
       if (self_.common_.direction != EdgeAtom::Direction::OUT) {
         auto in_edges = UnwrapEdgesResult(vertex.InEdges(storage::View::OLD, self_.common_.edge_types));
         for (const auto &edge : in_edges) {
+          if (context.auth_checker &&
+              !(context.auth_checker->Has(edge.From(), storage::View::OLD,
+                                          memgraph::query::AuthQuery::FineGrainedPrivilege::READ) &&
+                context.auth_checker->Has(edge, memgraph::query::AuthQuery::FineGrainedPrivilege::READ))) {
+            continue;
+          }
           expand_vertex(edge, EdgeAtom::Direction::IN, weight, depth);
         }
       }
@@ -2725,6 +2737,11 @@ SetLabels::SetLabelsCursor::SetLabelsCursor(const SetLabels &self, utils::Memory
 bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
   SCOPED_PROFILE_OP("SetLabels");
 
+  if (context.auth_checker &&
+      !context.auth_checker->Has(self_.labels_, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
+    throw QueryRuntimeException("Couldn't set label due to not having enough permission!");
+  }
+
   if (!input_cursor_->Pull(frame, context)) return false;
 
   TypedValue &vertex_value = frame[self_.input_symbol_];
@@ -2732,6 +2749,12 @@ bool SetLabels::SetLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
   if (vertex_value.IsNull()) return true;
   ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
   auto &vertex = vertex_value.ValueVertex();
+
+  if (context.auth_checker && !context.auth_checker->Has(vertex, storage::View::OLD,
+                                                         memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
+    throw QueryRuntimeException("Couldn't set label due to not having enough permission!");
+  }
+
   for (auto label : self_.labels_) {
     auto maybe_value = vertex.AddLabel(label);
     if (maybe_value.HasError()) {
@@ -2865,6 +2888,11 @@ RemoveLabels::RemoveLabelsCursor::RemoveLabelsCursor(const RemoveLabels &self, u
 bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &context) {
   SCOPED_PROFILE_OP("RemoveLabels");
 
+  if (context.auth_checker &&
+      !context.auth_checker->Has(self_.labels_, memgraph::query::AuthQuery::FineGrainedPrivilege::CREATE_DELETE)) {
+    throw QueryRuntimeException("Couldn't remove label due to not having enough permission!");
+  }
+
   if (!input_cursor_->Pull(frame, context)) return false;
 
   TypedValue &vertex_value = frame[self_.input_symbol_];
@@ -2872,6 +2900,11 @@ bool RemoveLabels::RemoveLabelsCursor::Pull(Frame &frame, ExecutionContext &cont
   if (vertex_value.IsNull()) return true;
   ExpectType(self_.input_symbol_, vertex_value, TypedValue::Type::Vertex);
   auto &vertex = vertex_value.ValueVertex();
+  if (context.auth_checker && !context.auth_checker->Has(vertex, storage::View::OLD,
+                                                         memgraph::query::AuthQuery::FineGrainedPrivilege::UPDATE)) {
+    throw QueryRuntimeException("Couldn't remove label due to not having enough permission!");
+  }
+
   for (auto label : self_.labels_) {
     auto maybe_value = vertex.RemoveLabel(label);
     if (maybe_value.HasError()) {
diff --git a/tests/e2e/fine_grained_access/create_delete_filtering_tests.py b/tests/e2e/fine_grained_access/create_delete_filtering_tests.py
index 3e0e5118e..1eb607715 100644
--- a/tests/e2e/fine_grained_access/create_delete_filtering_tests.py
+++ b/tests/e2e/fine_grained_access/create_delete_filtering_tests.py
@@ -470,5 +470,48 @@ def test_merge_edge_second_node_label_granted():
         )
 
 
+def test_set_label_when_label_granted():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connection = common.connect(username="user", password="test")
+    common.reset_and_prepare(admin_connection.cursor())
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :update_label_2 TO user;")
+
+    common.execute_and_fetch_all(user_connection.cursor(), "MATCH (p:test_delete) SET p:update_label_2;")
+
+
+def test_set_label_when_label_denied():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connection = common.connect(username="user", password="test")
+
+    common.reset_and_prepare(admin_connection.cursor())
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY CREATE_DELETE ON LABELS :update_label_2 TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :test_delete TO user;")
+
+    with pytest.raises(DatabaseError):
+        common.execute_and_fetch_all(user_connection.cursor(), "MATCH (p:test_delete) SET p:update_label_2;")
+
+
+def test_remove_label_when_label_granted():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connection = common.connect(username="user", password="test")
+
+    common.reset_and_prepare(admin_connection.cursor())
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT CREATE_DELETE ON LABELS :test_delete TO user;")
+
+    common.execute_and_fetch_all(user_connection.cursor(), "MATCH (p:test_delete) REMOVE p:test_delete;")
+
+
+def test_remove_label_when_label_denied():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connection = common.connect(username="user", password="test")
+
+    common.reset_and_prepare(admin_connection.cursor())
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY CREATE_DELETE ON LABELS :update_label_2 TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS :test_delete TO user;")
+
+    with pytest.raises(DatabaseError):
+        common.execute_and_fetch_all(user_connection.cursor(), "MATCH (p:test_delete) REMOVE p:test_delete;")
+
+
 if __name__ == "__main__":
     sys.exit(pytest.main([__file__, "-rA"]))
diff --git a/tests/e2e/fine_grained_access/path_filtering_tests.py b/tests/e2e/fine_grained_access/path_filtering_tests.py
index 5881537bd..311168408 100644
--- a/tests/e2e/fine_grained_access/path_filtering_tests.py
+++ b/tests/e2e/fine_grained_access/path_filtering_tests.py
@@ -525,5 +525,193 @@ def test_bfs_single_source_denied_edge_type_3():
     assert source_destination_path[0][0] == expected_path
 
 
+def test_all_shortest_paths_when_all_edge_types_all_labels_granted():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
+
+    total_paths_results = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n)-[r *allShortest (r, n | r.weight)]->(m) RETURN extract( node in nodes(p) | node.id);",
+    )
+    path_result = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n:label0)-[r *allShortest (r, n | r.weight) path_length]->(m:label4) RETURN path_length,nodes(p);",
+    )
+
+    expected_path = [0, 1, 3, 4, 5]
+    expected_all_paths = [
+        [0, 1],
+        [0, 1, 2],
+        [0, 1, 3],
+        [0, 1, 3, 4],
+        [0, 1, 3, 4, 5],
+        [1, 2],
+        [1, 3],
+        [1, 3, 4],
+        [1, 3, 4, 5],
+        [2, 1],
+        [2, 3],
+        [2, 3, 4],
+        [2, 3, 4, 5],
+        [3, 4],
+        [3, 4, 5],
+        [4, 3],
+        [4, 5],
+    ]
+
+    assert len(total_paths_results) == 16
+    assert all(path[0] in expected_all_paths for path in total_paths_results)
+    assert path_result[0][0] == 20
+    assert all(node.id in expected_path for node in path_result[0][1])
+
+
+def test_all_shortest_paths_when_all_edge_types_all_labels_denied():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON LABELS * TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON EDGE_TYPES * TO user;")
+
+    results = common.execute_and_fetch_all(
+        user_connnection.cursor(), "MATCH p=(n)-[r *allShortest (r, n | r.weight)]->(m) RETURN p;"
+    )
+
+    assert len(results) == 0
+
+
+def test_all_shortest_paths_when_denied_start():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(
+        admin_connection.cursor(), "GRANT READ ON LABELS :label1, :label2, :label3, :label4 TO user;"
+    )
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON LABELS :label0 TO user;")
+
+    path_length_result = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n:label0)-[r *allShortest (r, n | r.weight) path_length]->(m:label4) RETURN path_length;",
+    )
+
+    assert len(path_length_result) == 0
+
+
+def test_all_shortest_paths_when_denied_destination():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(
+        admin_connection.cursor(), "GRANT READ ON LABELS :label0, :label1, :label2, :label3 TO user;"
+    )
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON LABELS :label4 TO user;")
+
+    path_length_result = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n:label0)-[r *allShortest (r, n | r.weight) path_length]->(m:label4) RETURN path_length;",
+    )
+
+    assert len(path_length_result) == 0
+
+
+def test_all_shortest_paths_when_denied_label_1():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(
+        admin_connection.cursor(), "GRANT READ ON LABELS :label0, :label2, :label3, :label4 TO user;"
+    )
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON LABELS :label1 TO user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON EDGE_TYPES * TO user;")
+
+    total_paths_results = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n)-[r *allShortest (r, n | r.weight)]->(m) RETURN extract( node in nodes(p) | node.id);",
+    )
+
+    path_result = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n:label0)-[r *allShortest (r, n | r.weight) path_length]->(m:label4) RETURN path_length, nodes(p);",
+    )
+
+    expected_path = [0, 2, 3, 4, 5]
+
+    expected_all_paths = [
+        [0, 2],
+        [0, 2, 3],
+        [0, 2, 3, 4],
+        [0, 2, 3, 4, 5],
+        [2, 3],
+        [2, 3, 4],
+        [2, 3, 4, 5],
+        [3, 4],
+        [3, 4, 5],
+        [4, 3],
+        [4, 5],
+    ]
+
+    assert len(total_paths_results) == 11
+    assert all(path[0] in expected_all_paths for path in total_paths_results)
+    assert path_result[0][0] == 30
+    assert all(node.id in expected_path for node in path_result[0][1])
+
+
+def test_all_shortest_paths_when_denied_edge_type_3():
+    admin_connection = common.connect(username="admin", password="test")
+    user_connnection = common.connect(username="user", password="test")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE LABELS * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "REVOKE EDGE_TYPES * FROM user;")
+    common.execute_and_fetch_all(admin_connection.cursor(), "GRANT READ ON LABELS * TO user;")
+    common.execute_and_fetch_all(
+        admin_connection.cursor(), "GRANT READ ON EDGE_TYPES :edge_type_1, :edge_type_2, :edge_type_4 TO user;"
+    )
+    common.execute_and_fetch_all(admin_connection.cursor(), "DENY READ ON EDGE_TYPES :edge_type_3 TO user;")
+
+    path_result = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n:label0)-[r *allShortest (r, n | r.weight) path_length]->(m:label4) RETURN path_length, nodes(p);",
+    )
+
+    total_paths_results = common.execute_and_fetch_all(
+        user_connnection.cursor(),
+        "MATCH p=(n)-[r *allShortest (r, n | r.weight)]->(m) RETURN extract( node in nodes(p) | node.id);",
+    )
+
+    expected_path = [0, 1, 2, 3, 5]
+    expected_all_paths = [
+        [0, 1],
+        [0, 1, 2],
+        [0, 1, 2, 4],
+        [0, 1, 2, 4, 3],
+        [0, 1, 2, 4, 5],
+        [1, 2, 4, 3],
+        [1, 2],
+        [1, 2, 4],
+        [1, 2, 4, 5],
+        [2, 1],
+        [2, 4, 3],
+        [2, 4],
+        [2, 4, 5],
+        [3, 4],
+        [3, 4, 5],
+        [4, 3],
+        [4, 5],
+    ]
+
+    assert len(total_paths_results) == 16
+    assert all(path[0] in expected_all_paths for path in total_paths_results)
+    assert path_result[0][0] == 25
+    assert all(node.id in expected_path for node in path_result[0][1])
+
+
 if __name__ == "__main__":
     sys.exit(pytest.main([__file__, "-rA"]))
diff --git a/tests/unit/query_plan_create_set_remove_delete.cpp b/tests/unit/query_plan_create_set_remove_delete.cpp
index f423aa1f6..72cff71f8 100644
--- a/tests/unit/query_plan_create_set_remove_delete.cpp
+++ b/tests/unit/query_plan_create_set_remove_delete.cpp
@@ -1242,6 +1242,80 @@ TEST(QueryPlan, SetLabels) {
   }
 }
 
+TEST(QueryPlan, SetLabelsWithFineGrained) {
+  auto set_labels = [&](memgraph::auth::User user, memgraph::query::DbAccessor dba,
+                        std::vector<memgraph::storage::LabelId> labels) {
+    ASSERT_TRUE(dba.InsertVertex().AddLabel(labels[0]).HasValue());
+    ASSERT_TRUE(dba.InsertVertex().AddLabel(labels[0]).HasValue());
+    dba.AdvanceCommand();
+
+    AstStorage storage;
+    SymbolTable symbol_table;
+
+    auto n = MakeScanAll(storage, symbol_table, "n");
+    auto label_set =
+        std::make_shared<plan::SetLabels>(n.op_, n.sym_, std::vector<memgraph::storage::LabelId>{labels[1], labels[2]});
+    memgraph::glue::FineGrainedAuthChecker auth_checker{user, &dba};
+    auto context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
+
+    PullAll(*label_set, &context);
+  };
+
+  // All labels granted
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("*",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    set_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3});
+    for (auto vertex : dba.Vertices(memgraph::storage::View::OLD)) {
+      EXPECT_EQ(3, vertex.Labels(memgraph::storage::View::NEW)->size());
+      EXPECT_TRUE(*vertex.HasLabel(memgraph::storage::View::NEW, label2));
+      EXPECT_TRUE(*vertex.HasLabel(memgraph::storage::View::NEW, label3));
+    }
+  }
+
+  // All labels denied
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Deny("*",
+                                                                memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    ASSERT_THROW(set_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3}),
+                 QueryRuntimeException);
+  }
+
+  // label2 denied
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("label1",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    user.fine_grained_access_handler().label_permissions().Deny("label2",
+                                                                memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    user.fine_grained_access_handler().label_permissions().Grant("label3",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    ASSERT_THROW(set_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3}),
+                 QueryRuntimeException);
+  }
+}
+
 TEST(QueryPlan, RemoveProperty) {
   memgraph::storage::Storage db;
   auto storage_dba = db.Access();
@@ -1339,6 +1413,86 @@ TEST(QueryPlan, RemoveLabels) {
   }
 }
 
+TEST(QueryPlan, RemoveLabelsFineGrainedFiltering) {
+  auto remove_labels = [&](memgraph::auth::User user, memgraph::query::DbAccessor dba,
+                           std::vector<memgraph::storage::LabelId> labels) {
+    auto v1 = dba.InsertVertex();
+    ASSERT_TRUE(v1.AddLabel(labels[0]).HasValue());
+    ASSERT_TRUE(v1.AddLabel(labels[1]).HasValue());
+    ASSERT_TRUE(v1.AddLabel(labels[2]).HasValue());
+    auto v2 = dba.InsertVertex();
+    ASSERT_TRUE(v2.AddLabel(labels[0]).HasValue());
+    ASSERT_TRUE(v2.AddLabel(labels[2]).HasValue());
+    dba.AdvanceCommand();
+
+    AstStorage storage;
+    SymbolTable symbol_table;
+
+    auto n = MakeScanAll(storage, symbol_table, "n");
+    auto label_remove = std::make_shared<plan::RemoveLabels>(
+        n.op_, n.sym_, std::vector<memgraph::storage::LabelId>{labels[0], labels[1]});
+    memgraph::glue::FineGrainedAuthChecker auth_checker{user, &dba};
+
+    auto context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
+
+    PullAll(*label_remove, &context);
+  };
+
+  // All labels granted
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("*",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    remove_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3});
+    for (auto vertex : dba.Vertices(memgraph::storage::View::OLD)) {
+      EXPECT_EQ(1, vertex.Labels(memgraph::storage::View::NEW)->size());
+      EXPECT_FALSE(*vertex.HasLabel(memgraph::storage::View::NEW, label2));
+      EXPECT_TRUE(*vertex.HasLabel(memgraph::storage::View::NEW, label3));
+    }
+  }
+
+  // All labels denied
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Deny("*",
+                                                                memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    ASSERT_THROW(remove_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3}),
+                 QueryRuntimeException);
+  }
+
+  // label2 denied
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("label1",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    user.fine_grained_access_handler().label_permissions().Deny("label2",
+                                                                memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+    user.fine_grained_access_handler().label_permissions().Grant("label3",
+                                                                 memgraph::auth::FineGrainedPermission::CREATE_DELETE);
+
+    memgraph::storage::Storage db;
+    auto storage_dba = db.Access();
+    memgraph::query::DbAccessor dba(&storage_dba);
+    auto label1 = dba.NameToLabel("label1");
+    auto label2 = dba.NameToLabel("label2");
+    auto label3 = dba.NameToLabel("label3");
+    ASSERT_THROW(remove_labels(user, dba, std::vector<memgraph::storage::LabelId>{label1, label2, label3}),
+                 QueryRuntimeException);
+  }
+}
+
 TEST(QueryPlan, NodeFilterSet) {
   memgraph::storage::Storage db;
   auto storage_dba = db.Access();
diff --git a/tests/unit/query_plan_match_filter_return.cpp b/tests/unit/query_plan_match_filter_return.cpp
index ece795e2c..9a6c48b9c 100644
--- a/tests/unit/query_plan_match_filter_return.cpp
+++ b/tests/unit/query_plan_match_filter_return.cpp
@@ -2030,6 +2030,106 @@ TEST_F(QueryPlanExpandWeightedShortestPath, NegativeUpperBound) {
   EXPECT_THROW(ExpandWShortest(EdgeAtom::Direction::BOTH, -1, LITERAL(true)), QueryRuntimeException);
 }
 
+TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
+  // All edge_types and labels allowed
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    EXPECT_EQ(results[0].path.size(), 1);
+    EXPECT_EQ(GetDoubleProp(results[0].path[0]), 3);
+    EXPECT_EQ(results[0].total_weight, 3);
+
+    EXPECT_EQ(results[1].path.size(), 1);
+    EXPECT_EQ(GetDoubleProp(results[1].path[0]), 5);
+    EXPECT_EQ(results[1].total_weight, 5);
+
+    EXPECT_EQ(results[2].path.size(), 2);
+    EXPECT_EQ(GetDoubleProp(results[2].path[0]), 3);
+    EXPECT_EQ(GetDoubleProp(results[2].path[1]), 3);
+    EXPECT_EQ(results[2].total_weight, 6);
+
+    EXPECT_EQ(results[3].path.size(), 3);
+    EXPECT_EQ(GetDoubleProp(results[3].path[0]), 3);
+    EXPECT_EQ(GetDoubleProp(results[3].path[1]), 3);
+    EXPECT_EQ(GetDoubleProp(results[3].path[2]), 3);
+    EXPECT_EQ(results[3].total_weight, 9);
+  }
+
+  // Denied all labels
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Deny("*", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(results.size(), 0);
+  }
+
+  // Denied all edge types
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Deny("*", memgraph::auth::FineGrainedPermission::READ);
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(results.size(), 0);
+  }
+
+  // Denied first vertex label
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Deny("l0", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(results.size(), 0);
+  }
+
+  // Denied vertex label 2
+  {
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("l0", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().label_permissions().Grant("l1", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().label_permissions().Grant("l2", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().label_permissions().Grant("l3", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().label_permissions().Grant("l4", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(results.size(), 4);
+
+    user.fine_grained_access_handler().label_permissions().Deny("l2", memgraph::auth::FineGrainedPermission::READ);
+    auto filtered_results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(filtered_results.size(), 3);
+  }
+
+  // Deny edge type (created vertex 5 and edge vertex 4 to vertex 5)
+  {
+    v.push_back(dba.InsertVertex());
+    ASSERT_TRUE(v.back().SetProperty(prop.second, memgraph::storage::PropertyValue(5)).HasValue());
+    ASSERT_TRUE(v.back().AddLabel(db.NameToLabel("l5")).HasValue());
+    dba.AdvanceCommand();
+    memgraph::storage::EdgeTypeId edge_type_filter = dba.NameToEdgeType("edge_type_filter");
+    auto edge = dba.InsertEdge(&v[4], &v[5], edge_type_filter);
+    ASSERT_TRUE(edge->SetProperty(prop.second, memgraph::storage::PropertyValue(1)).HasValue());
+    e.emplace(std::make_pair(4, 5), *edge);
+    dba.AdvanceCommand();
+
+    memgraph::auth::User user{"test"};
+    user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(results.size(), 5);
+
+    user.fine_grained_access_handler().edge_type_permissions().Grant("edge_type",
+                                                                     memgraph::auth::FineGrainedPermission::READ);
+    user.fine_grained_access_handler().edge_type_permissions().Deny("edge_type_filter",
+                                                                    memgraph::auth::FineGrainedPermission::READ);
+    auto filtered_results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    ASSERT_EQ(filtered_results.size(), 4);
+  }
+}
+
 /** A test fixture for all shortest paths expansion */
 class QueryPlanExpandAllShortestPaths : public testing::Test {
  public:
@@ -2069,6 +2169,8 @@ class QueryPlanExpandAllShortestPaths : public testing::Test {
     for (int i = 0; i < 5; i++) {
       v.push_back(dba.InsertVertex());
       ASSERT_TRUE(v.back().SetProperty(prop.second, memgraph::storage::PropertyValue(i)).HasValue());
+      auto label = fmt::format("l{}", i);
+      ASSERT_TRUE(v.back().AddLabel(db.NameToLabel(label)).HasValue());
     }
 
     auto add_edge = [&](int from, int to, double weight) {
@@ -2091,7 +2193,8 @@ class QueryPlanExpandAllShortestPaths : public testing::Test {
   // params returns a vector of pairs. each pair is (vector-of-edges,
   // vertex)
   auto ExpandAllShortest(EdgeAtom::Direction direction, std::optional<int> max_depth, Expression *where,
-                         std::optional<int> node_id = 0, ScanAllTuple *existing_node_input = nullptr) {
+                         std::optional<int> node_id = 0, ScanAllTuple *existing_node_input = nullptr,
+                         const memgraph::auth::User *user = nullptr) {
     // scan the nodes optionally filtering on property value
     auto n = MakeScanAll(storage, symbol_table, "n", existing_node_input ? existing_node_input->op_ : nullptr);
     auto last_op = n.op_;
@@ -2114,7 +2217,13 @@ class QueryPlanExpandAllShortestPaths : public testing::Test {
     Frame frame(symbol_table.max_position());
     auto cursor = last_op->MakeCursor(memgraph::utils::NewDeleteResource());
     std::vector<ResultType> results;
-    auto context = MakeContext(storage, symbol_table, &dba);
+    ExecutionContext context;
+    if (user) {
+      memgraph::glue::FineGrainedAuthChecker auth_checker{*user, &dba};
+      context = MakeContextWithFineGrainedChecker(storage, symbol_table, &dba, &auth_checker);
+    } else {
+      context = MakeContext(storage, symbol_table, &dba);
+    }
     while (cursor->Pull(frame, context)) {
       results.push_back(ResultType{std::vector<memgraph::query::EdgeAccessor>(), frame[node_sym].ValueVertex(),
                                    frame[total_weight].ValueDouble()});
@@ -2383,48 +2492,27 @@ TEST_F(QueryPlanExpandAllShortestPaths, MultiEdge) {
   EXPECT_EQ(results[5].total_weight, 9);
 }
 
-TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
+TEST_F(QueryPlanExpandAllShortestPaths, BasicWithFineGrainedFiltering) {
   // All edge_types and labels allowed
   {
     memgraph::auth::User user{"test"};
     user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true));
+    sort(results.begin(), results.end(), compareResultType);
+
     EXPECT_EQ(results[0].path.size(), 1);
-    EXPECT_EQ(GetDoubleProp(results[0].path[0]), 3);
-    EXPECT_EQ(results[0].total_weight, 3);
-
     EXPECT_EQ(results[1].path.size(), 1);
-    EXPECT_EQ(GetDoubleProp(results[1].path[0]), 5);
-    EXPECT_EQ(results[1].total_weight, 5);
-
     EXPECT_EQ(results[2].path.size(), 2);
-    EXPECT_EQ(GetDoubleProp(results[2].path[0]), 3);
-    EXPECT_EQ(GetDoubleProp(results[2].path[1]), 3);
-    EXPECT_EQ(results[2].total_weight, 6);
 
-    EXPECT_EQ(results[3].path.size(), 3);
-    EXPECT_EQ(GetDoubleProp(results[3].path[0]), 3);
-    EXPECT_EQ(GetDoubleProp(results[3].path[1]), 3);
     EXPECT_EQ(GetDoubleProp(results[3].path[2]), 3);
-    EXPECT_EQ(results[3].total_weight, 9);
   }
-
   // Denied all labels
-  {
-    memgraph::auth::User user{"test"};
-    user.fine_grained_access_handler().label_permissions().Deny("*", memgraph::auth::FineGrainedPermission::READ);
-    user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
-    ASSERT_EQ(results.size(), 0);
-  }
-
-  // Denied all edge types
   {
     memgraph::auth::User user{"test"};
     user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Deny("*", memgraph::auth::FineGrainedPermission::READ);
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
     ASSERT_EQ(results.size(), 0);
   }
 
@@ -2433,8 +2521,8 @@ TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
     memgraph::auth::User user{"test"};
     user.fine_grained_access_handler().label_permissions().Deny("l0", memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
+    auto results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
 
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
     ASSERT_EQ(results.size(), 0);
   }
 
@@ -2448,11 +2536,11 @@ TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
     user.fine_grained_access_handler().label_permissions().Grant("l4", memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
 
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
     ASSERT_EQ(results.size(), 4);
-
     user.fine_grained_access_handler().label_permissions().Deny("l2", memgraph::auth::FineGrainedPermission::READ);
-    auto filtered_results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto filtered_results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+
     ASSERT_EQ(filtered_results.size(), 3);
   }
 
@@ -2471,14 +2559,15 @@ TEST_F(QueryPlanExpandWeightedShortestPath, FineGrainedFiltering) {
     memgraph::auth::User user{"test"};
     user.fine_grained_access_handler().label_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Grant("*", memgraph::auth::FineGrainedPermission::READ);
-    auto results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
     ASSERT_EQ(results.size(), 5);
 
     user.fine_grained_access_handler().edge_type_permissions().Grant("edge_type",
                                                                      memgraph::auth::FineGrainedPermission::READ);
     user.fine_grained_access_handler().edge_type_permissions().Deny("edge_type_filter",
                                                                     memgraph::auth::FineGrainedPermission::READ);
-    auto filtered_results = ExpandWShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+    auto filtered_results = ExpandAllShortest(EdgeAtom::Direction::BOTH, 1000, LITERAL(true), 0, nullptr, &user);
+
     ASSERT_EQ(filtered_results.size(), 4);
   }
 }