fix ldappool bad password retry logic
This patch fixes a bug in ldappool which causes a bind attempt utilizing a bad password to be retried until the retry limit has been reached. Instead ldappool will now break out of the retry loop if the ldap connection try block catches a ldap.INVALID_PASSWORD exception. Previously ldappool would attempt to catch ldap.LDAPError which is the base exception class for all ldap errors in the python-ldap library. This is an issue because Keystone by default enables ldappool and configures the default retry value to be 3. An LDAP server with a password lockout threshold of 3 bad passwords will lock out a user after a single bad password attempt through Keystone. Change-Id: I2a9b850ce977260d4df1e9edf86417b8042a6fb8 Closes-Bug: #1785898
This commit is contained in:
parent
459e1b1399
commit
459000d7aa
|
@ -252,6 +252,11 @@ class ConnectionManager(object):
|
||||||
conn.timeout = self.timeout
|
conn.timeout = self.timeout
|
||||||
self._bind(conn, bind, passwd)
|
self._bind(conn, bind, passwd)
|
||||||
connected = True
|
connected = True
|
||||||
|
except ldap.INVALID_CREDENTIALS as error:
|
||||||
|
exc = error
|
||||||
|
log.error('Invalid credentials. Cancelling retry',
|
||||||
|
exc_info=True)
|
||||||
|
break
|
||||||
except ldap.LDAPError as error:
|
except ldap.LDAPError as error:
|
||||||
exc = error
|
exc = error
|
||||||
time.sleep(self.retry_delay)
|
time.sleep(self.retry_delay)
|
||||||
|
|
|
@ -55,6 +55,10 @@ def _bind_fails2(self, who='', cred='', **kw):
|
||||||
raise ldap.SERVER_DOWN('LDAP connection invalid')
|
raise ldap.SERVER_DOWN('LDAP connection invalid')
|
||||||
|
|
||||||
|
|
||||||
|
def _bind_fails_invalid_credentials(self, who='', cred='', **kw):
|
||||||
|
raise ldap.INVALID_CREDENTIALS('LDAP connection invalid')
|
||||||
|
|
||||||
|
|
||||||
def _start_tls_s(self):
|
def _start_tls_s(self):
|
||||||
if self.start_tls_already_called_flag:
|
if self.start_tls_already_called_flag:
|
||||||
raise ldap.LOCAL_ERROR
|
raise ldap.LOCAL_ERROR
|
||||||
|
@ -157,3 +161,26 @@ class TestLDAPConnection(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise AssertionError()
|
raise AssertionError()
|
||||||
|
|
||||||
|
def test_simple_bind_fails_invalid_credentials(self):
|
||||||
|
unbinds = []
|
||||||
|
|
||||||
|
def _unbind(self):
|
||||||
|
unbinds.append(1)
|
||||||
|
|
||||||
|
# the binding fails with an LDAPError
|
||||||
|
ldappool.StateConnector.simple_bind_s = _bind_fails_invalid_credentials
|
||||||
|
ldappool.StateConnector.unbind_s = _unbind
|
||||||
|
uri = ''
|
||||||
|
dn = 'uid=adminuser,ou=logins,dc=mozilla'
|
||||||
|
passwd = 'adminuser'
|
||||||
|
cm = ldappool.ConnectionManager(uri, dn, passwd, use_pool=True, size=2)
|
||||||
|
self.assertEqual(len(cm), 0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with cm.connection('dn', 'pass'):
|
||||||
|
pass
|
||||||
|
except ldap.INVALID_CREDENTIALS:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise AssertionError()
|
||||||
|
|
Loading…
Reference in New Issue