Projet

Général

Profil

0005-ldap-handle-ppolicy-control-changing-reseting-passwo.patch

Benjamin Renard, 22 septembre 2022 18:24

Télécharger (6,12 ko)

Voir les différences:

Subject: [PATCH 5/5] ldap: handle ppolicy control changing/reseting password

 src/authentic2/backends/ldap_backend.py | 51 ++++++++++++++++++++++---
 tests/test_ldap.py                      |  6 +--
 2 files changed, 48 insertions(+), 9 deletions(-)
src/authentic2/backends/ldap_backend.py
592 592
        return blocks
593 593

  
594 594
    @classmethod
595
    def process_controls(cls, request, block, conn, authz_id, ctrls):
595
    def process_bind_controls(cls, request, block, conn, authz_id, ctrls):
596 596
        attributes = cls.get_ppolicy_attributes(block, conn, authz_id)
597 597
        for c in ctrls:
598 598
            if c.controlType == ppolicy.PasswordPolicyControl.controlType:
......
605 605
                message = str(vars(c))
606 606
            log.info('ldap: bind error with authz_id "%s" -> "%s"', authz_id, message)
607 607

  
608
    @classmethod
609
    def process_modify_password_controls(cls, block, conn, authz_id, ctrls):
610
        attributes = cls.get_ppolicy_attributes(block, conn, authz_id)
611
        errors = []
612
        for c in ctrls:
613
            if c.controlType == ppolicy.PasswordPolicyControl.controlType:
614
                message = ' '.join(password_policy_control_messages(c, attributes))
615
            else:
616
                message = str(vars(c))
617
            log.info('ldap: fail to modify password of "%s" -> "%s"', authz_id, message)
618
            errors.append(message)
619

  
620
        raise PasswordChangeError(' '.join(errors))
621

  
608 622
    @classmethod
609 623
    def check_group_to_role_mappings(cls, block):
610 624
        group_to_role_mapping = block.get('group_to_role_mapping')
......
730 744
                            else:
731 745
                                serverctrls = []
732 746
                            results = conn.simple_bind_s(authz_id, password, serverctrls=serverctrls)
733
                            self.process_controls(request, block, conn, authz_id, results[3])
747
                            self.process_bind_controls(request, block, conn, authz_id, results[3])
734 748
                            user_login_success(authz_id)
735 749
                            if not block['connect_with_user_credentials']:
736 750
                                try:
......
741 755
                            break
742 756
                        except ldap.INVALID_CREDENTIALS as e:
743 757
                            if block.get('use_controls') and len(e.args) > 0 and 'ctrls' in e.args[0]:
744
                                self.process_controls(
758
                                self.process_bind_controls(
745 759
                                    request, block, conn, authz_id, DecodeControlTuples(e.args[0]['ctrls'])
746 760
                                )
747 761
                            success, error = self.bind(block, conn)
......
1770 1784
    def modify_password(cls, conn, block, dn, old_password, new_password):
1771 1785
        '''Change user password with adaptation for Active Directory'''
1772 1786
        if old_password is not None and (block['use_password_modify'] and not block['active_directory']):
1773
            conn.passwd_s(dn, old_password, new_password)
1787
            try:
1788
                if block.get('use_controls'):
1789
                    serverctrls = [ppolicy.PasswordPolicyControl()]
1790
                else:
1791
                    serverctrls = []
1792
                results = conn.passwd_s(dn, old_password, new_password, serverctrls=serverctrls)
1793
                cls.process_modify_password_controls(block, conn, dn, results[3])
1794
            except ldap.LDAPError as e:
1795
                if block.get('use_controls') and len(e.args) > 0 and 'ctrls' in e.args[0]:
1796
                    cls.process_modify_password_controls(
1797
                        block, conn, dn, DecodeControlTuples(e.args[0]['ctrls'])
1798
                    )
1799
                raise
1774 1800
        else:
1775 1801
            modlist = []
1776 1802
            if block['active_directory']:
......
1785 1811
                    modlist = [(ldap.MOD_REPLACE, key, [value])]
1786 1812
            else:
1787 1813
                key = 'userPassword'
1788
                modlist = [(ldap.MOD_REPLACE, key, [new_password])]
1789
            conn.modify_s(dn, modlist)
1814
                modlist = [(ldap.MOD_REPLACE, key, [new_password.encode('utf-8')])]
1815
            try:
1816
                if block.get('use_controls'):
1817
                    serverctrls = [ppolicy.PasswordPolicyControl()]
1818
                else:
1819
                    serverctrls = []
1820
                results = conn.modify_ext_s(dn, modlist, serverctrls=serverctrls)
1821
                cls.process_modify_password_controls(block, conn, dn, results[3])
1822
            except ldap.LDAPError as e:
1823
                if block.get('use_controls') and len(e.args) > 0 and 'ctrls' in e.args[0]:
1824
                    cls.process_modify_password_controls(
1825
                        block, conn, dn, DecodeControlTuples(e.args[0]['ctrls'])
1826
                    )
1827
                raise
1828

  
1790 1829
        log.debug('modified password for dn %r', dn)
1791 1830

  
1792 1831
    @classmethod
tests/test_ldap.py
2191 2191
        '/login/', {'login-password-submit': '1', 'username': USERNAME, 'password': PASS}, follow=True
2192 2192
    )
2193 2193

  
2194
    def patched_process_controls(cls, request, block, conn, authz_id, ctrls):
2194
    def patched_process_bind_controls(cls, request, block, conn, authz_id, ctrls):
2195 2195
        raise exception[0]('oops')
2196 2196

  
2197 2197
    monkeypatch.setattr(
2198 2198
        ldap_backend.LDAPBackend,
2199
        'process_controls',
2200
        patched_process_controls,
2199
        'process_bind_controls',
2200
        patched_process_bind_controls,
2201 2201
    )
2202 2202
    client.post(
2203 2203
        '/login/', {'login-password-submit': '1', 'username': USERNAME, 'password': PASS}, follow=True
2204
-