Attention

This document was written for an unsupported version of Plone, Plone 2.1.x, and was last updated 1606 days ago.

For more information, see the version support policy.

To learn how to upgrade to the current version of Plone, read the upgrade manual.

ActiveDirectory with read and write functionality

by Hedley Roos last modified Dec 30, 2008 03:03 PM
Plone supports ActiveDirectory authentication out of the box, but not writing to it. This is a complete example with screenshots and monkey patches to accomplish that. It shows how to completely move storage of users, groups and roles to ActiveDirectory.

Software environment:

  • CMFPlone 2.1.2
  • LDAPUserFolder 2.6
  • GroupUserFolder 3.5
  • Windows Small Business Server 2003 for ActiveDirectory

Software versions are for reference only. Your environment may be different but there is a good chance that this howto still applies.

Setting up your acl_users

This applies to the acl_users of your Plone site, not the acl_users in Zope!
The goal is to add a new User source (LDAP) and make it the only User source, and replace the Groups source with LDAPGroupFolder.

  • In the ZMI navidate to acl_users | Sources
  • Select Add LDAPUserFolder and click Add. You will be redirected.
  • Click the Schema tab and enter values as in the screenshot.
  • Schema
  • Click the Configure tab and enter values as in the screenshot. Replace Users Base DN, Groups Base DN and Manager DN with your AD settings.
  • Configure
  • Add an LDAP server (basically enter the IP address of your AD server)
  • Type in the address bar of your browser $PLONE_URL/acl_users/manage_main. If you actually type $PLONE_URL then this howto is not for you. Add a PythonScript called gruf_ldap_required_fields with parameter login and with content
# For Active Directory
di = {}
di['userAccountControl'] = '66048'
di['sAMAccountName'] = login
di['accountExpires'] = '9223372036854775807'
# Extract FQDN from configuration
# context.groups_base is something similar to "ou=dha-sa,dc=Upfront,dc=local". We want Upfront@local
fqdn = ''.join(context.groups_base[context.groups_base.lower().find(',dc=')+1:])
fqdn = fqdn.replace('dc=', '')
fqdn = fqdn.replace('DC=', '')
fqdn = fqdn.replace(',', '.')
di['userPrincipalName'] = '%s@%s' % (login, fqdn)
di['pwdLastSet'] = '-1'
return di
  • Navigate to acl_users | Sources
  • Replace Groups Source with LDAPGroupFolder
  • Navigate to acl_users | Sources
  • Disable the original User Folder
  • Sources
  • Go to the Management Console for AD on your Windows server. You probably already have an Organizational Unit where you want users and groups to be stored. In the screenshot my Organizational Unit is called dha-sa. Manually add new groups called Manager, Reviewer, Member, Administrators, Reviewers. The first three will be mapped to Zope roles, the last two to Plone groups. If you have other roles and groups add them to AD now. Even though LDAPUserFolder will map groups automatically in future we have to do the initial mapping.
  • Management Console
  • Click the new LDAP User Folder
  • Click the Groups tab
  • Some of the mappings in LDAP group to Zope role mappings may be wrong at this point. Delete the wrong ones and remap. The screenshot shows the correct setting.
  • Groups
The acl_users folder is now complete.

Monkey patches

There are a few problem areas in the code which wreak havoc.Unpack ActiveDirectoryPatches-0.1.2.tar.gz to your Products directory and restart Zope. These patches address the problems and will hopefully surface in the standard distribution in future. Note: monkey patches don't modify any existing source code.

Issues

Groups may have roles in Plone, and LDAPUserFolder does correctly store the roles for groups in ActiveDirectory, but it cannot retrieve these roles! I wrote a horrible hardcoded method to address this issue. Any help from expert LDAPUserFolder users (Jens...) is appreciated.

This method lives in GroupUserFolder.GRUFUser on the GRUFGroup class. It overrides getRoles from GRUFUserAtom.    
security.declarePublic('getRoles')
def getRoles(self):
"""
Overriding GRUFUserAtom.getRoles allows retrieval of Roles for Groups stored in LDAP.
Storage of Roles for Groups in LDAP already works.
"""
if self._all_roles is not None:
return self._all_roles

# xxx: Ugly hardcoded stuff - fix!!!
gruf = self.aq_parent
import zLOG
if gruf.haveLDAPGroupFolder():
import ldap
l = ldap.open("192.168.1.63", port=389)
l.simple_bind_s('administrator', 'password')
baseDN = "dc=Upfront,dc=local"
searchScope = ldap.SCOPE_SUBTREE
retrieveAttributes = ['memberOf']
ldap_result_id = l.search(baseDN, searchScope, '(&(cn=%s)(objectClass=group))' % self, retrieveAttributes)
res = []
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
if result_type == ldap.RES_SEARCH_ENTRY:
try:
# Extract role
s = result_data[0][1]['memberOf'][0]
res.append(''.join(s[3:s.find(',')]))
except:
pass
return res
else:
return GRUFUserAtom.getRoles(self)
This approach may be wrong so use at your own discretion.

Contribute

Something wrong or out of date? Anybody can edit or create a new article in the knowledge base. Simply create an account on this site, log in, and click the Edit button to contribute.