diff --git a/data/users.py b/data/users.py index fd3263a0a..0f228786f 100644 --- a/data/users.py +++ b/data/users.py @@ -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) diff --git a/requirements-nover.txt b/requirements-nover.txt index f0ac2cdf9..d76e671b5 100644 --- a/requirements-nover.txt +++ b/requirements-nover.txt @@ -51,3 +51,4 @@ cachetools mock psutil stringscore +mockldap diff --git a/requirements.txt b/requirements.txt index e3d00eeb0..08eddb442 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,6 +37,7 @@ jsonschema==2.4.0 marisa-trie==0.7 mixpanel-py==3.2.1 mock==1.0.1 +mockldap==0.2.4 paramiko==1.15.2 peewee==2.4.7 psutil==2.2.1 diff --git a/static/directives/config/config-setup-tool.html b/static/directives/config/config-setup-tool.html index 35511916f..7c2fa2e19 100644 --- a/static/directives/config/config-setup-tool.html +++ b/static/directives/config/config-setup-tool.html @@ -310,12 +310,12 @@
-