From 6022be5ff19f61a6089a4154b2fba52cc1d7fd1c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 22 Dec 2023 00:25:08 +0100 Subject: [PATCH] Prevent unecessary import resulting in catastrophies + lazy-load the session secrets --- src/app.py | 3 ++- src/authenticators/ldap_admin.py | 17 ++++++++++++++--- src/authenticators/ldap_ynhuser.py | 21 ++++++++++++++++----- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/app.py b/src/app.py index c7c0f9d83b..aef3b0121e 100644 --- a/src/app.py +++ b/src/app.py @@ -96,6 +96,8 @@ "doc", ] +PORTAL_SETTINGS_DIR = "/etc/yunohost/portal" + def app_list(full=False, upgradable=False): """ @@ -1619,7 +1621,6 @@ def app_ssowatconf(): _get_domain_portal_dict, ) from yunohost.permission import user_permission_list - from yunohost.portal import PORTAL_SETTINGS_DIR domains = domain_list()["domains"] portal_domains = domain_list(exclude_subdomains=True)["domains"] diff --git a/src/authenticators/ldap_admin.py b/src/authenticators/ldap_admin.py index d9e1920920..24a5b42b88 100644 --- a/src/authenticators/ldap_admin.py +++ b/src/authenticators/ldap_admin.py @@ -34,7 +34,18 @@ logger = logging.getLogger("yunohost.authenticators.ldap_admin") -SESSION_SECRET = open("/etc/yunohost/.admin_cookie_secret").read().strip() + +def SESSION_SECRET(): + # Only load this once actually requested to avoid boring issues like + # "secret doesnt exists yet" (before postinstall) and therefore service + # miserably fail to start + if not SESSION_SECRET.value: + SESSION_SECRET.value = open("/etc/yunohost/.admin_cookie_secret").read().strip() + assert SESSION_SECRET.value + return SESSION_SECRET.value + + +SESSION_SECRET.value = None SESSION_FOLDER = "/var/cache/yunohost/sessions" SESSION_VALIDITY = 3 * 24 * 3600 # 3 days @@ -148,7 +159,7 @@ def set_session_cookie(self, infos): response.set_cookie( "yunohost.admin", - jwt.encode(infos, SESSION_SECRET, algorithm="HS256"), + jwt.encode(infos, SESSION_SECRET(), algorithm="HS256"), secure=True, httponly=True, path="/", @@ -166,7 +177,7 @@ def get_session_cookie(self, raise_if_no_session_exists=True): token = request.get_cookie("yunohost.admin", default="").encode() infos = jwt.decode( token, - SESSION_SECRET, + SESSION_SECRET(), algorithms="HS256", options={"require": ["id", "user"]}, ) diff --git a/src/authenticators/ldap_ynhuser.py b/src/authenticators/ldap_ynhuser.py index 0c5c1a80f3..09eeb4d185 100644 --- a/src/authenticators/ldap_ynhuser.py +++ b/src/authenticators/ldap_ynhuser.py @@ -23,7 +23,18 @@ logger = logging.getLogger("yunohostportal.authenticators.ldap_ynhuser") -SESSION_SECRET = open("/etc/yunohost/.ssowat_cookie_secret").read().strip() + +def SESSION_SECRET(): + # Only load this once actually requested to avoid boring issues like + # "secret doesnt exists yet" (before postinstall) and therefore service + # miserably fail to start + if not SESSION_SECRET.value: + SESSION_SECRET.value = open("/etc/yunohost/.ssowat_cookie_secret").read().strip() + assert SESSION_SECRET.value + return SESSION_SECRET.value + + +SESSION_SECRET.value = None SESSION_FOLDER = "/var/cache/yunohost-portal/sessions" SESSION_VALIDITY = 3 * 24 * 3600 # 3 days @@ -87,7 +98,7 @@ def user_is_allowed_on_domain(user: str, domain: str) -> bool: # The result is a string formatted as | # For example: ctl8kk5GevYdaA5VZ2S88Q==|yTAzCx0Gd1+MCit4EQl9lA== def encrypt(data): - alg = algorithms.AES(SESSION_SECRET.encode()) + alg = algorithms.AES(SESSION_SECRET().encode()) iv = os.urandom(int(alg.block_size / 8)) E = Cipher(alg, modes.CBC(iv), default_backend()).encryptor() @@ -104,7 +115,7 @@ def decrypt(data_enc_and_iv_b64): data_enc = base64.b64decode(data_enc_b64) iv = base64.b64decode(iv_b64) - alg = algorithms.AES(SESSION_SECRET.encode()) + alg = algorithms.AES(SESSION_SECRET().encode()) D = Cipher(alg, modes.CBC(iv), default_backend()).decryptor() p = padding.PKCS7(alg.block_size).unpadder() data_padded = D.update(data_enc) @@ -181,7 +192,7 @@ def set_session_cookie(self, infos): response.set_cookie( "yunohost.portal", - jwt.encode(infos, SESSION_SECRET, algorithm="HS256"), + jwt.encode(infos, SESSION_SECRET(), algorithm="HS256"), secure=True, httponly=True, path="/", @@ -200,7 +211,7 @@ def get_session_cookie(self, decrypt_pwd=False): token = request.get_cookie("yunohost.portal", default="").encode() infos = jwt.decode( token, - SESSION_SECRET, + SESSION_SECRET(), algorithms="HS256", options={"require": ["id", "host", "user", "pwd"]}, )