0001-WIP-ldap_backend-fix-encoding-errors-during-user-syn.patch
src/authentic2/backends/ldap_backend.py | ||
---|---|---|
319 | 319 |
# First get our configuration into a standard format |
320 | 320 |
for block in blocks: |
321 | 321 |
cls.update_default(block) |
322 |
# python-ldap needs UTF-8 encoded strings |
|
323 |
if isinstance(block.get('base_dn'), unicode): |
|
324 |
block['base_dn'] = block['base_dn'].encode('utf-8') |
|
322 | 325 |
log.debug('got config %r', blocks) |
323 | 326 |
return blocks |
324 | 327 | |
... | ... | |
349 | 352 |
utf8_username = smart_bytes(username) |
350 | 353 |
utf8_password = smart_bytes(password) |
351 | 354 | |
355 |
# python-ldap needs UTF-8 encoded strings |
|
356 |
for dn_subelement in ('basedn', 'user_basedn', 'user_dn_template'): |
|
357 |
if isinstance(block.get(dn_subelement), unicode): |
|
358 |
block[dn_sublement] = block[dn_subelement].encode('utf-8') |
|
359 | ||
352 | 360 |
for conn in self.get_connections(block): |
353 | 361 |
authz_ids = [] |
354 | 362 |
user_basedn = block.get('user_basedn') or block['basedn'] |
... | ... | |
522 | 530 |
'''Retrieve group DNs from the LDAP by attributes (memberOf) or by |
523 | 531 |
filter. |
524 | 532 |
''' |
533 |
# python-ldap needs UTF-8 encoded strings |
|
534 |
if isinstance(block.get('group_base_dn'), unicode): |
|
535 |
block['group_base_dn'] = block['group_base_dn'].encode('utf-8') |
|
525 | 536 |
group_base_dn = block.get('group_basedn', block['basedn']) |
526 | 537 |
member_of_attribute = block['member_of_attribute'] |
527 | 538 |
group_filter = block['group_filter'] |
... | ... | |
535 | 546 |
params = attributes.copy() |
536 | 547 |
params['user_dn'] = dn |
537 | 548 |
query = FilterFormatter().format(group_filter, **params) |
549 |
if isinstance(query, unicode): |
|
550 |
query = query.encode('utf-8') |
|
538 | 551 |
try: |
539 | 552 |
results = conn.search_s(group_base_dn, ldap.SCOPE_SUBTREE, query, []) |
540 | 553 |
except ldap.NO_SUCH_OBJECT: |
... | ... | |
840 | 853 |
if conn is None: |
841 | 854 |
logger.warning(u'unable to synchronize with LDAP servers %r', block['url']) |
842 | 855 |
continue |
856 |
# python-ldap needs UTF-8 encoded strings. |
|
857 |
if isinstance(block.get('user_basedn'), unicode): |
|
858 |
block['user_basedn'] = block['user_basedn'].encode('utf-8') |
|
843 | 859 |
user_basedn = block.get('user_basedn') or block['basedn'] |
844 | 860 |
user_filter = block['sync_ldap_users_filter'] or block['user_filter'] |
845 | 861 |
user_filter = user_filter.replace('%s', '*') |
... | ... | |
950 | 966 |
auth = handler_class(*sasl_params) |
951 | 967 |
conn.sasl_interactive_bind_s(who, auth) |
952 | 968 |
elif block['binddn'] and block['bindpw']: |
969 |
# python-ldap needs UTF-8 encoded strings |
|
970 |
if isinstance(block.get('binddn'), unicode): |
|
971 |
block['binddn'] = block['binddn'].encode('utf-8') |
|
953 | 972 |
conn.bind_s(block['binddn'], block['bindpw']) |
954 | 973 |
yield conn |
955 | 974 |
except ldap.INVALID_CREDENTIALS: |
... | ... | |
1072 | 1091 |
results = conn.search_s(dn, ldap.SCOPE_BASE) |
1073 | 1092 |
else: |
1074 | 1093 |
ldap_filter = self.external_id_to_filter(external_id, external_id_tuple) |
1094 |
# python-ldap needs UTF-8 encoded strings |
|
1095 |
if isinstance(block.get('basedn'), unicode): |
|
1096 |
block['basedn'] = block['basedn'].encode('utf-8') |
|
1075 | 1097 |
results = conn.search_s(block['basedn'], |
1076 | 1098 |
ldap.SCOPE_SUBTREE, ldap_filter) |
1077 | 1099 |
if not results: |
tests/test_ldap.py | ||
---|---|---|
23 | 23 |
DN = 'cn=%s,o=orga' % escape_dn_chars(CN) |
24 | 24 |
PASS = 'passé' |
25 | 25 | |
26 |
USERNAME_ACCENTS = u'étienne.michü' |
|
27 |
UID_ACCENTS = 'étienne.michü' |
|
28 |
CN_ACCENTS = 'Étienne Michü' |
|
29 |
DN_ACCENTS = 'cn=%s,o=orga' % (escape_dn_chars(CN_ACCENTS)) |
|
30 | ||
26 | 31 | |
27 | 32 |
@pytest.fixture |
28 | 33 |
def slapd(request): |
... | ... | |
41 | 46 |
member: {dn} |
42 | 47 | |
43 | 48 |
'''.format(dn=DN, uid=UID, password=PASS)) |
49 |
result = slapd.add_ldif('''dn: {dn} |
|
50 |
objectClass: inetOrgPerson |
|
51 |
userPassword: {password} |
|
52 |
uid: {uid} |
|
53 |
cn: Étienne Michü |
|
54 |
sn: Michü |
|
55 |
gn: Étienne |
|
56 |
mail: emichu@example.net |
|
57 | ||
58 |
'''.format(dn=DN_ACCENTS, uid=UID_ACCENTS, password=PASS)) |
|
44 | 59 |
for i in range(100): |
45 | 60 |
slapd.add_ldif('''dn: uid=michu{i},o=orga |
46 | 61 |
objectClass: inetOrgPerson |
... | ... | |
101 | 116 | |
102 | 117 | |
103 | 118 |
@pytest.mark.django_db |
119 |
def test_accents_in_dn(slapd, settings, client): |
|
120 |
settings.LDAP_AUTH_SETTINGS = [{ |
|
121 |
'url': [slapd.ldap_url], |
|
122 |
'basedn': 'o=orga', |
|
123 |
'use_tls': False, |
|
124 |
}] |
|
125 |
result = client.post('/login/', {'login-password-submit': '1', |
|
126 |
'username': USERNAME_ACCENTS, |
|
127 |
'password': PASS}, follow=True) |
|
128 |
assert result.status_code == 200 |
|
129 |
assert u'Étienne Michü' in unicode(str(result), 'utf-8') |
|
130 |
User = get_user_model() |
|
131 |
assert User.objects.count() == 1 |
|
132 |
user = User.objects.get() |
|
133 |
assert user.username == u'%s@ldap' % USERNAME_ACCENTS |
|
134 |
assert user.first_name == u'Étienne' |
|
135 |
assert user.last_name == u'Michü' |
|
136 | ||
137 | ||
138 |
@pytest.mark.django_db |
|
104 | 139 |
def test_simple_with_binddn(slapd, settings, client): |
105 | 140 |
settings.LDAP_AUTH_SETTINGS = [{ |
106 | 141 |
'url': [slapd.ldap_url], |
... | ... | |
330 | 365 |
# Provision all users and their groups |
331 | 366 |
assert User.objects.count() == 0 |
332 | 367 |
users = list(ldap_backend.LDAPBackend.get_users()) |
333 |
assert len(users) == 101
|
|
334 |
assert User.objects.count() == 101
|
|
368 |
assert len(users) == 102
|
|
369 |
assert User.objects.count() == 102
|
|
335 | 370 |
assert bulk_create.call_count == 101 |
336 |
assert save.call_count == 303
|
|
371 |
assert save.call_count == 306
|
|
337 | 372 | |
338 | 373 |
# Check that if nothing changed no save() is made |
339 | 374 |
save.reset_mock() |
... | ... | |
346 | 381 |
save.reset_mock() |
347 | 382 |
bulk_create.reset_mock() |
348 | 383 |
User.objects.last().delete() |
349 |
assert User.objects.count() == 100 |
|
350 |
users = list(ldap_backend.LDAPBackend.get_users()) |
|
351 |
assert len(users) == 101 |
|
352 | 384 |
assert User.objects.count() == 101 |
385 |
users = list(ldap_backend.LDAPBackend.get_users()) |
|
386 |
assert len(users) == 102 |
|
387 |
assert User.objects.count() == 102 |
|
353 | 388 |
assert save.call_count == 3 |
354 | 389 |
assert bulk_create.call_count == 1 |
355 | 390 | |
356 |
- |