LDAP improvements:

- Better logging
  - Better error messages
  - Add unit tests
  - Clean up the setup tool for LDAP
This commit is contained in:
Joseph Schorr 2015-05-11 21:23:18 -04:00
parent 3e1abba284
commit efab02ae47
5 changed files with 173 additions and 28 deletions

View file

@ -11,12 +11,23 @@ from util.validation import generate_valid_usernames
from data import model
logger = logging.getLogger(__name__)
if os.environ.get('LDAP_DEBUG') == '1':
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
logger.addHandler(ch)
class DatabaseUsers(object):
def verify_user(self, username_or_email, password):
""" Simply delegate to the model implementation. """
return model.verify_user(username_or_email, password)
result = model.verify_user(username_or_email, password)
if not result:
return (None, 'Invalid Username or Password')
return (result, None)
def user_exists(self, username):
return model.get_user(username) is not None
@ -30,9 +41,10 @@ class LDAPConnection(object):
self._conn = None
def __enter__(self):
trace_level = 2 if os.environ.get('LDAP_DEBUG') else 0
trace_level = 2 if os.environ.get('LDAP_DEBUG') == '1' else 0
self._conn = ldap.initialize(self._ldap_uri, trace_level=trace_level)
self._conn.simple_bind_s(self._user_dn, self._user_pw)
return self._conn
def __exit__(self, exc_type, value, tb):
@ -55,7 +67,7 @@ class LDAPUsers(object):
query = u'(|({0}={2})({1}={2}))'.format(self._uid_attr, self._email_attr,
username_or_email)
logger.debug('Conducting user search: %s => %s', user_search_dn, query)
logger.debug('Conducting user search: %s under %s', query, user_search_dn)
try:
user = conn.search_s(user_search_dn, ldap.SCOPE_SUBTREE, query.encode('utf-8'))
except ldap.LDAPError:
@ -75,12 +87,12 @@ class LDAPUsers(object):
# Make sure that even if the server supports anonymous binds, we don't allow it
if not password:
return None
return (None, 'Anonymous binding not allowed')
found_user = self._ldap_user_search(username_or_email)
if found_user is None:
return None
return (None, 'Username not found')
found_dn, found_response = found_user
@ -91,9 +103,15 @@ class LDAPUsers(object):
pass
except ldap.INVALID_CREDENTIALS:
logger.exception('Invalid LDAP credentials')
return None
return (None, 'Invalid password')
# Now check if we have a federated login for this user
if not found_response.get(self._uid_attr):
return (None, 'Missing uid field "%s" in user record' % self._uid_attr)
if not found_response.get(self._email_attr):
return (None, 'Missing mail field "%s" in user record' % self._email_attr)
username = found_response[self._uid_attr][0].decode('utf-8')
email = found_response[self._email_attr][0]
db_user = model.verify_federated_login('ldap', username)
@ -107,7 +125,7 @@ class LDAPUsers(object):
if not valid_username:
logger.error('Unable to pick a username for user: %s', username)
return None
return (None, 'Unable to pick a username. Please report this to your administrator.')
db_user = model.create_federated_user(valid_username, email, 'ldap', username,
set_password_notification=False)
@ -116,7 +134,7 @@ class LDAPUsers(object):
db_user.email = email
db_user.save()
return db_user
return (db_user, None)
def user_exists(self, username):
found_user = self._ldap_user_search(username)
@ -225,12 +243,7 @@ class UserAuthentication(object):
else:
password = decrypted
result = self.state.verify_user(username_or_email, password)
if result:
return (result, '')
else:
return (result, 'Invalid password.')
return self.state.verify_user(username_or_email, password)
def __getattr__(self, name):
return getattr(self.state, name, None)