Project

General

Profile

0001-ldap-log-controls-on-authenticate-and-enable-ppolicy.patch

Loïc Dachary, 09 February 2021 06:43 PM

Download (4.81 KB)

View differences:

Subject: [PATCH] ldap: log controls on authenticate and enable ppolicy

 src/authentic2/backends/ldap_backend.py | 10 ++--
 tests/test_ldap.py                      | 69 +++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 3 deletions(-)
src/authentic2/backends/ldap_backend.py
23 23
    from ldap.filter import filter_format
24 24
    from ldap.dn import escape_dn_chars
25 25
    from ldap.ldapobject import ReconnectLDAPObject as NativeLDAPObject
26
    from ldap.controls import SimplePagedResultsControl
26
    from ldap.controls import SimplePagedResultsControl, DecodeControlTuples
27
    from ldap.controls.ppolicy import PasswordPolicyControl
27 28
    PYTHON_LDAP3 = [int(x) for x in ldap.__version__.split('.')] >= [3]
28 29
    LDAPObject = NativeLDAPObject
29 30
except ImportError:
......
628 629
                        if failed:
629 630
                            continue
630 631
                        try:
631
                            conn.simple_bind_s(authz_id, password)
632
                            conn.simple_bind_s(authz_id, password, serverctrls=[PasswordPolicyControl()])
632 633
                            user_login_success(authz_id)
633 634
                            if not block['connect_with_user_credentials']:
634 635
                                try:
......
637 638
                                    log.exception(u'rebind failure after login bind')
638 639
                                    raise ldap.SERVER_DOWN
639 640
                            break
640
                        except ldap.INVALID_CREDENTIALS:
641
                        except ldap.INVALID_CREDENTIALS as e:
642
                            if len(e.args) > 0 and 'ctrls' in e.args[0]:
643
                                for c in DecodeControlTuples(e.args[0]['ctrls']):
644
                                    log.info('%s: %s', authz_id, vars(c))
641 645
                            user_login_failure(authz_id)
642 646
                            pass
643 647
                    else:
tests/test_ldap.py
23 23

  
24 24
import ldap
25 25
from ldap.dn import escape_dn_chars
26
from ldap.controls.ppolicy import PasswordPolicyControl
26 27

  
27 28
from ldaptools.slapd import Slapd, has_slapd
28 29
from django.contrib.auth import get_user_model
......
78 79
        yield s
79 80

  
80 81

  
82
@pytest.fixture
83
def slapd_ppolicy():
84
    with create_slapd() as slapd:
85
        conn = slapd.get_connection_admin()
86
        assert conn.protocol_version == ldap.VERSION3
87
        conn.modify_s(
88
            'cn=module{0},cn=config',
89
            [
90
                (ldap.MOD_ADD, 'olcModuleLoad', [
91
                    force_bytes('ppolicy')
92
                ])
93
            ])
94
        slapd.add_ldif(open('/etc/ldap/schema/ppolicy.ldif').read())
95
        slapd.add_ldif('''
96
dn: olcOverlay={0}ppolicy,olcDatabase={2}mdb,cn=config
97
objectclass: olcOverlayConfig
98
objectclass: olcPPolicyConfig
99
olcoverlay: {0}ppolicy
100
olcppolicydefault: cn=default,ou=ppolicies,o=ôrga
101
olcppolicyforwardupdates: FALSE
102
olcppolicyhashcleartext: TRUE
103
olcppolicyuselockout: FALSE
104
''')
105

  
106
        slapd.add_ldif('''
107
dn: ou=ppolicies,o=ôrga
108
objectclass: organizationalUnit
109
ou: ppolicies
110
''')
111

  
112
        slapd.add_ldif('''
113
dn: cn=default,ou=ppolicies,o=ôrga
114
cn: default
115
objectclass: top
116
objectclass: device
117
objectclass: pwdPolicy
118
objectclass: pwdPolicyChecker
119
pwdAttribute: userPassword
120
pwdMinAge: 0
121
pwdMaxAge: 0
122
pwdInHistory: 0
123
pwdCheckQuality: 1
124
pwdMinLength: 8
125
pwdExpireWarning: 0
126
pwdGraceAuthnLimit: 0
127
pwdLockout: FALSE
128
pwdLockoutDuration: 0
129
pwdMaxFailure: 0
130
pwdMaxRecordedFailure: 0
131
pwdFailureCountInterval: 0
132
pwdMustChange: FALSE
133
pwdAllowUserChange: FALSE
134
pwdSafeModify: FALSE
135
''')
136
        yield slapd
137

  
138

  
81 139
@pytest.fixture
82 140
def tls_slapd():
83 141
    tcp_port = utils.find_free_tcp_port()
......
872 930
    assert user.pk == user2.pk
873 931

  
874 932

  
933
def test_authenticate_ppolicy(slapd_ppolicy, settings, db, caplog):
934
    settings.LDAP_AUTH_SETTINGS = [{
935
        'url': [slapd_ppolicy.ldap_url],
936
        'basedn': u'o=ôrga',
937
        'use_tls': False,
938
    }]
939
    assert authenticate(username=u'etienne.michu', password='incorrect') is None
940
    assert "failed to login" in caplog.text
941
    assert PasswordPolicyControl.controlType in caplog.text
942

  
943

  
875 944
def test_ou_selector(slapd, settings, app, ou1):
876 945
    settings.LDAP_AUTH_SETTINGS = [{
877 946
        'url': [slapd.ldap_url],
878
-