From 5eb706767c985a2edfea9852f934a10526e6f877 Mon Sep 17 00:00:00 2001
From: jrybicki-jsc <j.rybicki@fz-juelich.de>
Date: Tue, 8 Jun 2021 13:56:38 +0200
Subject: [PATCH] first steps against path traversal

---
 apiserver/storage/JsonFileStorageAdapter.py | 13 +++++++++----
 tests/apiserver_tests/test_put.py           | 12 ------------
 tests/storage_tests/test_jsonbackend.py     | 19 +++++++++++++++++++
 3 files changed, 28 insertions(+), 16 deletions(-)
 delete mode 100644 tests/apiserver_tests/test_put.py

diff --git a/apiserver/storage/JsonFileStorageAdapter.py b/apiserver/storage/JsonFileStorageAdapter.py
index bdae20d..4510694 100644
--- a/apiserver/storage/JsonFileStorageAdapter.py
+++ b/apiserver/storage/JsonFileStorageAdapter.py
@@ -50,11 +50,16 @@ class JsonFileStorageAdapter(AbstractLocationDataStorageAdapter):
 
     def __get_object_path(self, value: str, oid: str) -> str:
         localpath = os.path.join(self.data_dir, value)
-        fullpath = os.path.join(localpath, oid)
-        if not os.path.isfile(fullpath):
+        full_path = os.path.join(localpath, oid)
+        common = os.path.commonprefix((os.path.realpath(full_path),os.path.realpath(self.data_dir)))
+        if common != os.path.realpath(self.data_dir):
+            print(f"Escaping the data dir! {common} {full_path}")
+            raise FileNotFoundError()
+            
+        if not os.path.isfile(full_path):
             raise FileNotFoundError(
-                f"The requested object ({oid}) does not exist.")
-        return fullpath
+                f"The requested object ({oid}) {full_path} does not exist.")
+        return full_path
 
     def get_list(self, n_type: LocationDataType) -> List:
         local_path = self.__setup_path(n_type.value)
diff --git a/tests/apiserver_tests/test_put.py b/tests/apiserver_tests/test_put.py
deleted file mode 100644
index 3c435a8..0000000
--- a/tests/apiserver_tests/test_put.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# These Tests check if the PUT calls work as intended, checking both valid puts and invalid puts
-
-from fastapi.testclient import TestClient
-
-from context import apiserver
-from context import storage
-
-client = TestClient(apiserver.app)
-
-# PUT a new dataset, store the id in global variable, verify via a GET if it worked
-
-# PUT an invalid type (i.e. a type not in the enum)
diff --git a/tests/storage_tests/test_jsonbackend.py b/tests/storage_tests/test_jsonbackend.py
index 5dada28..f977080 100644
--- a/tests/storage_tests/test_jsonbackend.py
+++ b/tests/storage_tests/test_jsonbackend.py
@@ -6,6 +6,7 @@ from collections import namedtuple
 import os
 import pathlib
 import shutil
+import json
 
 
 class SomeTests(unittest.TestCase):
@@ -81,3 +82,21 @@ class SomeTests(unittest.TestCase):
                                               data=new_data, usr='tst2')
         self.assertEqual(new_data, r)
         self.assertEqual(oid, oid2)
+
+
+    def test_path_traversal(self):
+        l_data = LocationData(name='test1', url='http://n.go', metadata=[])
+
+        with open('/tmp/hackme', 'w+') as f:
+            json.dump({'secret': 'data', 'users': [], 'actualData': {'name': 'some', 'url': 'oo'}}, f)
+
+        (oid, data) = self.store.add_new(n_type=LocationDataType.DATASET, data=l_data, user_name='test_user')
+        details = None
+        try: 
+            details = self.store.get_details(n_type=LocationDataType.DATASET, oid='../../../tmp/hackme')
+        except:
+            pass 
+        print(details)
+        self.assertIsNone(details)
+
+
-- 
GitLab