diff options
author | Petr Viktorin <pviktori@redhat.com> | 2013-01-31 08:26:38 -0500 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2013-03-13 12:36:33 +0100 |
commit | 664248d5b846321f61e0776b646cca82c5a17884 (patch) | |
tree | 63547fb882cfc17b82284042da8a3073bc42f8bd /ipapython | |
parent | a0242334feb3da01430f517806768965dabe92c2 (diff) | |
download | freeipa.git-664248d5b846321f61e0776b646cca82c5a17884.tar.gz freeipa.git-664248d5b846321f61e0776b646cca82c5a17884.tar.xz freeipa.git-664248d5b846321f61e0776b646cca82c5a17884.zip |
Use IPAdmin rather than raw python-ldap in migration.py and ipadiscovery.py
These used ipautil.get_ipa_basedn. Convert that to use the new wrappers.
Beef up the error handling in ipaldap to accomodate the errors we catch
in the server discovery.
Add a DatabaseTimeout exception to errors.py.
These were the last uses of ipautil.convert_ldap_error, remove that.
https://fedorahosted.org/freeipa/ticket/3487
https://fedorahosted.org/freeipa/ticket/3446
Diffstat (limited to 'ipapython')
-rw-r--r-- | ipapython/ipaldap.py | 53 | ||||
-rw-r--r-- | ipapython/ipautil.py | 68 |
2 files changed, 46 insertions, 75 deletions
diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py index 1403c9e8..10492d17 100644 --- a/ipapython/ipaldap.py +++ b/ipapython/ipaldap.py @@ -899,9 +899,7 @@ class LDAPClient(object): try: yield except ldap.TIMEOUT: - desc = '' - info = '' - raise + raise errors.DatabaseTimeout() except ldap.LDAPError, e: desc = e.args[0]['desc'].strip() info = e.args[0].get('info', '').strip() @@ -923,6 +921,8 @@ class LDAPClient(object): raise errors.ACIError(info=info) except ldap.INVALID_CREDENTIALS: raise errors.ACIError(info="%s %s" % (info, desc)) + except ldap.INAPPROPRIATE_AUTH: + raise errors.ACIError(info="%s: %s" % (desc, info)) except ldap.NO_SUCH_ATTRIBUTE: # this is raised when a 'delete' attribute isn't found. # it indicates the previous attribute was removed by another @@ -946,16 +946,19 @@ class LDAPClient(object): raise errors.NotAllowedOnNonLeaf() except ldap.SERVER_DOWN: raise errors.NetworkError(uri=self.ldap_uri, - error=u'LDAP Server Down') + error=info) except ldap.LOCAL_ERROR: raise errors.ACIError(info=info) except ldap.SUCCESS: pass + except ldap.CONNECT_ERROR: + raise errors.DatabaseError(desc=desc, info=info) except ldap.LDAPError, e: if 'NOT_ALLOWED_TO_DELEGATE' in info: raise errors.ACIError( info="KDC returned NOT_ALLOWED_TO_DELEGATE") - self.log.info('Unhandled LDAPError: %s' % str(e)) + self.log.debug( + 'Unhandled LDAPError: %s: %s' % (type(e).__name__, str(e))) raise errors.DatabaseError(desc=desc, info=info) @property @@ -1658,7 +1661,7 @@ class IPAdmin(LDAPClient): def __init__(self, host='', port=389, cacert=None, debug=None, ldapi=False, realm=None, protocol=None, force_schema_updates=True, start_tls=False, ldap_uri=None, no_schema=False, - decode_attrs=True, sasl_nocanon=False): + decode_attrs=True, sasl_nocanon=False, demand_cert=False): self.conn = None log_mgr.get_logger(self, True) if debug and debug.lower() == "on": @@ -1678,15 +1681,21 @@ class IPAdmin(LDAPClient): LDAPClient.__init__(self, ldap_uri) - self.conn = IPASimpleLDAPObject(ldap_uri, force_schema_updates=True, - no_schema=no_schema, - decode_attrs=decode_attrs) + with self.error_handler(): + self.conn = IPASimpleLDAPObject(ldap_uri, + force_schema_updates=True, + no_schema=no_schema, + decode_attrs=decode_attrs) + + if demand_cert: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, True) + self.conn.set_option(ldap.OPT_X_TLS_DEMAND, True) - if sasl_nocanon: - self.conn.set_option(ldap.OPT_X_SASL_NOCANON, ldap.OPT_ON) + if sasl_nocanon: + self.conn.set_option(ldap.OPT_X_SASL_NOCANON, ldap.OPT_ON) - if start_tls: - self.conn.start_tls_s() + if start_tls: + self.conn.start_tls_s() def __str__(self): return self.host + ":" + str(self.port) @@ -1700,18 +1709,16 @@ class IPAdmin(LDAPClient): wait_for_open_ports(host, int(port), timeout) def __bind_with_wait(self, bind_func, timeout, *args, **kwargs): - try: - bind_func(*args, **kwargs) - except (ldap.CONNECT_ERROR, ldap.SERVER_DOWN), e: - if not timeout or 'TLS' in e.args[0].get('info', ''): - # No connection to continue on if we have a TLS failure - # https://bugzilla.redhat.com/show_bug.cgi?id=784989 - raise e + with self.error_handler(): try: + bind_func(*args, **kwargs) + except (ldap.CONNECT_ERROR, ldap.SERVER_DOWN), e: + if not timeout or 'TLS' in e.args[0].get('info', ''): + # No connection to continue on if we have a TLS failure + # https://bugzilla.redhat.com/show_bug.cgi?id=784989 + raise self.__wait_for_connection(timeout) - except: - raise e - bind_func(*args, **kwargs) + bind_func(*args, **kwargs) def do_simple_bind(self, binddn=DN(('cn', 'directory manager')), bindpw="", timeout=DEFAULT_TIMEOUT): diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index c0ac3a1f..3d174ed0 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -34,7 +34,6 @@ import stat import shutil import urllib2 import socket -import ldap import struct from types import * import re @@ -829,30 +828,31 @@ def get_ipa_basedn(conn): None is returned if the suffix is not found - :param conn: Bound LDAP connection that will be used for searching + :param conn: Bound LDAPClient that will be used for searching """ - entries = conn.search_ext_s( - '', scope=ldap.SCOPE_BASE, attrlist=['defaultnamingcontext', 'namingcontexts'] - ) + entry = conn.get_entry( + DN(), attrs_list=['defaultnamingcontext', 'namingcontexts']) - contexts = entries[0][1]['namingcontexts'] - if entries[0][1].get('defaultnamingcontext'): + # FIXME: import ipalib here to prevent import loops + from ipalib import errors + + contexts = entry['namingcontexts'] + if 'defaultnamingcontext' in entry: # If there is a defaultNamingContext examine that one first - default = entries[0][1]['defaultnamingcontext'][0] + default = entry.single_value('defaultnamingcontext') if default in contexts: contexts.remove(default) - contexts.insert(0, entries[0][1]['defaultnamingcontext'][0]) + contexts.insert(0, default) for context in contexts: root_logger.debug("Check if naming context '%s' is for IPA" % context) try: - entry = conn.search_s(context, ldap.SCOPE_BASE, "(info=IPA*)") - except ldap.NO_SUCH_OBJECT: - root_logger.debug("LDAP server did not return info attribute to check for IPA version") - continue - if len(entry) == 0: - root_logger.debug("Info attribute with IPA server version not found") + [entry] = conn.get_entries( + DN(context), conn.SCOPE_BASE, "(info=IPA*)") + except errors.NotFound: + root_logger.debug("LDAP server did not return info attribute to " + "check for IPA version") continue - info = entry[0][1]['info'][0].lower() + info = entry.single_value('info').lower() if info != IPA_BASEDN_INFO: root_logger.debug("Detected IPA server version (%s) did not match the client (%s)" \ % (info, IPA_BASEDN_INFO)) @@ -1174,39 +1174,3 @@ def restore_hostname(statestore): run(['/bin/hostname', old_hostname]) except CalledProcessError, e: print >>sys.stderr, "Failed to set this machine hostname back to %s: %s" % (old_hostname, str(e)) - -def convert_ldap_error(exc): - """ - Make LDAP exceptions prettier. - - Some LDAP exceptions have a dict with descriptive information, if - this exception has a dict extract useful information from it and - format it into something usable and return that. If the LDAP - exception does not have an information dict then return the name - of the LDAP exception. - - If the exception is not an LDAP exception then convert the - exception to a string and return that instead. - """ - if isinstance(exc, ldap.LDAPError): - name = exc.__class__.__name__ - - if len(exc.args): - d = exc.args[0] - if isinstance(d, dict): - desc = d.get('desc', '').strip() - info = d.get('info', '').strip() - if desc and info: - return '%s %s' % (desc, info) - elif desc: - return desc - elif info: - return info - else: - return name - else: - return name - else: - return name - else: - return str(exc) |