Description

LDAP is case-insensitive for usernames. MoinMoin is case-sensitive. Moin should get the proper case from LDAP when performing LDAP authentication.

There was some talk about this in #moin a while back:

11:09 < esk> so... LDAP usernames are usually case-insensitive, but moinmoin usernames are case-sensitive.  Would it be reasonable to have moin log you in as the username returned by an ldap query instead of the username you entered?
11:09 < esk> (I think PAM handles logins this way)
11:10 < intgr> Yeah, you should always use the canonical username for every user.
11:11 -!- starshine_away is now known as starshine
11:11 < ThomasWaldmann> esk: what's the problem with just entering the name with correct casing?
11:11 < esk> bad users ;)
11:11 < esk> they are used to the case-insensitivity
11:11 < ThomasWaldmann> so you won't have bad users on the wiki
11:11 < ThomasWaldmann> (that could be sold as a feature :)
11:12 < intgr> Well, all the bad users will be impersonating you with ThomasWaLdmann :)
11:12 < intgr> s/with/as/
11:13 < starshine> actually the flipside of that is you want them to feel like it's easy so they get hooked on wiki and make it grow.
11:14  * ThomasWaldmann looks in ldap_login src
11:14 < esk> it shouldn't take much to fix it... add an ldap_username_attribute to the config and add it to your list of attributes
11:16 < esk> in attrlist
11:16 < ThomasWaldmann> esk: it would be good to make a FeatureRequest for that and provide all details you know
11:16 < esk> okay
11:17 < ThomasWaldmann> the problem is that I don't use ldap myself, so I need rather concrete and clear requests
11:17 < ThomasWaldmann> useful information includes defaults for that lda_username_attribute (like you have it with AD, openldap, samba, whatever)
11:18 < ThomasWaldmann> esk: btw, did you try ldaps: ?
11:18 < esk> yes
11:18 < ThomasWaldmann> did it work "as is"?
11:19 < ThomasWaldmann> (btw, you can also attach a patch, if you already have done it)
11:19 < esk> it works fine if you use ldaps://ldap.server, I was trying with ldap.server and the TLS stuff
11:20 < esk> which was where I went wrong

Component selection

Details

MoinMoin Version

1.5.8

OS and Version

RHEL 5

Python Version

2.4

Server Setup

apache

Server Details

Language you are using the wiki in (set in the browser/UserPreferences)

Workaround

I changed the following and added 'ldap_username_attribute=sAMAccountName' in my farmconfig.

--- moin/auth.py.org    2007-08-08 14:24:01.000000000 -0600
+++ /usr/lib/python2.4/site-packages/MoinMoin/auth.py   2007-11-10 02:43:16.000000000 -0700
@@ -132,6 +132,8 @@
     login = kw.get('login')
     logout = kw.get('logout')
     user_obj = kw.get('user_obj')
+    if user_obj and user_obj.name:
+        username = user_obj.name # Needed so ldap_login can change the username
     #request.log("auth.moin_cookie: name=%s login=%r logout=%r user_obj=%r" % (username, login, logout, user_obj))
     if login:
         u = user.User(request, name=username, password=password,
@@ -332,6 +334,8 @@
     login = kw.get('login')
     logout = kw.get('logout')
     user_obj = kw.get('user_obj')
+    if user_obj and user_obj.name:
+        username = user_obj.name

     cfg = request.cfg
     verbose = cfg.ldap_verbose
@@ -395,15 +399,22 @@
             l.simple_bind_s(ldap_binddn.encode(coding), ldap_bindpw.encode(coding))
             if verbose: request.log("LDAP: Bound with binddn %s" % ldap_binddn)

+            possible_attrs=[cfg.ldap_email_attribute,
+                            cfg.ldap_aliasname_attribute,
+                            cfg.ldap_surname_attribute,
+                            cfg.ldap_givenname_attribute,
+                            cfg.ldap_username_attribute,
+                           ]
+            attrs = []
+            for i in possible_attrs:
+                if i:
+                    attrs.append(i)
+
             # you can use %(username)s here to get the stuff entered in the form:
             filterstr = cfg.ldap_filter % locals()
             if verbose: request.log("LDAP: Searching %s" % filterstr)
             lusers = l.search_st(cfg.ldap_base, cfg.ldap_scope, filterstr.encode(coding),
-                                 attrlist=[cfg.ldap_email_attribute,
-                                           cfg.ldap_aliasname_attribute,
-                                           cfg.ldap_surname_attribute,
-                                           cfg.ldap_givenname_attribute,
-                                 ], timeout=cfg.ldap_timeout)
+                                 attrlist=attrs, timeout=cfg.ldap_timeout)
             # we remove entries with dn == None to get the real result list:
             lusers = [(dn, ldap_dict) for dn, ldap_dict in lusers if dn is not None]
             if verbose:
@@ -421,12 +432,32 @@
                 return None, False # if ldap returns unusable results, we veto the user and don't let him in

             dn, ldap_dict = lusers[0]
+
+            if cfg.ldap_username_attribute:
+                old_username = username
+                username = ldap_dict[cfg.ldap_username_attribute][0]
+                if old_username != username and verbose:
+                    request.log("Changed username to %s." % (username,))
+
             if verbose: request.log("LDAP: DN found is %s, trying to bind with pw" % dn)
             l.simple_bind_s(dn, password.encode(coding))
             if verbose: request.log("LDAP: Bound with dn %s (username: %s)" % (dn, username))

-            email = ldap_dict.get(cfg.ldap_email_attribute, [''])[0]
-            email = email.decode(coding)
+            #u = user.User(request, auth_username=username, password=password, auth_method='ldap', auth_attribs=('name', 'password', 'email', 'mailto_author',))
+            user_args = {}
+            user_args['auth_username'] = username
+            user_args['auth_method'] = 'ldap'
+            user_args['name'] = username
+            # FIXME: can this be left out?
+            user_args['password'] = password
+            user_args['auth_attribs'] = ('name','password',)
+            if cfg.ldap_aliasname_attribute or cfg.ldap_surname_attribute:
+                user_args['auth_attribs'] = user_args['auth_attribs'] + ('aliasname',)
+            email = ''
+            if cfg.ldap_email_attribute:
+                email = ldap_dict.get(cfg.ldap_email_attribute, [''])[0]
+                email = email.decode(coding)
+                user_args['auth_attribs'] = user_args['auth_attribs'] + ('email','mailto_author',)

             aliasname = ''
             try:
@@ -442,10 +473,11 @@
                     aliasname = sn
             aliasname = aliasname.decode(coding)

-            u = user.User(request, auth_username=username, password=password, auth_method='ldap', auth_attribs=('name', 'password', 'email', 'mailto_author',))
-            u.name = username
-            u.aliasname = aliasname
-            u.email = email
+            u = user.User(request, **user_args)
+            if 'email' in user_args['auth_attribs']:
+                u.email = email
+            if 'aliasname' in user_args['auth_attribs']:
+                u.aliasname = aliasname
             u.remember_me = 0 # 0 enforces cookie_lifetime config param
             if verbose: request.log("LDAP: creating userprefs with name %s email %s alias %s" % (username, email, aliasname))

@@ -455,7 +487,9 @@

         if u:
             u.create_or_update(True)
-        return user_obj, True # == nop, moin_cookie has to set the cookie and return the user obj
+        if verbose: request.log("LDAP: Success!")
+        if verbose: request.log("LDAP: name: %s" % (u.name,))
+        return u, True # moin_cookie still has to set the cookie and return the user obj, but make our changes stick

     except:
         import traceback

Discussion

Does this patch work for new users only or does it also fix the wrong case of already existing user names? -- AnkeHeinrich 2007-11-12 22:52:13

(!) A tested patch based on current 1.6 branch (either latest beta/rc or hg checkout) would be appreciated.

Plan


CategoryMoinMoinBug

MoinMoin: MoinMoinBugs/LdapUsernameIssues (last edited 2007-12-02 13:39:39 by ThomasWaldmann)