forked from Github-Mirrors/canaille
refactor: ldap backend use a server control to re-read objects after update
This commit is contained in:
parent
06181ac479
commit
7b054bb571
3 changed files with 17 additions and 9 deletions
|
@ -4,6 +4,7 @@ from collections.abc import Iterable
|
||||||
|
|
||||||
import ldap.dn
|
import ldap.dn
|
||||||
import ldap.filter
|
import ldap.filter
|
||||||
|
from ldap.controls.readentry import PostReadControl
|
||||||
|
|
||||||
from canaille.backends.models import BackendModel
|
from canaille.backends.models import BackendModel
|
||||||
|
|
||||||
|
@ -136,6 +137,7 @@ class LDAPObject(BackendModel, metaclass=LDAPObjectMetaclass):
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
ldap_attributes = self.may() + self.must()
|
ldap_attributes = self.may() + self.must()
|
||||||
|
|
||||||
if not (
|
if not (
|
||||||
isinstance(other, self.__class__)
|
isinstance(other, self.__class__)
|
||||||
and self.may() == other.may()
|
and self.may() == other.may()
|
||||||
|
@ -414,6 +416,13 @@ class LDAPObject(BackendModel, metaclass=LDAPObjectMetaclass):
|
||||||
|
|
||||||
self.set_ldap_attribute("objectClass", self.ldap_object_class)
|
self.set_ldap_attribute("objectClass", self.ldap_object_class)
|
||||||
|
|
||||||
|
# PostReadControl allows to read the updated object attributes on creation/edition
|
||||||
|
attributes = ["objectClass"] + [
|
||||||
|
self.python_attribute_to_ldap(name) for name in self.attributes
|
||||||
|
]
|
||||||
|
attributes.remove("dn")
|
||||||
|
read_post_control = PostReadControl(criticality=True, attrList=attributes)
|
||||||
|
|
||||||
# Object already exists in the LDAP database
|
# Object already exists in the LDAP database
|
||||||
if self.exists:
|
if self.exists:
|
||||||
deletions = [
|
deletions = [
|
||||||
|
@ -435,7 +444,9 @@ class LDAPObject(BackendModel, metaclass=LDAPObjectMetaclass):
|
||||||
(ldap.MOD_REPLACE, name, values)
|
(ldap.MOD_REPLACE, name, values)
|
||||||
for name, values in formatted_changes.items()
|
for name, values in formatted_changes.items()
|
||||||
]
|
]
|
||||||
conn.modify_s(self.dn, modlist)
|
_, _, _, [result] = conn.modify_ext_s(
|
||||||
|
self.dn, modlist, serverctrls=[read_post_control]
|
||||||
|
)
|
||||||
|
|
||||||
# Object does not exist yet in the LDAP database
|
# Object does not exist yet in the LDAP database
|
||||||
else:
|
else:
|
||||||
|
@ -445,11 +456,13 @@ class LDAPObject(BackendModel, metaclass=LDAPObjectMetaclass):
|
||||||
if value and value[0]
|
if value and value[0]
|
||||||
}
|
}
|
||||||
formatted_changes = python_attrs_to_ldap(changes, null_allowed=False)
|
formatted_changes = python_attrs_to_ldap(changes, null_allowed=False)
|
||||||
attributes = [(name, values) for name, values in formatted_changes.items()]
|
modlist = [(name, values) for name, values in formatted_changes.items()]
|
||||||
conn.add_s(self.dn, attributes)
|
_, _, _, [result] = conn.add_ext_s(
|
||||||
|
self.dn, modlist, serverctrls=[read_post_control]
|
||||||
|
)
|
||||||
|
|
||||||
self.exists = True
|
self.exists = True
|
||||||
self.state = {**self.state, **self.changes}
|
self.state = {**result.entry, **self.changes}
|
||||||
self.changes = {}
|
self.changes = {}
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
|
|
@ -226,7 +226,6 @@ def test_model_creation_edition_datetime(testclient, backend):
|
||||||
formatted_name="foo",
|
formatted_name="foo",
|
||||||
)
|
)
|
||||||
user.save()
|
user.save()
|
||||||
user.reload()
|
|
||||||
assert user.created == datetime.datetime(
|
assert user.created == datetime.datetime(
|
||||||
2020, 1, 1, 2, tzinfo=datetime.timezone.utc
|
2020, 1, 1, 2, tzinfo=datetime.timezone.utc
|
||||||
)
|
)
|
||||||
|
@ -237,7 +236,6 @@ def test_model_creation_edition_datetime(testclient, backend):
|
||||||
with freezegun.freeze_time("2021-01-01 02:00:00"):
|
with freezegun.freeze_time("2021-01-01 02:00:00"):
|
||||||
user.family_name = "bar"
|
user.family_name = "bar"
|
||||||
user.save()
|
user.save()
|
||||||
user.reload()
|
|
||||||
assert user.created == datetime.datetime(
|
assert user.created == datetime.datetime(
|
||||||
2020, 1, 1, 2, tzinfo=datetime.timezone.utc
|
2020, 1, 1, 2, tzinfo=datetime.timezone.utc
|
||||||
)
|
)
|
||||||
|
|
|
@ -33,7 +33,6 @@ def test_revokation(testclient, client, consent, logged_user, token):
|
||||||
def test_revokation_already_revoked(testclient, client, consent, logged_user):
|
def test_revokation_already_revoked(testclient, client, consent, logged_user):
|
||||||
consent.revoke()
|
consent.revoke()
|
||||||
|
|
||||||
consent.reload()
|
|
||||||
assert consent.revoked
|
assert consent.revoked
|
||||||
|
|
||||||
res = testclient.get(f"/consent/revoke/{consent.consent_id}", status=302)
|
res = testclient.get(f"/consent/revoke/{consent.consent_id}", status=302)
|
||||||
|
@ -47,7 +46,6 @@ def test_revokation_already_revoked(testclient, client, consent, logged_user):
|
||||||
def test_restoration(testclient, client, consent, logged_user, token):
|
def test_restoration(testclient, client, consent, logged_user, token):
|
||||||
consent.revoke()
|
consent.revoke()
|
||||||
|
|
||||||
consent.reload()
|
|
||||||
assert consent.revoked
|
assert consent.revoked
|
||||||
token.reload()
|
token.reload()
|
||||||
assert token.revoked
|
assert token.revoked
|
||||||
|
@ -101,7 +99,6 @@ def test_oidc_authorization_after_revokation(
|
||||||
):
|
):
|
||||||
consent.revoke()
|
consent.revoke()
|
||||||
|
|
||||||
consent.reload()
|
|
||||||
assert consent.revoked
|
assert consent.revoked
|
||||||
|
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
|
|
Loading…
Reference in a new issue