tests.py 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690
  1. # coding: utf-8
  2. # Copyright (c) 2009, Peter Sagerson
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # - Redistributions of source code must retain the above copyright notice, this
  9. # list of conditions and the following disclaimer.
  10. #
  11. # - Redistributions in binary form must reproduce the above copyright notice,
  12. # this list of conditions and the following disclaimer in the documentation
  13. # and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. from __future__ import absolute_import, division, print_function, unicode_literals
  26. from copy import deepcopy
  27. import logging
  28. import pickle
  29. import unittest
  30. import warnings
  31. import ldap
  32. import django
  33. from django.contrib.auth.models import Group, Permission, User
  34. from django.core.cache import cache
  35. from django.core.exceptions import ImproperlyConfigured
  36. from django.test import TestCase
  37. from django.test.utils import override_settings
  38. from django.utils.encoding import force_str
  39. from django_auth_ldap import backend
  40. from django_auth_ldap.config import (
  41. GroupOfNamesType, LDAPGroupQuery, LDAPSearch, LDAPSearchUnion, MemberDNGroupType, NestedMemberDNGroupType,
  42. NISGroupType, PosixGroupType
  43. )
  44. from .models import TestUser
  45. try:
  46. import mockldap
  47. except ImportError:
  48. mockldap = None
  49. class TestSettings(backend.LDAPSettings):
  50. """
  51. A replacement for backend.LDAPSettings that does not load settings
  52. from django.conf.
  53. """
  54. def __init__(self, **kwargs):
  55. for name, default in self.defaults.items():
  56. value = kwargs.get(name, default)
  57. setattr(self, name, value)
  58. @unittest.skipIf(mockldap is None, "django_auth_ldap tests require the mockldap package.")
  59. class LDAPTest(TestCase):
  60. top = ("o=test", {"o": "test"})
  61. people = ("ou=people,o=test", {"ou": "people"})
  62. groups = ("ou=groups,o=test", {"ou": "groups"})
  63. moregroups = ("ou=moregroups,o=test", {"ou": "moregroups"})
  64. mirror_groups = ("ou=mirror_groups,o=test", {"ou": "mirror_groups"})
  65. alice = ("uid=alice,ou=people,o=test", {
  66. "uid": ["alice"],
  67. "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"],
  68. "userPassword": ["password"],
  69. "uidNumber": ["1000"],
  70. "gidNumber": ["1000"],
  71. "givenName": ["Alice"],
  72. "sn": ["Adams"]
  73. })
  74. bob = ("uid=bob,ou=people,o=test", {
  75. "uid": ["bob"],
  76. "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"],
  77. "userPassword": ["password"],
  78. "uidNumber": ["1001"],
  79. "gidNumber": ["50"],
  80. "givenName": ["Robert"],
  81. "sn": ["Barker"]
  82. })
  83. dressler = (force_str("uid=dreßler,ou=people,o=test"), {
  84. "uid": [force_str("dreßler")],
  85. "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"],
  86. "userPassword": ["password"],
  87. "uidNumber": ["1002"],
  88. "gidNumber": ["50"],
  89. "givenName": ["Wolfgang"],
  90. "sn": [force_str("Dreßler")]
  91. })
  92. nobody = ("uid=nobody,ou=people,o=test", {
  93. "uid": ["nobody"],
  94. "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"],
  95. "userPassword": ["password"],
  96. "binaryAttr": ["\xb2"] # Invalid UTF-8
  97. })
  98. # posixGroup objects
  99. active_px = ("cn=active_px,ou=groups,o=test", {
  100. "cn": ["active_px"],
  101. "objectClass": ["posixGroup"],
  102. "gidNumber": ["1000"],
  103. "memberUid": [],
  104. })
  105. staff_px = ("cn=staff_px,ou=groups,o=test", {
  106. "cn": ["staff_px"],
  107. "objectClass": ["posixGroup"],
  108. "gidNumber": ["1001"],
  109. "memberUid": ["alice"],
  110. })
  111. superuser_px = ("cn=superuser_px,ou=groups,o=test", {
  112. "cn": ["superuser_px"],
  113. "objectClass": ["posixGroup"],
  114. "gidNumber": ["1002"],
  115. "memberUid": ["alice"],
  116. })
  117. # groupOfNames groups
  118. empty_gon = ("cn=empty_gon,ou=groups,o=test", {
  119. "cn": ["empty_gon"],
  120. "objectClass": ["groupOfNames"],
  121. "member": []
  122. })
  123. active_gon = ("cn=active_gon,ou=groups,o=test", {
  124. "cn": ["active_gon"],
  125. "objectClass": ["groupOfNames"],
  126. "member": ["uid=alice,ou=people,o=test"]
  127. })
  128. staff_gon = ("cn=staff_gon,ou=groups,o=test", {
  129. "cn": ["staff_gon"],
  130. "objectClass": ["groupOfNames"],
  131. "member": ["uid=alice,ou=people,o=test"]
  132. })
  133. superuser_gon = ("cn=superuser_gon,ou=groups,o=test", {
  134. "cn": ["superuser_gon"],
  135. "objectClass": ["groupOfNames"],
  136. "member": ["uid=alice,ou=people,o=test"]
  137. })
  138. other_gon = ("cn=other_gon,ou=moregroups,o=test", {
  139. "cn": ["other_gon"],
  140. "objectClass": ["groupOfNames"],
  141. "member": ["uid=bob,ou=people,o=test"]
  142. })
  143. # groupOfNames objects for LDAPGroupQuery testing
  144. alice_gon = ("cn=alice_gon,ou=query_groups,o=test", {
  145. "cn": ["alice_gon"],
  146. "objectClass": ["groupOfNames"],
  147. "member": ["uid=alice,ou=people,o=test"]
  148. })
  149. mutual_gon = ("cn=mutual_gon,ou=query_groups,o=test", {
  150. "cn": ["mutual_gon"],
  151. "objectClass": ["groupOfNames"],
  152. "member": ["uid=alice,ou=people,o=test", "uid=bob,ou=people,o=test"]
  153. })
  154. bob_gon = ("cn=bob_gon,ou=query_groups,o=test", {
  155. "cn": ["bob_gon"],
  156. "objectClass": ["groupOfNames"],
  157. "member": ["uid=bob,ou=people,o=test"]
  158. })
  159. # groupOfNames objects for selective group mirroring.
  160. mirror1 = ("cn=mirror1,ou=mirror_groups,o=test", {
  161. "cn": ["mirror1"],
  162. "objectClass": ["groupOfNames"],
  163. "member": ["uid=alice,ou=people,o=test"]
  164. })
  165. mirror2 = ("cn=mirror2,ou=mirror_groups,o=test", {
  166. "cn": ["mirror2"],
  167. "objectClass": ["groupOfNames"],
  168. "member": []
  169. })
  170. mirror3 = ("cn=mirror3,ou=mirror_groups,o=test", {
  171. "cn": ["mirror3"],
  172. "objectClass": ["groupOfNames"],
  173. "member": ["uid=alice,ou=people,o=test"]
  174. })
  175. mirror4 = ("cn=mirror4,ou=mirror_groups,o=test", {
  176. "cn": ["mirror4"],
  177. "objectClass": ["groupOfNames"],
  178. "member": []
  179. })
  180. # nisGroup objects
  181. active_nis = ("cn=active_nis,ou=groups,o=test", {
  182. "cn": ["active_nis"],
  183. "objectClass": ["nisNetgroup"],
  184. "nisNetgroupTriple": ["(,alice,)"]
  185. })
  186. staff_nis = ("cn=staff_nis,ou=groups,o=test", {
  187. "cn": ["staff_nis"],
  188. "objectClass": ["nisNetgroup"],
  189. "nisNetgroupTriple": ["(,alice,)"],
  190. })
  191. superuser_nis = ("cn=superuser_nis,ou=groups,o=test", {
  192. "cn": ["superuser_nis"],
  193. "objectClass": ["nisNetgroup"],
  194. "nisNetgroupTriple": ["(,alice,)"],
  195. })
  196. # Nested groups with a circular reference
  197. parent_gon = ("cn=parent_gon,ou=groups,o=test", {
  198. "cn": ["parent_gon"],
  199. "objectClass": ["groupOfNames"],
  200. "member": ["cn=nested_gon,ou=groups,o=test"]
  201. })
  202. nested_gon = ("CN=nested_gon,ou=groups,o=test", {
  203. "cn": ["nested_gon"],
  204. "objectClass": ["groupOfNames"],
  205. "member": [
  206. "uid=alice,ou=people,o=test",
  207. "cn=circular_gon,ou=groups,o=test"
  208. ]
  209. })
  210. circular_gon = ("cn=circular_gon,ou=groups,o=test", {
  211. "cn": ["circular_gon"],
  212. "objectClass": ["groupOfNames"],
  213. "member": ["cn=parent_gon,ou=groups,o=test"]
  214. })
  215. directory = dict([
  216. top, people, groups, moregroups, mirror_groups, alice, bob, dressler,
  217. nobody, active_px, staff_px, superuser_px, empty_gon, active_gon,
  218. staff_gon, superuser_gon, other_gon, alice_gon, mutual_gon, bob_gon,
  219. mirror1, mirror2, mirror3, mirror4, active_nis, staff_nis,
  220. superuser_nis, parent_gon, nested_gon, circular_gon
  221. ])
  222. @classmethod
  223. def configure_logger(cls):
  224. logger = logging.getLogger('django_auth_ldap')
  225. formatter = logging.Formatter("LDAP auth - %(levelname)s - %(message)s")
  226. handler = logging.StreamHandler()
  227. handler.setLevel(logging.DEBUG)
  228. handler.setFormatter(formatter)
  229. logger.addHandler(handler)
  230. logger.setLevel(logging.CRITICAL)
  231. @classmethod
  232. def setUpClass(cls):
  233. cls.configure_logger()
  234. cls.mockldap = mockldap.MockLdap(cls.directory)
  235. warnings.filterwarnings(
  236. 'ignore', category=UnicodeWarning, module='mockldap.ldapobject'
  237. )
  238. @classmethod
  239. def tearDownClass(cls):
  240. del cls.mockldap
  241. def setUp(self):
  242. cache.clear()
  243. self.mockldap.start()
  244. self.ldapobj = self.mockldap['ldap://localhost']
  245. self.backend = backend.LDAPBackend()
  246. self.backend.ldap # Force global configuration
  247. def tearDown(self):
  248. self.mockldap.stop()
  249. del self.ldapobj
  250. #
  251. # Tests
  252. #
  253. def test_options(self):
  254. self._init_settings(
  255. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  256. CONNECTION_OPTIONS={'opt1': 'value1'}
  257. )
  258. self.backend.authenticate(username='alice', password='password')
  259. self.assertEqual(self.ldapobj.get_option('opt1'), 'value1')
  260. def test_callable_server_uri(self):
  261. self._init_settings(
  262. SERVER_URI=lambda: 'ldap://ldap.example.com',
  263. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  264. )
  265. self.backend.authenticate(username='alice', password='password')
  266. ldapobj = self.mockldap['ldap://ldap.example.com']
  267. self.assertEqual(
  268. ldapobj.methods_called(with_args=True),
  269. [('initialize', ('ldap://ldap.example.com',), {}),
  270. ('simple_bind_s', ('uid=alice,ou=people,o=test', 'password'), {})]
  271. )
  272. def test_simple_bind(self):
  273. self._init_settings(
  274. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  275. )
  276. user_count = User.objects.count()
  277. user = self.backend.authenticate(username='alice', password='password')
  278. self.assertFalse(user.has_usable_password())
  279. self.assertEqual(user.username, 'alice')
  280. self.assertEqual(User.objects.count(), user_count + 1)
  281. self.assertEqual(
  282. self.ldapobj.methods_called(),
  283. ['initialize', 'simple_bind_s']
  284. )
  285. def test_default_settings(self):
  286. class MyBackend(backend.LDAPBackend):
  287. default_settings = {
  288. 'USER_DN_TEMPLATE': 'uid=%(user)s,ou=people,o=test',
  289. }
  290. self.backend = MyBackend()
  291. user_count = User.objects.count()
  292. user = self.backend.authenticate(username='alice', password='password')
  293. self.assertFalse(user.has_usable_password())
  294. self.assertEqual(user.username, 'alice')
  295. self.assertEqual(User.objects.count(), user_count + 1)
  296. self.assertEqual(
  297. self.ldapobj.methods_called(),
  298. ['initialize', 'simple_bind_s']
  299. )
  300. @override_settings(AUTH_LDAP_USER_SEARCH=LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'))
  301. def test_login_with_multiple_auth_backends(self):
  302. auth = self.client.login(username='alice', password='password')
  303. self.assertTrue(auth)
  304. @override_settings(AUTH_LDAP_USER_SEARCH=LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'))
  305. def test_bad_login_with_multiple_auth_backends(self):
  306. auth = self.client.login(username='invalid', password='i_do_not_exist')
  307. self.assertFalse(auth)
  308. def test_simple_bind_escaped(self):
  309. """ Bind with a username that requires escaping. """
  310. self._init_settings(
  311. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  312. )
  313. user = self.backend.authenticate(username='alice,1', password='password')
  314. self.assertIsNone(user)
  315. self.assertEqual(
  316. self.ldapobj.methods_called(with_args=True),
  317. [('initialize', ('ldap://localhost',), {}),
  318. ('simple_bind_s', ('uid=alice\\,1,ou=people,o=test', 'password'), {})]
  319. )
  320. def test_new_user_lowercase(self):
  321. self._init_settings(
  322. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  323. )
  324. user_count = User.objects.count()
  325. user = self.backend.authenticate(username='Alice', password='password')
  326. self.assertFalse(user.has_usable_password())
  327. self.assertEqual(user.username, 'alice')
  328. self.assertEqual(User.objects.count(), user_count + 1)
  329. self.assertEqual(
  330. self.ldapobj.methods_called(),
  331. ['initialize', 'simple_bind_s']
  332. )
  333. def test_deepcopy(self):
  334. self._init_settings(
  335. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  336. )
  337. user = self.backend.authenticate(username='Alice', password='password')
  338. user = deepcopy(user)
  339. @override_settings(AUTH_USER_MODEL='tests.TestUser')
  340. def test_auth_custom_user(self):
  341. self._init_settings(
  342. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  343. USER_ATTR_MAP={'uid_number': 'uidNumber'},
  344. )
  345. user = self.backend.authenticate(username='Alice', password='password')
  346. self.assertIsInstance(user, TestUser)
  347. @override_settings(AUTH_USER_MODEL='tests.TestUser')
  348. def test_get_custom_user(self):
  349. self._init_settings(
  350. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  351. USER_ATTR_MAP={'uid_number': 'uidNumber'},
  352. )
  353. user = self.backend.authenticate(username='Alice', password='password')
  354. user = self.backend.get_user(user.id)
  355. self.assertIsInstance(user, TestUser)
  356. @override_settings(AUTH_USER_MODEL='tests.TestUser')
  357. def test_get_custom_field(self):
  358. self._init_settings(
  359. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  360. USER_ATTR_MAP={
  361. 'uid_number': 'uidNumber',
  362. },
  363. USER_QUERY_FIELD='uid_number',
  364. )
  365. alice = TestUser.objects.create(identifier='abcdef', uid_number=1000)
  366. user = self.backend.authenticate(username='Alice', password='password')
  367. self.assertIsInstance(user, TestUser)
  368. self.assertEqual(user.pk, alice.pk)
  369. def test_new_user_whitespace(self):
  370. self._init_settings(
  371. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  372. )
  373. user_count = User.objects.count()
  374. user = self.backend.authenticate(username=' alice', password='password')
  375. user = self.backend.authenticate(username='alice ', password='password')
  376. self.assertFalse(user.has_usable_password())
  377. self.assertEqual(user.username, 'alice')
  378. self.assertEqual(User.objects.count(), user_count + 1)
  379. def test_simple_bind_bad_user(self):
  380. self._init_settings(
  381. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  382. )
  383. user_count = User.objects.count()
  384. user = self.backend.authenticate(username='evil_alice', password='password')
  385. self.assertIsNone(user)
  386. self.assertEqual(User.objects.count(), user_count)
  387. self.assertEqual(
  388. self.ldapobj.methods_called(),
  389. ['initialize', 'simple_bind_s']
  390. )
  391. def test_simple_bind_bad_password(self):
  392. self._init_settings(
  393. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  394. )
  395. user_count = User.objects.count()
  396. user = self.backend.authenticate(username='alice', password='bogus')
  397. self.assertIsNone(user)
  398. self.assertEqual(User.objects.count(), user_count)
  399. self.assertEqual(
  400. self.ldapobj.methods_called(),
  401. ['initialize', 'simple_bind_s']
  402. )
  403. def test_existing_user(self):
  404. self._init_settings(
  405. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  406. )
  407. User.objects.create(username='alice')
  408. user_count = User.objects.count()
  409. user = self.backend.authenticate(username='alice', password='password')
  410. # Make sure we only created one user
  411. self.assertIsNotNone(user)
  412. self.assertEqual(User.objects.count(), user_count)
  413. def test_existing_user_insensitive(self):
  414. self._init_settings(
  415. USER_SEARCH=LDAPSearch(
  416. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  417. )
  418. )
  419. # mockldap doesn't handle case-insensitive matching properly.
  420. self.ldapobj.search_s.seed('ou=people,o=test', ldap.SCOPE_SUBTREE,
  421. '(uid=Alice)', None)([self.alice])
  422. User.objects.create(username='alice')
  423. user = self.backend.authenticate(username='Alice', password='password')
  424. self.assertIsNotNone(user)
  425. self.assertEqual(user.username, 'alice')
  426. self.assertEqual(User.objects.count(), 1)
  427. def test_convert_username(self):
  428. class MyBackend(backend.LDAPBackend):
  429. def ldap_to_django_username(self, username):
  430. return 'ldap_%s' % username
  431. def django_to_ldap_username(self, username):
  432. return username[5:]
  433. self.backend = MyBackend()
  434. self._init_settings(
  435. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  436. )
  437. user_count = User.objects.count()
  438. user1 = self.backend.authenticate(username='alice', password='password')
  439. user2 = self.backend.get_user(user1.pk)
  440. self.assertEqual(User.objects.count(), user_count + 1)
  441. self.assertEqual(user1.username, 'ldap_alice')
  442. self.assertEqual(user1.ldap_user._username, 'alice')
  443. self.assertEqual(user1.ldap_username, 'alice')
  444. self.assertEqual(user2.username, 'ldap_alice')
  445. self.assertEqual(user2.ldap_user._username, 'alice')
  446. self.assertEqual(user2.ldap_username, 'alice')
  447. def test_search_bind(self):
  448. self._init_settings(
  449. USER_SEARCH=LDAPSearch(
  450. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  451. )
  452. )
  453. user_count = User.objects.count()
  454. user = self.backend.authenticate(username='alice', password='password')
  455. self.assertIsNotNone(user)
  456. self.assertEqual(User.objects.count(), user_count + 1)
  457. self.assertEqual(
  458. self.ldapobj.methods_called(),
  459. ['initialize', 'simple_bind_s', 'search_s', 'simple_bind_s']
  460. )
  461. def test_search_bind_escaped(self):
  462. """ Search for a username that requires escaping. """
  463. self._init_settings(
  464. USER_SEARCH=LDAPSearch(
  465. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  466. )
  467. )
  468. user = self.backend.authenticate(username='alice*', password='password')
  469. self.assertIsNone(user)
  470. self.assertEqual(
  471. self.ldapobj.methods_called(with_args=True),
  472. [('initialize', ('ldap://localhost',), {}),
  473. ('simple_bind_s', ('', ''), {}),
  474. ('search_s', ('ou=people,o=test', ldap.SCOPE_SUBTREE, '(uid=alice\\2a)', None), {})]
  475. )
  476. def test_search_bind_no_user(self):
  477. self._init_settings(
  478. USER_SEARCH=LDAPSearch(
  479. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(cn=%(user)s)'
  480. )
  481. )
  482. user = self.backend.authenticate(username='alice', password='password')
  483. self.assertIsNone(user)
  484. self.assertEqual(
  485. self.ldapobj.methods_called(),
  486. ['initialize', 'simple_bind_s', 'search_s']
  487. )
  488. def test_search_bind_multiple_users(self):
  489. self._init_settings(
  490. USER_SEARCH=LDAPSearch(
  491. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=*)'
  492. )
  493. )
  494. user = self.backend.authenticate(username='alice', password='password')
  495. self.assertIsNone(user)
  496. self.assertEqual(
  497. self.ldapobj.methods_called(),
  498. ['initialize', 'simple_bind_s', 'search_s']
  499. )
  500. def test_search_bind_bad_password(self):
  501. self._init_settings(
  502. USER_SEARCH=LDAPSearch(
  503. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  504. )
  505. )
  506. user = self.backend.authenticate(username='alice', password='bogus')
  507. self.assertIsNone(user)
  508. self.assertEqual(
  509. self.ldapobj.methods_called(),
  510. ['initialize', 'simple_bind_s', 'search_s', 'simple_bind_s']
  511. )
  512. def test_search_bind_with_credentials(self):
  513. self._init_settings(
  514. BIND_DN='uid=bob,ou=people,o=test',
  515. BIND_PASSWORD='password',
  516. USER_SEARCH=LDAPSearch(
  517. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  518. )
  519. )
  520. user = self.backend.authenticate(username='alice', password='password')
  521. self.assertIsNotNone(user)
  522. self.assertIsNotNone(user.ldap_user)
  523. self.assertEqual(user.ldap_user.dn, self.alice[0])
  524. self.assertEqual(user.ldap_user.attrs, ldap.cidict.cidict(self.alice[1]))
  525. self.assertEqual(
  526. self.ldapobj.methods_called(),
  527. ['initialize', 'simple_bind_s', 'search_s', 'simple_bind_s']
  528. )
  529. def test_search_bind_with_bad_credentials(self):
  530. self._init_settings(
  531. BIND_DN='uid=bob,ou=people,o=test',
  532. BIND_PASSWORD='bogus',
  533. USER_SEARCH=LDAPSearch(
  534. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  535. )
  536. )
  537. user = self.backend.authenticate(username='alice', password='password')
  538. self.assertIsNone(user)
  539. self.assertEqual(
  540. self.ldapobj.methods_called(),
  541. ['initialize', 'simple_bind_s']
  542. )
  543. def test_unicode_user(self):
  544. self._init_settings(
  545. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  546. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'}
  547. )
  548. user = self.backend.authenticate(username='dreßler', password='password')
  549. self.assertIsNotNone(user)
  550. self.assertEqual(user.username, 'dreßler')
  551. self.assertEqual(user.last_name, 'Dreßler')
  552. def test_cidict(self):
  553. self._init_settings(
  554. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  555. )
  556. user = self.backend.authenticate(username="alice", password="password")
  557. self.assertIsInstance(user.ldap_user.attrs, ldap.cidict.cidict)
  558. def test_populate_user(self):
  559. self._init_settings(
  560. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  561. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'}
  562. )
  563. user = self.backend.authenticate(username='alice', password='password')
  564. self.assertEqual(user.username, 'alice')
  565. self.assertEqual(user.first_name, 'Alice')
  566. self.assertEqual(user.last_name, 'Adams')
  567. # init, bind as user, bind anonymous, lookup user attrs
  568. self.assertEqual(
  569. self.ldapobj.methods_called(),
  570. ['initialize', 'simple_bind_s', 'simple_bind_s', 'search_s']
  571. )
  572. def test_populate_user_with_missing_attribute(self):
  573. self._init_settings(
  574. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  575. USER_ATTR_MAP={
  576. 'first_name': 'givenName',
  577. 'last_name': 'sn',
  578. 'email': 'mail',
  579. }
  580. )
  581. user = self.backend.authenticate(username='alice', password='password')
  582. self.assertEqual(user.username, 'alice')
  583. self.assertEqual(user.first_name, 'Alice')
  584. self.assertEqual(user.last_name, 'Adams')
  585. self.assertEqual(user.email, '')
  586. @override_settings(AUTH_USER_MODEL='tests.TestUser')
  587. def test_authenticate_with_buggy_setter_raises_exception(self):
  588. self._init_settings(
  589. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  590. USER_ATTR_MAP={
  591. 'first_name': 'givenName',
  592. 'uid_number': 'uidNumber',
  593. },
  594. )
  595. with self.assertRaisesMessage(Exception, 'Oops...'):
  596. self.backend.authenticate(username='alice', password='password')
  597. @override_settings(AUTH_USER_MODEL='tests.TestUser')
  598. def test_populate_user_with_buggy_setter_raises_exception(self):
  599. self._init_settings(
  600. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  601. USER_ATTR_MAP={
  602. 'first_name': 'givenName',
  603. 'uid_number': 'uidNumber',
  604. },
  605. )
  606. with self.assertRaisesMessage(Exception, 'Oops...'):
  607. self.backend.populate_user('alice')
  608. def test_populate_with_attrlist(self):
  609. self._init_settings(
  610. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  611. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'},
  612. USER_ATTRLIST=['*', '+'],
  613. )
  614. user = self.backend.authenticate(username='alice', password='password')
  615. self.assertEqual(user.username, 'alice')
  616. # init, bind as user, bind anonymous, lookup user attrs
  617. self.assertEqual(
  618. self.ldapobj.methods_called(),
  619. ['initialize', 'simple_bind_s', 'simple_bind_s', 'search_s']
  620. )
  621. self.assertEqual(
  622. self.ldapobj.methods_called(with_args=True)[3],
  623. ('search_s', ('uid=alice,ou=people,o=test', ldap.SCOPE_BASE, '(objectClass=*)', ['*', '+']), {})
  624. )
  625. def test_bind_as_user(self):
  626. self._init_settings(
  627. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  628. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'},
  629. BIND_AS_AUTHENTICATING_USER=True,
  630. )
  631. user = self.backend.authenticate(username='alice', password='password')
  632. self.assertEqual(user.username, 'alice')
  633. self.assertEqual(user.first_name, 'Alice')
  634. self.assertEqual(user.last_name, 'Adams')
  635. # init, bind as user, lookup user attrs
  636. self.assertEqual(
  637. self.ldapobj.methods_called(),
  638. ['initialize', 'simple_bind_s', 'search_s']
  639. )
  640. def test_signal_populate_user(self):
  641. self._init_settings(
  642. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test'
  643. )
  644. def handle_populate_user(sender, **kwargs):
  645. self.assertIn('user', kwargs)
  646. self.assertIn('ldap_user', kwargs)
  647. kwargs['user'].populate_user_handled = True
  648. backend.populate_user.connect(handle_populate_user)
  649. user = self.backend.authenticate(username='alice', password='password')
  650. self.assertTrue(user.populate_user_handled)
  651. backend.populate_user.disconnect(handle_populate_user)
  652. def test_auth_signal_ldap_error(self):
  653. self._init_settings(
  654. BIND_DN='uid=bob,ou=people,o=test',
  655. BIND_PASSWORD='bogus',
  656. USER_SEARCH=LDAPSearch(
  657. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  658. )
  659. )
  660. def handle_ldap_error(sender, **kwargs):
  661. self.assertEqual(kwargs['context'], 'authenticate')
  662. raise kwargs['exception']
  663. backend.ldap_error.connect(handle_ldap_error)
  664. with self.assertRaises(ldap.LDAPError):
  665. self.backend.authenticate(username='alice', password='password')
  666. backend.ldap_error.disconnect(handle_ldap_error)
  667. def test_populate_signal_ldap_error(self):
  668. self._init_settings(
  669. BIND_DN='uid=bob,ou=people,o=test',
  670. BIND_PASSWORD='bogus',
  671. USER_SEARCH=LDAPSearch(
  672. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  673. )
  674. )
  675. user = self.backend.populate_user('alice')
  676. self.assertIsNone(user)
  677. def test_no_update_existing(self):
  678. self._init_settings(
  679. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  680. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'},
  681. ALWAYS_UPDATE_USER=False
  682. )
  683. User.objects.create(username='alice', first_name='Alicia', last_name='Astro')
  684. alice = self.backend.authenticate(username='alice', password='password')
  685. bob = self.backend.authenticate(username='bob', password='password')
  686. self.assertEqual(alice.first_name, 'Alicia')
  687. self.assertEqual(alice.last_name, 'Astro')
  688. self.assertEqual(bob.first_name, 'Robert')
  689. self.assertEqual(bob.last_name, 'Barker')
  690. def test_require_group(self):
  691. self._init_settings(
  692. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  693. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  694. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  695. REQUIRE_GROUP="cn=active_gon,ou=groups,o=test"
  696. )
  697. alice = self.backend.authenticate(username='alice', password='password')
  698. bob = self.backend.authenticate(username='bob', password='password')
  699. self.assertIsNotNone(alice)
  700. self.assertIsNone(bob)
  701. self.assertEqual(
  702. self.ldapobj.methods_called(),
  703. ['initialize', 'simple_bind_s', 'simple_bind_s', 'compare_s',
  704. 'initialize', 'simple_bind_s', 'simple_bind_s', 'compare_s']
  705. )
  706. def test_simple_group_query(self):
  707. self._init_settings(
  708. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  709. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  710. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  711. )
  712. alice = self.backend.authenticate(username='alice', password='password')
  713. query = LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test')
  714. self.assertTrue(query.resolve(alice.ldap_user))
  715. def test_negated_group_query(self):
  716. self._init_settings(
  717. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  718. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  719. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  720. )
  721. alice = self.backend.authenticate(username='alice', password='password')
  722. query = ~LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test')
  723. self.assertFalse(query.resolve(alice.ldap_user))
  724. def test_or_group_query(self):
  725. self._init_settings(
  726. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  727. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  728. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  729. )
  730. alice = self.backend.authenticate(username='alice', password='password')
  731. bob = self.backend.authenticate(username='bob', password='password')
  732. query = (
  733. LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test') |
  734. LDAPGroupQuery('cn=bob_gon,ou=query_groups,o=test')
  735. )
  736. self.assertTrue(query.resolve(alice.ldap_user))
  737. self.assertTrue(query.resolve(bob.ldap_user))
  738. def test_and_group_query(self):
  739. self._init_settings(
  740. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  741. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  742. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  743. )
  744. alice = self.backend.authenticate(username='alice', password='password')
  745. bob = self.backend.authenticate(username='bob', password='password')
  746. query = (
  747. LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test') &
  748. LDAPGroupQuery('cn=mutual_gon,ou=query_groups,o=test')
  749. )
  750. self.assertTrue(query.resolve(alice.ldap_user))
  751. self.assertFalse(query.resolve(bob.ldap_user))
  752. def test_nested_group_query(self):
  753. self._init_settings(
  754. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  755. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  756. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  757. )
  758. alice = self.backend.authenticate(username='alice', password='password')
  759. bob = self.backend.authenticate(username='bob', password='password')
  760. query = (
  761. (
  762. LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test') &
  763. LDAPGroupQuery('cn=mutual_gon,ou=query_groups,o=test')
  764. ) |
  765. LDAPGroupQuery('cn=bob_gon,ou=query_groups,o=test')
  766. )
  767. self.assertTrue(query.resolve(alice.ldap_user))
  768. self.assertTrue(query.resolve(bob.ldap_user))
  769. def test_require_group_as_group_query(self):
  770. query = (
  771. LDAPGroupQuery('cn=alice_gon,ou=query_groups,o=test') &
  772. LDAPGroupQuery('cn=mutual_gon,ou=query_groups,o=test')
  773. )
  774. self._init_settings(
  775. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  776. GROUP_SEARCH=LDAPSearch('ou=query_groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  777. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  778. REQUIRE_GROUP=query
  779. )
  780. alice = self.backend.authenticate(username='alice', password='password')
  781. bob = self.backend.authenticate(username='bob', password='password')
  782. self.assertIsNotNone(alice)
  783. self.assertIsNone(bob)
  784. def test_group_union(self):
  785. self._init_settings(
  786. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  787. GROUP_SEARCH=LDAPSearchUnion(
  788. LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  789. LDAPSearch('ou=moregroups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)')
  790. ),
  791. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  792. REQUIRE_GROUP="cn=other_gon,ou=moregroups,o=test"
  793. )
  794. alice = self.backend.authenticate(username='alice', password='password')
  795. bob = self.backend.authenticate(username='bob', password='password')
  796. self.assertIsNone(alice)
  797. self.assertIsNotNone(bob)
  798. self.assertEqual(bob.ldap_user.group_names, {'other_gon'})
  799. def test_nested_group_union(self):
  800. self._init_settings(
  801. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  802. GROUP_SEARCH=LDAPSearchUnion(
  803. LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)'),
  804. LDAPSearch('ou=moregroups,o=test', ldap.SCOPE_SUBTREE, '(objectClass=groupOfNames)')
  805. ),
  806. GROUP_TYPE=NestedMemberDNGroupType(member_attr='member'),
  807. REQUIRE_GROUP="cn=other_gon,ou=moregroups,o=test"
  808. )
  809. alice = self.backend.authenticate(username='alice', password='password')
  810. bob = self.backend.authenticate(username='bob', password='password')
  811. self.assertIsNone(alice)
  812. self.assertIsNotNone(bob)
  813. self.assertEqual(bob.ldap_user.group_names, {'other_gon'})
  814. def test_denied_group(self):
  815. self._init_settings(
  816. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  817. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  818. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  819. DENY_GROUP="cn=active_gon,ou=groups,o=test"
  820. )
  821. alice = self.backend.authenticate(username='alice', password='password')
  822. bob = self.backend.authenticate(username='bob', password='password')
  823. self.assertIsNone(alice)
  824. self.assertIsNotNone(bob)
  825. self.assertEqual(
  826. self.ldapobj.methods_called(),
  827. ['initialize', 'simple_bind_s', 'simple_bind_s', 'compare_s',
  828. 'initialize', 'simple_bind_s', 'simple_bind_s', 'compare_s']
  829. )
  830. def test_group_dns(self):
  831. self._init_settings(
  832. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  833. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  834. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  835. )
  836. alice = self.backend.authenticate(username='alice', password='password')
  837. self.assertEqual(
  838. alice.ldap_user.group_dns,
  839. {g[0].lower() for g in [self.active_gon, self.staff_gon, self.superuser_gon, self.nested_gon]}
  840. )
  841. def test_group_names(self):
  842. self._init_settings(
  843. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  844. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  845. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  846. )
  847. alice = self.backend.authenticate(username='alice', password='password')
  848. self.assertEqual(alice.ldap_user.group_names, {'active_gon', 'staff_gon', 'superuser_gon', 'nested_gon'})
  849. def test_dn_group_membership(self):
  850. self._init_settings(
  851. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  852. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  853. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  854. USER_FLAGS_BY_GROUP={
  855. 'is_active': LDAPGroupQuery("cn=active_gon,ou=groups,o=test"),
  856. 'is_staff': ["cn=empty_gon,ou=groups,o=test",
  857. "cn=staff_gon,ou=groups,o=test"],
  858. 'is_superuser': "cn=superuser_gon,ou=groups,o=test"
  859. }
  860. )
  861. alice = self.backend.authenticate(username='alice', password='password')
  862. bob = self.backend.authenticate(username='bob', password='password')
  863. self.assertTrue(alice.is_active)
  864. self.assertTrue(alice.is_staff)
  865. self.assertTrue(alice.is_superuser)
  866. self.assertFalse(bob.is_active)
  867. self.assertFalse(bob.is_staff)
  868. self.assertFalse(bob.is_superuser)
  869. def test_user_flags_misconfigured(self):
  870. self._init_settings(
  871. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  872. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  873. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  874. USER_FLAGS_BY_GROUP={
  875. 'is_active': LDAPGroupQuery("cn=active_gon,ou=groups,o=test"),
  876. 'is_staff': [],
  877. 'is_superuser': "cn=superuser_gon,ou=groups,o=test"
  878. }
  879. )
  880. with self.assertRaises(ImproperlyConfigured):
  881. self.backend.authenticate(username='alice', password='password')
  882. def test_posix_membership(self):
  883. self._init_settings(
  884. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  885. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  886. GROUP_TYPE=PosixGroupType(),
  887. USER_FLAGS_BY_GROUP={
  888. 'is_active': "cn=active_px,ou=groups,o=test",
  889. 'is_staff': "cn=staff_px,ou=groups,o=test",
  890. 'is_superuser': "cn=superuser_px,ou=groups,o=test"
  891. }
  892. )
  893. alice = self.backend.authenticate(username='alice', password='password')
  894. bob = self.backend.authenticate(username='bob', password='password')
  895. self.assertTrue(alice.is_active)
  896. self.assertTrue(alice.is_staff)
  897. self.assertTrue(alice.is_superuser)
  898. self.assertFalse(bob.is_active)
  899. self.assertFalse(bob.is_staff)
  900. self.assertFalse(bob.is_superuser)
  901. def test_nis_membership(self):
  902. self._init_settings(
  903. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  904. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  905. GROUP_TYPE=NISGroupType(),
  906. USER_FLAGS_BY_GROUP={
  907. 'is_active': "cn=active_nis,ou=groups,o=test",
  908. 'is_staff': "cn=staff_nis,ou=groups,o=test",
  909. 'is_superuser': "cn=superuser_nis,ou=groups,o=test"
  910. }
  911. )
  912. alice = self.backend.authenticate(username='alice', password='password')
  913. bob = self.backend.authenticate(username='bob', password='password')
  914. self.assertTrue(alice.is_active)
  915. self.assertTrue(alice.is_staff)
  916. self.assertTrue(alice.is_superuser)
  917. self.assertFalse(bob.is_active)
  918. self.assertFalse(bob.is_staff)
  919. self.assertFalse(bob.is_superuser)
  920. def test_nested_dn_group_membership(self):
  921. self._init_settings(
  922. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  923. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  924. GROUP_TYPE=NestedMemberDNGroupType(member_attr='member'),
  925. USER_FLAGS_BY_GROUP={
  926. 'is_active': "cn=parent_gon,ou=groups,o=test",
  927. 'is_staff': "cn=parent_gon,ou=groups,o=test",
  928. }
  929. )
  930. alice = self.backend.authenticate(username='alice', password='password')
  931. bob = self.backend.authenticate(username='bob', password='password')
  932. self.assertTrue(alice.is_active)
  933. self.assertTrue(alice.is_staff)
  934. self.assertFalse(bob.is_active)
  935. self.assertFalse(bob.is_staff)
  936. def test_posix_missing_attributes(self):
  937. self._init_settings(
  938. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  939. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  940. GROUP_TYPE=PosixGroupType(),
  941. USER_FLAGS_BY_GROUP={
  942. 'is_active': "cn=active_px,ou=groups,o=test"
  943. }
  944. )
  945. nobody = self.backend.authenticate(username='nobody', password='password')
  946. self.assertFalse(nobody.is_active)
  947. def test_dn_group_permissions(self):
  948. self._init_settings(
  949. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  950. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  951. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  952. FIND_GROUP_PERMS=True
  953. )
  954. self._init_groups()
  955. alice = User.objects.create(username='alice')
  956. alice = self.backend.get_user(alice.pk)
  957. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  958. self.assertEqual(self.backend.get_all_permissions(alice), {"auth.add_user", "auth.change_user"})
  959. self.assertTrue(self.backend.has_perm(alice, "auth.add_user"))
  960. self.assertTrue(self.backend.has_module_perms(alice, "auth"))
  961. def test_group_permissions_ldap_error(self):
  962. self._init_settings(
  963. BIND_DN='uid=bob,ou=people,o=test',
  964. BIND_PASSWORD='bogus',
  965. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  966. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  967. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  968. FIND_GROUP_PERMS=True
  969. )
  970. self._init_groups()
  971. alice = User.objects.create(username='alice')
  972. alice = self.backend.get_user(alice.pk)
  973. self.assertEqual(self.backend.get_group_permissions(alice), set())
  974. def test_empty_group_permissions(self):
  975. self._init_settings(
  976. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  977. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  978. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  979. FIND_GROUP_PERMS=True
  980. )
  981. self._init_groups()
  982. bob = User.objects.create(username='bob')
  983. bob = self.backend.get_user(bob.pk)
  984. self.assertEqual(self.backend.get_group_permissions(bob), set())
  985. self.assertEqual(self.backend.get_all_permissions(bob), set())
  986. self.assertFalse(self.backend.has_perm(bob, "auth.add_user"))
  987. self.assertFalse(self.backend.has_module_perms(bob, "auth"))
  988. def test_posix_group_permissions(self):
  989. self._init_settings(
  990. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  991. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE,
  992. '(objectClass=posixGroup)'),
  993. GROUP_TYPE=PosixGroupType(),
  994. FIND_GROUP_PERMS=True
  995. )
  996. self._init_groups()
  997. alice = User.objects.create(username='alice')
  998. alice = self.backend.get_user(alice.pk)
  999. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  1000. self.assertEqual(self.backend.get_all_permissions(alice), {"auth.add_user", "auth.change_user"})
  1001. self.assertTrue(self.backend.has_perm(alice, "auth.add_user"))
  1002. self.assertTrue(self.backend.has_module_perms(alice, "auth"))
  1003. def test_posix_group_permissions_no_gid(self):
  1004. self._init_settings(
  1005. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1006. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE,
  1007. '(objectClass=posixGroup)'),
  1008. GROUP_TYPE=PosixGroupType(),
  1009. FIND_GROUP_PERMS=True
  1010. )
  1011. self._init_groups()
  1012. self.ldapobj.modify_s(self.alice[0], [(ldap.MOD_DELETE, 'gidNumber', None)])
  1013. self.ldapobj.modify_s(self.active_px[0], [(ldap.MOD_ADD, 'memberUid', ['alice'])])
  1014. alice = User.objects.create(username='alice')
  1015. alice = self.backend.get_user(alice.pk)
  1016. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  1017. self.assertEqual(self.backend.get_all_permissions(alice), {"auth.add_user", "auth.change_user"})
  1018. self.assertTrue(self.backend.has_perm(alice, "auth.add_user"))
  1019. self.assertTrue(self.backend.has_module_perms(alice, "auth"))
  1020. def test_nis_group_permissions(self):
  1021. self._init_settings(
  1022. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1023. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE,
  1024. '(objectClass=nisNetgroup)'),
  1025. GROUP_TYPE=NISGroupType(),
  1026. FIND_GROUP_PERMS=True
  1027. )
  1028. self._init_groups()
  1029. alice = User.objects.create(username='alice')
  1030. alice = self.backend.get_user(alice.pk)
  1031. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  1032. self.assertEqual(self.backend.get_all_permissions(alice), {"auth.add_user", "auth.change_user"})
  1033. self.assertTrue(self.backend.has_perm(alice, "auth.add_user"))
  1034. self.assertTrue(self.backend.has_module_perms(alice, "auth"))
  1035. def test_foreign_user_permissions(self):
  1036. self._init_settings(
  1037. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1038. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1039. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  1040. FIND_GROUP_PERMS=True
  1041. )
  1042. self._init_groups()
  1043. alice = User.objects.create(username='alice')
  1044. self.assertEqual(self.backend.get_group_permissions(alice), set())
  1045. def test_group_cache(self):
  1046. self._init_settings(
  1047. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1048. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1049. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  1050. FIND_GROUP_PERMS=True,
  1051. CACHE_GROUPS=True
  1052. )
  1053. self._init_groups()
  1054. alice_id = User.objects.create(username='alice').pk
  1055. bob_id = User.objects.create(username='bob').pk
  1056. # Check permissions twice for each user
  1057. for i in range(2):
  1058. alice = self.backend.get_user(alice_id)
  1059. self.assertEqual(
  1060. self.backend.get_group_permissions(alice),
  1061. {"auth.add_user", "auth.change_user"}
  1062. )
  1063. bob = self.backend.get_user(bob_id)
  1064. self.assertEqual(self.backend.get_group_permissions(bob), set())
  1065. # Should have executed one LDAP search per user
  1066. self.assertEqual(
  1067. self.ldapobj.methods_called(),
  1068. ['initialize', 'simple_bind_s', 'search_s',
  1069. 'initialize', 'simple_bind_s', 'search_s']
  1070. )
  1071. def test_group_mirroring(self):
  1072. self._init_settings(
  1073. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1074. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE,
  1075. '(objectClass=posixGroup)'),
  1076. GROUP_TYPE=PosixGroupType(),
  1077. MIRROR_GROUPS=True,
  1078. )
  1079. self.assertEqual(Group.objects.count(), 0)
  1080. alice = self.backend.authenticate(username='alice', password='password')
  1081. self.assertEqual(Group.objects.count(), 3)
  1082. self.assertEqual(set(alice.groups.all()), set(Group.objects.all()))
  1083. def test_nested_group_mirroring(self):
  1084. self._init_settings(
  1085. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1086. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE,
  1087. '(objectClass=groupOfNames)'),
  1088. GROUP_TYPE=NestedMemberDNGroupType(member_attr='member'),
  1089. MIRROR_GROUPS=True,
  1090. )
  1091. alice = self.backend.authenticate(username='alice', password='password')
  1092. self.assertEqual(
  1093. set(Group.objects.all().values_list('name', flat=True)),
  1094. {'active_gon', 'staff_gon', 'superuser_gon', 'nested_gon',
  1095. 'parent_gon', 'circular_gon'}
  1096. )
  1097. self.assertEqual(set(alice.groups.all()), set(Group.objects.all()))
  1098. #
  1099. # When selectively mirroring groups, there are eight scenarios for any
  1100. # given user/group pair:
  1101. #
  1102. # (is-member-in-LDAP, not-member-in-LDAP)
  1103. # x (is-member-in-Django, not-member-in-Django)
  1104. # x (synced, not-synced)
  1105. #
  1106. # The four test cases below take these scenarios four at a time for each of
  1107. # the two settings.
  1108. def test_group_mirroring_whitelist_update(self):
  1109. self._init_settings(
  1110. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1111. GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
  1112. '(objectClass=groupOfNames)'),
  1113. GROUP_TYPE=GroupOfNamesType(),
  1114. MIRROR_GROUPS=['mirror1', 'mirror2']
  1115. )
  1116. groups = {}
  1117. for name in ('mirror{}'.format(i) for i in range(1, 5)):
  1118. groups[name] = Group.objects.create(name=name)
  1119. alice = self.backend.populate_user('alice')
  1120. if django.VERSION < (1, 11):
  1121. alice.groups = [groups['mirror2'], groups['mirror4']]
  1122. else:
  1123. alice.groups.set([groups['mirror2'], groups['mirror4']])
  1124. alice = self.backend.authenticate(username='alice', password='password')
  1125. self.assertEqual(
  1126. set(alice.groups.values_list("name", flat=True)),
  1127. {'mirror1', 'mirror4'}
  1128. )
  1129. def test_group_mirroring_whitelist_noop(self):
  1130. self._init_settings(
  1131. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1132. GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
  1133. '(objectClass=groupOfNames)'),
  1134. GROUP_TYPE=GroupOfNamesType(),
  1135. MIRROR_GROUPS=['mirror1', 'mirror2']
  1136. )
  1137. groups = {}
  1138. for name in ('mirror{}'.format(i) for i in range(1, 5)):
  1139. groups[name] = Group.objects.create(name=name)
  1140. alice = self.backend.populate_user('alice')
  1141. if django.VERSION < (1, 11):
  1142. alice.groups = [groups['mirror1'], groups['mirror3']]
  1143. else:
  1144. alice.groups.set([groups['mirror1'], groups['mirror3']])
  1145. alice = self.backend.authenticate(username='alice', password='password')
  1146. self.assertEqual(
  1147. set(alice.groups.values_list("name", flat=True)),
  1148. {'mirror1', 'mirror3'}
  1149. )
  1150. def test_group_mirroring_blacklist_update(self):
  1151. self._init_settings(
  1152. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1153. GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
  1154. '(objectClass=groupOfNames)'),
  1155. GROUP_TYPE=GroupOfNamesType(),
  1156. MIRROR_GROUPS_EXCEPT=['mirror1', 'mirror2']
  1157. )
  1158. groups = {}
  1159. for name in ('mirror{}'.format(i) for i in range(1, 5)):
  1160. groups[name] = Group.objects.create(name=name)
  1161. alice = self.backend.populate_user('alice')
  1162. if django.VERSION < (1, 11):
  1163. alice.groups = [groups['mirror2'], groups['mirror4']]
  1164. else:
  1165. alice.groups.set([groups['mirror2'], groups['mirror4']])
  1166. alice = self.backend.authenticate(username='alice', password='password')
  1167. self.assertEqual(
  1168. set(alice.groups.values_list("name", flat=True)),
  1169. {'mirror2', 'mirror3'}
  1170. )
  1171. def test_group_mirroring_blacklist_noop(self):
  1172. self._init_settings(
  1173. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1174. GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
  1175. '(objectClass=groupOfNames)'),
  1176. GROUP_TYPE=GroupOfNamesType(),
  1177. MIRROR_GROUPS_EXCEPT=['mirror1', 'mirror2']
  1178. )
  1179. groups = {}
  1180. for name in ('mirror{}'.format(i) for i in range(1, 5)):
  1181. groups[name] = Group.objects.create(name=name)
  1182. alice = self.backend.populate_user('alice')
  1183. if django.VERSION < (1, 11):
  1184. alice.groups = [groups['mirror1'], groups['mirror3']]
  1185. else:
  1186. alice.groups.set([groups['mirror1'], groups['mirror3']])
  1187. alice = self.backend.authenticate(username='alice', password='password')
  1188. self.assertEqual(
  1189. set(alice.groups.values_list("name", flat=True)),
  1190. {'mirror1', 'mirror3'}
  1191. )
  1192. def test_authorize_external_users(self):
  1193. self._init_settings(
  1194. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1195. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1196. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  1197. FIND_GROUP_PERMS=True,
  1198. AUTHORIZE_ALL_USERS=True
  1199. )
  1200. self._init_groups()
  1201. alice = User.objects.create(username='alice')
  1202. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  1203. def test_authorize_external_unknown(self):
  1204. self._init_settings(
  1205. USER_SEARCH=LDAPSearch(
  1206. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  1207. ),
  1208. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1209. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  1210. FIND_GROUP_PERMS=True,
  1211. AUTHORIZE_ALL_USERS=True
  1212. )
  1213. self._init_groups()
  1214. alice = User.objects.create(username='not-in-ldap')
  1215. self.assertEqual(self.backend.get_group_permissions(alice), set())
  1216. def test_create_without_auth(self):
  1217. self._init_settings(
  1218. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1219. )
  1220. alice = self.backend.populate_user('alice')
  1221. bob = self.backend.populate_user('bob')
  1222. self.assertIsNotNone(alice)
  1223. self.assertEqual(alice.first_name, "")
  1224. self.assertEqual(alice.last_name, "")
  1225. self.assertTrue(alice.is_active)
  1226. self.assertFalse(alice.is_staff)
  1227. self.assertFalse(alice.is_superuser)
  1228. self.assertIsNotNone(bob)
  1229. self.assertEqual(bob.first_name, "")
  1230. self.assertEqual(bob.last_name, "")
  1231. self.assertTrue(bob.is_active)
  1232. self.assertFalse(bob.is_staff)
  1233. self.assertFalse(bob.is_superuser)
  1234. def test_populate_without_auth(self):
  1235. self._init_settings(
  1236. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1237. ALWAYS_UPDATE_USER=False,
  1238. USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'},
  1239. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1240. GROUP_TYPE=GroupOfNamesType(),
  1241. USER_FLAGS_BY_GROUP={
  1242. 'is_active': "cn=active_gon,ou=groups,o=test",
  1243. 'is_staff': "cn=staff_gon,ou=groups,o=test",
  1244. 'is_superuser': "cn=superuser_gon,ou=groups,o=test"
  1245. }
  1246. )
  1247. User.objects.create(username='alice')
  1248. User.objects.create(username='bob')
  1249. alice = self.backend.populate_user('alice')
  1250. bob = self.backend.populate_user('bob')
  1251. self.assertIsNotNone(alice)
  1252. self.assertEqual(alice.first_name, "Alice")
  1253. self.assertEqual(alice.last_name, "Adams")
  1254. self.assertTrue(alice.is_active)
  1255. self.assertTrue(alice.is_staff)
  1256. self.assertTrue(alice.is_superuser)
  1257. self.assertIsNotNone(bob)
  1258. self.assertEqual(bob.first_name, "Robert")
  1259. self.assertEqual(bob.last_name, "Barker")
  1260. self.assertFalse(bob.is_active)
  1261. self.assertFalse(bob.is_staff)
  1262. self.assertFalse(bob.is_superuser)
  1263. def test_populate_bogus_user(self):
  1264. self._init_settings(
  1265. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1266. )
  1267. bogus = self.backend.populate_user('bogus')
  1268. self.assertIsNone(bogus)
  1269. def test_start_tls_missing(self):
  1270. self._init_settings(
  1271. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1272. START_TLS=False,
  1273. )
  1274. self.assertFalse(self.ldapobj.tls_enabled)
  1275. self.backend.authenticate(username='alice', password='password')
  1276. self.assertFalse(self.ldapobj.tls_enabled)
  1277. def test_start_tls(self):
  1278. self._init_settings(
  1279. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1280. START_TLS=True,
  1281. )
  1282. self.assertFalse(self.ldapobj.tls_enabled)
  1283. self.backend.authenticate(username='alice', password='password')
  1284. self.assertTrue(self.ldapobj.tls_enabled)
  1285. def test_null_search_results(self):
  1286. """
  1287. Make sure we're not phased by referrals.
  1288. """
  1289. self._init_settings(
  1290. USER_SEARCH=LDAPSearch(
  1291. "ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'
  1292. )
  1293. )
  1294. self.backend.authenticate(username='alice', password='password')
  1295. def test_union_search(self):
  1296. self._init_settings(
  1297. USER_SEARCH=LDAPSearchUnion(
  1298. LDAPSearch("ou=groups,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'),
  1299. LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'),
  1300. )
  1301. )
  1302. alice = self.backend.authenticate(username='alice', password='password')
  1303. self.assertIsNotNone(alice)
  1304. self.assertEqual(
  1305. self.ldapobj.methods_called(),
  1306. ['initialize', 'simple_bind_s', 'search', 'search', 'result',
  1307. 'result', 'simple_bind_s']
  1308. )
  1309. def test_deny_empty_password(self):
  1310. self._init_settings(
  1311. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1312. )
  1313. alice = self.backend.authenticate(username='alice', password='')
  1314. self.assertIsNone(alice)
  1315. self.assertEqual(self.ldapobj.methods_called(), [])
  1316. def test_permit_empty_password(self):
  1317. self._init_settings(
  1318. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1319. PERMIT_EMPTY_PASSWORD=True,
  1320. )
  1321. alice = self.backend.authenticate(username='alice', password='')
  1322. self.assertIsNone(alice)
  1323. self.assertEqual(
  1324. self.ldapobj.methods_called(),
  1325. ['initialize', 'simple_bind_s']
  1326. )
  1327. def test_permit_null_password(self):
  1328. self._init_settings(
  1329. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1330. PERMIT_EMPTY_PASSWORD=True,
  1331. )
  1332. alice = self.backend.authenticate(username='alice', password=None)
  1333. self.assertIsNone(alice)
  1334. self.assertEqual(
  1335. self.ldapobj.methods_called(),
  1336. ['initialize', 'simple_bind_s']
  1337. )
  1338. def test_pickle(self):
  1339. self._init_settings(
  1340. USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
  1341. GROUP_SEARCH=LDAPSearch('ou=groups,o=test', ldap.SCOPE_SUBTREE),
  1342. GROUP_TYPE=MemberDNGroupType(member_attr='member'),
  1343. FIND_GROUP_PERMS=True
  1344. )
  1345. self._init_groups()
  1346. alice0 = self.backend.authenticate(username='alice', password='password')
  1347. pickled = pickle.dumps(alice0, pickle.HIGHEST_PROTOCOL)
  1348. alice = pickle.loads(pickled)
  1349. alice.ldap_user.backend.settings = alice0.ldap_user.backend.settings
  1350. self.assertIsNotNone(alice)
  1351. self.assertEqual(self.backend.get_group_permissions(alice), {"auth.add_user", "auth.change_user"})
  1352. self.assertEqual(self.backend.get_all_permissions(alice), {"auth.add_user", "auth.change_user"})
  1353. self.assertTrue(self.backend.has_perm(alice, "auth.add_user"))
  1354. self.assertTrue(self.backend.has_module_perms(alice, "auth"))
  1355. def test_search_attrlist(self):
  1356. search = LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=alice)', ['*', '+'])
  1357. search.execute(self.ldapobj)
  1358. self.assertEqual(
  1359. self.ldapobj.methods_called(with_args=True),
  1360. [('search_s', ('ou=people,o=test', ldap.SCOPE_SUBTREE, '(uid=alice)', ['*', '+']), {})]
  1361. )
  1362. def test_get_or_create_user_deprecated(self):
  1363. class MyBackend(backend.LDAPBackend):
  1364. def get_or_create_user(self, username, ldap_user):
  1365. return super(MyBackend, self).get_or_create_user(username, ldap_user)
  1366. self.backend = MyBackend()
  1367. self._init_settings(USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test')
  1368. with warnings.catch_warnings(record=True) as w:
  1369. warnings.simplefilter('always')
  1370. self.backend.authenticate(username='alice', password='password')
  1371. self.assertEqual(len(w), 1)
  1372. self.assertEqual(w[0].category, DeprecationWarning)
  1373. def test_custom_backend_without_get_or_create_no_warning(self):
  1374. class MyBackend(backend.LDAPBackend):
  1375. pass
  1376. self.backend = MyBackend()
  1377. self._init_settings(USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test')
  1378. with warnings.catch_warnings(record=True) as w:
  1379. warnings.simplefilter('always')
  1380. self.backend.authenticate(username='alice', password='password')
  1381. self.assertEqual(len(w), 0)
  1382. def test_override_authenticate_access_ldap_user(self):
  1383. class MyBackend(backend.LDAPBackend):
  1384. def authenticate_ldap_user(self, ldap_user, password):
  1385. ldap_user.foo = 'bar'
  1386. return super(MyBackend, self).authenticate_ldap_user(ldap_user, password)
  1387. self.backend = MyBackend()
  1388. self._init_settings(USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test')
  1389. user = self.backend.authenticate(username='alice', password='password')
  1390. self.assertEqual(user.ldap_user.foo, 'bar')
  1391. #
  1392. # Utilities
  1393. #
  1394. def _init_settings(self, **kwargs):
  1395. self.backend.settings = TestSettings(**kwargs)
  1396. def _init_groups(self):
  1397. permissions = [
  1398. Permission.objects.get(codename="add_user"),
  1399. Permission.objects.get(codename="change_user")
  1400. ]
  1401. active_gon = Group.objects.create(name='active_gon')
  1402. active_gon.permissions.add(*permissions)
  1403. active_px = Group.objects.create(name='active_px')
  1404. active_px.permissions.add(*permissions)
  1405. active_nis = Group.objects.create(name='active_nis')
  1406. active_nis.permissions.add(*permissions)