[Zope] Help: Zope and LDAP

Tim Hawes User.Name@ncmail.net
Thu, 14 Feb 2002 18:23:18 -0500


I am new to this list, new to Zope, and new to Python. I am, however, an
old hat to perl, c/c++, and LDAP. I am very interested in Python and
would consider picking up the now unmaintained ZopeLDAP package, that is
if noone picks it up before me.

I have not been able to get the addSubentry() function to work in
ZopeLDAP. The docs are not very clear to me in how to use it.

>From "PROGRAMMING.txt":
   1. Getting an Entry Object and its attributes

    Using an LDAP Filter object is the best way to get an Entry object.
    LDAP Filter objects act like methods\functions and return a sequence

    of entry objects (so they can be used with any sort of looping
    structure).  For example, if you had an LDAP Filter titled
    'lookupByEmail' with the parameter 'email' with the content::

       mail=<dtml-var name="mail">*

    Can be used in DTML like this::
[DTML example skipped]

    Or in a Python Script like this::

       entries = container.lookupByEmail(email='jef')

       for entry in entries:
        # do something here...

This all works fine and dandy for LDAP queries, and I can get selected
fields from our LDAP tree in an HTML table quite rapidly with this. The
problem comes in the explanation of how addSubentry() works...

   3.1. Adding subentries

    Adding subentries to an Entry object is done through the
    'addSubentry' method.  Adding subentries is protected by the
    permission **Create New Entry Objects**.

    **addSubentry(rdn, [attrs,kw])** -- Add a new subentry identified by

    the rdn.  The rdn **MUST** be a string in the form 'attr=value',
    such as 'ou=Housewares' or 'cn=Davy Jones'.  The rest of the
    signature can be a combination of a dictionary of attributes
    passed in to 'attrs' or keyword arguments.  If no 'objectClass'
    attribute is passed in, the default objectClass is 'top'.  The
    newly created Entry object is returned, wrapped in the acquisition
    context of its parent.  Some example uses are::

      betty = housewares.addSubentry("cn=Betty Ford", {
                "objectClass": ["top", "person"],
                "sn": "Ford",
              })

      clinic = betty.addSubentry("sn=Clinic",
                         objectClass=["top","place"],
                         description="A good place to go..."
               )


I take this to mean that in order to add subentries, I have to first
create an Entry object as specified in the first paragraph that would
seclude the object I want to add the object to?!

Anyway, I have read and reread this file and it still makes no sense to
me. I tried adding an LDAP filter that isolates the organizational unit
I want to add entries to (ou=People,<basedn>)
specify a basedn with an LDAP filter method called rootOU. I then write
this script to work the magic I am hoping for:

  entries = container.rootOU()
  People = entries[0]

  fname = "BBBB"
  lname = "cccc"
  name = "%s %s" % (fname, lname)
  uidname = "%s.%s" % (fname, lname)
  rdn = "uid=%s" % uidname

  newentry =
People.addSubentry(rdn,{"objectClass":["top","person","organizationalPerson","inetorgperson","dirmuser"],

                "sn":lname, "cn":name})

  print "Success"

  return printed

On test, I get this exception:
  Error Type: TYPE_OR_VALUE_EXISTS
  Error Value: {'desc': 'Type or value exists'}
Traceback (innermost last):
  File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line 223,
in publish_module
  File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line 187,
in publish
  File /usr/local/zope/2.4.3/lib/python/Zope/__init__.py, line 226, in
zpublisher_exception_hook
    (Object: Admin)
  File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line 171,
in publish
  File /usr/local/zope/2.4.3/lib/python/ZPublisher/mapply.py, line 160,
in mapply
    (Object: copy_of_addentry)
  File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line 112,
in call_object
    (Object: copy_of_addentry)
  File /usr/local/zope/2.4.3/lib/python/Shared/DC/Scripts/Bindings.py,
line 324, in __call__
    (Object: copy_of_addentry)
  File /usr/local/zope/2.4.3/lib/python/Shared/DC/Scripts/Bindings.py,
line 354, in _bindAndExec
    (Object: copy_of_addentry)
  File
/usr/local/zope/2.4.3/lib/python/Products/PythonScripts/PythonScript.py,
line 363, in _exec
    (Object: copy_of_addentry)
    (Info: ({'script': <PythonScript instance at f538b8>, 'context':
<Folder instance at ff6ad0>, 'container': <Folder instance at ff6ad0>,
'traverse_subpath': []}, (), {}, None))
  File Script (Python), line 11, in copy_of_addentry
    (Object: guarded_getitem)
  File
/usr/local/zope/2.4.3/lib/python/Products/ZLDAPConnection/Entry.py, line
249, in addSubentry
    (Object: GenericEntry)
  File
/usr/local/zope/2.4.3/lib/python/Products/ZLDAPConnection/ZLDAP.py, line
344, in _addEntry
    (Object: Hrdhhs34_Directory)
TYPE_OR_VALUE_EXISTS: (see above)

After pulling hair out of my "already-balding-head" I resolved to
by-pass ZopeLDAP altogether and use the python-ldap module directly,
much more closely resembles the LDAP C API. I add ldap as one of the
allowable modules for Zope, restart it, and when I try to
ldap.simple_bind(), I get prompted to login frivolously (just like what
happens when you try to import a module in a python script that is
forbidden), so I cancel and get:

  An error was encountered while publishing this resource.

  Unauthorized

  Sorry, a site error occurred.

  Traceback (innermost last):
    File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line
223, in publish_module
    File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line
187, in publish
    File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line
171, in publish
    File /usr/local/zope/2.4.3/lib/python/ZPublisher/mapply.py, line
160, in mapply
      (Object: python-ldap-test)
    File /usr/local/zope/2.4.3/lib/python/ZPublisher/Publish.py, line
112, in call_object
      (Object: python-ldap-test)
    File /usr/local/zope/2.4.3/lib/python/Shared/DC/Scripts/Bindings.py,
line 324, in __call__
      (Object: python-ldap-test)
    File /usr/local/zope/2.4.3/lib/python/Shared/DC/Scripts/Bindings.py,
line 354, in _bindAndExec
      (Object: python-ldap-test)
    File
/usr/local/zope/2.4.3/lib/python/Products/PythonScripts/PythonScript.py,
line 363, in _exec
      (Object: python-ldap-test)
      (Info: ({'script': <PythonScript instance at db4410>, 'context':
<Folder instance at ff6ad0>, 'container': <Folder instance at ff6ad0>,
'traverse_subpath': []}, (), {}, None))
    File Script (Python), line 3, in python-ldap-test
      (Object: guarded_getattr)
    File /usr/local/zope/2.4.3/lib/python/AccessControl/ZopeGuards.py,
line 122, in guarded_getattr
    File
/usr/local/zope/2.4.3/lib/python/AccessControl/SecurityManager.py, line
149, in validate
    File
/usr/local/zope/2.4.3/lib/python/AccessControl/ZopeSecurityPolicy.py,
line 172, in validate
  Unauthorized: simple_bind

I would think think that a simple_bind() method would be implicitly
allowed with the ldap module!

Can anyone help? If ZopeLDAP is simply beyond support, I would be more
than happy to utilize python-ldap instead (being already familiar with
the C API).

Thank you.