Skip to content

Commit f2b4f07

Browse files
committed
Refactor LDAP test to remove dependency on mockldap
Signed-off-by: tdruez <[email protected]>
1 parent 3639e17 commit f2b4f07

File tree

1 file changed

+164
-109
lines changed

1 file changed

+164
-109
lines changed

dje/tests/test_ldap.py

Lines changed: 164 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from django.apps import apps
1313
from django.conf import settings
14+
from django.contrib.auth import authenticate
1415
from django.contrib.auth import get_user_model
1516
from django.contrib.auth.models import Group
1617
from django.contrib.auth.models import Permission
@@ -21,11 +22,12 @@
2122
from django.urls import reverse
2223

2324
import ldap
25+
import slapdtest
2426
from django_auth_ldap.backend import _LDAPUserGroups
2527
from django_auth_ldap.config import GroupOfNamesType
2628
from django_auth_ldap.config import LDAPSearch
2729
from guardian.shortcuts import assign_perm
28-
from mockldap import MockLdap
30+
from ldap.ldapobject import SimpleLDAPObject
2931

3032
from dje.ldap_backend import DejaCodeLDAPBackend
3133
from dje.models import Dataspace
@@ -38,103 +40,88 @@
3840
Product = apps.get_model("product_portfolio", "Product")
3941

4042

41-
AUTH_LDAP_USER_ATTR_MAP = {
42-
"first_name": "givenName",
43-
"last_name": "sn",
44-
"email": "mail",
45-
}
46-
47-
48-
LDAP_GROUP_SETTINGS = {
49-
"AUTH_LDAP_GROUP_SEARCH": LDAPSearch(
50-
"ou=groups,dc=nexb,dc=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
51-
),
52-
"AUTH_LDAP_GROUP_TYPE": GroupOfNamesType(),
53-
}
43+
LDIF = """
44+
dn: o=test
45+
objectClass: organization
46+
o: test
47+
48+
dn: ou=people,o=test
49+
objectClass: organizationalUnit
50+
ou: people
51+
52+
dn: ou=groups,o=test
53+
objectClass: organizationalUnit
54+
ou: groups
55+
56+
dn: uid=bob,ou=people,o=test
57+
objectClass: person
58+
objectClass: organizationalPerson
59+
objectClass: inetOrgPerson
60+
objectClass: posixAccount
61+
cn: bob
62+
uid: bob
63+
userPassword: secret
64+
uidNumber: 1001
65+
gidNumber: 50
66+
givenName: Robert
67+
sn: Smith
68+
homeDirectory: /home/bob
69+
70+
71+
dn: cn=active,ou=groups,o=test
72+
cn: active
73+
objectClass: groupOfNames
74+
member: uid=bob,ou=people,o=test
75+
"""
5476

5577

5678
@override_settings(
57-
AUTH_LDAP_SERVER_URI="ldap://localhost/",
5879
AUTHENTICATION_BACKENDS=("dje.ldap_backend.DejaCodeLDAPBackend",),
5980
AUTH_LDAP_DATASPACE="nexB",
60-
AUTH_LDAP_USER_SEARCH=LDAPSearch(
61-
"ou=people,dc=nexb,dc=com", ldap.SCOPE_SUBTREE, "(samaccountname=%(user)s)"
81+
AUTH_LDAP_START_TLS=False,
82+
AUTH_LDAP_USER_DN_TEMPLATE="uid=%(user)s,ou=people,o=test",
83+
AUTH_LDAP_USER_SEARCH=LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"),
84+
AUTH_LDAP_UBIND_AS_AUTHENTICATING_USER=True,
85+
AUTH_LDAP_USER_ATTR_MAP={
86+
"first_name": "givenName",
87+
"last_name": "sn",
88+
"email": "mail",
89+
},
90+
AUTH_LDAP_GROUP_SEARCH=LDAPSearch(
91+
"ou=groups,o=test", ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
6292
),
63-
**LDAP_GROUP_SETTINGS,
93+
AUTH_LDAP_GROUP_TYPE=GroupOfNamesType(),
6494
)
6595
class DejaCodeLDAPBackendTestCase(TestCase):
66-
top = ("dc=com", {"dc": "com"})
67-
nexb = ("dc=nexb,dc=com", {"dc": "nexb"})
68-
people = ("ou=people,dc=nexb,dc=com", {"ou": "people"})
69-
groups = ("ou=groups,dc=nexb,dc=com", {"ou": "groups"})
70-
71-
bob = (
72-
"cn=bob,ou=people,dc=nexb,dc=com",
73-
{
74-
"cn": "bob",
75-
"samaccountname": "bob",
76-
"uid": ["bob"],
77-
"userPassword": ["secret"],
78-
"mail": ["[email protected]"],
79-
"givenName": ["Robert"],
80-
"sn": ["Smith"],
81-
},
82-
)
83-
84-
group_active = (
85-
"cn=active,ou=groups,dc=nexb,dc=com",
86-
{
87-
"cn": ["active"],
88-
"objectClass": ["groupOfNames"],
89-
"member": ["cn=bob,ou=people,dc=nexb,dc=com"],
90-
},
91-
)
92-
93-
group_not_in_database = (
94-
"cn=not_in_database,ou=groups,dc=nexb,dc=com",
95-
{
96-
"cn": ["not_in_database"],
97-
"objectClass": ["groupOfNames"],
98-
"member": ["cn=bob,ou=people,dc=nexb,dc=com"],
99-
},
100-
)
101-
102-
group_superuser = (
103-
"cn=superuser,ou=groups,dc=nexb,dc=com",
104-
{
105-
"cn": ["superuser"],
106-
"objectClass": ["groupOfNames"],
107-
"member": ["cn=bob,ou=people,dc=nexb,dc=com"],
108-
},
109-
)
110-
111-
# This is the content of our mock LDAP directory. It takes the form
112-
# {dn: {attr: [value, ...], ...}, ...}.
113-
directory = dict(
114-
[
115-
top,
116-
nexb,
117-
people,
118-
groups,
119-
bob,
120-
group_active,
121-
group_not_in_database,
122-
group_superuser,
123-
]
124-
)
96+
server_class = slapdtest.SlapdObject
97+
ldap_object_class = SimpleLDAPObject
12598

12699
@classmethod
127100
def setUpClass(cls):
128101
super().setUpClass()
129102
cls.configure_logger()
130-
# We only need to create the MockLdap instance once. The content we
131-
# pass in will be used for all LDAP connections.
132-
cls.mockldap = MockLdap(cls.directory)
103+
104+
cls.server = cls.server_class()
105+
cls.server.suffix = "o=test"
106+
cls.server.openldap_schema_files = [
107+
"core.ldif",
108+
"cosine.ldif",
109+
"inetorgperson.ldif",
110+
"nis.ldif",
111+
]
112+
cls.server.start()
113+
cls.server.ldapadd(LDIF)
114+
115+
# Override the AUTH_LDAP_SERVER_URI with the dynamic URI
116+
cls._settings_override = override_settings(AUTH_LDAP_SERVER_URI=cls.server.ldap_uri)
117+
cls._settings_override.enable()
133118

134119
@classmethod
135120
def tearDownClass(cls):
136121
super().tearDownClass()
137-
del cls.mockldap
122+
cls.server.stop()
123+
# Disable the settings override
124+
cls._settings_override.disable()
138125

139126
@classmethod
140127
def configure_logger(cls):
@@ -145,24 +132,46 @@ def configure_logger(cls):
145132
def setUp(self):
146133
cache.clear()
147134

148-
# Patch ldap.initialize
149-
self.mockldap.start()
150-
self.ldapobj = self.mockldap["ldap://localhost/"]
151-
152-
# DejaCode objects
153135
self.nexb_dataspace = Dataspace.objects.create(name="nexB")
154136
self.dejacode_group_active = Group.objects.create(name="active")
155137
self.dejacode_group1 = Group.objects.create(name="group1")
156-
157138
change_license_perm = Permission.objects.get_by_natural_key(
158139
"change_license", "license_library", "license"
159140
)
160141
self.dejacode_group_active.permissions.add(change_license_perm)
161142

162-
def tearDown(self):
163-
# Stop patching ldap.initialize and reset state.
164-
self.mockldap.stop()
165-
del self.ldapobj
143+
def test_ldap_authentication_populate_user(self):
144+
user = authenticate(username="bob", password="secret")
145+
self.assertEqual(user.username, "bob")
146+
self.assertEqual(user.first_name, "Robert")
147+
self.assertEqual(user.last_name, "Smith")
148+
self.assertEqual(user.email, "[email protected]")
149+
150+
def test_bind_and_search(self):
151+
# Connect to the temporary slapd server
152+
conn = self.ldap_object_class(self.server.ldap_uri)
153+
conn.simple_bind_s(self.server.root_dn, self.server.root_pw)
154+
155+
# Search for the top entry
156+
result = conn.search_s(self.server.suffix, ldap.SCOPE_BASE)
157+
self.assertEqual(len(result), 1)
158+
dn, entry = result[0]
159+
self.assertEqual(dn, self.server.suffix)
160+
161+
def test_ldap_group_active_properly_setup_and_searchable(self):
162+
conn = self.ldap_object_class(self.server.ldap_uri)
163+
results = conn.search_s("ou=groups,o=test", ldap.SCOPE_ONELEVEL, "(cn=active)")
164+
expected = [
165+
(
166+
"cn=active,ou=groups,o=test",
167+
{
168+
"cn": [b"active"],
169+
"objectClass": [b"groupOfNames"],
170+
"member": [b"uid=bob,ou=people,o=test"],
171+
},
172+
)
173+
]
174+
self.assertEqual(expected, results)
166175

167176
@override_settings(AUTH_LDAP_AUTOCREATE_USER=False)
168177
def test_ldap_authentication_no_autocreate_user(self):
@@ -208,7 +217,7 @@ def test_ldap_authentication_autocreate_user_proper_dataspace(self):
208217
# Next login, the DB user is re-used
209218
self.assertTrue(self.client.login(username="bob", password="secret"))
210219

211-
@override_settings(AUTH_LDAP_USER_ATTR_MAP=AUTH_LDAP_USER_ATTR_MAP)
220+
# @override_settings(AUTH_LDAP_USER_ATTR_MAP=AUTH_LDAP_USER_ATTR_MAP)
212221
def test_ldap_authentication_autocreate_user_with_attr_map(self):
213222
self.assertFalse(DejacodeUser.objects.filter(username="bob").exists())
214223

@@ -221,7 +230,7 @@ def test_ldap_authentication_autocreate_user_with_attr_map(self):
221230
self.assertEqual(self.nexb_dataspace, created_user.dataspace)
222231

223232
@override_settings(
224-
AUTH_LDAP_USER_ATTR_MAP=AUTH_LDAP_USER_ATTR_MAP,
233+
# AUTH_LDAP_USER_ATTR_MAP=AUTH_LDAP_USER_ATTR_MAP,
225234
AUTH_LDAP_ALWAYS_UPDATE_USER=True,
226235
)
227236
def test_ldap_authentication_update_user_with_attr_map(self):
@@ -243,22 +252,6 @@ def test_ldap_authentication_update_user_with_attr_map(self):
243252
self.assertEqual("[email protected]", user.email)
244253
self.assertEqual(self.nexb_dataspace, user.dataspace)
245254

246-
def test_ldap_group_active_properly_setup_and_searchable(self):
247-
conn = ldap.initialize("ldap://localhost/")
248-
results = conn.search_s("ou=groups,dc=nexb,dc=com", ldap.SCOPE_ONELEVEL, "(cn=active)")
249-
250-
expected = [
251-
(
252-
"cn=active,ou=groups,dc=nexb,dc=com",
253-
{
254-
"cn": ["active"],
255-
"objectClass": ["groupOfNames"],
256-
"member": ["cn=bob,ou=people,dc=nexb,dc=com"],
257-
},
258-
)
259-
]
260-
self.assertEqual(expected, results)
261-
262255
@override_settings(AUTH_LDAP_FIND_GROUP_PERMS=True)
263256
def test_ldap_authentication_group_permissions(self):
264257
bob = create_user("bob", self.nexb_dataspace, email="[email protected]", is_staff=True)
@@ -390,3 +383,65 @@ def test_ldap_object_secured_access(self):
390383
# The `ObjectPermissionBackend` is not needed since `ProductSecuredManager.get_queryset()`
391384
# calls directly `guardian.shortcuts.get_objects_for_user`
392385
self.assertEqual(200, self.client.get(url).status_code)
386+
387+
388+
# class DejaCodeLDAPBackendTestCase(TestCase):
389+
# top = ("dc=com", {"dc": "com"})
390+
# nexb = ("dc=nexb,dc=com", {"dc": "nexb"})
391+
# people = ("ou=people,dc=nexb,dc=com", {"ou": "people"})
392+
# groups = ("ou=groups,dc=nexb,dc=com", {"ou": "groups"})
393+
#
394+
# bob = (
395+
# "cn=bob,ou=people,dc=nexb,dc=com",
396+
# {
397+
# "cn": "bob",
398+
# "samaccountname": "bob",
399+
# "uid": ["bob"],
400+
# "userPassword": ["secret"],
401+
# "mail": ["[email protected]"],
402+
# "givenName": ["Robert"],
403+
# "sn": ["Smith"],
404+
# },
405+
# )
406+
#
407+
# group_active = (
408+
# "cn=active,ou=groups,dc=nexb,dc=com",
409+
# {
410+
# "cn": ["active"],
411+
# "objectClass": ["groupOfNames"],
412+
# "member": ["cn=bob,ou=people,dc=nexb,dc=com"],
413+
# },
414+
# )
415+
#
416+
# group_not_in_database = (
417+
# "cn=not_in_database,ou=groups,dc=nexb,dc=com",
418+
# {
419+
# "cn": ["not_in_database"],
420+
# "objectClass": ["groupOfNames"],
421+
# "member": ["cn=bob,ou=people,dc=nexb,dc=com"],
422+
# },
423+
# )
424+
#
425+
# group_superuser = (
426+
# "cn=superuser,ou=groups,dc=nexb,dc=com",
427+
# {
428+
# "cn": ["superuser"],
429+
# "objectClass": ["groupOfNames"],
430+
# "member": ["cn=bob,ou=people,dc=nexb,dc=com"],
431+
# },
432+
# )
433+
#
434+
# # This is the content of our mock LDAP directory. It takes the form
435+
# # {dn: {attr: [value, ...], ...}, ...}.
436+
# directory = dict(
437+
# [
438+
# top,
439+
# nexb,
440+
# people,
441+
# groups,
442+
# bob,
443+
# group_active,
444+
# group_not_in_database,
445+
# group_superuser,
446+
# ]
447+
# )

0 commit comments

Comments
 (0)