From: Rob Crittenden Date: Mon, 20 Jul 2015 20:42:36 +0000 (-0400) Subject: Report to user if an LDAP error occurs X-Git-Tag: v1.1.0~44 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Fipsilon.git;a=commitdiff_plain;h=5f591228346bd96561b693cae43b8f14e4c3b26d Report to user if an LDAP error occurs Catch LDAP errors and display them properly rather than just dumping the exception. Rename variable authed to authok. Add test for case where LDAP server is not started to confirm the user receives the error alert. https://fedorahosted.org/ipsilon/ticket/55 Signed-off-by: Rob Crittenden Reviewed-by: Patrick Uiterwijk --- diff --git a/Makefile b/Makefile index f7f7d16..d15ca4d 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,7 @@ tests: wrappers PYTHONPATH=./ ./tests/tests.py --test=pgdb PYTHONPATH=./ ./tests/tests.py --test=fconf PYTHONPATH=./ ./tests/tests.py --test=ldap + PYTHONPATH=./ ./tests/tests.py --test=ldapdown PYTHONPATH=./ ./tests/tests.py --test=openid test: lp-test unittests tests diff --git a/ipsilon/login/authldap.py b/ipsilon/login/authldap.py index ce096f4..321c461 100644 --- a/ipsilon/login/authldap.py +++ b/ipsilon/login/authldap.py @@ -61,21 +61,32 @@ class LDAP(LoginFormBase, Log): username = kwargs.get("login_name") password = kwargs.get("login_password") userattrs = None - authed = False + authok = False errmsg = None if username and password: try: userattrs = self._authenticate(username, password) - authed = True - except Exception, e: # pylint: disable=broad-except + authok = True + except ldap.INVALID_CREDENTIALS as e: errmsg = "Authentication failed" + self.error(errmsg) + except ldap.LDAPError as e: + errmsg = 'Internal system error' + if isinstance(e, ldap.TIMEOUT): + self.error('LDAP request timed out') + else: + desc = e.args[0]['desc'].strip() + info = e.args[0].get('info', '').strip() + self.error("%s: %s %s" % (e.__class__.__name__, + desc, info)) + except Exception as e: # pylint: disable=broad-except + errmsg = 'Internal system error' self.error("Exception raised: [%s]" % repr(e)) else: - errmsg = "Username or password is missing" - self.error(errmsg) + self.error("Username or password is missing") - if authed: + if authok: return self.lm.auth_successful(self.trans, username, 'password', userdata=userattrs) diff --git a/tests/helpers/http.py b/tests/helpers/http.py index 0643fb1..8c0a291 100755 --- a/tests/helpers/http.py +++ b/tests/helpers/http.py @@ -300,7 +300,7 @@ class HttpSessions(object): raise ValueError("Unhandled status (%d) on url %s" % ( r.status_code, url)) - def auth_to_idp(self, idp, krb=False): + def auth_to_idp(self, idp, krb=False, rule=None, expected=None): srv = self.servers[idp] target_url = '%s/%s/' % (srv['baseuri'], idp) @@ -316,8 +316,12 @@ class HttpSessions(object): page = self.fetch_page(idp, url, krb=krb) - page.expected_value('//div[@id="welcome"]/p/text()', - 'Welcome %s!' % srv['user']) + if rule is None: + rule = '//div[@id="welcome"]/p/text()' + if expected is None: + expected = 'Welcome %s!' % srv['user'] + + page.expected_value(rule, expected) def logout_from_idp(self, idp): diff --git a/tests/ldapdown.py b/tests/ldapdown.py new file mode 100755 index 0000000..2c7138c --- /dev/null +++ b/tests/ldapdown.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +# +# Copyright (C) 2015 Ipsilon project Contributors, for license see COPYING + +# Test that we get a reasonable error back when the LDAP backend is down + +from helpers.common import IpsilonTestBase # pylint: disable=relative-import +from helpers.http import HttpSessions # pylint: disable=relative-import +import os +import sys +from string import Template + + +idp_g = {'TEMPLATES': '${TESTDIR}/templates/install', + 'CONFDIR': '${TESTDIR}/etc', + 'DATADIR': '${TESTDIR}/lib', + 'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d', + 'STATICDIR': '${ROOTDIR}', + 'BINDIR': '${ROOTDIR}/ipsilon', + 'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'} + + +idp_a = {'hostname': '${ADDRESS}:${PORT}', + 'admin_user': 'tuser', + 'system_user': '${TEST_USER}', + 'instance': '${NAME}', + 'secure': 'no', + 'pam': 'no', + 'gssapi': 'no', + 'ipa': 'no', + 'ldap': 'yes', + 'ldap_server_url': 'ldap://${ADDRESS}:45389/', + 'ldap_bind_dn_template': + 'uid=%(username)s,ou=People,dc=example,dc=com', + 'ldap_tls_level': 'NoTLS', + 'server_debugging': 'True'} + + +sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d', + 'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf', + 'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf', + 'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'} + + +sp_a = {'hostname': '${ADDRESS}:${PORT}', + 'saml_idp_metadata': 'http://127.0.0.10:45080/idp1/saml2/metadata', + 'saml_secure_setup': 'False', + 'saml_auth': '/sp', + 'httpd_user': '${TEST_USER}'} + + +def fixup_sp_httpd(httpdir): + merge = """ + MellonSetEnv "GROUPS" "groups" + MellonMergeEnvVars On +""" + with open(httpdir + '/conf.d/ipsilon-saml.conf', 'r') as f: + conf = f.read() + conf = conf.replace('', merge, 1) + with open(httpdir + '/conf.d/ipsilon-saml.conf', 'w') as f: + f.write(conf) + + location = """ + +Alias /sp ${HTTPDIR}/sp + + + Require all granted + Options +Includes + +""" + t = Template(location) + text = t.substitute({'HTTPDIR': httpdir}) + with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f: + f.write(text) + + index = """""" + os.mkdir(httpdir + '/sp') + with open(httpdir + '/sp/index.shtml', 'w') as f: + f.write(index) + + +class IpsilonTest(IpsilonTestBase): + + def __init__(self): + super(IpsilonTest, self).__init__('ldapdown', __file__) + + def setup_servers(self, env=None): + + print "Installing IDP's ldap server" + addr = '127.0.0.10' + port = '45389' + conf = self.setup_ldap(env) + + print "Not starting IDP's ldap server" + + print "Installing IDP server" + name = 'idp1' + addr = '127.0.0.10' + port = '45080' + idp = self.generate_profile(idp_g, idp_a, name, addr, port) + conf = self.setup_idp_server(idp, name, addr, port, env) + + print "Starting IDP's httpd server" + self.start_http_server(conf, env) + + print "Installing SP server" + name = 'sp1' + addr = '127.0.0.11' + port = '45081' + sp = self.generate_profile(sp_g, sp_a, name, addr, port) + conf = self.setup_sp_server(sp, name, addr, port, env) + fixup_sp_httpd(os.path.dirname(conf)) + + print "Starting SP's httpd server" + self.start_http_server(conf, env) + + +if __name__ == '__main__': + + idpname = 'idp1' + spname = 'sp1' + user = 'tuser' + + sess = HttpSessions() + sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'tuser') + sess.add_server(spname, 'http://127.0.0.11:45081') + + print "ldapdown: Authenticate to IDP with no LDAP backend...", + try: + sess.auth_to_idp( + idpname, + rule='//div[@class="alert alert-danger"]/p/text()', + expected="Internal system error" + ) + except Exception, e: # pylint: disable=broad-except + print >> sys.stderr, " ERROR: %s" % repr(e) + sys.exit(1) + print " SUCCESS"