Project

General

Profile

0001-authenticators-attach-login-failure-record-to-user-5.patch

Valentin Deniaud, 25 March 2021 03:19 PM

Download (6.1 KB)

View differences:

Subject: [PATCH] authenticators: attach login failure record to user (#51626)

 src/authentic2/authenticators.py          |  6 +++++-
 src/authentic2/backends/ldap_backend.py   |  6 +++++-
 src/authentic2/backends/models_backend.py |  2 ++
 src/authentic2/journal_event_types.py     |  4 ++--
 tests/test_ldap.py                        | 20 ++++++++++++++++++++
 tests/test_login.py                       |  5 ++++-
 6 files changed, 38 insertions(+), 5 deletions(-)
src/authentic2/authenticators.py
100 100
        data = request.POST if is_post else None
101 101
        initial = {}
102 102
        preferred_ous = []
103
        request.failed_logins = {}
103 104

  
104 105
        # Special handling when the form contains an OU selector
105 106
        if app_settings.A2_LOGIN_FORM_OU_SELECTOR:
......
139 140
                return response
140 141
            else:
141 142
                username = form.cleaned_data.get('username', '').strip()
142
                if username:
143
                if request.failed_logins:
144
                    for user in request.failed_logins.values():
145
                        request.journal.record('user.login.failure', user=user, username=username)
146
                elif username:
143 147
                    request.journal.record('user.login.failure', username=username)
144 148
        context['form'] = form
145 149
        return render(request, 'authentic2/login_password_form.html', context)
src/authentic2/backends/ldap_backend.py
720 720
                        except ldap.INVALID_CREDENTIALS as e:
721 721
                            if block.get('use_controls') and len(e.args) > 0 and 'ctrls' in e.args[0]:
722 722
                                self.process_controls(request, authz_id, DecodeControlTuples(e.args[0]['ctrls']))
723
                            attributes = self.get_ldap_attributes(block, conn, authz_id)
724
                            user = self.lookup_existing_user(authz_id, block, attributes)
725
                            if user and hasattr(request, 'failed_logins'):
726
                                request.failed_logins[user.uuid] = user
723 727
                            user_login_failure(authz_id)
724 728
                            pass
725 729
                    else:
......
1234 1238
        for lookup_type in block['lookups']:
1235 1239
            if lookup_type == 'username':
1236 1240
                return self.lookup_by_username(username)
1237
            elif lookup_type == 'external_id':
1241
            elif lookup_type == 'external_id' and attributes:
1238 1242
                return self.lookup_by_external_id(block, attributes)
1239 1243

  
1240 1244
    def update_user_identifiers(self, user, username, block, attributes):
src/authentic2/backends/models_backend.py
83 83
                return user
84 84
            else:
85 85
                user_login_failure(user.get_username())
86
                if hasattr(request, 'failed_logins'):
87
                    request.failed_logins[user.uuid] = user
86 88

  
87 89
    def get_user(self, user_id):
88 90
        UserModel = get_user_model()
src/authentic2/journal_event_types.py
149 149
    label = _('login failure')
150 150

  
151 151
    @classmethod
152
    def record(cls, service, username):
153
        super().record(service=service, data={'username': username})
152
    def record(cls, service, username, user):
153
        super().record(user=user, service=service, data={'username': username})
154 154

  
155 155
    @classmethod
156 156
    def get_message(cls, event, context):
tests/test_ldap.py
258 258
    utils.login(app, UID, password=PASS, path='/admin/')
259 259

  
260 260

  
261
def test_login_failure(slapd, simple_user, settings, app, db):
262
    settings.LDAP_AUTH_SETTINGS = [{
263
        'url': [slapd.ldap_url],
264
        'basedn': u'o=ôrga',
265
        'use_tls': False,
266
        'is_superuser': True,
267
        'is_staff': True,
268
    }]
269
    # create ldap user
270
    utils.login(app, UID, password=PASS, path='/admin/')
271
    utils.logout(app)
272
    user = ldap_backend.LDAPUser.objects.get(username='%s@ldap' % UID)
273

  
274
    utils.login(app, simple_user, password='wrong', fail=True)
275
    utils.assert_event('user.login.failure', user=simple_user, username=simple_user.username)
276

  
277
    utils.login(app, UID, password='wrong', fail=True)
278
    utils.assert_event('user.login.failure', user=user, username=UID)
279

  
280

  
261 281
def test_keep_password_in_session(slapd, settings, client, db):
262 282
    settings.LDAP_AUTH_SETTINGS = [{
263 283
        'url': [slapd.ldap_url],
tests/test_login.py
36 36

  
37 37
def test_failure(db, app, simple_user):
38 38
    login(app, simple_user, password='wrong', fail=True)
39
    assert_event('user.login.failure', username=simple_user.username)
39
    assert_event('user.login.failure', user=simple_user, username=simple_user.username)
40

  
41
    login(app, 'noone', password='wrong', fail=True)
42
    assert_event('user.login.failure', username='noone')
40 43

  
41 44

  
42 45
def test_login_inactive_user(db, app):
43
-