diff --git a/ldapcherry/backend/backendLdap.py b/ldapcherry/backend/backendLdap.py index 610a439..e8ad15c 100644 --- a/ldapcherry/backend/backendLdap.py +++ b/ldapcherry/backend/backendLdap.py @@ -10,6 +10,7 @@ import ldap import ldap.modlist as modlist import logging import ldapcherry.backend +import os import re class DelUserDontExists(Exception): @@ -17,6 +18,11 @@ class DelUserDontExists(Exception): self.user = user self.log = "cannot remove user, user <%(user)s> does not exist" % { 'user' : user} +class CaFileDontExist(Exception): + def __init__(self, cafile): + self.cafile = cafile + self.log = "CA file %(cafile)s don't exist" % { 'cafile': cafile } + NO_ATTR = 0 DISPLAYED_ATTRS = 1 LISTED_ATTRS = 2 @@ -112,20 +118,31 @@ class Backend(ldapcherry.backend.Backend): def _connect(self): ldap_client = ldap.initialize(self.uri) - ldap_client.set_option(ldap.OPT_REFERRALS, 0) - ldap_client.set_option(ldap.OPT_TIMEOUT, self.timeout) + ldap.set_option(ldap.OPT_REFERRALS, 0) + ldap.set_option(ldap.OPT_TIMEOUT, self.timeout) if self.starttls == 'on': - ldap_client.set_option(ldap.OPT_X_TLS_DEMAND, True) + ldap.set_option(ldap.OPT_X_TLS_DEMAND, True) else: - ldap_client.set_option(ldap.OPT_X_TLS_DEMAND, False) + ldap.set_option(ldap.OPT_X_TLS_DEMAND, False) if self.ca and self.checkcert == 'on': - ldap_client.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca) + if os.path.isfile(self.ca): + ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca) + else: + raise CaFileDontExist(self.ca) #else: - # ldap_client.set_option(ldap.OPT_X_TLS_CACERTFILE, '') + # ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, '') if self.checkcert == 'off': - ldap_client.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) + # this is dark magic + # remove any of these two lines and it doesn't work + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + ldap_client.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) else: + # this is even darker magic ldap_client.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) + # it doesn't make sense to set it to never (don't check certifate) + # but it only works with this option... and it checks the certificat + # (I've lost my sanity over this) + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) if self.starttls == 'on': try: ldap_client.start_tls_s() diff --git a/tests/test_BackendLdap.py b/tests/test_BackendLdap.py index 3fe92e5..7d0628d 100644 --- a/tests/test_BackendLdap.py +++ b/tests/test_BackendLdap.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import pytest import sys from sets import Set -from ldapcherry.backend.backendLdap import Backend, DelUserDontExists +from ldapcherry.backend.backendLdap import Backend, DelUserDontExists, CaFileDontExist from ldapcherry.exceptions import * from disable import travis_disabled import cherrypy @@ -21,7 +21,7 @@ cfg = { 'binddn' : 'cn=dnscherry,dc=example,dc=org', 'password' : 'password', 'uri' : 'ldap://ldap.dnscherry.org:390', -'ca' : './test/cfg/ca.crt', +'ca' : './tests/test_env/etc/ldapcherry/TEST-cacert.pem', 'starttls' : 'off', 'checkcert' : 'off', 'user_filter_tmpl' : '(uid=%(username)s)', @@ -46,7 +46,6 @@ class TestError(object): inv = Backend(cfg, cherrypy.log, 'ldap', attr, 'uid') return True - @travis_disabled def testConnectSSLNoCheck(self): cfg2 = cfg.copy() cfg2['uri'] = 'ldaps://ldap.ldapcherry.org:637' @@ -61,7 +60,6 @@ class TestError(object): ldap.simple_bind_s(inv.binddn, inv.bindpassword) return True - @travis_disabled def testConnectSSL(self): cfg2 = cfg.copy() cfg2['uri'] = 'ldaps://ldap.dnscherry.org:637' @@ -75,28 +73,40 @@ class TestError(object): cfg2['uri'] = 'ldaps://notaldap:637' cfg2['checkcert'] = 'on' inv = Backend(cfg2, cherrypy.log, 'ldap', attr, 'uid') - ldapc = inv._connect() try: + ldapc = inv._connect() ldapc.simple_bind_s(inv.binddn, inv.bindpassword) except ldap.SERVER_DOWN as e: return else: raise AssertionError("expected an exception") - @travis_disabled + def testMissingCA(self): + cfg2 = cfg.copy() + cfg2['uri'] = 'ldaps://ldap.dnscherry.org:637' + cfg2['checkcert'] = 'on' + cfg2['ca'] = './test/cfg/not_a_ca.crt' + try: + inv = Backend(cfg2, cherrypy.log, 'ldap', attr, 'uid') + ldapc = inv._connect() + except CaFileDontExist as e: + return + else: + raise AssertionError("expected an exception") + def testConnectSSLWrongCA(self): cfg2 = cfg.copy() cfg2['uri'] = 'ldaps://ldap.ldapcherry.org:637' cfg2['checkcert'] = 'on' - cfg2['ca'] = './test/cfg/wrong_ca.crt' inv = Backend(cfg2, cherrypy.log, 'ldap', attr, 'uid') ldapc = inv._connect() try: ldapc.simple_bind_s(inv.binddn, inv.bindpassword) except ldap.SERVER_DOWN as e: assert e[0]['info'] == 'TLS: hostname does not match CN in peer certificate' + else: + raise AssertionError("expected an exception") - @travis_disabled def testConnectStartTLS(self): cfg2 = cfg.copy() cfg2['uri'] = 'ldap://ldap.ldapcherry.org:390' @@ -105,10 +115,7 @@ class TestError(object): cfg2['ca'] = './test/cfg/ca.crt' inv = Backend(cfg2, cherrypy.log, 'ldap', attr, 'uid') ldapc = inv._connect() - try: - ldapc.simple_bind_s(inv.binddn, inv.bindpassword) - except ldap.SERVER_DOWN as e: - assert e[0]['info'] == 'TLS: hostname does not match CN in peer certificate' + ldapc.simple_bind_s(inv.binddn, inv.bindpassword) def testAuthSuccess(self): inv = Backend(cfg, cherrypy.log, 'ldap', attr, 'uid')