0001-ldap-add-useful-output-to-sync-ldap-users-command-54.patch
src/authentic2/backends/ldap_backend.py | ||
---|---|---|
1543 | 1543 | |
1544 | 1544 |
@classmethod |
1545 | 1545 |
def get_users(cls): |
1546 |
for block in cls.get_config(): |
|
1546 |
blocks = cls.get_config() |
|
1547 |
if not blocks: |
|
1548 |
log.info('No LDAP server configured.') |
|
1549 |
return |
|
1550 |
for block in blocks: |
|
1551 |
log.info('Synchronising users from realm "%s"', block['realm']) |
|
1547 | 1552 |
conn = cls.get_connection(block) |
1548 | 1553 |
if conn is None: |
1549 | 1554 |
log.warning('unable to synchronize with LDAP servers %s', force_text(block['url'])) |
... | ... | |
1552 | 1557 |
user_basedn = force_text(block.get('user_basedn') or block['basedn']) |
1553 | 1558 |
user_filter = cls.get_sync_ldap_user_filter(block) |
1554 | 1559 |
attribute_names = cls.get_ldap_attributes_names(block) |
1560 |
log.info('Searching for %s', user_filter) |
|
1555 | 1561 |
results = cls.paged_search( |
1556 | 1562 |
conn, user_basedn, ldap.SCOPE_SUBTREE, user_filter, attrlist=attribute_names |
1557 | 1563 |
) |
1558 | 1564 |
backend = cls() |
1565 |
count = 0 |
|
1559 | 1566 |
for dn, attrs in results: |
1560 |
yield backend._return_user(dn, None, conn, block, attrs) |
|
1567 |
count += 1 |
|
1568 |
user = backend._return_user(dn, None, conn, block, attrs) |
|
1569 |
if getattr(user, '_changed', False): |
|
1570 |
log.debug( |
|
1571 |
'Updated user %s (username %s, full name %s)', |
|
1572 |
user.uuid, |
|
1573 |
user.get_username(), |
|
1574 |
user.get_full_name(), |
|
1575 |
) |
|
1576 |
yield user |
|
1577 |
log.info('Server returned %s users.', count) |
|
1561 | 1578 | |
1562 | 1579 |
@classmethod |
1563 | 1580 |
def deactivate_orphaned_users(cls): |
... | ... | |
1711 | 1728 |
user_credentials = block['connect_with_user_credentials'] and credentials |
1712 | 1729 |
success, error = cls.bind(block, conn, credentials=user_credentials) |
1713 | 1730 |
if success: |
1731 |
log.info('Connected to server %s', url) |
|
1714 | 1732 |
yield conn |
1715 | 1733 |
else: |
1716 | 1734 |
if block['replicas']: |
... | ... | |
1726 | 1744 |
who, password = credentials[0], credentials[1] |
1727 | 1745 |
password = force_text(password) |
1728 | 1746 |
conn.simple_bind_s(who, password) |
1747 |
log.info('Binding with %s account: success', who) |
|
1729 | 1748 |
elif block['bindsasl']: |
1730 | 1749 |
sasl_mech, who, sasl_params = map_text(block['bindsasl']) |
1731 | 1750 |
handler_class = getattr(ldap.sasl, sasl_mech) |
1732 | 1751 |
auth = handler_class(*sasl_params) |
1733 | 1752 |
conn.sasl_interactive_bind_s(who, auth) |
1753 |
log.info('Binding with %s account: success', who) |
|
1734 | 1754 |
elif block['binddn'] and block['bindpw']: |
1735 | 1755 |
who = force_text(block['binddn']) |
1736 | 1756 |
conn.simple_bind_s(who, force_text(block['bindpw'])) |
1757 |
log.info('Binding with %s binddn: success', who) |
|
1737 | 1758 |
else: |
1738 | 1759 |
who = 'anonymous' |
1739 | 1760 |
conn.simple_bind_s() |
1761 |
log.info('Binding anonymously: success') |
|
1740 | 1762 |
return True, None |
1741 | 1763 |
except ldap.INVALID_CREDENTIALS: |
1742 | 1764 |
return False, 'invalid credentials' |
src/authentic2/management/commands/sync-ldap-users.py | ||
---|---|---|
21 | 21 |
except ImportError: |
22 | 22 |
ldap = None |
23 | 23 | |
24 |
import logging |
|
25 | ||
24 | 26 |
from django.core.management.base import BaseCommand |
25 | 27 | |
26 | 28 |
from authentic2.backends.ldap_backend import LDAPBackend |
27 | 29 | |
30 |
logger = logging.getLogger(__name__) |
|
31 | ||
28 | 32 | |
29 | 33 |
class Command(BaseCommand): |
30 | 34 |
def handle(self, *args, **kwargs): |
31 | 35 |
verbosity = int(kwargs['verbosity']) |
32 |
if verbosity > 1: |
|
33 |
print('Updated users :') |
|
36 |
root_logger = logging.getLogger() |
|
37 |
if verbosity == 0: |
|
38 |
root_logger.setLevel(logging.WARNING) |
|
39 |
elif verbosity == 1: |
|
40 |
root_logger.setLevel(logging.INFO) |
|
41 |
elif verbosity == 2: |
|
42 |
root_logger.setLevel(logging.DEBUG) |
|
43 | ||
34 | 44 |
for user in LDAPBackend.get_users(): |
35 |
if getattr(user, '_changed', False) and verbosity > 1: |
|
36 |
print(' -', user.uuid, user.get_username(), user.get_full_name()) |
|
45 |
continue |
tests/test_ldap.py | ||
---|---|---|
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import json |
18 |
import logging |
|
18 | 19 |
import os |
19 | 20 |
import time |
20 | 21 |
import urllib.parse |
... | ... | |
1605 | 1606 |
assert '_auth_user_id' in app.session |
1606 | 1607 | |
1607 | 1608 | |
1608 |
def test_sync_ldap_users(slapd, settings, app, db, capsys): |
|
1609 |
def test_sync_ldap_users(slapd, settings, app, db, caplog): |
|
1610 |
root_logger = logging.getLogger() |
|
1611 |
initial_log_level = root_logger.level |
|
1612 | ||
1613 |
management.call_command('sync-ldap-users') |
|
1614 |
assert len(caplog.records) == 1 |
|
1615 |
assert caplog.records[0].message == 'No LDAP server configured.' |
|
1616 | ||
1609 | 1617 |
settings.LDAP_AUTH_SETTINGS = [ |
1610 | 1618 |
{ |
1611 | 1619 |
'url': [slapd.ldap_url], |
... | ... | |
1633 | 1641 |
) |
1634 | 1642 | |
1635 | 1643 |
assert User.objects.count() == 0 |
1636 |
capsys.readouterr() |
|
1637 |
management.call_command('sync-ldap-users', verbosity=2) |
|
1638 |
assert len(capsys.readouterr().out.splitlines()) == 7 |
|
1644 |
caplog.clear() |
|
1645 |
management.call_command('sync-ldap-users') |
|
1646 |
assert caplog.messages == [ |
|
1647 |
'Synchronising users from realm "ldap"', |
|
1648 |
'Binding anonymously: success', |
|
1649 |
'Connected to server %s' % slapd.ldap_url, |
|
1650 |
'Searching for (|(mail=*)(uid=*))', |
|
1651 |
'Server returned 6 users.', |
|
1652 |
] |
|
1653 | ||
1639 | 1654 |
assert User.objects.count() == 6 |
1640 | 1655 |
assert all(user.first_name == 'Étienne' for user in User.objects.all()) |
1641 | 1656 |
assert all(user.attributes.first_name == 'Étienne' for user in User.objects.all()) |
... | ... | |
1652 | 1667 |
for user in User.objects.all() |
1653 | 1668 |
] |
1654 | 1669 |
) |
1655 |
capsys.readouterr() |
|
1670 | ||
1671 |
User.objects.update(first_name='John') |
|
1672 |
caplog.clear() |
|
1673 |
management.call_command('sync-ldap-users', verbosity=2) |
|
1674 |
assert len(caplog.records) == 42 |
|
1675 |
assert ( |
|
1676 |
caplog.records[10].message |
|
1677 |
== 'Updated user %s (username etienne.michu@ldap, full name Étienne Michu)' |
|
1678 |
% User.objects.first().uuid |
|
1679 |
) |
|
1680 | ||
1681 |
caplog.clear() |
|
1656 | 1682 |
management.call_command('sync-ldap-users', verbosity=2) |
1657 |
assert len(capsys.readouterr().out.splitlines()) == 1 |
|
1683 |
assert len(caplog.records) == 36 # users have not been updated |
|
1684 | ||
1685 |
caplog.clear() |
|
1686 |
management.call_command('sync-ldap-users', verbosity=0) |
|
1687 |
assert len(caplog.records) == 0 |
|
1688 | ||
1689 |
root_logger.setLevel(initial_log_level) |
|
1658 | 1690 | |
1659 | 1691 | |
1660 | 1692 |
def test_alert_on_wrong_user_filter(slapd, settings, client, db, caplog): |
1661 |
- |