0001-authenticators-attach-login-failure-record-to-user-5.patch
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 |
- |