Authentication using LDAP

Please note that LDAP authentication is implemented in MoinMoin since version 1.6. Instructions are located at the HelpOnAuthentication page

I (NickPhillips) really need Moin to authenticate users using LDAP.

The "pluggable" authentication in Moin 1.5 makes this reasonably easy, except for one minor point.

The way our LDAP auth needs to work is as follows:

Note: I removed some outdated code, please see the hg repo (or latest moin release) for the latest code. -- ThomasWaldmann 2006-12-23 02:51:11

Improvements

First, I'd like to be caching the LDAP connection between requests. This could be especially useful when using mod_python. I'm new to Python and mod_python, but if they work similarly to mod_perl (which I am familiar with), then this shouldn't be too hard. The question is just "where do I want to store this damn LDAP object?"

Second, I really don't want users to end up having LDAP usernames as WikiNames. I need to come up with a way of translating one to the other, so that the LDAP username is never displayed on the wiki except in the login box. I'm not sure how the UserPreferences form should handle this.

Because the login names we have are ugly and make it hard to see who is who. They're intended purely as a unique id for authentication, and I'd like to use a name that's intended as a human-readable name for places that it's intended it should be read by humans :) I don't mean that I want to force the use of caps, just that I want to be able to map from a name that's not intended for humans to one that is. And vice-versa. The mapping could be a simple case of applying some algorithm to the login to get the WikiName, or a further LDAP lookup, or a lookup in a flat file, or some arbitrary database...

It seems to me like this could easily be done "pluggably", by plugging in a module that's required to provide two functions -- one to translate a WikiName to a login name, and one the other way. In the default case, each would just return its argument.

That's what I'm doing. Except that I don't yet have a way of automatically setting the aliasname.

It wouldn't be too hard to allow an authenticated bind for the search, but I think you may confusing things when you talk about mail. This module is for authentication, and any other information lookups should be performed in a separate module -- what if I want to use LDAP for auth but MySQL for getting email address, aliasname etc.?

News 2006-12-22

I updated the ldap auth code in the 1.5 branch (see CHANGES for details). If you run a ldap setup, please help testing this and report about success/failure below.

[Mon Jun 11 16:40:04 2007] LDAP: Setting misc. options... [Mon Jun 11 16:40:04 2007] LDAP: caught an exception, traceback follows... [Mon Jun 11 16:40:04 2007] Traceback (most recent call last):

AttributeError: 'module' object has no attribute 'TLS_AVAIL'}}}

Test script

This can be used to debug ldap auth problems, especially if your LDAP/AD setup is rather complex:

/!\ it seems that this script isn't functional (Debian, Python 2.4). There is at least a problem with users_passwords definition (lines 26-30) and its use.

I have changed this:

users_passwords = [
    ('username':'user1', 'password':'correctpass1'),
    ('username':'user1', 'password':''), # check whoami output for this!
    ('username':'user1', 'password':'wrongpass1'),
]

and (line 34)

for user in users_passwords:

(line 49)

l.simple_bind_s(first_dn, user['password'])

But they are still problems i haven't solved.

   1 #!/opt/python/bin/python
   2 # -*- coding: iso-8859-1 -*-
   3 """
   4 This script can be used for some basic LDAP / Active Directory Testing.
   5 
   6 You need to configure the variables below this comment to match your setup.
   7 
   8 If it does not authenticate your users correctly, you maybe also want to look
   9 at the code below and find out why it does not work.
  10 
  11 Please contribute changes back to us.
  12 
  13 MoinMoin development at http://moinmoin.wikiwikiweb.de/
  14 """
  15 
  16 server_uri = 'ldap://ldap.example.org/'
  17 #server_uri = 'ldaps://ldap.example.org/'
  18 
  19 # if bind_user and bind_pw is both '' it does an anonymous bind
  20 bind_user = ''
  21 bind_pw = ''
  22 
  23 base_dn = 'dc=example,dc=org'
  24 filter_str = '(uid=%s)' # check if this is correct for you!
  25 
  26 users_passwords = [
  27     ('user1', 'correctpass1'),
  28     ('user1', ''), # check whoami output for this!
  29     ('user1', 'wrongpass1'),
  30 ]
  31 
  32 import ldap
  33 
  34 for user, password in users_passwords:
  35     # This is only required if you are using a self signed cert. 
  36     # Probably turn it off for production code.
  37     if server_uri.startswith('ldaps:'):
  38         ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
  39 
  40     # ActiveDirectory? Do this, otherwise, leave it out.
  41     ldap.set_option(ldap.OPT_REFERRALS, 0)
  42 
  43     print "Initializing connection to %s ..." % server_uri
  44     l = ldap.initialize(server_uri)
  45     print "LDAP protocol version %d" % l.protocol_version
  46     #l.protocol_version = ldap.VERSION3
  47 
  48     print "Binding to directory using bind user %r (and configured password) ..." % bind_user
  49     l.bind_s(bind_user, bind_pw)
  50 
  51     search_filter = filter_str % user
  52     print "Searching under base dn %s for %s ..." % (base_dn, search_filter)
  53     lusers = l.search_s(base_dn, ldap.SCOPE_SUBTREE, search_filter)
  54     results = len(lusers)
  55     print "Results: %d" % results
  56     if results:
  57         for dn, ldap_dict in lusers:
  58             print "    %s" % dn
  59         first_dn = lusers[0][0]
  60         print "Trying to authenticate with first found dn %s (and configured password) ..." % first_dn
  61         try:
  62             l.bind_s(first_dn, password)
  63             print "Succcessfully bound - whoami says: %s" % l.whoami_s()
  64         except ldap.INVALID_CREDENTIALS, err:
  65             print "LDAP Error: %s" % err
  66     print "Unbinding from directory ..."
  67     l.unbind()
  68     print "-"*70
ldaptest.py


CategoryFeatureImplemented

MoinMoin: FeatureRequests/AuthLDAP (last edited 2008-10-22 13:58:17 by EricVeirasGalisson)