From 075526303eff445b93ebdb1002a740abd77e29a1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 14 Jun 2021 17:00:41 +0200 Subject: [PATCH] Misc tweaks and fixes, port ldap auth test from moulinette --- debian/control | 1 + locales/en.json | 3 ++ src/yunohost/authenticators/ldap_admin.py | 20 ++------ src/yunohost/tests/test_ldap.py | 58 +++++++++++++++++++++++ src/yunohost/utils/ldap.py | 2 +- tests/test_i18n_keys.py | 1 + 6 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 src/yunohost/tests/test_ldap.py diff --git a/debian/control b/debian/control index ef5061fe7..4c34d4c0a 100644 --- a/debian/control +++ b/debian/control @@ -14,6 +14,7 @@ Depends: ${python3:Depends}, ${misc:Depends} , python3-psutil, python3-requests, python3-dnspython, python3-openssl , python3-miniupnpc, python3-dbus, python3-jinja2 , python3-toml, python3-packaging, python3-publicsuffix + , python3-ldap , apt, apt-transport-https, apt-utils, dirmngr , php7.3-common, php7.3-fpm, php7.3-ldap, php7.3-intl , mariadb-server, php7.3-mysql diff --git a/locales/en.json b/locales/en.json index 199c21b66..4eba8c9f0 100644 --- a/locales/en.json +++ b/locales/en.json @@ -358,6 +358,8 @@ "invalid_regex": "Invalid regex:'{regex:s}'", "ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it", "iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it", + "ldap_server_down": "Unable to reach LDAP server", + "ldap_server_is_down_restart_it": "The LDAP service is down, attempt to restart it...", "log_corrupted_md_file": "The YAML metadata file associated with logs is damaged: '{md_file}\nError: {error}'", "log_link_to_log": "Full log of this operation: '{desc}'", "log_help_to_get_log": "To view the log of the operation '{desc}', use the command 'yunohost log show {name}{name}'", @@ -470,6 +472,7 @@ "migrations_to_be_ran_manually": "Migration {id} has to be run manually. Please go to Tools → Migrations on the webadmin page, or run `yunohost tools migrations run`.", "not_enough_disk_space": "Not enough free space on '{path:s}'", "invalid_number": "Must be a number", + "invalid_password": "Invalid password", "operation_interrupted": "The operation was manually interrupted?", "packages_upgrade_failed": "Could not upgrade all the packages", "password_listed": "This password is among the most used passwords in the world. Please choose something more unique.", diff --git a/src/yunohost/authenticators/ldap_admin.py b/src/yunohost/authenticators/ldap_admin.py index 734148536..47efe5bf9 100644 --- a/src/yunohost/authenticators/ldap_admin.py +++ b/src/yunohost/authenticators/ldap_admin.py @@ -7,7 +7,6 @@ import ldap.sasl import time from moulinette import m18n -from moulinette.core import MoulinetteError from moulinette.authentication import BaseAuthenticator from yunohost.utils.error import YunohostError @@ -15,19 +14,6 @@ logger = logging.getLogger("yunohost.authenticators.ldap_admin") class Authenticator(BaseAuthenticator): - """LDAP Authenticator - - Initialize a LDAP connexion for the given arguments. It attempts to - authenticate a user if 'user_rdn' is given - by associating user_rdn - and base_dn - and provides extra methods to manage opened connexion. - - Keyword arguments: - - uri -- The LDAP server URI - - base_dn -- The base dn - - user_rdn -- The user rdn to authenticate - - """ - name = "ldap_admin" def __init__(self, *args, **kwargs): @@ -46,10 +32,10 @@ class Authenticator(BaseAuthenticator): try: con = _reconnect() except ldap.INVALID_CREDENTIALS: - raise MoulinetteError("invalid_password") + raise YunohostError("invalid_password") except ldap.SERVER_DOWN: # ldap is down, attempt to restart it before really failing - logger.warning(m18n.g("ldap_server_is_down_restart_it")) + logger.warning(m18n.n("ldap_server_is_down_restart_it")) os.system("systemctl restart slapd") time.sleep(10) # waits 10 secondes so we are sure that slapd has restarted @@ -67,7 +53,7 @@ class Authenticator(BaseAuthenticator): raise else: if who != self.admindn: - raise MoulinetteError(f"Not logged with the appropriate identity ? Found {who}, expected {self.admindn} !?") + raise YunohostError(f"Not logged with the appropriate identity ? Found {who}, expected {self.admindn} !?", raw_msg=True) finally: # Free the connection, we don't really need it to keep it open as the point is only to check authentication... if con: diff --git a/src/yunohost/tests/test_ldap.py b/src/yunohost/tests/test_ldap.py new file mode 100644 index 000000000..b3a5efc09 --- /dev/null +++ b/src/yunohost/tests/test_ldap.py @@ -0,0 +1,58 @@ +import pytest +import os + +from yunohost.authenticators.ldap_admin import Authenticator as LDAPAuth +from yunohost.tools import tools_adminpw + +from moulinette import m18n +from moulinette.core import MoulinetteError + +def setup_function(function): + + if os.system("systemctl is-active slapd") != 0: + os.system("systemctl start slapd && sleep 3") + + tools_adminpw("yunohost", check_strength=False) + + +def test_authenticate(): + LDAPAuth().authenticate(password="yunohost") + + +def test_authenticate_with_wrong_password(): + with pytest.raises(MoulinetteError) as exception: + LDAPAuth().authenticate(password="bad_password_lul") + + translation = m18n.g("invalid_password") + expected_msg = translation.format() + assert expected_msg in str(exception) + + +def test_authenticate_server_down(mocker): + os.system("systemctl stop slapd && sleep 3") + + # Now if slapd is down, moulinette tries to restart it + mocker.patch("os.system") + mocker.patch("time.sleep") + with pytest.raises(MoulinetteError) as exception: + LDAPAuth().authenticate(password="yunohost") + + translation = m18n.n("ldap_server_down") + expected_msg = translation.format() + assert expected_msg in str(exception) + + +def test_authenticate_change_password(): + + LDAPAuth().authenticate(password="yunohost") + + tools_adminpw("plopette", check_strength=False) + + with pytest.raises(MoulinetteError) as exception: + LDAPAuth().authenticate(password="yunohost") + + translation = m18n.g("invalid_password") + expected_msg = translation.format() + assert expected_msg in str(exception) + + LDAPAuth().authenticate(password="plopette") diff --git a/src/yunohost/utils/ldap.py b/src/yunohost/utils/ldap.py index 28d7a17ce..1298eff69 100644 --- a/src/yunohost/utils/ldap.py +++ b/src/yunohost/utils/ldap.py @@ -94,7 +94,7 @@ class LDAPInterface(): con = _reconnect() except ldap.SERVER_DOWN: # ldap is down, attempt to restart it before really failing - logger.warning(m18n.g("ldap_server_is_down_restart_it")) + logger.warning(m18n.n("ldap_server_is_down_restart_it")) os.system("systemctl restart slapd") time.sleep(10) # waits 10 secondes so we are sure that slapd has restarted try: diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 6876cbcd8..773a7f826 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -33,6 +33,7 @@ def find_expected_string_keys(): python_files = glob.glob("src/yunohost/*.py") python_files.extend(glob.glob("src/yunohost/utils/*.py")) python_files.extend(glob.glob("src/yunohost/data_migrations/*.py")) + python_files.extend(glob.glob("src/yunohost/authenticators/*.py")) python_files.extend(glob.glob("data/hooks/diagnosis/*.py")) python_files.append("bin/yunohost")