Merge branch 'ldapobject-refactor' into 'main'

Miscellaneous refactoring

See merge request yaal/canaille!69
This commit is contained in:
Éloi Rivard 2022-11-15 11:51:22 +00:00
commit 7a74df2c67
6 changed files with 72 additions and 48 deletions

View file

@ -1,9 +1,19 @@
import datetime
from enum import Enum
import ldap.dn
import ldap.filter
from flask import g
LDAP_NULL_DATE = "000001010000Z"
class Syntax(str, Enum):
GENERALIZED_TIME = "1.3.6.1.4.1.1466.115.121.1.24"
INTEGER = "1.3.6.1.4.1.1466.115.121.1.27"
JPEG = "1.3.6.1.4.1.1466.115.121.1.28"
BOOLEAN = "1.3.6.1.4.1.1466.115.121.1.7"
class LDAPObject:
_object_class_by_name = None
@ -175,17 +185,25 @@ class LDAPObject:
except KeyError:
return value
if syntax == "1.3.6.1.4.1.1466.115.121.1.24": # Generalized Time
if syntax == Syntax.GENERALIZED_TIME:
value = value.decode("utf-8")
return datetime.datetime.strptime(value, "%Y%m%d%H%M%SZ") if value else None
if value == LDAP_NULL_DATE:
# python cannot represent datetimes with year 0
return datetime.datetime.min
else:
return (
datetime.datetime.strptime(value, "%Y%m%d%H%M%SZ")
if value
else None
)
if syntax == "1.3.6.1.4.1.1466.115.121.1.27": # Integer
if syntax == Syntax.INTEGER:
return int(value.decode("utf-8"))
if syntax == "1.3.6.1.4.1.1466.115.121.1.28": # JPEG
if syntax == Syntax.JPEG:
return value
if syntax == "1.3.6.1.4.1.1466.115.121.1.7": # Boolean
if syntax == Syntax.BOOLEAN:
return value.decode("utf-8").upper() == "TRUE"
return value.decode("utf-8")
@ -197,16 +215,19 @@ class LDAPObject:
except KeyError:
return value
if syntax == "1.3.6.1.4.1.1466.115.121.1.24": # Generalized Time
if syntax == Syntax.GENERALIZED_TIME and isinstance(value, datetime.datetime):
if value == datetime.datetime.min:
return LDAP_NULL_DATE.encode("utf-8")
else:
return value.strftime("%Y%m%d%H%M%SZ").encode("utf-8")
if syntax == "1.3.6.1.4.1.1466.115.121.1.27": # Integer
if syntax == Syntax.INTEGER and isinstance(value, int):
return str(value).encode("utf-8")
if syntax == "1.3.6.1.4.1.1466.115.121.1.28": # JPEG
if syntax == Syntax.JPEG:
return value
if syntax == "1.3.6.1.4.1.1466.115.121.1.7": # Boolean
if syntax == Syntax.BOOLEAN and isinstance(value, bool):
return ("TRUE" if value else "FALSE").encode("utf-8")
return value.encode("utf-8")
@ -243,7 +264,7 @@ class LDAPObject:
deletions = [
name
for name, value in self.changes.items()
if value is None and name in self.attrs
if (value is None or value == [None]) and name in self.attrs
]
changes = {
name: value
@ -333,20 +354,18 @@ class LDAPObject:
else name
)
if (not self.may or attribute_name not in self.may) and (
not self.must or attribute_name not in self.must
):
return super().__getattribute__(attribute_name)
if attribute_name in self.ldap_object_attributes():
if (
not self.ldap_object_attributes()
or not self.ldap_object_attributes()[attribute_name].single_value
):
return self.changes.get(name, self.attrs.get(attribute_name, []))
else:
return self.changes.get(
attribute_name, self.attrs.get(attribute_name, [None])
)[0]
return self.changes.get(attribute_name, self.attrs.get(attribute_name, [None]))[
0
]
return super().__getattribute__(attribute_name)
def __setattr__(self, name, value):
attribute_name = (
@ -357,9 +376,7 @@ class LDAPObject:
super().__setattr__(attribute_name, value)
if (self.may and attribute_name in self.may) or (
self.must and attribute_name in self.must
):
if attribute_name in self.ldap_object_attributes():
if self.ldap_object_attributes()[attribute_name].single_value:
self.changes[attribute_name] = [value]
else:

View file

@ -1,6 +1,6 @@
$('.confirm').click(function(e){
e.preventDefault();
$('.ui.modal')
$('#modal-' + e.target.id + '.ui.modal')
.modal({
onApprove : function() {
$('.confirm').unbind('click').click();

View file

@ -23,7 +23,7 @@
{% block content %}
{% if self_deletion or (user.can_manage_users and edited_user) %}
<div class="ui basic modal">
<div id="modal-delete" class="ui basic modal">
<div class="ui icon header">
<i class="user minus icon"></i>
{% trans %}Account deletion{% endtrans %}

View file

@ -15,7 +15,7 @@ slapd = slapd.Slapd(
"nis.ldif",
"inetorgperson.ldif",
"../canaille/ldap_backend/schemas/oauth2-openldap.ldif",
"ldif/memberof.ldif",
"ldif/memberof-config.ldif",
),
)
slapd.start()
@ -39,13 +39,11 @@ try:
+ "\n"
)
with open("ldif/bootstrap-tree.ldif") as fd:
try:
slapd.ldapadd(fd.read())
except RuntimeError:
pass
with open("ldif/bootstrap-data.ldif") as fd:
for ldif in (
"ldif/bootstrap-tree.ldif",
"ldif/bootstrap-data.ldif",
):
with open(ldif) as fd:
try:
slapd.ldapadd(fd.read())
except RuntimeError:

View file

@ -27,6 +27,7 @@ class CustomSlapdObject(slapd.Slapd):
"nis.ldif",
"inetorgperson.ldif",
"canaille/ldap_backend/schemas/oauth2-openldap.ldif",
"demo/ldif/memberof-config.ldif",
),
)
@ -80,7 +81,7 @@ def keypair_path(keypair, tmp_path):
@pytest.fixture(scope="session")
def slapd_server():
def raw_slapd_server():
slapd = CustomSlapdObject()
try:
slapd.start()
@ -110,15 +111,23 @@ def slapd_server():
+ "\n"
)
LDAPObject.root_dn = slapd.suffix
yield slapd
finally:
slapd.stop()
@pytest.fixture(scope="session")
def slapd_server(raw_slapd_server):
for ldif in ("demo/ldif/bootstrap-tree.ldif",):
with open(ldif) as fd:
raw_slapd_server.ldapadd(fd.read())
LDAPObject.root_dn = raw_slapd_server.suffix
User.base = "ou=users"
User.object_class = ["inetOrgPerson"]
Group.base = "ou=groups"
Group.object_class = ["groupOfNames"]
yield slapd
finally:
slapd.stop()
yield raw_slapd_server
@pytest.fixture