You can subscribe to this list here.
2000 |
Jan
|
Feb
(34) |
Mar
(9) |
Apr
|
May
(2) |
Jun
(14) |
Jul
(67) |
Aug
(34) |
Sep
(5) |
Oct
(20) |
Nov
(22) |
Dec
(31) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(15) |
Feb
(16) |
Mar
(20) |
Apr
(13) |
May
(72) |
Jun
(42) |
Jul
(41) |
Aug
(11) |
Sep
(19) |
Oct
(67) |
Nov
(59) |
Dec
(57) |
2002 |
Jan
(74) |
Feb
(69) |
Mar
(34) |
Apr
(55) |
May
(47) |
Jun
(74) |
Jul
(116) |
Aug
(68) |
Sep
(25) |
Oct
(42) |
Nov
(28) |
Dec
(52) |
2003 |
Jan
(19) |
Feb
(18) |
Mar
(35) |
Apr
(49) |
May
(73) |
Jun
(39) |
Jul
(26) |
Aug
(59) |
Sep
(33) |
Oct
(56) |
Nov
(69) |
Dec
(137) |
2004 |
Jan
(276) |
Feb
(15) |
Mar
(18) |
Apr
(27) |
May
(25) |
Jun
(7) |
Jul
(13) |
Aug
(2) |
Sep
(2) |
Oct
(10) |
Nov
(27) |
Dec
(28) |
2005 |
Jan
(22) |
Feb
(25) |
Mar
(41) |
Apr
(17) |
May
(36) |
Jun
(13) |
Jul
(22) |
Aug
(12) |
Sep
(23) |
Oct
(6) |
Nov
(4) |
Dec
|
2006 |
Jan
(11) |
Feb
(3) |
Mar
(5) |
Apr
(22) |
May
(1) |
Jun
(10) |
Jul
(19) |
Aug
(7) |
Sep
(25) |
Oct
(23) |
Nov
(5) |
Dec
(27) |
2007 |
Jan
(25) |
Feb
(17) |
Mar
(44) |
Apr
(8) |
May
(33) |
Jun
(31) |
Jul
(42) |
Aug
(16) |
Sep
(12) |
Oct
(16) |
Nov
(23) |
Dec
(73) |
2008 |
Jan
(26) |
Feb
(6) |
Mar
(46) |
Apr
(17) |
May
(1) |
Jun
(44) |
Jul
(9) |
Aug
(34) |
Sep
(20) |
Oct
(2) |
Nov
(4) |
Dec
(16) |
2009 |
Jan
(14) |
Feb
(3) |
Mar
(45) |
Apr
(52) |
May
(34) |
Jun
(32) |
Jul
(24) |
Aug
(52) |
Sep
(22) |
Oct
(23) |
Nov
(19) |
Dec
(10) |
2010 |
Jan
(10) |
Feb
(13) |
Mar
(22) |
Apr
(9) |
May
(1) |
Jun
(1) |
Jul
(8) |
Aug
(9) |
Sep
(10) |
Oct
(1) |
Nov
(2) |
Dec
(3) |
2011 |
Jan
|
Feb
(18) |
Mar
(39) |
Apr
(5) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Andreas H. <aha...@te...> - 2007-06-05 21:12:52
|
I have been having fun with controls. Today I tried to use the Pre-Read control together with the modify+increment extension, so that modify+increment becomes actually useful. I first added the encoding part to the ldap.so module, but later got a response from the pyasn1 mailing list and tried again in pure python. The result is attached. It's not complete yet, just a test. The script uses mod_increment to increment uidNumber and gidNumber by one. Attached to the modify operation is the preread control, so the response includes the value prior to the modification. Here is the output of two consecutive runs. Both attributes started at 1000 in LDAP: $ ./preread-asn1.py res: (103, [], 2, [PreReadControl(1.3.6.1.1.13.1,1.3.6.1.1.13.1,'0M\x04\x1fcn=unixIdPool,dc=example,dc=com0*0\x13\x04\tgidNumber1\x06\x04\x0410000\x13\x04\tuidNumber1\x06\x04\x041000')]) $ ./preread-asn1.py res: (103, [], 2, [PreReadControl(1.3.6.1.1.13.1,1.3.6.1.1.13.1,'0M\x04\x1fcn=unixIdPool,dc=example,dc=com0*0\x13\x04\tgidNumber1\x06\x04\x0410010\x13\x04\tuidNumber1\x06\x04\x041001')]) First one returns "1000", and the second one "1001" for both attributes. Now it's at 1002. The decoding part will probably be more difficult... As the control response is a SearchResultEntry which is a bit more complex to decode. |
From: <mi...@st...> - 2007-06-05 09:56:59
|
Andreas Hasenack wrote: > Attached. Ok. Committed it. Thanks. Ciao, Michael. |
From: Andreas H. <aha...@te...> - 2007-06-04 21:49:57
|
Attached. Simple example: print "Before:" print ld.search_s(BASE, ldap.SCOPE_SUBTREE, "(objectClass=sambaUnixIdPool)", ['uidNumber']) modlist = [(ldap.MOD_INCREMENT, "uidNumber", "1")] res = ld.modify_s("cn=unixIdPool,dc=example,dc=com", modlist) print "After:" print ld.search_s(BASE, ldap.SCOPE_SUBTREE, "(objectClass=sambaUnixIdPool)", ['uidNumber']) Output: $ ./modify+increment.py Before: [('cn=unixIdPool,dc=example,dc=com', {'uidNumber': ['1042']})] After: [('cn=unixIdPool,dc=example,dc=com', {'uidNumber': ['1043']})] |
From: <mi...@st...> - 2007-06-04 14:06:45
|
HI! Don't want to blame anybody but it seems unfeasible to determine the status of the ldaptor project. Therefore I prefer not to rely on it at all. And IIRC it's strictly GPL. python-ldap has a more liberal license. Therefore we cannot copy code from it. Ciao, Michael. On 2:19:03 pm 2007-06-04 "Chaos Eternal" <cha...@gm...> wrote: > oops, I forget to check the activity. > but from Debian's view: http://packages.qa.debian.org/l/ldaptor.html > , the project's activity lasts until Oct, 2006. > > On 6/4/07, Roland Hedberg <rol...@ad...> wrote: > > > > Chaos Eternal wrote: > > > Ldaptor is a pure-Python library that implements > > > > That it is, but do anyone know if it is actively maintained ? > > > > Looking at the Trac-page for the project > > (http://www.inoi.fi/open/trac/ldaptor) , it seems that nothing has > > happend with ldaptor since 2005. > > > > -- Roland |
From: Chaos E. <cha...@gm...> - 2007-06-04 12:19:04
|
oops, I forget to check the activity. but from Debian's view: http://packages.qa.debian.org/l/ldaptor.html , the project's activity lasts until Oct, 2006. On 6/4/07, Roland Hedberg <rol...@ad...> wrote: > > Chaos Eternal wrote: > > Ldaptor is a pure-Python library that implements > > That it is, but do anyone know if it is actively maintained ? > > Looking at the Trac-page for the project > (http://www.inoi.fi/open/trac/ldaptor) , it seems that nothing has > happend with ldaptor since 2005. > > -- Roland > -- Best Regards Chaos Eternal |
From: <mi...@st...> - 2007-06-04 11:31:03
|
On 8:00:48 am 2007-06-04 Roland Hedberg <rol...@ad...> wrote: > Chaos Eternal wrote: > > Ldaptor is a pure-Python library that implements > > That it is, but do anyone know if it is actively maintained ? > > Looking at the Trac-page for the project > (http://www.inoi.fi/open/trac/ldaptor) , it seems that nothing has > happend with ldaptor since 2005. IIRC I've contacted the author to join forces several years ago. No response. Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-06-04 11:30:53
|
On 6/3/07, Michael Str=F6der <mi...@st...> wrote: > > Alain Spineux wrote: > > > > Alain, this seems to make sense. But are you sure that it's valid > for > > all versions of Cyrus-SASL? I > > > > No :-( > > So let's keep it as it is. Right. Ciao, Michael. > > Regards --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: Roland H. <rol...@ad...> - 2007-06-04 07:04:40
|
Chaos Eternal wrote: > Ldaptor is a pure-Python library that implements That it is, but do anyone know if it is actively maintained ? Looking at the Trac-page for the project (http://www.inoi.fi/open/trac/ldaptor) , it seems that nothing has happend with ldaptor since 2005. -- Roland |
From: <mi...@st...> - 2007-06-04 05:37:13
|
Alain Spineux wrote: > > On 6/1/07, *Michael Ströder* <mi...@st... > <mailto:mi...@st...>> wrote: > > Alain Spineux wrote: > > > > May I suggest to change (in file LDAPObject.c ) > >> #include <sasl.h> > > into > >> #include <sasl/sasl.h> > > Alain, this seems to make sense. But are you sure that it's valid for > all versions of Cyrus-SASL? I > > No :-( So let's keep it as it is. Ciao, Michael. |
From: Chaos E. <cha...@gm...> - 2007-06-03 11:39:51
|
Ldaptor is a pure-Python library that implements . - LDAP client logic. . - separately-accessible LDAP and BER protocol message generation/parsing. . - ASCII-format LDAP filter generation and parsing. . - LDIF format data generation. . - Samba password changing logic. . On 6/1/07, Andreas Hasenack <aha...@te...> wrote: > > On Fri, Jun 01, 2007 at 04:44:32PM +0800, Chaos Eternal wrote: > > I have tested LDAP Server Side Sort with Novell's eDirectory 8.8.1using > > BER constructor form LDAPTOR project and python-ldap's ldap interface. > > from my side, it works. > > so why not try LDAPTOR's BER constructor for your purpose? > > I think I would really like something like openldap's ber_printf > routines. Seems fairly easy to construct these sequences with it. I > don't know about LAPTOR, never heard of it before. Is it some sort of > python interface to liblber? (Yes, I know, I can google it :P) > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Python-LDAP-dev mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/python-ldap-dev > -- Best Regards Chaos Eternal |
From: Andreas H. <aha...@te...> - 2007-06-01 14:28:42
|
On Thu, May 31, 2007 at 07:23:36PM -0300, Andreas Hasenack wrote: > I will still see about the decode part and then post what I have. Attached is my current patch. Keep in mind I did this basically using the current code as a template. I ended up not implementing the decode part, I'm not sure for what it would be needed. Just for completeness? |
From: Andreas H. <aha...@te...> - 2007-06-01 12:16:16
|
On Fri, Jun 01, 2007 at 12:51:08AM +0200, Michael Ströder wrote: > Andreas Hasenack wrote: > > > > Luckily in my case the OpenLDAP library already has a > > function called ldap_put_vrFilter() which I could use to do all the > > encoding of a ValuesReturn filter. > > [..] > > I will still see about the decode part and then post what I have. > > Since which version of OpenLDAP is ldap_put_vrFilter() present? Found it in the first public 2.3.x version (2.3.4) and also in late 2.2.x versions. I didn't check further back. So I guess it would be OK to use it, given that python-ldap currently requires openldap 2.3.x. |
From: Andreas H. <aha...@te...> - 2007-06-01 12:07:46
|
On Fri, Jun 01, 2007 at 04:44:32PM +0800, Chaos Eternal wrote: > I have tested LDAP Server Side Sort with Novell's eDirectory 8.8.1 using > BER constructor form LDAPTOR project and python-ldap's ldap interface. > from my side, it works. > so why not try LDAPTOR's BER constructor for your purpose? I think I would really like something like openldap's ber_printf routines. Seems fairly easy to construct these sequences with it. I don't know about LAPTOR, never heard of it before. Is it some sort of python interface to liblber? (Yes, I know, I can google it :P) |
From: Alain S. <asp...@gm...> - 2007-06-01 11:19:34
|
On 6/1/07, Michael Str=F6der <mi...@st...> wrote: > > Alain Spineux wrote: > > > > May I suggest to change (in file LDAPObject.c ) > > > >> #include <sasl.h> > > > > into > > > >> #include <sasl/sasl.h> > > > > That way you can change (in file setup.cfg) > > > >> library_dirs =3D /usr/local/openldap- 2.3/lib > >> include_dirs =3D /usr/local/openldap-2.3/include /usr/include/sasl > > > > into > > > >> library_dirs =3D /usr/local/openldap-2.3/lib > >> include_dirs =3D /usr/local/openldap-2.3/include > > > > That way gcc will use its own header location and not use the > > one installed in /usr/include/sasl by any linux distribution > > This is useful when having multiple version of gcc ... > > > > That way on my own system I don't need tu update setup.cfg. > > Alain, this seems to make sense. But are you sure that it's valid for > all versions of Cyrus-SASL? I No :-( I looked postfix sources and found about SASL 1.5.5 On some systems this generates the necessary Makefile definitions: (for SASL version 1.5.5): % make tidy # if you have left-over files from a previous build % make makefiles CCARGS=3D"-DUSE_SASL_AUTH -I/usr/local/include" \ AUXLIBS=3D"-L/usr/local/lib -lsasl" (for SASL version 2.1.1): % make tidy # if you have left-over files from a previous build % make makefiles CCARGS=3D"-DUSE_SASL_AUTH -I/usr/local/include/sasl" \ AUXLIBS=3D"-L/usr/local/lib -lsasl2" 'd love to accept this change but I wonder > whether it will break older installations. This is what I worry about. Note that you can correct the > current include-statement by tweaking setup.cfg. But not the other way. > > In OpenLDAP sources the following construct is used: > > #ifdef HAVE_SASL_SASL_H > #include <sasl/sasl.h> > #else > #include <sasl.h> > #endif > > I guess HAVE_SASL_SASL_H is set by autoconf though. Yes I saw that. Keep the idea in your mind, and a day, if you use like me a "tree rooted" system like openpkg, don't replace the current /usr/include/sasl with /openpkg/include/sasl/sasl.h, just apply my patch :-) Ciao, Michael. > Regards. Alain -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-06-01 10:00:30
|
Alain Spineux wrote: > > May I suggest to change (in file LDAPObject.c ) > >> #include <sasl.h> > > into > >> #include <sasl/sasl.h> > > That way you can change (in file setup.cfg) > >> library_dirs = /usr/local/openldap- 2.3/lib >> include_dirs = /usr/local/openldap-2.3/include /usr/include/sasl > > into > >> library_dirs = /usr/local/openldap-2.3/lib >> include_dirs = /usr/local/openldap-2.3/include > > That way gcc will use its own header location and not use the > one installed in /usr/include/sasl by any linux distribution > This is useful when having multiple version of gcc ... > > That way on my own system I don't need tu update setup.cfg. Alain, this seems to make sense. But are you sure that it's valid for all versions of Cyrus-SASL? I'd love to accept this change but I wonder whether it will break older installations. Note that you can correct the current include-statement by tweaking setup.cfg. But not the other way. In OpenLDAP sources the following construct is used: #ifdef HAVE_SASL_SASL_H #include <sasl/sasl.h> #else #include <sasl.h> #endif I guess HAVE_SASL_SASL_H is set by autoconf though. Ciao, Michael. |
From: Chaos E. <cha...@gm...> - 2007-06-01 08:44:31
|
I have tested LDAP Server Side Sort with Novell's eDirectory 8.8.1 using BER constructor form LDAPTOR project and python-ldap's ldap interface. from my side, it works. so why not try LDAPTOR's BER constructor for your purpose? On 6/1/07, Andreas Hasenack <aha...@te...> wrote: > > On Thursday 31 May 2007 19:51:08 Michael Str=F6der wrote: > > Andreas Hasenack wrote: > > > Luckily in my case the OpenLDAP library already has a > > > function called ldap_put_vrFilter() which I could use to do all the > > > encoding of a ValuesReturn filter. > > > [..] > > > I will still see about the decode part and then post what I have. > > > > Since which version of OpenLDAP is ldap_put_vrFilter() present? > > I don't know. I only checked /usr/include/ldap.h to make sure it's a > public > function and not an internal one. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Python-LDAP-dev mailing list > Pyt...@li... > https://lists.sourceforge.net/lists/listinfo/python-ldap-dev > --=20 Best Regards Chaos Eternal |
From: Andreas H. <aha...@te...> - 2007-06-01 00:04:25
|
On Thursday 31 May 2007 19:51:08 Michael Str=F6der wrote: > Andreas Hasenack wrote: > > Luckily in my case the OpenLDAP library already has a > > function called ldap_put_vrFilter() which I could use to do all the > > encoding of a ValuesReturn filter. > > [..] > > I will still see about the decode part and then post what I have. > > Since which version of OpenLDAP is ldap_put_vrFilter() present? I don't know. I only checked /usr/include/ldap.h to make sure it's a public= =20 function and not an internal one. |
From: Alain S. <asp...@gm...> - 2007-05-31 23:26:58
|
Hello May I suggest to change (in file LDAPObject.c ) > #include <sasl.h> into > #include <sasl/sasl.h> That way you can change (in file setup.cfg) > library_dirs = /usr/local/openldap-2.3/lib > include_dirs = /usr/local/openldap-2.3/include /usr/include/sasl into > library_dirs = /usr/local/openldap-2.3/lib > include_dirs = /usr/local/openldap-2.3/include That way gcc will use its own header location and not use the one installed in /usr/include/sasl by any linux distribution This is useful when having multiple version of gcc ... That way on my own system I don't need tu update setup.cfg. I hope this will do the same for lot of other user. I looked in cyrus-imapd source, all files use <sasl/sasl.h> ! Here is the patch Best regards. Alain diff -r -c python-ldap-2.3.orig/Modules/LDAPObject.c python-ldap-2.3 /Modules/LDAPObject.c *** python-ldap-2.3.orig/Modules/LDAPObject.c Tue Mar 27 22:34:31 2007 --- python-ldap-2.3/Modules/LDAPObject.c Fri Jun 1 01:01:50 2007 *************** *** 18,24 **** #include "options.h" #ifdef HAVE_SASL ! #include <sasl.h> #endif static void free_attrs(char***); --- 18,24 ---- #include "options.h" #ifdef HAVE_SASL ! #include <sasl/sasl.h> #endif static void free_attrs(char***); diff -r -c python-ldap-2.3.orig/setup.cfg python-ldap-2.3/setup.cfg *** python-ldap-2.3.orig/setup.cfg Wed Nov 15 18:26:26 2006 --- python-ldap-2.3/setup.cfg Fri Jun 1 01:02:04 2007 *************** *** 8,14 **** [_ldap] library_dirs = /usr/local/openldap-2.3/lib ! include_dirs = /usr/local/openldap-2.3/include /usr/include/sasl extra_compile_args = extra_objects = --- 8,14 ---- [_ldap] library_dirs = /usr/local/openldap-2.3/lib ! include_dirs = /usr/local/openldap-2.3/include extra_compile_args = extra_objects = -- -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-05-31 22:53:41
|
Andreas Hasenack wrote: > > Luckily in my case the OpenLDAP library already has a > function called ldap_put_vrFilter() which I could use to do all the > encoding of a ValuesReturn filter. > [..] > I will still see about the decode part and then post what I have. Since which version of OpenLDAP is ldap_put_vrFilter() present? Ciao, Michael. |
From: Andreas H. <aha...@te...> - 2007-05-31 22:23:47
|
On Mon, May 28, 2007 at 08:07:09PM +0200, Michael Ströder wrote: > Andreas Hasenack wrote: > > > > last Friday I played a bit with controls in python-ldap. I was trying to > > get the matched-values control (LDAP_CONTROL_VALUESRETURNFILTER) to > > work. > > Feel free to contribute your results. > > > It seems I have to manually do the BER encoding of the values. I googled > > for some modules and pyasn1 seems to be the most complete one, but I > > would have to basically write classes for the whole LDAP spec :( > > You can use pyasn1 for just creating the BER en-/decoding the control > values. Please look into Lib/ldap/controls.py to get the idea how you > can implement the methods for encoding and decoding in sub-classes of > ldap.controls.LDAPControl. I think it worked. Luckily in my case the OpenLDAP library already has a function called ldap_put_vrFilter() which I could use to do all the encoding of a ValuesReturn filter. Using a bit of monkey see, monkey do, I have such a filter working now: mv = MatchedValuesControl(criticality=True,"(mail=*@example.com)") res = ld.search_ext_s(base, scope, filter, attrlist = ['mail'], serverctrls = [mv]) In this example, if the entry matching the filter has: mail: fo...@ex... mail: fo...@ex... The result will only have "mail: fo...@ex...". Without the control, the result would have both mail attributes. I will still see about the decode part and then post what I have. |
From: Alain S. <asp...@gm...> - 2007-05-31 12:25:57
|
Hi I changed my code to make it more modular. class UnicodeLDAPInterface: ldapbaseclass=3DNone .... my code goes HERE class UnicodeLDAPObject(UnicodeLDAPInterface, LDAPObject): ldapbaseclass=3DLDAPObject class UnicodeReconnectLDAPObject(UnicodeLDAPInterface, ReconnectLDAPObject)= : ldapbaseclass=3DReconnectLDAPObject Here is the full code #!/usr/bin/env python2.4 import types, datetime import ldap, ldapurl, ldap.modlist from ldap.ldapobject import LDAPObject from ldap.ldapobject import ReconnectLDAPObject def unicode2utf8(st): """Convert unicode (and only unicode) string into utf-8 raw string as expected by ldap""" if isinstance(st, types.UnicodeType): return st.encode('utf-8') else: return st def utf82unicode(st): """encode st into utf-8""" return st.decode('utf-8') def encode_modlist(modlist, no_op): """encode ldap modlist structure set no_op=3DTrue for Tuple of kind (int,str,[str,...]) and False for (str, [str,...]) """ for i, mod in enumerate(modlist): if no_op: attr_name, attr_values=3Dmod else: op, attr_name, attr_values=3Dmod attr_name=3Dunicode2utf8(attr_name) if isinstance(attr_values, (types.ListType, types.TupleType)): attr_values=3Dmap(unicode2utf8, attr_values) else: attr_values=3Dunicode2utf8(attr_values) if no_op: modlist[i]=3D(attr_name, attr_values) else: modlist[i]=3D(op, attr_name, attr_values) return modlist def _print_ldap_result(ldap_result): for dn, item in ldap_result: print 'DN=3D', repr(dn) for k, v in item.iteritems(): print '\t%s: %s' % (k, repr(v)) print class UnicodeLDAPInterface: ldapbaseclass=3DNone decoder_expiration_delay=3D300 # the expiration delay for an object in self.unicode_decoder def __init__(self, uri, **kwargs): self.ldapbaseclass.__init__(self, uri, **kwargs) self.unicode_decoder=3D{} # { (msgid, expiration, decoder_data) ...= } # I use an expiration time to avoid the list to become to big when the # server don't answere some requests def _set_unicode_decoder(self, msgid, value): """protect unicode_decoder against multi-threading update or add the decoder """ self._ldap_object_lock.acquire() try: self.unicode_decoder[msgid]=3Dvalue finally: self._ldap_object_lock.release() def _remove_unicode_decoder(self, msgid): """protect unicode_decoder against multi-threading remove the decoder """ self._ldap_object_lock.acquire() try: try: del self.unicode_decoder[msgid] except: # ignore any errors pass finally: self._ldap_object_lock.release() def _get_unicode_decoder(self, msgid): """protect unicode_decoder against multi-threading read the decoder info for msgid """ self._ldap_object_lock.acquire() try: return self.unicode_decoder[msgid] finally: self._ldap_object_lock.release() def _expire_unicode_decoder(self): """cleanup any expired decoder""" self._ldap_object_lock.acquire() now=3Ddatetime.datetime.now() for msgid in self.unicode_decoder.keys(): if self.unicode_decoder[msgid][1]<now: del self.unicode_decoder[msgid] self._ldap_object_lock.release() def search_ext(self,base,scope, filterstr, attrlist, *args, **kwargs): # base,scope, filterstr=3D'(objectClass=3D*)',attrlist=3DNone,attrsonly=3D0,serverctrls= =3DNone,clientctrls=3DNone,timeout=3D-1,sizelimit=3D0 # convert filter filterstr_u=3Dunicode2utf8(filterstr) # convert arglist and keep a copy of original values for later decoding attrlist_u=3D[] decoder=3D{} # will keep only fields to decode if attrlist!=3DNone: for attr in attrlist: if isinstance(attr, types.UnicodeType): attr=3Dattr.encode('utf-8') decoder[attr]=3DTrue attrlist_u.append(attr) msgid=3Dself.ldapbaseclass.search_ext(self,base,scope, filterstr_u, attrlist_u, *args, **kwargs) if decoder: timeout=3Dkwargs.get('timeout', None) if timeout=3D=3DNone or timeout<=3D0: timeout=3Dself.decoder_expiration_delay self._set_unicode_decoder(msgid,(msgid, datetime.datetime.now()+datetime.timedelta(seconds=3Dtimeout), decoder)) return msgid def result3(self, *args, **kwargs): # kwargs=3D(self, msgid=3D_ldap.RES_ANY,all=3D1,timeout=3DNone): rtype, rdata, rmsgid, decoded_serverctrls=3Dself.ldapbaseclass.result3(self, *args, **kwargs) try: msgid, expire, decoder=3Dself._get_unicode_decoder(rmsgid) except KeyError: pass # no decoder for this =3D> nothing to decode else: if rtype not in [ ldap.RES_SEARCH_ENTRY, ldap.RES_SEARCH_REFERENCE ]: # this was the last result self._remove_unicode_decoder(rmsgid) else: # reset the timeout timeout=3Dkwargs.get('timeout', None) if timeout=3D=3DNone or timeout<=3D0: timeout=3Dself.expiration_delay self._set_unicode_decoder(msgid, (msgid, datetime.datetime.now()+datetime.timedelta(seconds=3Dtimeout), decoder)) # now decode the result if rdata: if rtype in [ldap.RES_SEARCH_ENTRY, ldap.RES_SEARCH_REFERENCE, ldap.RES_SEARCH_RESULT]: # FIXME: I dont know what is a RES_SEARCH_REFERENCE rdata_u=3D[] for i, (dn, attrs) in enumerate(rdata): # FIXME: should I handle the 'dn' the same way if decoder.has_key('dn'): dn=3Dutf82unicode(dn) for key in attrs.keys(): if decoder.has_key(key): attrs[key]=3Dmap(utf82unicode, attrs[key]) # print '\tITEM=3D', dn, attrs rdata[i]=3D(dn, attrs) self._expire_unicode_decoder() return rtype, rdata, rmsgid, decoded_serverctrls def add_ext(self, dn, modlist, *args, **kwargs): # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) # print 'MODLIST', modlist modlist=3Dencode_modlist(modlist, True) # print 'MODLIST unicode', modlist return self.ldapbaseclass.add_ext(self, dn, modlist, *args, **kwargs) def modify_ext(self, dn, modlist, *args, **kwargs): # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) # print 'MODLIST', modlist modlist=3Dencode_modlist(modlist, False) # print 'MODLIST unicode', modlist return self.ldapbaseclass.modify_ext(self, dn, modlist, *args, **kwargs) def delete_ext(self, dn, *args, **kwargs): # args=3D(self,dn,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) return self.ldapbaseclass.delete_ext(self, dn, *args, **kwargs) def abandon_ext(self, msgid, *args, **kwargs): # args=3D(self,msgid,serverctrls=3DNone,clientctrls=3DNone) result=3Dself.ldapbaseclass.abandon_ext(self, msgid, *args, **kwarg= s) self._remove_unicode_decoder(msgid) return result def cancel_ext(self, cancelid, *args, **kwargs): # args=3D(self,msgid,serverctrls=3DNone,clientctrls=3DNone) result=3Dself.ldapbaseclass.cancel_ext(self, cancelid, *args, **kwargs) self._remove_unicode_decoder(cancelid) return result class UnicodeLDAPObject(UnicodeLDAPInterface, LDAPObject): ldapbaseclass=3DLDAPObject class UnicodeReconnectLDAPObject(UnicodeLDAPInterface, ReconnectLDAPObject)= : ldapbaseclass=3DReconnectLDAPObject if __name__=3D=3D'__main__': import sys, os, time host=3D'localhost' port=3D389 base_dn=3D'dc=3Dasxnet,dc=3Dloc' if True: who=3D'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' cred=3D'********' else: who=3D'cn=3Dnobody,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' cred=3D'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' ldap_url=3Dldapurl.LDAPUrl('ldap://%s:%d/%s' % (host, port, base_dn)) ldap_url.applyDefaults({ 'who': who, 'cred' : cred, }) print ldap_url #l=3DLDAPObject(ldap_url.initializeUrl()) #l=3DUnicodeLDAPObject(ldap_url.initializeUrl()) l=3DUnicodeReconnectLDAPObject(ldap_url.initializeUrl()) l.simple_bind_s(ldap_url.who, ldap_url.cred) print 'Connected as', l.whoami_s() first_name=3D'Michael' first_name2=3Du'Micha\xebl' last_name=3Du'Str\xf6der' email=3D'mi...@st...' street=3Du'Hauptstra\xe1e' country=3D'Germany' cn=3D'%s %s' %(first_name, last_name) dn=3D'cn=3D%s,%s' %(cn, base_dn) info=3D{ u'cn' : (cn, ), 'mail' : (email, ), 'objectClass' : ('top', 'inetOrgPerson', 'kolabInetOrgPerson',), u'sn' : (last_name, ), u'givenName' : (first_name, ), u'street': (street, ), 'c': (country, ), 'telephoneNumber': '+49 1111111111', } ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , info.keys()) if ldap_result: print '=3D=3D Found' _print_ldap_result(ldap_result) l.delete_s(dn) print '=3D=3D Deleted' l.add_s(dn, ldap.modlist.addModlist(info)) print '=3D=3D Created' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , info.keys()) _print_ldap_result(ldap_result) l.modify_s(dn, [(ldap.MOD_REPLACE, u'givenName', first_name2), (ldap.MOD_ADD, 'telephoneNumber', ( '+49 1234567890', )), ]) print '=3D=3DModified' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , info.keys()) _print_ldap_result(ldap_result) print '=3D=3DDisplay once more' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , ['*', '+', u'dn', u'givenName', u'creatorsName'] ) _print_ldap_result(ldap_result) On 5/29/07, Alain Spineux <asp...@gm...> wrote: > > Hi Michael > > When investigating about python and unicode, I read somewhere (in a PEP > I thing) that python functions should accept and manage unicode string > as well as normal string.Of course if these strings could contains user > readable characters. > > This is not the case for python-ldap functions. Sometime when calling > python-ldap, we don't know well the origin ( a function is not suposed > to know its caller :-) of the arguments we are using : user input, > web interface, mysql database, ldap result, web form, > literal, text file, text parsing... some are unicode, other not. > I thing python-ldap function must accept unicode arguments. > > As we discussed at length previously, the decoding of the result is > less easy because, the library cannot guess alone the meaning of > these values. > > I'm not supporting the idea of downloading and use the ldap > schema. I cannot imaging a connection less application > like a web application doing that at any request! Or keeping a cache > for the schema ... > > Anyway I see 2 solutions > > 1. Let result() return non unicode strings. _HERE_ The user know all > returned > strings are normal strings utf-8 encoded and he can do the encoding > himself. A helper function doing the job for the result structure > should be welcome. > > 2. Do the conversion regarding the info provided in the query, as my > source sample does. > > I answer now some of your previous comment: > > > > In this case maybe is it possible to use [ '*', u'givenName', u'sn' ] > > > to convert only 'givenName' and 'sn' > > > But then you will not gain much! Still the application has to know whic= h > > attributes have to be converted. =3D> It's not worth hiding the convers= ion > > > within python-ldap. > > I don't really hide the conversion, because the user has to request it > using > unicode field name. And second, I do more work: I keep a link between > the msgid and the request to know with fields I have to convert and > also destroy the link when unneeded anymore. > > > The only clean solution would be something involving LDAP schema > processing! > > You know better than me how costly it is, in developing time, and its > overhead for CPU and network load. > Do you really consider to add the schema processing for unicode > integration in the future? Or are you > hoping that someone will send you a patch :-) ? > > > I know you were not very exited by my ideas, anyway the unicode support > for > argument encoding is important. (this is my opinion) > Feel free to suggest some cosmetic changes: function name, class name, th= e > > way I wrap your base class ..... > > Keep in mind, none of my code break compatibility with existing > application. > > Best regards. > > > > On 5/24/07, Alain Spineux <asp...@gm...> wrote: > > > > > > > > On 5/24/07, Michael Str=F6der < mi...@st...> wrote: > > > > > > Alain Spineux wrote: > > > > > > > > Yes but what about unknown field type ? > > > > > > If you really want to dive into this look in directory > > > pylib/w2lapp/schema/ of web2ldap's source. It works for me but I did > > > not > > > consider this whole framework mature enough to be incorporated into > > > python-ldap. > > > > > > I dont want to look at the schema: > > > > Here are the sources and the results. > > I use your more appropriate name for unicode testing :-) > > > > > > #!/usr/bin/env python2.4 > > > > import sys, os, time > > import ldap, ldapurl, ldap.modlist > > import types > > import datetime > > > > host=3D'localhost' > > port=3D389 > > base_dn=3D'dc=3Dasxnet,dc=3Dloc' > > > > if True: > > who=3D'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' > > cred=3D''********' > > else: > > who=3D'cn=3Dnobody,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' > > cred=3D'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' > > > > > > def unicode2utf8(st): > > """Convert unicode (and only unicode) string into utf-8 raw string > > as expected by ldap""" > > > > if isinstance(st, types.UnicodeType ): > > return st.encode('utf-8') > > else: > > return st > > > > def utf82unicode(st): > > """encode st into utf-8""" > > return st.decode('utf-8') > > > > > > def encode_modlist(modlist, no_op): > > """encode ldap modlist structure > > set no_op=3DTrue for Tuple of kind (int,str,[str,...]) > > and False for (str, [str,...]) > > """ > > > > for i, mod in enumerate(modlist): > > if no_op: > > attr_name, attr_values=3Dmod > > else: > > op, attr_name, attr_values=3Dmod > > > > attr_name=3Dunicode2utf8(attr_name) > > if isinstance(attr_values, ( types.ListType, types.TupleType)): > > attr_values=3Dmap(unicode2utf8, attr_values) > > else: > > attr_values=3Dunicode2utf8(attr_values) > > if no_op: > > modlist[i]=3D(attr_name, attr_values) > > else: > > modlist[i]=3D(op, attr_name, attr_values) > > > > return modlist > > > > class UnicodeLDAPObject(ldap.ldapobject.LDAPObject): > > > > expiration_delay=3D300 > > > > def __init__(self, uri, **kwargs): > > ldap.ldapobject.LDAPObject.__init__(self, uri, **kwargs) > > self.unicode_decoder=3D{} # (msgid, expiration, decoder_data) > > # I use an expiration time to avoid the list to become to big > > when the > > # server don't answere any request > > > > def search_ext(self,base,scope, filterstr, attrlist, *args, > > **kwargs): > > # base,scope, > > filterstr=3D'(objectClass=3D*)',attrlist=3DNone,attrsonly=3D0,serverctr= ls=3DNone,clientctrls=3DNone,timeout=3D-1,sizelimit=3D0 > > > > > > # convert filter > > filterstr=3Dunicode2utf8(filterstr) > > > > # convert arglist and keep a copy of original values for later > > decoding > > > > u_attrlist=3Dattrlist > > decoder=3D{} > > if u_attrlist!=3DNone: > > attrlist=3D[] > > for attr in u_attrlist: > > if isinstance(attr, types.UnicodeType): > > attr=3Dattr.encode('utf-8') > > # print 'ATTR', attr > > decoder[attr]=3DTrue > > attrlist.append(attr) > > > > msgid=3Dldap.ldapobject.LDAPObject.search_ext(self,base,scope, > > filterstr, attrlist, *args, **kwargs) > > > > if decoder: > > timeout=3Dkwargs.get('timeout', None) > > if timeout=3D=3DNone or timeout<=3D0: > > timeout=3Dself.expiration_delay > > self.unicode_decoder[msgid]=3D(msgid, datetime.datetime.now= ()+datetime.timedelta(seconds=3Dtimeout), decoder) > > return msgid > > > > def result3(self, *args, **kwargs): > > # kwargs=3D(self, msgid=3D_ldap.RES_ANY,all=3D1,timeout=3DNone)= : > > rtype, rdata, rmsgid, decoded_serverctrls=3D > > ldap.ldapobject.LDAPObject.result3(self, *args, **kwargs) > > > > if self.unicode_decoder.has_key(rmsgid): > > msgid, expire, decoder=3Dself.unicode_decoder[rmsgid] > > if rtype not in [ ldap.RES_SEARCH_ENTRY, > > ldap.RES_SEARCH_REFERENCE ]: > > # this was the last result > > del self.unicode_decoder[rmsgid] > > else: > > # reset the timeout > > timeout=3D kwargs.get('timeout', None) > > if timeout=3D=3DNone or timeout<=3D0: > > timeout=3Dself.expiration_delay > > self.unicode_decoder[msgid]=3D(msgid, > > datetime.datetime.now()+datetime.timedelta(seconds=3Dtimeout), decoder) > > > > # now decode the result > > if rdata: > > if rtype in [ldap.RES_SEARCH_ENTRY, > > ldap.RES_SEARCH_REFERENCE, ldap.RES_SEARCH_RESULT]: > > # FIXME: I dont know what is a RES_SEARCH_REFERENCE > > rdata_u=3D[] > > for i, (dn, attrs) in enumerate(rdata): > > # FIXME: should I handle the 'dn' the same way > > if decoder.has_key ('dn'): > > dn=3Dutf82unicode(dn) > > for key in attrs.keys(): > > if decoder.has_key(key): > > attrs[key]=3Dmap(utf82unicode, attrs[ke= y]) > > > > # print '\tITEM=3D', dn, attrs > > rdata[i]=3D(dn, attrs) > > > > else: > > # no decoder for this =3D> nothing to decode > > pass > > > > # remove other expired decoder info > > now=3Ddatetime.datetime.now() > > for msgid in self.unicode_decoder.keys(): > > if self.unicode_decoder[rmsgid][1]<now: > > del self.unicode_decoder[rmsgid] > > > > return rtype, rdata, rmsgid, decoded_serverctrls > > > > def add_ext(self, dn, modlist, *args, **kwargs): > > # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone= ) > > dn=3Dunicode2utf8(dn) > > # print 'MODLIST', modlist > > modlist=3Dencode_modlist(modlist, True) > > # print 'MODLIST unicode', modlist > > return ldap.ldapobject.LDAPObject.add_ext (self, dn, modlist, > > *args, **kwargs) > > > > def modify_ext(self, dn, modlist, *args, **kwargs): > > # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone= ) > > dn=3Dunicode2utf8(dn) > > # print 'MODLIST', modlist > > modlist=3Dencode_modlist(modlist, False) > > # print 'MODLIST unicode', modlist > > return ldap.ldapobject.LDAPObject.modify_ext(self, dn, modlist, > > *args, **kwargs) > > > > def delete_ext(self, dn, *args, **kwargs): > > # args=3D(self,dn,serverctrls=3DNone,clientctrls=3DNone) > > dn=3Dunicode2utf8(dn) > > return ldap.ldapobject.LDAPObject.delete_ext(self, dn, *args, > > **kwargs) > > > > > > > > def print_ldap_result(ldap_result): > > for dn, item in ldap_result: > > print 'DN=3D', repr(dn) > > for k, v in item.iteritems(): > > print '\t%s: %s' % (k, repr(v)) > > print > > > > ldap_url=3Dldapurl.LDAPUrl ('ldap://%s:%d/%s' % (host, port, base_dn)) > > ldap_url.applyDefaults({ > > 'who': who, > > 'cred' : cred, }) > > #l=3Dldap.ldapobject.LDAPObject(ldap_url.initializeUrl()) > > l=3DUnicodeLDAPObject(ldap_url.initializeUrl()) > > l.simple_bind_s(ldap_url.who, ldap_url.cred) > > print 'Connected as', l.whoami_s() > > > > > > first_name=3D'Michael' > > first_name2=3Du'Micha\xebl' > > last_name=3Du'Str\xf6der' > > email=3D' mi...@st...' > > street=3Du'Hauptstra\xe1e' > > country=3D'Germany' > > > > cn=3D'%s %s' %(first_name, last_name) > > dn=3D'cn=3D%s,%s' %(cn, base_dn) > > info=3D{ > > u'cn' : (cn, ), > > 'mail' : (email, ), > > 'objectClass' : ('top', 'inetOrgPerson', 'kolabInetOrgPerson',), > > u'sn' : (last_name, ), > > u'givenName' : (first_name, ), > > u'street': (street, ), > > 'c': (country, ), > > 'telephoneNumber': '+49 1111111111', > > } > > > > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL , '(cn=3D%s)' % (= cn,) > > , info.keys()) > > if ldap_result: > > print '=3D=3D Found' > > print_ldap_result(ldap_result) > > l.delete_s(dn) > > print '=3D=3D Deleted' > > > > l.add_s(dn, ldap.modlist.addModlist (info)) > > print '=3D=3D Created' > > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , > > info.keys()) > > print_ldap_result(ldap_result) > > > > l.modify_s(dn, [(ldap.MOD_REPLACE, u'givenName', first_name2), > > (ldap.MOD_ADD, 'telephoneNumber', ( '+49 1234567890', > > )), > > ]) > > > > print '=3D=3DModified' > > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , > > info.keys()) > > print_ldap_result(ldap_result) > > > > print '=3D=3DDisplay once more' > > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (c= n,) , > > ['*', '+', u'dn', u'givenName', u'creatorsName'] ) > > print_ldap_result(ldap_result) > > > > > > > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > > > > > > Connected as dn:cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc > > =3D=3D Found > > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > > c: ['Germany'] > > cn: [u'Michael Str\xf6der'] > > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > > street: [u'Hauptstra\xe1e'] > > sn: [u'Str\xf6der'] > > mail: ['mi...@st...'] > > givenName: [u'Micha\xebl'] > > > > =3D=3D Deleted > > =3D=3D Created > > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > > telephoneNumber: ['+49 1111111111'] > > c: ['Germany'] > > cn: [u'Michael Str\xf6der'] > > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > > street: [u'Hauptstra\xe1e'] > > sn: [u'Str\xf6der'] > > mail: ['mi...@st... '] > > givenName: [u'Michael'] > > > > =3D=3DModified > > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > > c: ['Germany'] > > cn: [u'Michael Str\xf6der'] > > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > > street: [u'Hauptstra\xe1e'] > > sn: [u'Str\xf6der'] > > mail: [' mi...@st...'] > > givenName: [u'Micha\xebl'] > > > > =3D=3DDisplay more > > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > > c: ['Germany'] > > cn: [u'Michael Str\xf6der'] > > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > > street: [u'Hauptstra\xe1e'] > > sn: [u'Str\xf6der'] > > mail: ['mi...@st...'] > > givenName: [u'Micha\xebl'] > > > > =3D=3DDisplay once more > > DN=3D u'cn=3DMichael Str\xf6der,dc=3Dasxnet,dc=3Dloc' > > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > > c: ['Germany'] > > entryCSN: ['20070524191126Z#000002#00#000000'] > > cn: ['Michael Str\xc3\xb6der'] > > entryDN: ['cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc'] > > createTimestamp: ['20070524191126Z'] > > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > > creatorsName: [u'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dlo= c'] > > entryUUID: ['5099e82e-9e76-102b-830b-0da78c7bd35e'] > > hasSubordinates: ['FALSE'] > > modifiersName: ['cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dlo= c'] > > street: ['Hauptstra\xc3\xa1e'] > > sn: ['Str\xc3\xb6der'] > > structuralObjectClass: ['inetOrgPerson'] > > subschemaSubentry: ['cn=3DSubschema'] > > mail: [' mi...@st...'] > > givenName: [u'Micha\xebl'] > > modifyTimestamp: ['20070524191126Z'] > > > > > > > > > > > > -- > > -- > > Alain Spineux > > aspineux gmail com > > May the sources be with you > > > > > > -- > -- > Alain Spineux > aspineux gmail com > May the sources be with you > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: Alain S. <asp...@gm...> - 2007-05-29 14:29:46
|
Hi Michael When investigating about python and unicode, I read somewhere (in a PEP I thing) that python functions should accept and manage unicode string as well as normal string.Of course if these strings could contains user readable characters. This is not the case for python-ldap functions. Sometime when calling python-ldap, we don't know well the origin ( a function is not suposed to know its caller :-) of the arguments we are using : user input, web interface, mysql database, ldap result, web form, literal, text file, text parsing... some are unicode, other not. I thing python-ldap function must accept unicode arguments. As we discussed at length previously, the decoding of the result is less easy because, the library cannot guess alone the meaning of these values. I'm not supporting the idea of downloading and use the ldap schema. I cannot imaging a connection less application like a web application doing that at any request! Or keeping a cache for the schema ... Anyway I see 2 solutions 1. Let result() return non unicode strings. _HERE_ The user know all returned strings are normal strings utf-8 encoded and he can do the encoding himself. A helper function doing the job for the result structure should be welcome. 2. Do the conversion regarding the info provided in the query, as my source sample does. I answer now some of your previous comment: > > In this case maybe is it possible to use [ '*', u'givenName', u'sn' ] > > to convert only 'givenName' and 'sn' > But then you will not gain much! Still the application has to know which > attributes have to be converted. =3D> It's not worth hiding the conversio= n > within python-ldap. I don't really hide the conversion, because the user has to request it usin= g unicode field name. And second, I do more work: I keep a link between the msgid and the request to know with fields I have to convert and also destroy the link when unneeded anymore. > The only clean solution would be something involving LDAP schema processing! You know better than me how costly it is, in developing time, and its overhead for CPU and network load. Do you really consider to add the schema processing for unicode integration in the future? Or are you hoping that someone will send you a patch :-) ? I know you were not very exited by my ideas, anyway the unicode support for argument encoding is important. (this is my opinion) Feel free to suggest some cosmetic changes: function name, class name, the way I wrap your base class ..... Keep in mind, none of my code break compatibility with existing application= . Best regards. On 5/24/07, Alain Spineux <asp...@gm...> wrote: > > > > On 5/24/07, Michael Str=F6der <mi...@st...> wrote: > > > > Alain Spineux wrote: > > > > > > Yes but what about unknown field type ? > > > > If you really want to dive into this look in directory > > pylib/w2lapp/schema/ of web2ldap's source. It works for me but I did no= t > > consider this whole framework mature enough to be incorporated into > > python-ldap. > > > I dont want to look at the schema: > > Here are the sources and the results. > I use your more appropriate name for unicode testing :-) > > > #!/usr/bin/env python2.4 > > import sys, os, time > import ldap, ldapurl, ldap.modlist > import types > import datetime > > host=3D'localhost' > port=3D389 > base_dn=3D'dc=3Dasxnet,dc=3Dloc' > > if True: > who=3D'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' > cred=3D''********' > else: > who=3D'cn=3Dnobody,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' > cred=3D'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' > > > def unicode2utf8(st): > """Convert unicode (and only unicode) string into utf-8 raw string as > expected by ldap""" > > if isinstance(st, types.UnicodeType): > return st.encode('utf-8') > else: > return st > > def utf82unicode(st): > """encode st into utf-8""" > return st.decode('utf-8') > > > def encode_modlist(modlist, no_op): > """encode ldap modlist structure > set no_op=3DTrue for Tuple of kind (int,str,[str,...]) > and False for (str, [str,...]) > """ > > for i, mod in enumerate(modlist): > if no_op: > attr_name, attr_values=3Dmod > else: > op, attr_name, attr_values=3Dmod > > attr_name=3Dunicode2utf8(attr_name) > if isinstance(attr_values, ( types.ListType, types.TupleType)): > attr_values=3Dmap(unicode2utf8, attr_values) > else: > attr_values=3Dunicode2utf8(attr_values) > if no_op: > modlist[i]=3D(attr_name, attr_values) > else: > modlist[i]=3D(op, attr_name, attr_values) > > return modlist > > class UnicodeLDAPObject(ldap.ldapobject.LDAPObject): > > expiration_delay=3D300 > > def __init__(self, uri, **kwargs): > ldap.ldapobject.LDAPObject.__init__(self, uri, **kwargs) > self.unicode_decoder=3D{} # (msgid, expiration, decoder_data) > # I use an expiration time to avoid the list to become to big whe= n > the > # server don't answere any request > > def search_ext(self,base,scope, filterstr, attrlist, *args, **kwargs)= : > # base,scope, > filterstr=3D'(objectClass=3D*)',attrlist=3DNone,attrsonly=3D0,serverctrls= =3DNone,clientctrls=3DNone,timeout=3D-1,sizelimit=3D0 > > > # convert filter > filterstr=3Dunicode2utf8(filterstr) > > # convert arglist and keep a copy of original values for later > decoding > > u_attrlist=3Dattrlist > decoder=3D{} > if u_attrlist!=3DNone: > attrlist=3D[] > for attr in u_attrlist: > if isinstance(attr, types.UnicodeType): > attr=3Dattr.encode('utf-8') > # print 'ATTR', attr > decoder[attr]=3DTrue > attrlist.append(attr) > > msgid=3Dldap.ldapobject.LDAPObject.search_ext(self,base,scope, > filterstr, attrlist, *args, **kwargs) > > if decoder: > timeout=3Dkwargs.get('timeout', None) > if timeout=3D=3DNone or timeout<=3D0: > timeout=3Dself.expiration_delay > self.unicode_decoder[msgid]=3D(msgid, datetime.datetime.now()= +datetime.timedelta(seconds=3Dtimeout), decoder) > return msgid > > def result3(self, *args, **kwargs): > # kwargs=3D(self, msgid=3D_ldap.RES_ANY,all=3D1,timeout=3DNone): > rtype, rdata, rmsgid, decoded_serverctrls=3D > ldap.ldapobject.LDAPObject.result3(self, *args, **kwargs) > > if self.unicode_decoder.has_key(rmsgid): > msgid, expire, decoder=3Dself.unicode_decoder[rmsgid] > if rtype not in [ ldap.RES_SEARCH_ENTRY, > ldap.RES_SEARCH_REFERENCE ]: > # this was the last result > del self.unicode_decoder[rmsgid] > else: > # reset the timeout > timeout=3D kwargs.get('timeout', None) > if timeout=3D=3DNone or timeout<=3D0: > timeout=3Dself.expiration_delay > self.unicode_decoder[msgid]=3D(msgid, datetime.datetime.n= ow()+datetime.timedelta(seconds=3Dtimeout), > decoder) > > # now decode the result > if rdata: > if rtype in [ldap.RES_SEARCH_ENTRY, > ldap.RES_SEARCH_REFERENCE, ldap.RES_SEARCH_RESULT]: > # FIXME: I dont know what is a RES_SEARCH_REFERENCE > rdata_u=3D[] > for i, (dn, attrs) in enumerate(rdata): > # FIXME: should I handle the 'dn' the same way > if decoder.has_key ('dn'): > dn=3Dutf82unicode(dn) > for key in attrs.keys(): > if decoder.has_key(key): > attrs[key]=3Dmap(utf82unicode, attrs[key]= ) > # print '\tITEM=3D', dn, attrs > rdata[i]=3D(dn, attrs) > > else: > # no decoder for this =3D> nothing to decode > pass > > # remove other expired decoder info > now=3Ddatetime.datetime.now() > for msgid in self.unicode_decoder.keys(): > if self.unicode_decoder[rmsgid][1]<now: > del self.unicode_decoder[rmsgid] > > return rtype, rdata, rmsgid, decoded_serverctrls > > def add_ext(self, dn, modlist, *args, **kwargs): > # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) > dn=3Dunicode2utf8(dn) > # print 'MODLIST', modlist > modlist=3Dencode_modlist(modlist, True) > # print 'MODLIST unicode', modlist > return ldap.ldapobject.LDAPObject.add_ext (self, dn, modlist, > *args, **kwargs) > > def modify_ext(self, dn, modlist, *args, **kwargs): > # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) > dn=3Dunicode2utf8(dn) > # print 'MODLIST', modlist > modlist=3Dencode_modlist(modlist, False) > # print 'MODLIST unicode', modlist > return ldap.ldapobject.LDAPObject.modify_ext(self, dn, modlist, > *args, **kwargs) > > def delete_ext(self, dn, *args, **kwargs): > # args=3D(self,dn,serverctrls=3DNone,clientctrls=3DNone) > dn=3Dunicode2utf8(dn) > return ldap.ldapobject.LDAPObject.delete_ext(self, dn, *args, > **kwargs) > > > > def print_ldap_result(ldap_result): > for dn, item in ldap_result: > print 'DN=3D', repr(dn) > for k, v in item.iteritems(): > print '\t%s: %s' % (k, repr(v)) > print > > ldap_url=3Dldapurl.LDAPUrl ('ldap://%s:%d/%s' % (host, port, base_dn)) > ldap_url.applyDefaults({ > 'who': who, > 'cred' : cred, }) > #l=3Dldap.ldapobject.LDAPObject(ldap_url.initializeUrl()) > l=3DUnicodeLDAPObject(ldap_url.initializeUrl()) > l.simple_bind_s(ldap_url.who, ldap_url.cred) > print 'Connected as', l.whoami_s() > > > first_name=3D'Michael' > first_name2=3Du'Micha\xebl' > last_name=3Du'Str\xf6der' > email=3D' mi...@st...' > street=3Du'Hauptstra\xe1e' > country=3D'Germany' > > cn=3D'%s %s' %(first_name, last_name) > dn=3D'cn=3D%s,%s' %(cn, base_dn) > info=3D{ > u'cn' : (cn, ), > 'mail' : (email, ), > 'objectClass' : ('top', 'inetOrgPerson', 'kolabInetOrgPerson',), > u'sn' : (last_name, ), > u'givenName' : (first_name, ), > u'street': (street, ), > 'c': (country, ), > 'telephoneNumber': '+49 1111111111', > } > > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL , '(cn=3D%s)' % (cn= ,) , > info.keys()) > if ldap_result: > print '=3D=3D Found' > print_ldap_result(ldap_result) > l.delete_s(dn) > print '=3D=3D Deleted' > > l.add_s(dn, ldap.modlist.addModlist (info)) > print '=3D=3D Created' > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,= ) , > info.keys()) > print_ldap_result(ldap_result) > > l.modify_s(dn, [(ldap.MOD_REPLACE, u'givenName', first_name2), > (ldap.MOD_ADD, 'telephoneNumber', ( '+49 1234567890', )), > ]) > > print '=3D=3DModified' > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,= ) , > info.keys()) > print_ldap_result(ldap_result) > > print '=3D=3DDisplay once more' > ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,= ) , > ['*', '+', u'dn', u'givenName', u'creatorsName'] ) > print_ldap_result(ldap_result) > > > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > > > Connected as dn:cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc > =3D=3D Found > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > c: ['Germany'] > cn: [u'Michael Str\xf6der'] > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > street: [u'Hauptstra\xe1e'] > sn: [u'Str\xf6der'] > mail: ['mi...@st...'] > givenName: [u'Micha\xebl'] > > =3D=3D Deleted > =3D=3D Created > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > telephoneNumber: ['+49 1111111111'] > c: ['Germany'] > cn: [u'Michael Str\xf6der'] > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > street: [u'Hauptstra\xe1e'] > sn: [u'Str\xf6der'] > mail: ['mi...@st...'] > givenName: [u'Michael'] > > =3D=3DModified > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > c: ['Germany'] > cn: [u'Michael Str\xf6der'] > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > street: [u'Hauptstra\xe1e'] > sn: [u'Str\xf6der'] > mail: [' mi...@st...'] > givenName: [u'Micha\xebl'] > > =3D=3DDisplay more > DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > c: ['Germany'] > cn: [u'Michael Str\xf6der'] > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > street: [u'Hauptstra\xe1e'] > sn: [u'Str\xf6der'] > mail: ['mi...@st...'] > givenName: [u'Micha\xebl'] > > =3D=3DDisplay once more > DN=3D u'cn=3DMichael Str\xf6der,dc=3Dasxnet,dc=3Dloc' > telephoneNumber: ['+49 1111111111', '+49 1234567890'] > c: ['Germany'] > entryCSN: ['20070524191126Z#000002#00#000000'] > cn: ['Michael Str\xc3\xb6der'] > entryDN: ['cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc'] > createTimestamp: ['20070524191126Z'] > objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] > creatorsName: [u'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc'= ] > entryUUID: ['5099e82e-9e76-102b-830b-0da78c7bd35e'] > hasSubordinates: ['FALSE'] > modifiersName: ['cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc'= ] > street: ['Hauptstra\xc3\xa1e'] > sn: ['Str\xc3\xb6der'] > structuralObjectClass: ['inetOrgPerson'] > subschemaSubentry: ['cn=3DSubschema'] > mail: [' mi...@st...'] > givenName: [u'Micha\xebl'] > modifyTimestamp: ['20070524191126Z'] > > > > > > -- > -- > Alain Spineux > aspineux gmail com > May the sources be with you > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-05-28 18:09:41
|
Andreas Hasenack wrote: > > last Friday I played a bit with controls in python-ldap. I was trying to > get the matched-values control (LDAP_CONTROL_VALUESRETURNFILTER) to > work. Feel free to contribute your results. > It seems I have to manually do the BER encoding of the values. I googled > for some modules and pyasn1 seems to be the most complete one, but I > would have to basically write classes for the whole LDAP spec :( You can use pyasn1 for just creating the BER en-/decoding the control values. Please look into Lib/ldap/controls.py to get the idea how you can implement the methods for encoding and decoding in sub-classes of ldap.controls.LDAPControl. > This mailing list had some discussion about this previously, and some > other names popped up, like pysnmp and pisces. pisces is pretty much dead although I'm still using it in web2ldap for certificate decoding. pyasn1 was extracted from pysnmp - same author. Ciao, Michael. |
From: Andreas H. <aha...@te...> - 2007-05-28 13:08:53
|
Hi, last Friday I played a bit with controls in python-ldap. I was trying to get the matched-values control (LDAP_CONTROL_VALUESRETURNFILTER) to work. It seems I have to manually do the BER encoding of the values. I googled for some modules and pyasn1 seems to be the most complete one, but I would have to basically write classes for the whole LDAP spec :( This mailing list had some discussion about this previously, and some other names popped up, like pysnmp and pisces. So, what are you guys using for LDAP BER encoding in python nowadays? |
From: Alain S. <asp...@gm...> - 2007-05-24 19:16:25
|
On 5/24/07, Michael Str=F6der <mi...@st...> wrote: > > Alain Spineux wrote: > > > > Yes but what about unknown field type ? > > If you really want to dive into this look in directory > pylib/w2lapp/schema/ of web2ldap's source. It works for me but I did not > consider this whole framework mature enough to be incorporated into > python-ldap. I dont want to look at the schema: Here are the sources and the results. I use your more appropriate name for unicode testing :-) #!/usr/bin/env python2.4 import sys, os, time import ldap, ldapurl, ldap.modlist import types import datetime host=3D'localhost' port=3D389 base_dn=3D'dc=3Dasxnet,dc=3Dloc' if True: who=3D'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' cred=3D''********' else: who=3D'cn=3Dnobody,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' cred=3D'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' def unicode2utf8(st): """Convert unicode (and only unicode) string into utf-8 raw string as expected by ldap""" if isinstance(st, types.UnicodeType): return st.encode('utf-8') else: return st def utf82unicode(st): """encode st into utf-8""" return st.decode('utf-8') def encode_modlist(modlist, no_op): """encode ldap modlist structure set no_op=3DTrue for Tuple of kind (int,str,[str,...]) and False for (str, [str,...]) """ for i, mod in enumerate(modlist): if no_op: attr_name, attr_values=3Dmod else: op, attr_name, attr_values=3Dmod attr_name=3Dunicode2utf8(attr_name) if isinstance(attr_values, (types.ListType, types.TupleType)): attr_values=3Dmap(unicode2utf8, attr_values) else: attr_values=3Dunicode2utf8(attr_values) if no_op: modlist[i]=3D(attr_name, attr_values) else: modlist[i]=3D(op, attr_name, attr_values) return modlist class UnicodeLDAPObject(ldap.ldapobject.LDAPObject): expiration_delay=3D300 def __init__(self, uri, **kwargs): ldap.ldapobject.LDAPObject.__init__(self, uri, **kwargs) self.unicode_decoder=3D{} # (msgid, expiration, decoder_data) # I use an expiration time to avoid the list to become to big when the # server don't answere any request def search_ext(self,base,scope, filterstr, attrlist, *args, **kwargs): # base,scope, filterstr=3D'(objectClass=3D*)',attrlist=3DNone,attrsonly=3D0,serverctrls= =3DNone,clientctrls=3DNone,timeout=3D-1,sizelimit=3D0 # convert filter filterstr=3Dunicode2utf8(filterstr) # convert arglist and keep a copy of original values for later decoding u_attrlist=3Dattrlist decoder=3D{} if u_attrlist!=3DNone: attrlist=3D[] for attr in u_attrlist: if isinstance(attr, types.UnicodeType): attr=3Dattr.encode('utf-8') # print 'ATTR', attr decoder[attr]=3DTrue attrlist.append(attr) msgid=3Dldap.ldapobject.LDAPObject.search_ext(self,base,scope, filterstr, attrlist, *args, **kwargs) if decoder: timeout=3Dkwargs.get('timeout', None) if timeout=3D=3DNone or timeout<=3D0: timeout=3Dself.expiration_delay self.unicode_decoder[msgid]=3D(msgid, datetime.datetime.now()+datetime.timedelta(seconds=3Dtimeout), decoder) return msgid def result3(self, *args, **kwargs): # kwargs=3D(self, msgid=3D_ldap.RES_ANY,all=3D1,timeout=3DNone): rtype, rdata, rmsgid, decoded_serverctrls=3D ldap.ldapobject.LDAPObject.result3(self, *args, **kwargs) if self.unicode_decoder.has_key(rmsgid): msgid, expire, decoder=3Dself.unicode_decoder[rmsgid] if rtype not in [ ldap.RES_SEARCH_ENTRY, ldap.RES_SEARCH_REFERENCE ]: # this was the last result del self.unicode_decoder[rmsgid] else: # reset the timeout timeout=3Dkwargs.get('timeout', None) if timeout=3D=3DNone or timeout<=3D0: timeout=3Dself.expiration_delay self.unicode_decoder[msgid]=3D(msgid, datetime.datetime.now()+datetime.timedelta(seconds=3Dtimeout), decoder) # now decode the result if rdata: if rtype in [ldap.RES_SEARCH_ENTRY, ldap.RES_SEARCH_REFERENCE, ldap.RES_SEARCH_RESULT]: # FIXME: I dont know what is a RES_SEARCH_REFERENCE rdata_u=3D[] for i, (dn, attrs) in enumerate(rdata): # FIXME: should I handle the 'dn' the same way if decoder.has_key('dn'): dn=3Dutf82unicode(dn) for key in attrs.keys(): if decoder.has_key(key): attrs[key]=3Dmap(utf82unicode, attrs[key]) # print '\tITEM=3D', dn, attrs rdata[i]=3D(dn, attrs) else: # no decoder for this =3D> nothing to decode pass # remove other expired decoder info now=3Ddatetime.datetime.now() for msgid in self.unicode_decoder.keys(): if self.unicode_decoder[rmsgid][1]<now: del self.unicode_decoder[rmsgid] return rtype, rdata, rmsgid, decoded_serverctrls def add_ext(self, dn, modlist, *args, **kwargs): # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) # print 'MODLIST', modlist modlist=3Dencode_modlist(modlist, True) # print 'MODLIST unicode', modlist return ldap.ldapobject.LDAPObject.add_ext(self, dn, modlist, *args, **kwargs) def modify_ext(self, dn, modlist, *args, **kwargs): # args=3D(self,dn,modlist,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) # print 'MODLIST', modlist modlist=3Dencode_modlist(modlist, False) # print 'MODLIST unicode', modlist return ldap.ldapobject.LDAPObject.modify_ext(self, dn, modlist, *args, **kwargs) def delete_ext(self, dn, *args, **kwargs): # args=3D(self,dn,serverctrls=3DNone,clientctrls=3DNone) dn=3Dunicode2utf8(dn) return ldap.ldapobject.LDAPObject.delete_ext(self, dn, *args, **kwargs) def print_ldap_result(ldap_result): for dn, item in ldap_result: print 'DN=3D', repr(dn) for k, v in item.iteritems(): print '\t%s: %s' % (k, repr(v)) print ldap_url=3Dldapurl.LDAPUrl('ldap://%s:%d/%s' % (host, port, base_dn)) ldap_url.applyDefaults({ 'who': who, 'cred' : cred, }) #l=3Dldap.ldapobject.LDAPObject(ldap_url.initializeUrl()) l=3DUnicodeLDAPObject(ldap_url.initializeUrl()) l.simple_bind_s(ldap_url.who, ldap_url.cred) print 'Connected as', l.whoami_s() first_name=3D'Michael' first_name2=3Du'Micha\xebl' last_name=3Du'Str\xf6der' email=3D'mi...@st...' street=3Du'Hauptstra\xe1e' country=3D'Germany' cn=3D'%s %s' %(first_name, last_name) dn=3D'cn=3D%s,%s' %(cn, base_dn) info=3D{ u'cn' : (cn, ), 'mail' : (email, ), 'objectClass' : ('top', 'inetOrgPerson', 'kolabInetOrgPerson',), u'sn' : (last_name, ), u'givenName' : (first_name, ), u'street': (street, ), 'c': (country, ), 'telephoneNumber': '+49 1111111111', } ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,) = , info.keys()) if ldap_result: print '=3D=3D Found' print_ldap_result(ldap_result) l.delete_s(dn) print '=3D=3D Deleted' l.add_s(dn, ldap.modlist.addModlist(info)) print '=3D=3D Created' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,) = , info.keys()) print_ldap_result(ldap_result) l.modify_s(dn, [(ldap.MOD_REPLACE, u'givenName', first_name2), (ldap.MOD_ADD, 'telephoneNumber', ( '+49 1234567890', )), ]) print '=3D=3DModified' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,) = , info.keys()) print_ldap_result(ldap_result) print '=3D=3DDisplay once more' ldap_result=3Dl.search_s(base_dn, ldap.SCOPE_ONELEVEL, '(cn=3D%s)' % (cn,) = , ['*', '+', u'dn', u'givenName', u'creatorsName'] ) print_ldap_result(ldap_result) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Connected as dn:cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc =3D=3D Found DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' telephoneNumber: ['+49 1111111111', '+49 1234567890'] c: ['Germany'] cn: [u'Michael Str\xf6der'] objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] street: [u'Hauptstra\xe1e'] sn: [u'Str\xf6der'] mail: ['mi...@st...'] givenName: [u'Micha\xebl'] =3D=3D Deleted =3D=3D Created DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' telephoneNumber: ['+49 1111111111'] c: ['Germany'] cn: [u'Michael Str\xf6der'] objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] street: [u'Hauptstra\xe1e'] sn: [u'Str\xf6der'] mail: ['mi...@st...'] givenName: [u'Michael'] =3D=3DModified DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' telephoneNumber: ['+49 1111111111', '+49 1234567890'] c: ['Germany'] cn: [u'Michael Str\xf6der'] objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] street: [u'Hauptstra\xe1e'] sn: [u'Str\xf6der'] mail: ['mi...@st...'] givenName: [u'Micha\xebl'] =3D=3DDisplay more DN=3D 'cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc' telephoneNumber: ['+49 1111111111', '+49 1234567890'] c: ['Germany'] cn: [u'Michael Str\xf6der'] objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] street: [u'Hauptstra\xe1e'] sn: [u'Str\xf6der'] mail: ['mi...@st...'] givenName: [u'Micha\xebl'] =3D=3DDisplay once more DN=3D u'cn=3DMichael Str\xf6der,dc=3Dasxnet,dc=3Dloc' telephoneNumber: ['+49 1111111111', '+49 1234567890'] c: ['Germany'] entryCSN: ['20070524191126Z#000002#00#000000'] cn: ['Michael Str\xc3\xb6der'] entryDN: ['cn=3DMichael Str\xc3\xb6der,dc=3Dasxnet,dc=3Dloc'] createTimestamp: ['20070524191126Z'] objectClass: ['top', 'inetOrgPerson', 'kolabInetOrgPerson'] creatorsName: [u'cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc'] entryUUID: ['5099e82e-9e76-102b-830b-0da78c7bd35e'] hasSubordinates: ['FALSE'] modifiersName: ['cn=3Dmanager,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc'] street: ['Hauptstra\xc3\xa1e'] sn: ['Str\xc3\xb6der'] structuralObjectClass: ['inetOrgPerson'] subschemaSubentry: ['cn=3DSubschema'] mail: ['mi...@st...'] givenName: [u'Micha\xebl'] modifyTimestamp: ['20070524191126Z'] --=20 -- Alain Spineux aspineux gmail com May the sources be with you |