We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Security: Stabalize the MongoDB serializer
### Describe the bug

This is the upstream bug report for SUSE/spacewalk#16737 which is a mirror issue of an internal Bugzilla issue.

Copied from the Bugzilla comment by @thesp0nge:

In mongodb serializer class, when the config file is read, there is no sanity check.
If the file get somewhat corrupted, it can lead to unexpected behaviour.

```python
def __connect(configfile: str = "/etc/cobbler/mongodb.conf"):
    """
    Reads the config file for mongodb and then connects to the mongodb.
    """
    cp = ConfigParser()
    cp.read(configfile)

    host = cp.get("connection", "host")
    port = int(cp.get("connection", "port"))
    # pylint: disable=global-statement
    global mongodb
    mongodb = MongoClient(host, port)['cobbler']
```

### Steps to reproduce

1. Corrupt the `mongodb.conf`
2. Start Cobbler
3. See error

### Expected behavior

We get a better exception and Cobbler is prevented from starting up.

### Cobbler version

<!--- Paste output from `cobbler version` -->
````paste below
````

### Operating system

<!--- On which operating system do you use Cobbler? -->

### Cobbler log

<!--- Paste (partial) output from `/var/log/cobbler/cobbler.log` -->
````paste below
````

### Screenshots

<!--- If applicable, add screenshots to help explain your problem. -->

### Additional information

<!--- Add any other context about the problem here. -->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cobbler/modules/serializers/mongodb.py`
Content:
```
1 """
2 Cobbler's Mongo database based object serializer.
3 Experimental version.
4 
5 Copyright 2006-2009, Red Hat, Inc and Others
6 Michael DeHaan <michael.dehaan AT gmail>
7 James Cammarata <jimi@sngx.net>
8 
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 02110-1301  USA
23 """
24 
25 from configparser import ConfigParser
26 
27 from cobbler import settings
28 from cobbler.cexceptions import CX
29 
30 try:
31     from pymongo import MongoClient
32     from pymongo.errors import ConnectionFailure, ConfigurationError
33     pymongo_loaded = True
34 except ModuleNotFoundError:
35     # FIXME: log message
36     pymongo_loaded = False
37 
38 mongodb = None
39 
40 
41 def __connect(configfile: str = "/etc/cobbler/mongodb.conf"):
42     """
43     Reads the config file for mongodb and then connects to the mongodb.
44     """
45     cp = ConfigParser()
46     cp.read(configfile)
47 
48     host = cp.get("connection", "host")
49     port = int(cp.get("connection", "port"))
50     # pylint: disable=global-statement
51     global mongodb
52     mongodb = MongoClient(host, port)['cobbler']
53     try:
54         # The ismaster command is cheap and doesn't require auth.
55         mongodb.admin.command('ismaster')
56     except ConnectionFailure as e:
57         # FIXME: log error
58         raise CX("Unable to connect to Mongo database or get database \"cobbler\"") from e
59     except ConfigurationError as e:
60         raise CX("The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.") from e
61 
62 
63 def register() -> str:
64     """
65     The mandatory Cobbler module registration hook.
66     """
67     # FIXME: only run this if enabled.
68     if not pymongo_loaded:
69         return ""
70     return "serializer"
71 
72 
73 def what() -> str:
74     """
75     Module identification function
76     """
77     return "serializer/mongodb"
78 
79 
80 def serialize_item(collection, item):
81     """
82     Save a collection item to database.
83 
84     :param collection: collection
85     :param item: collection item
86     """
87 
88     __connect()
89     collection = mongodb[collection.collection_type()]
90     data = collection.find_one({'name': item.name})
91     if data:
92         collection.update({'name': item.name}, item.serialize())
93     else:
94         collection.insert(item.serialize())
95 
96 
97 def serialize_delete(collection, item):
98     """
99     Delete a collection item from database.
100 
101     :param collection: collection
102     :param item: collection item
103     """
104 
105     __connect()
106     collection = mongodb[collection.collection_type()]
107     collection.remove({'name': item.name})
108 
109 
110 def serialize(collection):
111     """
112     Save a collection to database
113 
114     :param collection: collection
115     """
116 
117     # TODO: error detection
118     ctype = collection.collection_type()
119     if ctype != "settings":
120         for x in collection:
121             serialize_item(collection, x)
122 
123 
124 def deserialize_raw(collection_type: str):
125     """
126     Get a collection from mongodb and parse it into an object.
127 
128     :param collection_type: The collection type to fetch.
129     :return: The first element of the collection requested.
130     """
131     if collection_type == "settings":
132         return settings.read_settings_file()
133     else:
134         __connect()
135         collection = mongodb[collection_type]
136         return collection.find()
137 
138 
139 def deserialize(collection, topological: bool = True):
140     """
141     Load a collection from the database.
142 
143     :param collection: The collection to deserialize.
144     :param topological: If the collection list should be sorted by the collection dict depth value or not.
145     """
146 
147     datastruct = deserialize_raw(collection.collection_type())
148     if topological and type(datastruct) == list:
149         datastruct.sort(key=lambda x: x["depth"])
150     if type(datastruct) == dict:
151         collection.from_dict(datastruct)
152     elif type(datastruct) == list:
153         collection.from_list(datastruct)
154
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/cobbler/modules/serializers/mongodb.py b/cobbler/modules/serializers/mongodb.py
--- a/cobbler/modules/serializers/mongodb.py
+++ b/cobbler/modules/serializers/mongodb.py
@@ -21,7 +21,8 @@
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 02110-1301  USA
 """
-
+import configparser
+import pathlib
 from configparser import ConfigParser
 
 from cobbler import settings
@@ -30,6 +31,7 @@
 try:
     from pymongo import MongoClient
     from pymongo.errors import ConnectionFailure, ConfigurationError
+
     pymongo_loaded = True
 except ModuleNotFoundError:
     # FIXME: log message
@@ -42,22 +44,34 @@
     """
     Reads the config file for mongodb and then connects to the mongodb.
     """
-    cp = ConfigParser()
-    cp.read(configfile)
+    if not pathlib.Path(configfile).is_file():
+        raise FileNotFoundError(
+            "Specified Cobbler MongoDB config file could not be found!"
+        )
 
-    host = cp.get("connection", "host")
-    port = int(cp.get("connection", "port"))
+    cp = ConfigParser()
+    try:
+        cp.read(configfile)
+    except configparser.Error as cp_error:
+        raise configparser.Error(
+            "Could not read Cobbler MongoDB config file!"
+        ) from cp_error
+
+    host = cp.get("connection", "host", fallback="localhost")
+    port = cp.getint("connection", "port", fallback=27017)
     # pylint: disable=global-statement
     global mongodb
-    mongodb = MongoClient(host, port)['cobbler']
+    mongodb = MongoClient(host, port)["cobbler"]
     try:
         # The ismaster command is cheap and doesn't require auth.
-        mongodb.admin.command('ismaster')
+        mongodb.admin.command("ismaster")
     except ConnectionFailure as e:
         # FIXME: log error
-        raise CX("Unable to connect to Mongo database or get database \"cobbler\"") from e
+        raise CX('Unable to connect to Mongo database or get database "cobbler"') from e
     except ConfigurationError as e:
-        raise CX("The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.") from e
+        raise CX(
+            "The configuration of the MongoDB connection isn't correct, please check the Cobbler settings."
+        ) from e
 
 
 def register() -> str:
@@ -87,9 +101,9 @@
 
     __connect()
     collection = mongodb[collection.collection_type()]
-    data = collection.find_one({'name': item.name})
+    data = collection.find_one({"name": item.name})
     if data:
-        collection.update({'name': item.name}, item.serialize())
+        collection.update({"name": item.name}, item.serialize())
     else:
         collection.insert(item.serialize())
 
@@ -104,7 +118,7 @@
 
     __connect()
     collection = mongodb[collection.collection_type()]
-    collection.remove({'name': item.name})
+    collection.remove({"name": item.name})
 
 
 def serialize(collection):

{"golden_diff": "diff --git a/cobbler/modules/serializers/mongodb.py b/cobbler/modules/serializers/mongodb.py\n--- a/cobbler/modules/serializers/mongodb.py\n+++ b/cobbler/modules/serializers/mongodb.py\n@@ -21,7 +21,8 @@\n Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n 02110-1301  USA\n \"\"\"\n-\n+import configparser\n+import pathlib\n from configparser import ConfigParser\n \n from cobbler import settings\n@@ -30,6 +31,7 @@\n try:\n     from pymongo import MongoClient\n     from pymongo.errors import ConnectionFailure, ConfigurationError\n+\n     pymongo_loaded = True\n except ModuleNotFoundError:\n     # FIXME: log message\n@@ -42,22 +44,34 @@\n     \"\"\"\n     Reads the config file for mongodb and then connects to the mongodb.\n     \"\"\"\n-    cp = ConfigParser()\n-    cp.read(configfile)\n+    if not pathlib.Path(configfile).is_file():\n+        raise FileNotFoundError(\n+            \"Specified Cobbler MongoDB config file could not be found!\"\n+        )\n \n-    host = cp.get(\"connection\", \"host\")\n-    port = int(cp.get(\"connection\", \"port\"))\n+    cp = ConfigParser()\n+    try:\n+        cp.read(configfile)\n+    except configparser.Error as cp_error:\n+        raise configparser.Error(\n+            \"Could not read Cobbler MongoDB config file!\"\n+        ) from cp_error\n+\n+    host = cp.get(\"connection\", \"host\", fallback=\"localhost\")\n+    port = cp.getint(\"connection\", \"port\", fallback=27017)\n     # pylint: disable=global-statement\n     global mongodb\n-    mongodb = MongoClient(host, port)['cobbler']\n+    mongodb = MongoClient(host, port)[\"cobbler\"]\n     try:\n         # The ismaster command is cheap and doesn't require auth.\n-        mongodb.admin.command('ismaster')\n+        mongodb.admin.command(\"ismaster\")\n     except ConnectionFailure as e:\n         # FIXME: log error\n-        raise CX(\"Unable to connect to Mongo database or get database \\\"cobbler\\\"\") from e\n+        raise CX('Unable to connect to Mongo database or get database \"cobbler\"') from e\n     except ConfigurationError as e:\n-        raise CX(\"The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.\") from e\n+        raise CX(\n+            \"The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.\"\n+        ) from e\n \n \n def register() -> str:\n@@ -87,9 +101,9 @@\n \n     __connect()\n     collection = mongodb[collection.collection_type()]\n-    data = collection.find_one({'name': item.name})\n+    data = collection.find_one({\"name\": item.name})\n     if data:\n-        collection.update({'name': item.name}, item.serialize())\n+        collection.update({\"name\": item.name}, item.serialize())\n     else:\n         collection.insert(item.serialize())\n \n@@ -104,7 +118,7 @@\n \n     __connect()\n     collection = mongodb[collection.collection_type()]\n-    collection.remove({'name': item.name})\n+    collection.remove({\"name\": item.name})\n \n \n def serialize(collection):\n", "issue": "Security: Stabalize the MongoDB serializer\n### Describe the bug\r\n\r\nThis is the upstream bug report for SUSE/spacewalk#16737 which is a mirror issue of an internal Bugzilla issue.\r\n\r\nCopied from the Bugzilla comment by @thesp0nge:\r\n\r\nIn mongodb serializer class, when the config file is read, there is no sanity check.\r\nIf the file get somewhat corrupted, it can lead to unexpected behaviour.\r\n\r\n```python\r\ndef __connect(configfile: str = \"/etc/cobbler/mongodb.conf\"):\r\n    \"\"\"\r\n    Reads the config file for mongodb and then connects to the mongodb.\r\n    \"\"\"\r\n    cp = ConfigParser()\r\n    cp.read(configfile)\r\n\r\n    host = cp.get(\"connection\", \"host\")\r\n    port = int(cp.get(\"connection\", \"port\"))\r\n    # pylint: disable=global-statement\r\n    global mongodb\r\n    mongodb = MongoClient(host, port)['cobbler']\r\n```\r\n\r\n### Steps to reproduce\r\n\r\n1. Corrupt the `mongodb.conf`\r\n2. Start Cobbler\r\n3. See error\r\n\r\n### Expected behavior\r\n\r\nWe get a better exception and Cobbler is prevented from starting up.\r\n\r\n### Cobbler version\r\n\r\n<!--- Paste output from `cobbler version` -->\r\n````paste below\r\n````\r\n\r\n### Operating system\r\n\r\n<!--- On which operating system do you use Cobbler? -->\r\n\r\n### Cobbler log\r\n\r\n<!--- Paste (partial) output from `/var/log/cobbler/cobbler.log` -->\r\n````paste below\r\n````\r\n\r\n### Screenshots\r\n\r\n<!--- If applicable, add screenshots to help explain your problem. -->\r\n\r\n### Additional information\r\n\r\n<!--- Add any other context about the problem here. -->\r\n\n", "before_files": [{"content": "\"\"\"\nCobbler's Mongo database based object serializer.\nExperimental version.\n\nCopyright 2006-2009, Red Hat, Inc and Others\nMichael DeHaan <michael.dehaan AT gmail>\nJames Cammarata <jimi@sngx.net>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n02110-1301  USA\n\"\"\"\n\nfrom configparser import ConfigParser\n\nfrom cobbler import settings\nfrom cobbler.cexceptions import CX\n\ntry:\n    from pymongo import MongoClient\n    from pymongo.errors import ConnectionFailure, ConfigurationError\n    pymongo_loaded = True\nexcept ModuleNotFoundError:\n    # FIXME: log message\n    pymongo_loaded = False\n\nmongodb = None\n\n\ndef __connect(configfile: str = \"/etc/cobbler/mongodb.conf\"):\n    \"\"\"\n    Reads the config file for mongodb and then connects to the mongodb.\n    \"\"\"\n    cp = ConfigParser()\n    cp.read(configfile)\n\n    host = cp.get(\"connection\", \"host\")\n    port = int(cp.get(\"connection\", \"port\"))\n    # pylint: disable=global-statement\n    global mongodb\n    mongodb = MongoClient(host, port)['cobbler']\n    try:\n        # The ismaster command is cheap and doesn't require auth.\n        mongodb.admin.command('ismaster')\n    except ConnectionFailure as e:\n        # FIXME: log error\n        raise CX(\"Unable to connect to Mongo database or get database \\\"cobbler\\\"\") from e\n    except ConfigurationError as e:\n        raise CX(\"The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.\") from e\n\n\ndef register() -> str:\n    \"\"\"\n    The mandatory Cobbler module registration hook.\n    \"\"\"\n    # FIXME: only run this if enabled.\n    if not pymongo_loaded:\n        return \"\"\n    return \"serializer\"\n\n\ndef what() -> str:\n    \"\"\"\n    Module identification function\n    \"\"\"\n    return \"serializer/mongodb\"\n\n\ndef serialize_item(collection, item):\n    \"\"\"\n    Save a collection item to database.\n\n    :param collection: collection\n    :param item: collection item\n    \"\"\"\n\n    __connect()\n    collection = mongodb[collection.collection_type()]\n    data = collection.find_one({'name': item.name})\n    if data:\n        collection.update({'name': item.name}, item.serialize())\n    else:\n        collection.insert(item.serialize())\n\n\ndef serialize_delete(collection, item):\n    \"\"\"\n    Delete a collection item from database.\n\n    :param collection: collection\n    :param item: collection item\n    \"\"\"\n\n    __connect()\n    collection = mongodb[collection.collection_type()]\n    collection.remove({'name': item.name})\n\n\ndef serialize(collection):\n    \"\"\"\n    Save a collection to database\n\n    :param collection: collection\n    \"\"\"\n\n    # TODO: error detection\n    ctype = collection.collection_type()\n    if ctype != \"settings\":\n        for x in collection:\n            serialize_item(collection, x)\n\n\ndef deserialize_raw(collection_type: str):\n    \"\"\"\n    Get a collection from mongodb and parse it into an object.\n\n    :param collection_type: The collection type to fetch.\n    :return: The first element of the collection requested.\n    \"\"\"\n    if collection_type == \"settings\":\n        return settings.read_settings_file()\n    else:\n        __connect()\n        collection = mongodb[collection_type]\n        return collection.find()\n\n\ndef deserialize(collection, topological: bool = True):\n    \"\"\"\n    Load a collection from the database.\n\n    :param collection: The collection to deserialize.\n    :param topological: If the collection list should be sorted by the collection dict depth value or not.\n    \"\"\"\n\n    datastruct = deserialize_raw(collection.collection_type())\n    if topological and type(datastruct) == list:\n        datastruct.sort(key=lambda x: x[\"depth\"])\n    if type(datastruct) == dict:\n        collection.from_dict(datastruct)\n    elif type(datastruct) == list:\n        collection.from_list(datastruct)\n", "path": "cobbler/modules/serializers/mongodb.py"}], "after_files": [{"content": "\"\"\"\nCobbler's Mongo database based object serializer.\nExperimental version.\n\nCopyright 2006-2009, Red Hat, Inc and Others\nMichael DeHaan <michael.dehaan AT gmail>\nJames Cammarata <jimi@sngx.net>\n\nThis program is free software; you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation; either version 2 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n02110-1301  USA\n\"\"\"\nimport configparser\nimport pathlib\nfrom configparser import ConfigParser\n\nfrom cobbler import settings\nfrom cobbler.cexceptions import CX\n\ntry:\n    from pymongo import MongoClient\n    from pymongo.errors import ConnectionFailure, ConfigurationError\n\n    pymongo_loaded = True\nexcept ModuleNotFoundError:\n    # FIXME: log message\n    pymongo_loaded = False\n\nmongodb = None\n\n\ndef __connect(configfile: str = \"/etc/cobbler/mongodb.conf\"):\n    \"\"\"\n    Reads the config file for mongodb and then connects to the mongodb.\n    \"\"\"\n    if not pathlib.Path(configfile).is_file():\n        raise FileNotFoundError(\n            \"Specified Cobbler MongoDB config file could not be found!\"\n        )\n\n    cp = ConfigParser()\n    try:\n        cp.read(configfile)\n    except configparser.Error as cp_error:\n        raise configparser.Error(\n            \"Could not read Cobbler MongoDB config file!\"\n        ) from cp_error\n\n    host = cp.get(\"connection\", \"host\", fallback=\"localhost\")\n    port = cp.getint(\"connection\", \"port\", fallback=27017)\n    # pylint: disable=global-statement\n    global mongodb\n    mongodb = MongoClient(host, port)[\"cobbler\"]\n    try:\n        # The ismaster command is cheap and doesn't require auth.\n        mongodb.admin.command(\"ismaster\")\n    except ConnectionFailure as e:\n        # FIXME: log error\n        raise CX('Unable to connect to Mongo database or get database \"cobbler\"') from e\n    except ConfigurationError as e:\n        raise CX(\n            \"The configuration of the MongoDB connection isn't correct, please check the Cobbler settings.\"\n        ) from e\n\n\ndef register() -> str:\n    \"\"\"\n    The mandatory Cobbler module registration hook.\n    \"\"\"\n    # FIXME: only run this if enabled.\n    if not pymongo_loaded:\n        return \"\"\n    return \"serializer\"\n\n\ndef what() -> str:\n    \"\"\"\n    Module identification function\n    \"\"\"\n    return \"serializer/mongodb\"\n\n\ndef serialize_item(collection, item):\n    \"\"\"\n    Save a collection item to database.\n\n    :param collection: collection\n    :param item: collection item\n    \"\"\"\n\n    __connect()\n    collection = mongodb[collection.collection_type()]\n    data = collection.find_one({\"name\": item.name})\n    if data:\n        collection.update({\"name\": item.name}, item.serialize())\n    else:\n        collection.insert(item.serialize())\n\n\ndef serialize_delete(collection, item):\n    \"\"\"\n    Delete a collection item from database.\n\n    :param collection: collection\n    :param item: collection item\n    \"\"\"\n\n    __connect()\n    collection = mongodb[collection.collection_type()]\n    collection.remove({\"name\": item.name})\n\n\ndef serialize(collection):\n    \"\"\"\n    Save a collection to database\n\n    :param collection: collection\n    \"\"\"\n\n    # TODO: error detection\n    ctype = collection.collection_type()\n    if ctype != \"settings\":\n        for x in collection:\n            serialize_item(collection, x)\n\n\ndef deserialize_raw(collection_type: str):\n    \"\"\"\n    Get a collection from mongodb and parse it into an object.\n\n    :param collection_type: The collection type to fetch.\n    :return: The first element of the collection requested.\n    \"\"\"\n    if collection_type == \"settings\":\n        return settings.read_settings_file()\n    else:\n        __connect()\n        collection = mongodb[collection_type]\n        return collection.find()\n\n\ndef deserialize(collection, topological: bool = True):\n    \"\"\"\n    Load a collection from the database.\n\n    :param collection: The collection to deserialize.\n    :param topological: If the collection list should be sorted by the collection dict depth value or not.\n    \"\"\"\n\n    datastruct = deserialize_raw(collection.collection_type())\n    if topological and type(datastruct) == list:\n        datastruct.sort(key=lambda x: x[\"depth\"])\n    if type(datastruct) == dict:\n        collection.from_dict(datastruct)\n    elif type(datastruct) == list:\n        collection.from_list(datastruct)\n", "path": "cobbler/modules/serializers/mongodb.py"}]}