LDAP/LDIF Parsing

C

Cruelemort

All,

I am hoping someone would be able to help me with a problem. I have an
LDAP server running on a linux box, this LDAP server contains a
telephone list in various groupings, the ldif file of which is -

dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: Example Organisation

dn: ou=groupa,dc=example,dc=com
ou: groupa
objectClass: top
objectClass: organizationalUnit
description: Group A

dn: cn=johnsmith,ou=groupa,dc=example,dc=com
cn: johnsmith
objectClass: top
objectClass: person
sn: Smith
telephoneNumber: 112

dn: cn=davesteel,ou=groupa,dc=example,dc=com
cn: davesteel
objectClass: top
objectClass: person
sn: Steel
telephoneNumber: 113

dn: ou=groupb,dc=example,dc=com
ou: groupb
objectClass: top
objectClass: organizationalUnit
description: Group B

dn: cn=williamdavis,ou=groupb,dc=example,dc=com
cn: williamdavis
objectClass: top
objectClass: person
sn: Davis
telephoneNumber: 122

dn: cn=jamesjarvis,ou=groupb,dc=example,dc=com
cn: jamesjarvis
objectClass: top
objectClass: person
sn: Jarvis
telephoneNumber: 123

I am creating a python client program that will display the telephone
list in the same directory structure as is on the LDAP server (i.e. it
starts with buttons of all the groups, when you click on a group it
comes up with buttons of all the numbers or groups available, and you
can continually drill down).

I was wondering the best way to do this? I have installed and used the
python-ldap libraries and these allow me to access and search the
server, but the searches always return a horrible nesting of lists,
tuples and dictionaries, below is an example of returning just one
record -

('dc=example,dc=com', {'objectClass': ['top', 'dcObject',
'organization'], 'dc': ['example'], 'o': ['Example Organisation']})

Basically i think i need to parse the search results to create objects
and build the python buttons around this, but i was hoping someone
would be able to point me in the correct direction of how to do this?
Is there a parser available? (there is an ldif library available but
it is not obvious how this works, i cannot see much documentation, and
it seems to be deprecated...).

Many thanks.

Ian
 
D

Diez B. Roggisch

I was wondering the best way to do this? I have installed and used the
python-ldap libraries and these allow me to access and search the
server, but the searches always return a horrible nesting of lists,
tuples and dictionaries, below is an example of returning just one
record -

('dc=example,dc=com', {'objectClass': ['top', 'dcObject',
'organization'], 'dc': ['example'], 'o': ['Example Organisation']})


But this is exactly what your LDAP-record contains. What else should there
be? And no, you don't need a parser, as the above _is_ the parsed result.
No parser can possibly give you anything else.

You can of course create wrapper-objects, that you instantiate based on the
values in 'objectClass', and that allow convenient access to certain
properties. Yet this is entirely up to you, as there is no one else who can
forsee how things should look and work like in _your_ application.

Diez
 
B

Bruno Desthuilliers

Cruelemort a écrit :
All,

I am hoping someone would be able to help me with a problem. I have an
LDAP server running on a linux box, this LDAP server contains a
telephone list in various groupings, the ldif file of which is -
(snip)

I am creating a python client program that will display the telephone
list in the same directory structure as is on the LDAP server (i.e. it
starts with buttons of all the groups, when you click on a group it
comes up with buttons of all the numbers or groups available, and you
can continually drill down).

I was wondering the best way to do this? I have installed and used the
python-ldap libraries and these allow me to access and search the
server, but the searches always return a horrible nesting of lists,
tuples and dictionaries, below is an example of returning just one
record -

('dc=example,dc=com', {'objectClass': ['top', 'dcObject',
'organization'], 'dc': ['example'], 'o': ['Example Organisation']})

What's your problem ? That's exactly what your ldap record should look
like. A (base_dn, record) tuple, where the record is a dict of
attribute_name:[values, ...]
Basically i think i need to parse the search results to create objects

Q&D wrapper:

class LdapObject(object):
def __init__(self, ldapentry):
self.dn, self._record = ldapentry

def __getattr__(self, name):
try:
data = self._record[name]
except KeyError:
raise AttributeError(
"object %s has no attribute %s" % (self, name)
)
else:
# all LDAP attribs are multivalued by default,
# even when the schema says they are monovalued
if len(data) == 1:
return data[0]
else:
return data[:]

def isa(self, objectClass):
return objectClass in self.objectClass:

root = LdapObject(
('dc=example,dc=com',
{'objectClass': ['top', 'dcObject','organization'],
'dc': ['example'],
'o': ['Example Organisation']}
))

root.o
=> 'Example Organisation'
root.objectClass
=> ['top', 'dcObject','organization']
root.isa('organization')
=> True

FWIW, I once started writing an higher-level LDAP api (kind of an
Object-LDAP Mapper...) using descriptors for ldap attribute access, but
I never finished the damned thing, and it's in a very sorry state. I'll
have to get back to it one day...
and build the python buttons around this, but i was hoping someone
would be able to point me in the correct direction of how to do this?
Is there a parser available?

cf above.
 
A

aspineux

The tree hierarchy is defined by the DN of each object, the types of
the object is specified by its objectClass.
Just collect all items (or do it dynamically by tunning the scope and
the base of your search request)
 
C

Cruelemort

The tree hierarchy is defined by the DN of each object, the types of
the object is specified by its objectClass.
Just collect all items (or do it dynamically by tunning the scope and
the base of your search request)

I am hoping someone would be able to help me with a problem. I have an
LDAP server running on a linux box, this LDAP server contains a
telephone list in various groupings, the ldif file of which is -
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: Example Organisation
dn: ou=groupa,dc=example,dc=com
ou: groupa
objectClass: top
objectClass: organizationalUnit
description: Group A
dn: cn=johnsmith,ou=groupa,dc=example,dc=com
cn: johnsmith
objectClass: top
objectClass: person
sn: Smith
telephoneNumber: 112
dn: cn=davesteel,ou=groupa,dc=example,dc=com
cn: davesteel
objectClass: top
objectClass: person
sn: Steel
telephoneNumber: 113
dn: ou=groupb,dc=example,dc=com
ou: groupb
objectClass: top
objectClass: organizationalUnit
description: Group B
dn: cn=williamdavis,ou=groupb,dc=example,dc=com
cn: williamdavis
objectClass: top
objectClass: person
sn: Davis
telephoneNumber: 122
dn: cn=jamesjarvis,ou=groupb,dc=example,dc=com
cn: jamesjarvis
objectClass: top
objectClass: person
sn: Jarvis
telephoneNumber: 123
I am creating a python client program that will display the telephone
list in the same directory structure as is on the LDAP server (i.e. it
starts with buttons of all the groups, when you click on a group it
comes up with buttons of all the numbers or groups available, and you
can continually drill down).
I was wondering the best way to do this? I have installed and used the
python-ldap libraries and these allow me to access and search the
server, but the searches always return a horrible nesting of lists,
tuples and dictionaries, below is an example of returning just one
record -
('dc=example,dc=com', {'objectClass': ['top', 'dcObject',
'organization'], 'dc': ['example'], 'o': ['Example Organisation']})
Basically i think i need to parse the search results to create objects
and build the python buttons around this, but i was hoping someone
would be able to point me in the correct direction of how to do this?
Is there a parser available? (there is an ldif library available but
it is not obvious how this works, i cannot see much documentation, and
it seems to be deprecated...).
Many thanks.
Ian- Hide quoted text -

- Show quoted text -

Thanks for the replies all - it was a higher level wrapper like Bruno
mentioned that i was looking for (with objects and attributes based on
each objectClass), but the code posted above will work fine.

Many thanks all.

Ian
 
H

Hallvard B Furuseth

Bruno said:
class LdapObject(object):
(...)
def __getattr__(self, name):
try:
data = self._record[name]
except KeyError:
raise AttributeError(
"object %s has no attribute %s" % (self, name)
)

Note that LDAP attribute descriptions may be invalid Python
attribute names. E.g.
{...
'title;lang-en': ['The Boss']
'title;lang-no': ['Sjefen']}
So you'd have to call getattr() explicitly to get at all the attributes
this way.
else:
# all LDAP attribs are multivalued by default,
# even when the schema says they are monovalued
if len(data) == 1:
return data[0]
else:
return data[:]

IMHO, this just complicates the client code since the client needs to
inserts checks of isinstance(return value, list) all over the place.
Better to have a separate method which extracts just the first value of
an attribute, if you want that.
 
B

Bruno Desthuilliers

Hallvard B Furuseth a écrit :
Bruno said:
class LdapObject(object):
(...)
def __getattr__(self, name):
try:
data = self._record[name]
except KeyError:
raise AttributeError(
"object %s has no attribute %s" % (self, name)
)

Note that LDAP attribute descriptions may be invalid Python
attribute names. E.g.
{...
'title;lang-en': ['The Boss']
'title;lang-no': ['Sjefen']}
So you'd have to call getattr() explicitly to get at all the attributes
this way.

Yeps, true. Another solution would be to add a __getitem__ method
pointing to the same implementation, ie:

__getitem__ = __getattr__
else:
# all LDAP attribs are multivalued by default,
# even when the schema says they are monovalued
if len(data) == 1:
return data[0]
else:
return data[:]

IMHO, this just complicates the client code since the client needs to
inserts checks of isinstance(return value, list) all over the place.
Better to have a separate method which extracts just the first value of
an attribute, if you want that.

Most of the times, in a situation such as the one described by the OP,
one knows by advance if a given LDAP attribute will be used as
monovalued or multivalued. Well, this is at least my own experience...
 
?

=?ISO-8859-1?Q?Michael_Str=F6der?=

Cruelemort said:
I was wondering the best way to do this? I have installed and used the
python-ldap libraries and these allow me to access and search the
server, but the searches always return a horrible nesting of lists,
tuples and dictionaries, below is an example of returning just one
record -

('dc=example,dc=com', {'objectClass': ['top', 'dcObject',
'organization'], 'dc': ['example'], 'o': ['Example Organisation']})

It's just modeled after the X.500 data model. A DN and the entry. The
entry consists of attributes which consists of attribute type and a set
of attribute values.

You could write your own wrapper class around ldap.ldapobject.LDAPObject
and overrule method search_s().
(there is an ldif library available but
it is not obvious how this works, i cannot see much documentation, and
it seems to be deprecated...).

Module ldif is not deprecated. It's actively maintained by me like the
rest of python-ldap. It parses LDIF and returns the same data structure
as above. You don't need it for LDAP access anyway. Only for reading
LDIF files.

Ciao, Michael.
 
H

Hallvard B Furuseth

Bruno said:
Hallvard B Furuseth a écrit :
else:
# all LDAP attribs are multivalued by default,
# even when the schema says they are monovalued
if len(data) == 1:
return data[0]
else:
return data[:]
IMHO, this just complicates the client code since the client needs to
inserts checks of isinstance(return value, list) all over the place.
Better to have a separate method which extracts just the first value of
an attribute, if you want that.

Most of the times, in a situation such as the one described by the OP,
one knows by advance if a given LDAP attribute will be used as
monovalued or multivalued. Well, this is at least my own experience...

But if the attribute is multivalued, you don't know if it will contain
just one value or not. If you expect telephoneNumber to be multivalued,
but receive just one value '123',
for value in foo.telephoneNumber: print value
will print
1
2
3

BTW, Cruelemort, remember that attribute names are case-insensitive. If
you ask the server to for attribute "cn", it might still return "CN".
 
B

Bruno Desthuilliers

Hallvard B Furuseth a écrit :
Bruno said:
Hallvard B Furuseth a écrit :
else:
# all LDAP attribs are multivalued by default,
# even when the schema says they are monovalued
if len(data) == 1:
return data[0]
else:
return data[:]

IMHO, this just complicates the client code since the client needs to
inserts checks of isinstance(return value, list) all over the place.
Better to have a separate method which extracts just the first value of
an attribute, if you want that.

Most of the times, in a situation such as the one described by the OP,
one knows by advance if a given LDAP attribute will be used as
monovalued or multivalued. Well, this is at least my own experience...

But if the attribute is multivalued, you don't know if it will contain
just one value or not.

If you know which attributes are supposed to be multivalued in your
specific application, then it's time to write a more serious,
application-specific wrapper.
 
?

=?ISO-8859-1?Q?Michael_Str=F6der?=

Bruno said:
If you know which attributes are supposed to be multivalued in your
specific application, then it's time to write a more serious,
application-specific wrapper.

ldap.schema can be used to find that out.

Ciao, Michael.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top