From 752b21f96a1ab77d6bfc10f75d01be1abc8d9c61 Mon Sep 17 00:00:00 2001 From: Martin Hummel Date: Sat, 12 Sep 2026 18:10:12 +0200 Subject: [PATCH] Fix parent group lookup for dotted student usernames --- .../ldapconnector/pytests/test_models.py | 31 +++++++++++++++++++ .../ldapconnector/pytests/test_router.py | 24 ++++++++++++++ .../ldapconnector/urls/groups.py | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_models.py b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_models.py index 820ac68b..72e8badf 100644 --- a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_models.py +++ b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_models.py @@ -1,10 +1,12 @@ import pytest +from dataclasses import fields from unittest.mock import MagicMock from linuxmusterTools.ldapconnector.models.common import LMNModel from linuxmusterTools.ldapconnector.models.lmnusermixin import LMNUserMixin from linuxmusterTools.ldapconnector.models.lmngroup import LMNGroupModel from linuxmusterTools.ldapconnector.models.lmnproject import LMNProjectModel +from linuxmusterTools.ldapconnector.models.lmnuser import LMNUserModel from linuxmusterTools.ldapconnector.urls.ldaprouter import router DN = 'CN=johndoe,OU=7a,OU=Students,OU=default-school,OU=SCHOOLS,DC=linuxmuster,DC=lan' @@ -48,6 +50,35 @@ def test_common_name_on_ou_dn(self): assert obj.common_name('OU=Students,DC=test,DC=lan') == 'Students' +class TestStudentParents: + + @pytest.mark.parametrize('school, username', [ + ('default-school', 'anna.test'), + ('agy', 'agy-anna.test'), + ]) + @pytest.mark.parametrize('group, expected_parents', [ + ({}, []), + ({'member': ['CN=parent.test,OU=Parents,DC=test,DC=lan']}, ['parent.test']), + ]) + def test_initializes_dotted_student_with_parent_lookup( + self, monkeypatch, school, username, group, expected_parents + ): + read_group = MagicMock(return_value=group) + monkeypatch.setattr(router.lr, 'get_single', read_group) + data = {field.name: field.type() for field in fields(LMNUserModel) if field.init} + data.update(cn=username, sophomorixRole='student', sophomorixSchoolname=school) + + user = LMNUserModel(**data, custom_fields_config={}) + + assert user.parents == expected_parents + read_group.assert_called_once() + args, kwargs = read_group.call_args + assert args[0] is LMNGroupModel + assert f'(cn={username}-parents)' in args[1] + assert kwargs['school'] == school + assert kwargs['subdn'] == f'OU={school},OU=SCHOOLS,' + + class TestCheckSchoolclassNumber: def test_numeric_prefix_returns_int(self): diff --git a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_router.py b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_router.py index 0fc469a9..eb18d6ff 100644 --- a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_router.py +++ b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/pytests/test_router.py @@ -56,6 +56,30 @@ def test_groups_collection_route(self): func, data = router._find_method('/groups') assert func.type == 'collection' + @pytest.mark.parametrize('name', [ + 'anna.test-parents', + 'agy-anna.test-parents', + 'annatest-parents', + 'anna-test-parents', + 'anna_test-parents', + 'anna test-parents', + ]) + def test_single_unit_route(self, name): + func, data = router._find_method(f'/units/{name}') + assert func.type == 'single' + assert data == {'name': name} + assert f'(cn={name})' in func(**data) + + @pytest.mark.parametrize('name', [ + 'anna/test-parents', + 'anna*test-parents', + 'anna(test)-parents', + 'anna\\test-parents', + ]) + def test_single_unit_route_rejects_invalid_names(self, name): + with pytest.raises(Exception, match='unknown'): + router._find_method(f'/units/{name}') + def test_devices_collection_route(self): func, data = router._find_method('/devices') assert func.type == 'collection' diff --git a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/urls/groups.py b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/urls/groups.py index 25c5a043..f0868242 100644 --- a/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/urls/groups.py +++ b/usr/lib/python3/dist-packages/linuxmusterTools/ldapconnector/urls/groups.py @@ -14,7 +14,7 @@ def get_all_units(): return ldap_filter -@router.single(r'/units/(?P[\w\-_ ]*)', models.LMNGroupModel, subdn=f'OU={SCHOOL_MARKER},OU=SCHOOLS,') +@router.single(r'/units/(?P[\w\-_. ]*)', models.LMNGroupModel, subdn=f'OU={SCHOOL_MARKER},OU=SCHOOLS,') def get_group(name=''): """ Get a unit specified by its name. The terminology "unit" was chosen in order to differenciate with a "group" from