mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Move LDAPEntry to ipaserver.ipaldap and derive Entry from it
Legacy Entry methods such as setValue are added to LDAPEntry directly, so that we can use connection classes that return LDAPEntry with code that expects Entries. The Entry and its unique __init__ are still kept for compatibility. Part of the work for: https://fedorahosted.org/freeipa/ticket/2660
This commit is contained in:
committed by
Martin Kosek
parent
a8c0bf0c85
commit
49a0e3ac01
@@ -23,11 +23,8 @@ import sys
|
||||
import os
|
||||
import os.path
|
||||
import socket
|
||||
import ldif
|
||||
import re
|
||||
import string
|
||||
import ldap
|
||||
import cStringIO
|
||||
import time
|
||||
import struct
|
||||
import ldap.sasl
|
||||
@@ -38,10 +35,10 @@ from ipapython import ipautil
|
||||
from ipalib import errors
|
||||
from ipapython.ipautil import format_netloc, wait_for_open_socket, wait_for_open_ports
|
||||
from ipapython.dn import DN
|
||||
from ipaserver.plugins.ldap2 import IPASimpleLDAPObject, LDAPEntry
|
||||
from ipaserver.plugins.ldap2 import IPASimpleLDAPObject
|
||||
|
||||
# Global variable to define SASL auth
|
||||
SASL_AUTH = ldap.sasl.sasl({},'GSSAPI')
|
||||
SASL_AUTH = ldap.sasl.sasl({}, 'GSSAPI')
|
||||
DEFAULT_TIMEOUT = 10
|
||||
|
||||
class IPAEntryLDAPObject(IPASimpleLDAPObject):
|
||||
@@ -85,59 +82,111 @@ class IPAEntryLDAPObject(IPASimpleLDAPObject):
|
||||
else:
|
||||
return IPASimpleLDAPObject.add_ext_s(self, dn, modlist, serverctrls, clientctrls)
|
||||
|
||||
class Entry:
|
||||
"""
|
||||
This class represents an LDAP Entry object. An LDAP entry consists of
|
||||
a DN and a list of attributes. Each attribute consists of a name and
|
||||
a list of values. In python-ldap, entries are returned as a list of
|
||||
2-tuples. Instance variables:
|
||||
|
||||
* dn - DN object - the DN of the entry
|
||||
* data - CIDict - case insensitive dict of the attributes and values
|
||||
"""
|
||||
def __init__(self,entrydata):
|
||||
"""data is the raw data returned from the python-ldap result method, which is
|
||||
a search result entry or a reference or None.
|
||||
If creating a new empty entry, data is the string DN."""
|
||||
if entrydata:
|
||||
if isinstance(entrydata,LDAPEntry):
|
||||
self.dn = entrydata.dn
|
||||
self.data = entrydata
|
||||
elif isinstance(entrydata,tuple):
|
||||
self.dn = entrydata[0]
|
||||
self.data = ipautil.CIDict(entrydata[1])
|
||||
elif isinstance(entrydata,DN):
|
||||
self.dn = entrydata
|
||||
self.data = ipautil.CIDict()
|
||||
elif isinstance(entrydata, basestring):
|
||||
self.dn = DN(entrydata)
|
||||
self.data = ipautil.CIDict()
|
||||
elif isinstance(entrydata, dict):
|
||||
if hasattr(entrydata, 'dn'):
|
||||
entrydata['dn'] = entrydata.dn
|
||||
self.dn = entrydata['dn']
|
||||
del entrydata['dn']
|
||||
self.data = ipautil.CIDict(entrydata)
|
||||
else:
|
||||
raise TypeError("entrydata must be 2-tuple, DN, or basestring, got %s" % type(entrydata))
|
||||
# Make python-ldap tuple style result compatible with Entry and Entity
|
||||
# objects by allowing access to the dn (tuple index 0) via the 'dn'
|
||||
# attribute name and the attr dict (tuple index 1) via the 'data'
|
||||
# attribute name. Thus:
|
||||
# r = result[0]
|
||||
# r[0] == r.dn
|
||||
# r[1] == r.data
|
||||
class LDAPEntry(dict):
|
||||
__slots__ = ('_dn',)
|
||||
|
||||
def __init__(self, _dn=None, _obj=None, **kwargs):
|
||||
if isinstance(_dn, LDAPEntry):
|
||||
assert _obj is None
|
||||
_obj = _dn
|
||||
self._dn = DN(_obj._dn) #pylint: disable=E1103
|
||||
else:
|
||||
self.dn = DN()
|
||||
self.data = ipautil.CIDict()
|
||||
assert isinstance(_dn, DN)
|
||||
if _obj is None:
|
||||
_obj = {}
|
||||
self._dn = _dn
|
||||
|
||||
assert isinstance(self.dn, DN)
|
||||
super(LDAPEntry, self).__init__(self._init_iter(_obj, **kwargs))
|
||||
|
||||
dn = ipautil.dn_attribute_property('_dn')
|
||||
# properties for Entry and Entity compatibility
|
||||
@property
|
||||
def dn(self):
|
||||
return self._dn
|
||||
|
||||
def __nonzero__(self):
|
||||
"""This allows us to do tests like if entry: returns false if there is no data,
|
||||
true otherwise"""
|
||||
return self.data != None and len(self.data) > 0
|
||||
@dn.setter
|
||||
def dn(self, value):
|
||||
assert isinstance(value, DN)
|
||||
self._dn = value
|
||||
|
||||
def getValues(self,name):
|
||||
@property
|
||||
def data(self):
|
||||
# FIXME: for backwards compatibility only
|
||||
return self
|
||||
|
||||
def _attr_name(self, name):
|
||||
if not isinstance(name, basestring):
|
||||
raise TypeError(
|
||||
"attribute name must be unicode or str, got %s object %r" % (
|
||||
name.__class__.__name__, name))
|
||||
if isinstance(name, str):
|
||||
name = name.decode('ascii')
|
||||
return name.lower()
|
||||
|
||||
def _init_iter(self, _obj, **kwargs):
|
||||
_obj = dict(_obj, **kwargs)
|
||||
for (k, v) in _obj.iteritems():
|
||||
yield (self._attr_name(k), v)
|
||||
|
||||
def __repr__(self):
|
||||
dict_repr = super(LDAPEntry, self).__repr__()
|
||||
return '%s(%s, %s)' % (type(self).__name__, repr(self._dn), dict_repr)
|
||||
|
||||
def copy(self):
|
||||
return LDAPEntry(self)
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
super(LDAPEntry, self).__setitem__(self._attr_name(name), value)
|
||||
|
||||
def setdefault(self, name, default):
|
||||
return super(LDAPEntry, self).setdefault(self._attr_name(name), default)
|
||||
|
||||
def update(self, _obj={}, **kwargs):
|
||||
super(LDAPEntry, self).update(self._init_iter(_obj, **kwargs))
|
||||
|
||||
def __getitem__(self, name):
|
||||
# for python-ldap tuple compatibility
|
||||
if name == 0:
|
||||
return self._dn
|
||||
elif name == 1:
|
||||
return self
|
||||
|
||||
return super(LDAPEntry, self).__getitem__(self._attr_name(name))
|
||||
|
||||
def get(self, name, default=None):
|
||||
return super(LDAPEntry, self).get(self._attr_name(name), default)
|
||||
|
||||
def __delitem__(self, name):
|
||||
super(LDAPEntry, self).__delitem__(self._attr_name(name))
|
||||
|
||||
def pop(self, name, *default):
|
||||
return super(LDAPEntry, self).pop(self._attr_name(name), *default)
|
||||
|
||||
def __contains__(self, name):
|
||||
return super(LDAPEntry, self).__contains__(self._attr_name(name))
|
||||
|
||||
def has_key(self, name):
|
||||
return super(LDAPEntry, self).has_key(self._attr_name(name))
|
||||
|
||||
# for python-ldap tuple compatibility
|
||||
def __iter__(self):
|
||||
yield self._dn
|
||||
yield self
|
||||
|
||||
def getValues(self, name):
|
||||
# FIXME: for backwards compatibility only
|
||||
"""Get the list (array) of values for the attribute named name"""
|
||||
return self.data.get(name)
|
||||
|
||||
def getValue(self,name, default=None):
|
||||
def getValue(self, name, default=None):
|
||||
# FIXME: for backwards compatibility only
|
||||
"""Get the first value for the attribute named name"""
|
||||
value = self.data.get(name, default)
|
||||
if isinstance(value, (list, tuple)):
|
||||
@@ -145,6 +194,7 @@ class Entry:
|
||||
return value
|
||||
|
||||
def setValue(self, name, *value):
|
||||
# FIXME: for backwards compatibility only
|
||||
"""
|
||||
Set a value on this entry.
|
||||
|
||||
@@ -167,6 +217,7 @@ class Entry:
|
||||
setValues = setValue
|
||||
|
||||
def toTupleList(self):
|
||||
# FIXME: for backwards compatibility only
|
||||
"""Convert the attrs and values to a list of 2-tuples. The first element
|
||||
of the tuple is the attribute name. The second element is either a
|
||||
single value or a list of values."""
|
||||
@@ -177,6 +228,7 @@ class Entry:
|
||||
return r
|
||||
|
||||
def toDict(self):
|
||||
# FIXME: for backwards compatibility only
|
||||
"""Convert the attrs and values to a dict. The dict is keyed on the
|
||||
attribute name. The value is either single value or a list of values."""
|
||||
assert isinstance(self.dn, DN)
|
||||
@@ -186,29 +238,47 @@ class Entry:
|
||||
result['dn'] = self.dn
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
"""Convert the Entry to its LDIF representation"""
|
||||
return self.__repr__()
|
||||
|
||||
# the ldif class base64 encodes some attrs which I would rather see in
|
||||
# raw form - to encode specific attrs as base64, add them to the list below
|
||||
ldif.safe_string_re = re.compile('^$')
|
||||
base64_attrs = ['nsstate', 'krbprincipalkey', 'krbExtraData']
|
||||
class Entry(LDAPEntry):
|
||||
"""For compatibility with old code only
|
||||
|
||||
def __repr__(self):
|
||||
"""Convert the Entry to its LDIF representation"""
|
||||
sio = cStringIO.StringIO()
|
||||
# what's all this then? the unparse method will currently only accept
|
||||
# a list or a dict, not a class derived from them. self.data is a
|
||||
# cidict, so unparse barfs on it. I've filed a bug against python-ldap,
|
||||
# but in the meantime, we have to convert to a plain old dict for
|
||||
# printing
|
||||
# I also don't want to see wrapping, so set the line width really high
|
||||
# (1000)
|
||||
newdata = {}
|
||||
newdata.update(self.data)
|
||||
ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(str(self.dn),newdata)
|
||||
return sio.getvalue()
|
||||
This class represents an LDAP Entry object. An LDAP entry consists of
|
||||
a DN and a list of attributes. Each attribute consists of a name and
|
||||
a list of values. In python-ldap, entries are returned as a list of
|
||||
2-tuples. Instance variables:
|
||||
|
||||
* dn - DN object - the DN of the entry
|
||||
* data - CIDict - case insensitive dict of the attributes and values
|
||||
"""
|
||||
def __init__(self, entrydata):
|
||||
"""data is the raw data returned from the python-ldap result method, which is
|
||||
a search result entry or a reference or None.
|
||||
If creating a new empty entry, data is the string DN."""
|
||||
if entrydata:
|
||||
if isinstance(entrydata, (tuple, LDAPEntry)):
|
||||
dn = entrydata[0]
|
||||
data = ipautil.CIDict(entrydata[1])
|
||||
elif isinstance(entrydata, DN):
|
||||
dn = entrydata
|
||||
data = ipautil.CIDict()
|
||||
elif isinstance(entrydata, basestring):
|
||||
dn = DN(entrydata)
|
||||
data = ipautil.CIDict()
|
||||
elif isinstance(entrydata, dict):
|
||||
if hasattr(entrydata, 'dn'):
|
||||
entrydata['dn'] = entrydata.dn
|
||||
dn = entrydata['dn']
|
||||
del entrydata['dn']
|
||||
data = ipautil.CIDict(entrydata)
|
||||
else:
|
||||
raise TypeError(
|
||||
"entrydata must be 2-tuple, DN, or basestring, got %s" %
|
||||
type(entrydata))
|
||||
else:
|
||||
dn = DN()
|
||||
data = ipautil.CIDict()
|
||||
|
||||
super(Entry, self).__init__(dn, data)
|
||||
|
||||
|
||||
class IPAdmin(IPAEntryLDAPObject):
|
||||
|
||||
@@ -69,103 +69,6 @@ from ipalib.request import context
|
||||
|
||||
_debug_log_ldap = False
|
||||
|
||||
# Make python-ldap tuple style result compatible with Entry and Entity
|
||||
# objects by allowing access to the dn (tuple index 0) via the 'dn'
|
||||
# attribute name and the attr dict (tuple index 1) via the 'data'
|
||||
# attribute name. Thus:
|
||||
# r = result[0]
|
||||
# r[0] == r.dn
|
||||
# r[1] == r.data
|
||||
class LDAPEntry(dict):
|
||||
__slots__ = ('_dn',)
|
||||
|
||||
def __init__(self, _dn=None, _obj=None, **kwargs):
|
||||
if isinstance(_dn, LDAPEntry):
|
||||
assert _obj is None
|
||||
_obj = _dn
|
||||
self._dn = DN(_obj._dn) #pylint: disable=E1103
|
||||
else:
|
||||
assert isinstance(_dn, DN)
|
||||
if _obj is None:
|
||||
_obj = {}
|
||||
self._dn = _dn
|
||||
|
||||
super(LDAPEntry, self).__init__(self._init_iter(_obj, **kwargs))
|
||||
|
||||
# properties for Entry and Entity compatibility
|
||||
@property
|
||||
def dn(self):
|
||||
return self._dn
|
||||
|
||||
@dn.setter
|
||||
def dn(self, value):
|
||||
assert isinstance(value, DN)
|
||||
self._dn = value
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self
|
||||
|
||||
def _attr_name(self, name):
|
||||
if not isinstance(name, basestring):
|
||||
raise TypeError(
|
||||
"attribute name must be unicode or str, got %s object %r" % (
|
||||
name.__class__.__name__, name))
|
||||
if isinstance(name, str):
|
||||
name = name.decode('ascii')
|
||||
return name.lower()
|
||||
|
||||
def _init_iter(self, _obj, **kwargs):
|
||||
_obj = dict(_obj, **kwargs)
|
||||
for (k, v) in _obj.iteritems():
|
||||
yield (self._attr_name(k), v)
|
||||
|
||||
def __repr__(self):
|
||||
dict_repr = super(LDAPEntry, self).__repr__()
|
||||
return '%s(%s, %s)' % (type(self).__name__, repr(self._dn), dict_repr)
|
||||
|
||||
def copy(self):
|
||||
return LDAPEntry(self)
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
super(LDAPEntry, self).__setitem__(self._attr_name(name), value)
|
||||
|
||||
def setdefault(self, name, default):
|
||||
return super(LDAPEntry, self).setdefault(self._attr_name(name), default)
|
||||
|
||||
def update(self, _obj={}, **kwargs):
|
||||
super(LDAPEntry, self).update(self._init_iter(_obj, **kwargs))
|
||||
|
||||
def __getitem__(self, name):
|
||||
# for python-ldap tuple compatibility
|
||||
if name == 0:
|
||||
return self._dn
|
||||
elif name == 1:
|
||||
return self
|
||||
|
||||
return super(LDAPEntry, self).__getitem__(self._attr_name(name))
|
||||
|
||||
def get(self, name, default=None):
|
||||
return super(LDAPEntry, self).get(self._attr_name(name), default)
|
||||
|
||||
def __delitem__(self, name):
|
||||
super(LDAPEntry, self).__delitem__(self._attr_name(name))
|
||||
|
||||
def pop(self, name, *default):
|
||||
return super(LDAPEntry, self).pop(self._attr_name(name), *default)
|
||||
|
||||
def __contains__(self, name):
|
||||
return super(LDAPEntry, self).__contains__(self._attr_name(name))
|
||||
|
||||
def has_key(self, name):
|
||||
return super(LDAPEntry, self).has_key(self._attr_name(name))
|
||||
|
||||
# for python-ldap tuple compatibility
|
||||
def __iter__(self):
|
||||
yield self._dn
|
||||
yield self
|
||||
|
||||
|
||||
# Group Member types
|
||||
MEMBERS_ALL = 0
|
||||
MEMBERS_DIRECT = 1
|
||||
@@ -332,6 +235,7 @@ class SchemaCache(object):
|
||||
|
||||
schema_cache = SchemaCache()
|
||||
|
||||
|
||||
class IPASimpleLDAPObject(object):
|
||||
'''
|
||||
The purpose of this class is to provide a boundary between IPA and
|
||||
@@ -538,6 +442,10 @@ class IPASimpleLDAPObject(object):
|
||||
been converted to it's preferred IPA python type.
|
||||
'''
|
||||
|
||||
# FIXME: Temporarily import here to prevent import loops
|
||||
# Once ipaldap does not depend on ldap2, move the import to the top
|
||||
from ipaserver.ipaldap import LDAPEntry
|
||||
|
||||
ipa_result = []
|
||||
for dn_tuple in result:
|
||||
original_dn = dn_tuple[0]
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
import nose
|
||||
import os
|
||||
from ipaserver.plugins.ldap2 import ldap2, LDAPEntry
|
||||
from ipaserver.plugins.ldap2 import ldap2
|
||||
from ipaserver.ipaldap import LDAPEntry
|
||||
from ipalib.plugins.service import service, service_show
|
||||
from ipalib.plugins.host import host
|
||||
import nss.nss as nss
|
||||
|
||||
Reference in New Issue
Block a user