Start LDAPConnection, a common base for ldap2 and IPAdmin

The first method to be extracted is handle_errors

Part of the work for: https://fedorahosted.org/freeipa/ticket/2660
This commit is contained in:
Petr Viktorin 2013-01-17 10:50:16 -05:00 committed by Martin Kosek
parent 9d41ee4b31
commit df4ed77962
2 changed files with 101 additions and 123 deletions

View File

@ -816,18 +816,104 @@ class Entry(LDAPEntry):
super(Entry, self).__init__(dn, data)
class IPAdmin(IPAEntryLDAPObject):
class LDAPConnection(object):
"""LDAP backend class
This class abstracts a LDAP connection, providing methods that work with
LADPEntries.
This class is not intended to be used directly; instead, use one of its
subclasses, IPAdmin or the ldap2 plugin.
"""
def __init__(self, ldap_uri):
self.ldap_uri = ldap_uri
self.log = log_mgr.get_logger(self)
def handle_errors(self, e, arg_desc=None):
"""Universal LDAPError handler
:param e: The error to be raised
:param url: The URL of the server
"""
if not isinstance(e, _ldap.TIMEOUT):
desc = e.args[0]['desc'].strip()
info = e.args[0].get('info', '').strip()
if arg_desc is not None:
info = "%s arguments: %s" % (info, arg_desc)
else:
desc = ''
info = ''
try:
# re-raise the error so we can handle it
raise e
except _ldap.NO_SUCH_OBJECT:
raise errors.NotFound(reason=arg_desc or 'no such entry')
except _ldap.ALREADY_EXISTS:
raise errors.DuplicateEntry()
except _ldap.CONSTRAINT_VIOLATION:
# This error gets thrown by the uniqueness plugin
_msg = 'Another entry with the same attribute value already exists'
if info.startswith(_msg):
raise errors.DuplicateEntry()
else:
raise errors.DatabaseError(desc=desc, info=info)
except _ldap.INSUFFICIENT_ACCESS:
raise errors.ACIError(info=info)
except _ldap.INVALID_CREDENTIALS:
raise errors.ACIError(info="%s %s" % (info, desc))
except _ldap.NO_SUCH_ATTRIBUTE:
# this is raised when a 'delete' attribute isn't found.
# it indicates the previous attribute was removed by another
# update, making the oldentry stale.
raise errors.MidairCollision()
except _ldap.INVALID_SYNTAX:
raise errors.InvalidSyntax(attr=info)
except _ldap.OBJECT_CLASS_VIOLATION:
raise errors.ObjectclassViolation(info=info)
except _ldap.ADMINLIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.SIZELIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.TIMELIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.NOT_ALLOWED_ON_RDN:
raise errors.NotAllowedOnRDN(attr=info)
except _ldap.FILTER_ERROR:
raise errors.BadSearchFilter(info=info)
except _ldap.NOT_ALLOWED_ON_NONLEAF:
raise errors.NotAllowedOnNonLeaf()
except _ldap.SERVER_DOWN:
raise errors.NetworkError(uri=self.ldap_uri,
error=u'LDAP Server Down')
except _ldap.LOCAL_ERROR:
raise errors.ACIError(info=info)
except _ldap.SUCCESS:
pass
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))
raise errors.DatabaseError(desc=desc, info=info)
class IPAdmin(LDAPConnection, IPAEntryLDAPObject):
def __localinit(self):
if self.protocol == 'ldaps':
IPAEntryLDAPObject.__init__(self,'ldaps://%s' % format_netloc(self.host, self.port))
ldap_uri = 'ldaps://%s' % format_netloc(self.host, self.port)
elif self.protocol == 'ldapi':
IPAEntryLDAPObject.__init__(self,'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % "-".join(self.realm.split(".")))
ldap_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % (
"-".join(self.realm.split(".")))
elif self.protocol == 'ldap':
IPAEntryLDAPObject.__init__(self,'ldap://%s' % format_netloc(self.host, self.port))
ldap_uri = 'ldap://%s' % format_netloc(self.host, self.port)
else:
raise ValueError('Protocol %r not supported' % self.protocol)
LDAPConnection.__init__(self, ldap_uri)
IPAEntryLDAPObject.__init__(self, ldap_uri)
def __guess_protocol(self):
"""Return the protocol to use based on flags passed to the constructor
@ -913,51 +999,7 @@ class IPAdmin(IPAEntryLDAPObject):
return sctrl
def __handle_errors(self, e, **kw):
"""
Centralize error handling in one place.
e is the error to be raised
**kw is an exception-specific list of options
"""
if not isinstance(e,ldap.TIMEOUT):
desc = e.args[0]['desc'].strip()
info = e.args[0].get('info','').strip()
arg_desc = kw.get('arg_desc')
if arg_desc is not None:
info += " arguments: %s" % arg_desc
else:
desc = ''
info = ''
try:
# re-raise the error so we can handle it
raise e
except ldap.NO_SUCH_OBJECT, e:
arg_desc = kw.get('arg_desc', "entry not found")
raise errors.NotFound(reason=arg_desc)
except ldap.ALREADY_EXISTS, e:
raise errors.DuplicateEntry()
except ldap.CONSTRAINT_VIOLATION, e:
# This error gets thrown by the uniqueness plugin
if info.startswith('Another entry with the same attribute value already exists'):
raise errors.DuplicateEntry()
else:
raise errors.DatabaseError(desc=desc,info=info)
except ldap.INSUFFICIENT_ACCESS, e:
raise errors.ACIError(info=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
# update, making the oldentry stale.
raise errors.MidairCollision()
except ldap.ADMINLIMIT_EXCEEDED, e:
raise errors.LimitsExceeded()
except ldap.SIZELIMIT_EXCEEDED, e:
raise errors.LimitsExceeded()
except ldap.TIMELIMIT_EXCEEDED, e:
raise errors.LimitsExceeded()
except ldap.LDAPError, e:
raise errors.DatabaseError(desc=desc,info=info)
return self.handle_errors(e, **kw)
def __wait_for_connection(self, timeout):
lurl = ldapurl.LDAPUrl(self.uri)
@ -1189,7 +1231,7 @@ class IPAdmin(IPAEntryLDAPObject):
attrlist.append(attr)
timeout += int(time.time())
if isinstance(dn,Entry):
if isinstance(dn, LDAPEntry):
dn = dn.dn
assert isinstance(dn, DN)

View File

@ -37,11 +37,10 @@ import krbV
import ldap as _ldap
import ldap.filter as _ldap_filter
from ipapython.ipa_log_manager import log_mgr
from ipapython.dn import DN, RDN
from ipalib.errors import NetworkError
from ipaserver.ipaldap import (
SASL_AUTH, unicode_from_utf8, value_to_utf8, IPASimpleLDAPObject)
SASL_AUTH, unicode_from_utf8, value_to_utf8, IPASimpleLDAPObject,
LDAPConnection)
try:
@ -70,7 +69,7 @@ MEMBERS_DIRECT = 1
MEMBERS_INDIRECT = 2
class ldap2(CrudBackend):
class ldap2(LDAPConnection, CrudBackend):
"""
LDAP Backend Take 2.
"""
@ -90,12 +89,14 @@ class ldap2(CrudBackend):
def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None,
schema=None):
CrudBackend.__init__(self, shared_instance=shared_instance)
self.log = log_mgr.get_logger(self)
try:
self.ldap_uri = ldap_uri or api.env.ldap_uri
ldap_uri = ldap_uri or api.env.ldap_uri
except AttributeError:
self.ldap_uri = 'ldap://example.com'
ldap_uri = 'ldap://example.com'
CrudBackend.__init__(self, shared_instance=shared_instance)
LDAPConnection.__init__(self, ldap_uri)
try:
if base_dn is not None:
self.base_dn = DN(base_dn)
@ -115,71 +116,6 @@ class ldap2(CrudBackend):
return self.conn.schema
schema = property(_get_schema, None, None, 'schema associated with this LDAP server')
# universal LDAPError handler
def handle_errors(self, e):
"""
Centralize error handling in one place.
e is the error to be raised
"""
if not isinstance(e, _ldap.TIMEOUT):
desc = e.args[0]['desc'].strip()
info = e.args[0].get('info', '').strip()
else:
desc = ''
info = ''
try:
# re-raise the error so we can handle it
raise e
except _ldap.NO_SUCH_OBJECT:
raise errors.NotFound(reason='no such entry')
except _ldap.ALREADY_EXISTS:
raise errors.DuplicateEntry()
except _ldap.CONSTRAINT_VIOLATION:
# This error gets thrown by the uniqueness plugin
if info.startswith('Another entry with the same attribute value already exists'):
raise errors.DuplicateEntry()
else:
raise errors.DatabaseError(desc=desc, info=info)
except _ldap.INSUFFICIENT_ACCESS:
raise errors.ACIError(info=info)
except _ldap.INVALID_CREDENTIALS:
raise errors.ACIError(info="%s %s" % (info, desc))
except _ldap.NO_SUCH_ATTRIBUTE:
# this is raised when a 'delete' attribute isn't found.
# it indicates the previous attribute was removed by another
# update, making the oldentry stale.
raise errors.MidairCollision()
except _ldap.INVALID_SYNTAX:
raise errors.InvalidSyntax(attr=info)
except _ldap.OBJECT_CLASS_VIOLATION:
raise errors.ObjectclassViolation(info=info)
except _ldap.ADMINLIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.SIZELIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.TIMELIMIT_EXCEEDED:
raise errors.LimitsExceeded()
except _ldap.NOT_ALLOWED_ON_RDN:
raise errors.NotAllowedOnRDN(attr=info)
except _ldap.FILTER_ERROR:
raise errors.BadSearchFilter(info=info)
except _ldap.NOT_ALLOWED_ON_NONLEAF:
raise errors.NotAllowedOnNonLeaf()
except _ldap.SERVER_DOWN:
raise NetworkError(uri=self.ldap_uri,
error=u'LDAP Server Down')
except _ldap.LOCAL_ERROR:
raise errors.ACIError(info=info)
except _ldap.SUCCESS:
pass
except _ldap.LDAPError, e:
if 'NOT_ALLOWED_TO_DELEGATE' in info:
raise errors.ACIError(info="KDC returned NOT_ALLOWED_TO_DELEGATE")
self.info('Unhandled LDAPError: %s' % str(e))
raise errors.DatabaseError(desc=desc, info=info)
def get_syntax(self, attr, value):
if self.schema is None:
return None