diff --git a/README.md b/README.md index 0b1925c..504e00c 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ This is an application that makes B2RI production ready. To go to the original B * Parameters are sanitized * Users can manage what entry types want their beacon to show by editing a manage conf file inside source +### TLS configuration + +To enable TLS for the Becaon API set `beacon_server_crt` and `beacon_server_key` to the full paht of the server certificate and server key in `beacon/conf/conf.py` file. + +#### TLS secured MongoDB + +Edit the file `beacon/connections/mongo/conf.py` and set `database_certificate` to the full path to the client certificate. If a private CA is used also set the `database_cafile` to the full path to the CA certificate. + +* The MongoDB client certificate should be in the combined PEM format `client.key + "\n" + client.crt` ## Prerequisites diff --git a/beacon/__main__.py b/beacon/__main__.py index 99cf490..c9d3748 100644 --- a/beacon/__main__.py +++ b/beacon/__main__.py @@ -18,6 +18,7 @@ from aiohttp_cors import CorsViewMixin from datetime import datetime from beacon.conf import conf +import ssl class EndpointView(web.View, CorsViewMixin): def __init__(self, request: Request): @@ -410,10 +411,15 @@ async def create_api():# pragma: no cover cors.add(web.options('/api/g_variants', Resultset), cors_dict) ''' + ssl_context = None + if (os.path.isfile(conf.beacon_server_key)) and (os.path.isfile(conf.beacon_server_crt)): + ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_context.load_cert_chain(certfile=conf.beacon_server_crt, keyfile=conf.beacon_server_key) + print("Starting app") runner = web.AppRunner(app) await runner.setup() - site = web.TCPSite(runner, '0.0.0.0', 5050) + site = web.TCPSite(runner, '0.0.0.0', 5050, ssl_context=ssl_context) await site.start() while True: diff --git a/beacon/conf/conf.py b/beacon/conf/conf.py index caca479..2bdd330 100644 --- a/beacon/conf/conf.py +++ b/beacon/conf/conf.py @@ -49,4 +49,7 @@ org_welcome_url = 'https://ega-archive.org/' org_contact_url = 'mailto:beacon.ega@crg.eu' org_logo_url = 'https://legacy.ega-archive.org/images/logo.png' -org_info = '' \ No newline at end of file +org_info = '' + +beacon_server_crt = '' +beacon_server_key = '' \ No newline at end of file diff --git a/beacon/connections/mongo/__init__.py b/beacon/connections/mongo/__init__.py index 7c30532..6f4a8dc 100644 --- a/beacon/connections/mongo/__init__.py +++ b/beacon/connections/mongo/__init__.py @@ -1,11 +1,19 @@ from pymongo.mongo_client import MongoClient from beacon.connections.mongo import conf +import os -client = MongoClient("mongodb://{}:{}@{}:{}/{}?authSource={}".format( +uri = "mongodb://{}:{}@{}:{}/{}?authSource={}".format( conf.database_user, conf.database_password, conf.database_host, conf.database_port, conf.database_name, conf.database_auth_source -)) \ No newline at end of file +) + +if os.path.isfile(conf.database_certificate): + uri += '&tls=true&tlsCertificateKeyFile={}'.format(conf.database_certificate) + if os.path.isfile(conf.database_cafile): + uri += '&tlsCAFile={}'.format(conf.database_cafile) + +client = MongoClient(uri) \ No newline at end of file diff --git a/beacon/connections/mongo/conf.py b/beacon/connections/mongo/conf.py index 3c69141..26b792f 100644 --- a/beacon/connections/mongo/conf.py +++ b/beacon/connections/mongo/conf.py @@ -3,4 +3,6 @@ database_user = 'root' database_password = 'example' database_name = 'beacon' -database_auth_source = 'admin' \ No newline at end of file +database_auth_source = 'admin' +database_certificate = '' +database_cafile = '' \ No newline at end of file diff --git a/beacon/connections/mongo/extract_filtering_terms.py b/beacon/connections/mongo/extract_filtering_terms.py index 789fb88..8d340ca 100644 --- a/beacon/connections/mongo/extract_filtering_terms.py +++ b/beacon/connections/mongo/extract_filtering_terms.py @@ -28,17 +28,21 @@ ICD_REGEX = re.compile(r"(ICD[_A-Za-z0-9]+):([_A-Za-z0-9^\./-]+)") -client = MongoClient( - #"mongodb://127.0.0.1:27017/" - "mongodb://{}:{}@{}:{}/{}?authSource={}".format( - conf.database_user, - conf.database_password, - conf.database_host, - conf.database_port, - conf.database_name, - conf.database_auth_source, - ) - ) +uri = "mongodb://{}:{}@{}:{}/{}?authSource={}".format( + conf.database_user, + conf.database_password, + conf.database_host, + conf.database_port, + conf.database_name, + conf.database_auth_source +) + +if os.path.isfile(conf.database_certificate): + uri += '&tls=true&tlsCertificateKeyFile={}'.format(conf.database_certificate) + if os.path.isfile(conf.database_cafile): + uri += '&tlsCAFile={}'.format(conf.database_cafile) + +client = MongoClient(uri) ''' client = MongoClient( diff --git a/beacon/connections/mongo/get_descendants.py b/beacon/connections/mongo/get_descendants.py index b29a8d7..8bfd942 100644 --- a/beacon/connections/mongo/get_descendants.py +++ b/beacon/connections/mongo/get_descendants.py @@ -13,17 +13,21 @@ import conf -client = MongoClient( - #"mongodb://127.0.0.1:27017/" - "mongodb://{}:{}@{}:{}/{}?authSource={}".format( - conf.database_user, - conf.database_password, - conf.database_host, - conf.database_port, - conf.database_name, - conf.database_auth_source, - ) - ) +uri = "mongodb://{}:{}@{}:{}/{}?authSource={}".format( + conf.database_user, + conf.database_password, + conf.database_host, + conf.database_port, + conf.database_name, + conf.database_auth_source +) + +if os.path.isfile(conf.database_certificate): + uri += '&tls=true&tlsCertificateKeyFile={}'.format(conf.database_certificate) + if os.path.isfile(conf.database_cafile): + uri += '&tlsCAFile={}'.format(conf.database_cafile) + +client = MongoClient(uri) class MyProgressBar: def __init__(self): diff --git a/beacon/connections/mongo/ping.py b/beacon/connections/mongo/ping.py new file mode 100644 index 0000000..29130ad --- /dev/null +++ b/beacon/connections/mongo/ping.py @@ -0,0 +1,25 @@ +from pymongo.mongo_client import MongoClient +from pymongo.errors import ConnectionFailure +import conf +import os + + +uri = "mongodb://{}:{}@{}:{}/{}?authSource={}".format( + conf.database_user, + conf.database_password, + conf.database_host, + conf.database_port, + conf.database_name, + conf.database_auth_source +) + +if os.path.isfile(conf.database_certificate): + uri += '&tls=true&tlsCertificateKeyFile={}'.format(conf.database_certificate) + if os.path.isfile(conf.database_cafile): + uri += '&tlsCAFile={}'.format(conf.database_cafile) + +client = MongoClient(uri, serverSelectionTimeoutMS=30000) +try: + client.admin.command('ping') +except ConnectionFailure as err: + print(f"Database error encountered: {err}") \ No newline at end of file diff --git a/beacon/connections/mongo/reindex.py b/beacon/connections/mongo/reindex.py index 3b31b19..5d81337 100644 --- a/beacon/connections/mongo/reindex.py +++ b/beacon/connections/mongo/reindex.py @@ -1,17 +1,23 @@ from pymongo.mongo_client import MongoClient import conf +import os -client = MongoClient( - "mongodb://{}:{}@{}:{}/{}?authSource={}".format( - conf.database_user, - conf.database_password, - conf.database_host, - conf.database_port, - conf.database_name, - conf.database_auth_source, - ) - ) +uri = "mongodb://{}:{}@{}:{}/{}?authSource={}".format( + conf.database_user, + conf.database_password, + conf.database_host, + conf.database_port, + conf.database_name, + conf.database_auth_source +) + +if os.path.isfile(conf.database_certificate): + uri += '&tls=true&tlsCertificateKeyFile={}'.format(conf.database_certificate) + if os.path.isfile(conf.database_cafile): + uri += '&tlsCAFile={}'.format(conf.database_cafile) + +client = MongoClient(uri) try: client.beacon.drop_collection("synonyms") except Exception: