Changeset View
Changeset View
Standalone View
Standalone View
pykolab/auth/ldap/__init__.py
Show First 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | def authenticate(self, login, realm): | ||||
login[0], | login[0], | ||||
realm | realm | ||||
), | ), | ||||
level=8 | level=8 | ||||
) | ) | ||||
except: | except: | ||||
pass | pass | ||||
self.connect() | self.connect(immediate=True) | ||||
self._bind() | self._bind() | ||||
# See if we know a base_dn for the domain | # See if we know a base_dn for the domain | ||||
base_dn = None | base_dn = None | ||||
try: | try: | ||||
base_dn = auth_cache.get_entry(self.domain) | base_dn = auth_cache.get_entry(self.domain) | ||||
except: | except Exception, errmsg: | ||||
log.error(_("Authentication cache failed: %r") % (errmsg)) | |||||
pass | pass | ||||
if base_dn == None: | if base_dn == None: | ||||
config_base_dn = self.config_get('base_dn') | config_base_dn = self.config_get('base_dn') | ||||
ldap_base_dn = self._kolab_domain_root_dn(self.domain) | ldap_base_dn = self._kolab_domain_root_dn(self.domain) | ||||
if not ldap_base_dn == None and not ldap_base_dn == config_base_dn: | if not ldap_base_dn == None and not ldap_base_dn == config_base_dn: | ||||
base_dn = ldap_base_dn | base_dn = ldap_base_dn | ||||
else: | else: | ||||
base_dn = config_base_dn | base_dn = config_base_dn | ||||
try: | try: | ||||
auth_cache.set_entry(self.domain, base_dn) | auth_cache.set_entry(self.domain, base_dn) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Authentication cache failed: %r") % (errmsg)) | log.error(_("Authentication cache failed: %r") % (errmsg)) | ||||
pass | pass | ||||
try: | try: | ||||
user_filter = self.config_get_raw('user_filter') % ({'base_dn':base_dn}) | user_filter = self.config_get_raw('user_filter') % ( | ||||
{'base_dn': base_dn} | |||||
) | |||||
except TypeError, errmsg: | except TypeError, errmsg: | ||||
user_filter = self.config_get_raw('user_filter') | user_filter = self.config_get_raw('user_filter') | ||||
_filter = '(&(|' | _filter = '(&(|' | ||||
auth_attrs = self.config_get_list('auth_attributes') | auth_attrs = self.config_get_list('auth_attributes') | ||||
for attr in auth_attrs: | for attr in auth_attrs: | ||||
_filter += "(%s=%s)" % (attr, login[0]) | _filter += "(%s=%s)" % (attr, login[0]) | ||||
_filter += "(%s=%s@%s)" % (attr, login[0], realm) | _filter += "(%s=%s@%s)" % (attr, login[0], realm) | ||||
_filter += ')%s)' % (user_filter) | _filter += ')%s)' % (user_filter) | ||||
entry_dn = None | entry_dn = None | ||||
# Attempt to obtain an entry_dn from cache. | |||||
try: | try: | ||||
entry_dn = auth_cache.get_entry(_filter) | entry_dn = auth_cache.get_entry(_filter) | ||||
except: | except Exception, errmsg: | ||||
log.error(_("Authentication cache failed: %r") % (errmsg)) | |||||
pass | pass | ||||
if entry_dn == None: | retval = False | ||||
if entry_dn is None: | |||||
_search = self.ldap.search_ext( | _search = self.ldap.search_ext( | ||||
base_dn, | base_dn, | ||||
ldap.SCOPE_SUBTREE, | ldap.SCOPE_SUBTREE, | ||||
_filter, | _filter, | ||||
['entrydn'] | ['entrydn'] | ||||
) | ) | ||||
try: | try: | ||||
( | ( | ||||
_result_type, | _result_type, | ||||
_result_data, | _result_data, | ||||
_result_msgid, | _result_msgid, | ||||
_result_controls | _result_controls | ||||
) = self.ldap.result3(_search) | ) = self.ldap.result3(_search) | ||||
except ldap.SERVER_DOWN, errmsg: | except ldap.SERVER_DOWN, errmsg: | ||||
log.error(_("LDAP server unavailable: %r") % (errmsg)) | log.error(_("LDAP server unavailable: %r") % (errmsg)) | ||||
log.error(_("%s") % (traceback.format_exc())) | log.error(_("%s") % (traceback.format_exc())) | ||||
self._disconnect() | self._disconnect() | ||||
return False | return False | ||||
if len(_result_data) >= 1: | except Exception, errmsg: | ||||
log.error(_("Exception occurred: %r") % (errmsg)) | |||||
log.error(_("%s") % (traceback.format_exc())) | |||||
self._disconnect() | |||||
return False | |||||
log.debug( | |||||
_("Length of entries found: %r") % ( | |||||
len(_result_data) | |||||
), | |||||
level=8 | |||||
) | |||||
if len(_result_data) == 1: | |||||
(entry_dn, entry_attrs) = _result_data[0] | (entry_dn, entry_attrs) = _result_data[0] | ||||
elif len(_result_data) > 1: | |||||
try: | try: | ||||
# Needs to be synchronous or succeeds and continues setting retval | log.info( | ||||
# to True!! | _("Authentication for %r failed " + | ||||
"(multiple entries)") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
except: | |||||
pass | |||||
self._disconnect() | |||||
return False | |||||
else: | |||||
try: | |||||
log.info( | |||||
_("Authentication for %r failed (no entry)") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
except: | |||||
pass | |||||
self._disconnect() | |||||
return False | |||||
if entry_dn is None: | |||||
try: | |||||
log.info( | |||||
_("Authentication for %r failed (LDAP error?)") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
except: | |||||
pass | |||||
self._disconnect() | |||||
return False | |||||
try: | |||||
# Needs to be synchronous or succeeds and continues setting | |||||
# retval to True!! | |||||
retval = self._bind(entry_dn, login[1]) | retval = self._bind(entry_dn, login[1]) | ||||
if retval: | |||||
try: | |||||
log.info( | |||||
_("Authentication for %r succeeded") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
except: | |||||
pass | |||||
else: | |||||
try: | |||||
log.info( | |||||
_("Authentication for %r failed (error)") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
except: | |||||
pass | |||||
self._disconnect() | |||||
return False | |||||
try: | try: | ||||
auth_cache.set_entry(_filter, entry_dn) | auth_cache.set_entry(_filter, entry_dn) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.error(_("Authentication cache failed: %r") % (errmsg)) | log.error(_("Authentication cache failed: %r") % (errmsg)) | ||||
pass | pass | ||||
except ldap.SERVER_DOWN, errmsg: | except ldap.SERVER_DOWN, errmsg: | ||||
log.error(_("Authentication failed, LDAP server unavailable")) | log.error(_("Authentication failed, LDAP server unavailable")) | ||||
self._disconnect() | self._disconnect() | ||||
pass | |||||
except: | return False | ||||
except Exception, errmsg: | |||||
try: | try: | ||||
log.debug( | log.debug( | ||||
_("Failed to authenticate as user %s") % (login[0]), | _("Failed to authenticate as user %r") % ( | ||||
login[0] | |||||
), | |||||
level=8 | level=8 | ||||
) | ) | ||||
except: | except: | ||||
pass | pass | ||||
retval = False | self._disconnect() | ||||
return False | |||||
else: | else: | ||||
try: | try: | ||||
# Needs to be synchronous or succeeds and continues setting retval | # Needs to be synchronous or succeeds and continues setting | ||||
# to True!! | # retval to True!! | ||||
retval = self._bind(entry_dn, login[1]) | retval = self._bind(entry_dn, login[1]) | ||||
if retval: | |||||
log.info(_("Authentication for %r succeeded") % (login[0])) | |||||
else: | |||||
log.info( | |||||
_("Authentication for %r failed (password)") % ( | |||||
login[0] | |||||
) | |||||
) | |||||
self._disconnect() | |||||
return False | |||||
auth_cache.set_entry(_filter, entry_dn) | auth_cache.set_entry(_filter, entry_dn) | ||||
except ldap.NO_SUCH_OBJECT, errmsg: | except ldap.NO_SUCH_OBJECT, errmsg: | ||||
log.debug(_("Error occured, there is no such object: %r") % (errmsg), level=8) | log.debug( | ||||
_("Error occured, there is no such object: %r") % ( | |||||
errmsg | |||||
), | |||||
level=8 | |||||
) | |||||
self.bind = None | self.bind = None | ||||
try: | try: | ||||
auth_cache.del_entry(_filter) | auth_cache.del_entry(_filter) | ||||
except: | except: | ||||
log.error(_("Authentication cache failed to clear entry")) | log.error(_("Authentication cache failed to clear entry")) | ||||
pass | pass | ||||
return self.authenticate(login, realm) | retval = self.authenticate(login, realm) | ||||
except Exception, errmsg: | except Exception, errmsg: | ||||
log.debug(_("Exception occured: %r") %(errmsg)) | log.debug(_("Exception occured: %r") %(errmsg)) | ||||
try: | try: | ||||
log.debug( | log.debug( | ||||
_("Failed to authenticate as user %s") % (login[0]), | _("Failed to authenticate as user %r") % ( | ||||
login[0] | |||||
), | |||||
level=8 | level=8 | ||||
) | ) | ||||
except: | except: | ||||
pass | pass | ||||
retval = False | self._disconnect() | ||||
return False | |||||
self._disconnect() | |||||
return retval | return retval | ||||
def connect(self, priv=None): | def connect(self, priv=None, immediate=True): | ||||
""" | """ | ||||
Connect to the LDAP server through the uri configured. | Connect to the LDAP server through the uri configured. | ||||
""" | """ | ||||
# Already connected | |||||
if priv is None and self.ldap is not None: | if priv is None and self.ldap is not None: | ||||
return | return | ||||
# Already connected | |||||
if priv is not None and self.ldap_priv is not None: | if priv is not None and self.ldap_priv is not None: | ||||
return | return | ||||
log.debug(_("Connecting to LDAP..."), level=8) | log.debug(_("Connecting to LDAP..."), level=8) | ||||
uri = self.config_get('ldap_uri') | uri = self.config_get('ldap_uri') | ||||
log.debug(_("Attempting to use LDAP URI %s") % (uri), level=8) | log.debug(_("Attempting to use LDAP URI %s") % (uri), level=8) | ||||
trace_level = 0 | trace_level = 0 | ||||
if conf.debuglevel > 8: | if conf.debuglevel > 8: | ||||
trace_level = 1 | trace_level = 1 | ||||
if immediate: | |||||
retry_max = 1 | |||||
retry_delay = 1.0 | |||||
else: | |||||
retry_max = 200 | |||||
retry_delay = 3.0 | |||||
conn = ldap.ldapobject.ReconnectLDAPObject( | conn = ldap.ldapobject.ReconnectLDAPObject( | ||||
uri, | uri, | ||||
trace_level=trace_level, | trace_level=trace_level, | ||||
retry_max=200, | retry_max=retry_max, | ||||
retry_delay=3.0 | retry_delay=retry_delay | ||||
) | ) | ||||
conn.set_option(ldap.OPT_TIMEOUT, 10) | |||||
conn.protocol_version = 3 | conn.protocol_version = 3 | ||||
conn.supported_controls = [] | conn.supported_controls = [] | ||||
if priv is None: | if priv is None: | ||||
self.ldap = conn | self.ldap = conn | ||||
else: | else: | ||||
self.ldap_priv = conn | self.ldap_priv = conn | ||||
▲ Show 20 Lines • Show All 942 Lines • ▼ Show 20 Lines | |||||
### | ### | ||||
def _bind(self, bind_dn=None, bind_pw=None): | def _bind(self, bind_dn=None, bind_pw=None): | ||||
# If we have no LDAP, we have no previous state. | # If we have no LDAP, we have no previous state. | ||||
if self.ldap is None: | if self.ldap is None: | ||||
self.bind = None | self.bind = None | ||||
self.connect() | self.connect() | ||||
# If the bind_dn is None and the bind_pw is not... fail | |||||
if bind_dn is None and bind_pw is not None: | |||||
log.error(_("Attempting to bind without a DN but with a password")) | |||||
return False | |||||
# and the same vice-versa | |||||
if bind_dn is not None and bind_pw is None: | |||||
log.error(_("Attempting to bind with a DN but without a password")) | |||||
return False | |||||
# If we are to bind as foo, we have no state. | # If we are to bind as foo, we have no state. | ||||
if bind_dn is not None: | if bind_dn is not None: | ||||
self.bind = None | self.bind = None | ||||
# Only if we have no state and no bind credentials specified in the | # Only if we have no state and no bind credentials specified in the | ||||
# function call. | # function call. | ||||
if self.bind is None: | if self.bind is None: | ||||
if bind_dn is None: | if bind_dn is None: | ||||
bind_dn = self.config_get('service_bind_dn') | bind_dn = self.config_get('service_bind_dn') | ||||
if bind_pw is None: | if bind_pw is None: | ||||
bind_pw = self.config_get('service_bind_pw') | bind_pw = self.config_get('service_bind_pw') | ||||
if bind_dn is not None: | if bind_dn is not None: | ||||
log.debug(_("Binding with bind_dn: %s and password: %s") | log.debug(_("Binding with bind_dn: %s and password: %s") | ||||
% (bind_dn, '*' * len(bind_pw))) | % (bind_dn, '*' * len(bind_pw))) | ||||
# TODO: Binding errors control | # TODO: Binding errors control | ||||
try: | try: | ||||
# Must be synchronous | |||||
self.ldap.simple_bind_s(bind_dn, bind_pw) | self.ldap.simple_bind_s(bind_dn, bind_pw) | ||||
self.bind = {'dn': bind_dn, 'pw': bind_pw} | self.bind = {'dn': bind_dn, 'pw': bind_pw} | ||||
return True | return True | ||||
except ldap.SERVER_DOWN, errmsg: | except ldap.SERVER_DOWN, errmsg: | ||||
log.error(_("LDAP server unavailable: %r") % (errmsg)) | log.error(_("LDAP server unavailable: %r") % (errmsg)) | ||||
log.error(_("%s") % (traceback.format_exc())) | log.error(_("%s") % (traceback.format_exc())) | ||||
return False | return False | ||||
except ldap.INVALID_CREDENTIALS: | except ldap.INVALID_CREDENTIALS: | ||||
log.error(_("Invalid DN, username and/or password.")) | log.error(_("Invalid DN, username and/or password.")) | ||||
return False | return False | ||||
else: | else: | ||||
log.debug(_("bind() called but already bound"), level=8) | log.debug(_("bind() called but already bound"), level=8) | ||||
return True | return True | ||||
def _bind_priv(self): | def _bind_priv(self): | ||||
if self.ldap_priv is None: | if self.ldap_priv is None: | ||||
self.connect(True) | self.connect(True) | ||||
bind_dn = self.config_get('bind_dn') | bind_dn = self.config_get('bind_dn') | ||||
bind_pw = self.config_get('bind_pw') | bind_pw = self.config_get('bind_pw') | ||||
▲ Show 20 Lines • Show All 1,649 Lines • Show Last 20 Lines |