Project

General

Profile

0001-ldap-move-messages-from-hard-coded-to-settings-51294.patch

Loïc Dachary, 08 April 2021 01:34 PM

Download (7.49 KB)

View differences:

Subject: [PATCH] ldap: move messages from hard coded to settings (#51294)

Fixes: #51294

Licenses: MIT
 src/authentic2/backends/ldap_backend.py | 63 ++++++++++++-------------
 tests/test_ldap.py                      |  6 +--
 2 files changed, 34 insertions(+), 35 deletions(-)
src/authentic2/backends/ldap_backend.py
45 45
from django.contrib.auth.models import Group
46 46
from django.core.cache import cache
47 47
from django.core.exceptions import ImproperlyConfigured
48
from django.template import loader
48 49
from django.utils.encoding import force_bytes, force_text
49
from django.utils.translation import ngettext
50
from django.utils.translation import ugettext as _
50
from django.utils.translation import ugettext as _, gettext, ngettext
51 51

  
52 52
from authentic2 import app_settings, crypto
53 53
from authentic2.a2_rbac.models import Role
......
299 299
    raise NotImplementedError
300 300

  
301 301

  
302
def password_policy_control_messages(ctrl):
303
    messages = []
302
def password_policy_control_messages(ctrl, control_messages):
303
    results = []
304 304

  
305 305
    if ctrl.error:
306 306
        error = ppolicy.PasswordPolicyError.namedValues[ctrl.error]
307
        error2message = {
308
            'passwordExpired': _('The password expired'),
309
            'accountLocked': _('The account is locked.'),
310
            'changeAfterReset': _('The password was reset and must be changed.'),
311
            'passwordModNotAllowed': _('It is not possible to modify the password.'),
312
            'mustSupplyOldPassword': _('The old password must be supplied.'),
313
            'insufficientPasswordQuality': _('The password does not meet the quality requirements.'),
314
            'passwordTooShort': _('The password is too short.'),
315
            'passwordTooYoung': _('It is too soon to change the password.'),
316
            'passwordInHistory': _('This password was recently used and cannot be used again.'),
317
        }
318
        messages.append(error2message.get(error, _('Unexpected error {error}').format(error=error)))
319
        return messages
307
        if error not in control_messages:
308
            results.append(_('Unexpected error {error}').format(error=error))
309
        else:
310
            results.append(control_messages[error])
311
        return results
320 312

  
321 313
    if ctrl.timeBeforeExpiration:
322 314
        expiration_date = time.asctime(time.localtime(time.time() + ctrl.timeBeforeExpiration))
323
        messages.append(
324
            _('The password will expire at {expiration_date}.').format(expiration_date=expiration_date)
325
        )
315
        results.append(control_messages['expiration_date'].format(expiration_date=expiration_date))
326 316
    if ctrl.graceAuthNsRemaining:
327
        messages.append(
328
            ngettext(
329
                'This password expired: this is the last time it can be used.',
330
                'This password expired and can only be used {graceAuthNsRemaining} times, including this one.',
331
                ctrl.graceAuthNsRemaining,
332
            ).format(graceAuthNsRemaining=ctrl.graceAuthNsRemaining)
333
        )
334
    return messages
317
        results.append(control_messages['graceAuthNsRemaining'].format(graceAuthNsRemaining=ctrl.graceAuthNsRemaining))
318
    return results
335 319

  
336 320

  
337 321
class LDAPUser(User):
......
621 605
        'user_attributes': [],
622 606
        # https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#ldap-controls
623 607
        'use_controls': True,
608
        'ppolicy_messages': {
609
            'passwordExpired': gettext('The password expired'),
610
            'accountLocked': gettext('The account is locked.'),
611
            'changeAfterReset': gettext('The password was reset and must be changed.'),
612
            'passwordModNotAllowed': gettext('It is not possible to modify the password.'),
613
            'mustSupplyOldPassword': gettext('The old password must be supplied.'),
614
            'insufficientPasswordQuality': gettext('The password does not meet the quality requirements.'),
615
            'passwordTooShort': gettext('The password is too short.'),
616
            'passwordTooYoung': gettext('It is too soon to change the password.'),
617
            'passwordInHistory': gettext('This password was recently used and cannot be used again.'),
618
            'expiration_date': gettext('The password will expire at {expiration_date}.'),
619
            'graceAuthNsRemaining': gettext(
620
                'This password expired and can only be used {graceAuthNsRemaining} time(s), including this one.'
621
            ),
622
        },
624 623
    }
625 624
    _REQUIRED = ('url', 'basedn')
626 625
    _TO_ITERABLE = ('url', 'groupsu', 'groupstaff', 'groupactive')
......
660 659
        return blocks
661 660

  
662 661
    @staticmethod
663
    def process_controls(request, authz_id, ctrls):
662
    def process_controls(request, authz_id, ctrls, block):
664 663
        for c in ctrls:
665 664
            if c.controlType == ppolicy.PasswordPolicyControl.controlType:
666
                message = ' '.join(password_policy_control_messages(c))
665
                message = ' '.join(password_policy_control_messages(c, block['ppolicy_messages']))
667 666
                if request is not None:
668 667
                    messages.add_message(request, messages.WARNING, message)
669 668
                    if c.graceAuthNsRemaining or c.timeBeforeExpiration:
......
791 790
                            else:
792 791
                                serverctrls = []
793 792
                            results = conn.simple_bind_s(authz_id, password, serverctrls=serverctrls)
794
                            self.process_controls(request, authz_id, results[3])
793
                            self.process_controls(request, authz_id, results[3], block)
795 794
                            user_login_success(authz_id)
796 795
                            if not block['connect_with_user_credentials']:
797 796
                                try:
......
803 802
                        except ldap.INVALID_CREDENTIALS as e:
804 803
                            if block.get('use_controls') and len(e.args) > 0 and 'ctrls' in e.args[0]:
805 804
                                self.process_controls(
806
                                    request, authz_id, DecodeControlTuples(e.args[0]['ctrls'])
805
                                    request, authz_id, DecodeControlTuples(e.args[0]['ctrls']), block
807 806
                                )
808 807
                            attributes = self.get_ldap_attributes(block, conn, authz_id)
809 808
                            user = self.lookup_existing_user(authz_id, block, attributes)
tests/test_ldap.py
1229 1229

  
1230 1230
    assert 'used 2 time' not in caplog.text
1231 1231
    assert authenticate(username=USERNAME, password=password) is not None
1232
    assert 'used 2 times' in caplog.text
1232
    assert 'used 2 time' in caplog.text
1233 1233

  
1234
    assert 'last time' not in caplog.text
1234
    assert 'used 1 time' not in caplog.text
1235 1235
    assert authenticate(username=USERNAME, password=password) is not None
1236
    assert 'last time' in caplog.text
1236
    assert 'used 1 time' in caplog.text
1237 1237

  
1238 1238

  
1239 1239
def test_authenticate_ppolicy_pwdExpireWarning(slapd_ppolicy, settings, db, caplog):
1240
-