From 8886532ed6751b03035ca7d1b7c8fb979578ce1e Mon Sep 17 00:00:00 2001 From: "Jens L." Date: Thu, 5 Sep 2024 01:19:11 +0200 Subject: [PATCH] providers/ldap: fix incorrect permission check for search access (#11217) Signed-off-by: Jens Langhammer --- internal/outpost/ldap/bind/direct/bind.go | 2 +- tests/e2e/test_provider_ldap.py | 78 +++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/internal/outpost/ldap/bind/direct/bind.go b/internal/outpost/ldap/bind/direct/bind.go index e095d5715e..36697fbe0f 100644 --- a/internal/outpost/ldap/bind/direct/bind.go +++ b/internal/outpost/ldap/bind/direct/bind.go @@ -96,7 +96,7 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul return ldap.LDAPResultOperationsError, nil } flags.UserPk = userInfo.User.Pk - flags.CanSearch = access.HasSearchPermission != nil + flags.CanSearch = access.GetHasSearchPermission() db.si.SetFlags(req.BindDN, &flags) if flags.CanSearch { req.Log().Debug("Allowed access to search") diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py index af75a734f5..5d52198078 100644 --- a/tests/e2e/test_provider_ldap.py +++ b/tests/e2e/test_provider_ldap.py @@ -11,6 +11,7 @@ from ldap3.core.exceptions import LDAPInvalidCredentialsResult from authentik.blueprints.tests import apply_blueprint, reconcile_app from authentik.core.models import Application, User +from authentik.core.tests.utils import create_test_user from authentik.events.models import Event, EventAction from authentik.flows.models import Flow from authentik.lib.generators import generate_id @@ -331,6 +332,83 @@ class TestProviderLDAP(SeleniumTestCase): ] self.assert_list_dict_equal(expected, response) + @retry() + @apply_blueprint( + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", + ) + @reconcile_app("authentik_tenants") + @reconcile_app("authentik_outposts") + def test_ldap_bind_search_no_perms(self): + """Test simple bind + search""" + user = create_test_user() + self._prepare() + server = Server("ldap://localhost:3389", get_info=ALL) + _connection = Connection( + server, + raise_exceptions=True, + user=f"cn={user.username},ou=users,dc=ldap,dc=goauthentik,dc=io", + password=user.username, + ) + _connection.bind() + self.assertTrue( + Event.objects.filter( + action=EventAction.LOGIN, + user={ + "pk": user.pk, + "email": user.email, + "username": user.username, + }, + ) + ) + + _connection.search( + "ou=Users,DC=ldaP,dc=goauthentik,dc=io", + "(objectClass=user)", + search_scope=SUBTREE, + attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES], + ) + response: list = _connection.response + # Remove raw_attributes to make checking easier + for obj in response: + del obj["raw_attributes"] + del obj["raw_dn"] + obj["attributes"] = dict(obj["attributes"]) + expected = [ + { + "dn": f"cn={user.username},ou=users,dc=ldap,dc=goauthentik,dc=io", + "attributes": { + "cn": user.username, + "sAMAccountName": user.username, + "uid": user.uid, + "name": user.name, + "displayName": user.name, + "sn": user.name, + "mail": user.email, + "objectClass": [ + "top", + "person", + "organizationalPerson", + "inetOrgPerson", + "user", + "posixAccount", + "goauthentik.io/ldap/user", + ], + "uidNumber": 2000 + user.pk, + "gidNumber": 2000 + user.pk, + "memberOf": [ + f"cn={group.name},ou=groups,dc=ldap,dc=goauthentik,dc=io" + for group in user.ak_groups.all() + ], + "homeDirectory": f"/home/{user.username}", + "ak-active": True, + "ak-superuser": False, + }, + "type": "searchResEntry", + }, + ] + self.assert_list_dict_equal(expected, response) + def assert_list_dict_equal(self, expected: list[dict], actual: list[dict], match_key="dn"): """Assert a list of dictionaries is identical, ignoring the ordering of items""" self.assertEqual(len(expected), len(actual))