Opened 15 years ago
Last modified 6 years ago
#6268 new defect
LdapPlugin fails with MS Active Directory, lacks email / full name
Reported by: | Zachary Bedell | Owned by: | Emmanuel Blot |
---|---|---|---|
Priority: | normal | Component: | LdapPlugin |
Severity: | normal | Keywords: | ldap, activedirectory, windows, group, permissions |
Cc: | Trac Release: | 0.11 |
Description
I've run into a number of issues using the LdapPlugin against MS Active Directory. The plugin assumed that the Common Name (CN) attribute of a principal's Distinguished Name (DN) was always equivalent to its login name and that you could convert from DN to login name with simple string manipulation.
Alas, this is not (remotely) the case with our directory as various users may have as their CN their login name, their full given name, some variation on their given name (nick names), and in some cases completely meaningless identifiers. A mess, no doubt; but out of my control.
As far as my understanding of LDAP goes, assuming login == CN is somewhat simplistic and given to failure. I've modified the plugin to connect to the directory whenever a CN/DN/login translation is needed. I've also attempted to cache the conversions where practical in order to reduce the number of queries against the directory as much as possible. I suspect additional caching improvements are possible.
Attached to this ticket is a replaced api.py file which implements these changes. I'd ordinarily attach a patch, but the changes were extensive enough to render a patch relatively pointless.
Also included in this version is additional logic to extract the user's email and full name from the appropriate directory fields and insert them into the Trac session. The idea of piggybacking on the web filter system is from AccountLdapPlugin with some minor tweaks.
To use this version, you'll need to take the rest of the scaffolding from the trunk build of he LdapPlugin-0.11 and replace the ldaplugin/api.py file with the attached one.
Configuration settings like the following are working for our ActiveDirectory, but YMMV:
[ldap] enable=true use_tls=false host=your.server port=389 # Note: Must be the full DN, sAMAccount name or email-like domain login will NOT work bind_user=CN=LDAP Search User,OU=Windows Systems,... bind_passwd=pass # Use authenticated bind group_bind = true # Adjust DN's to taste basedn=OU=RTP,... group_rdn = OU=Programming,... user_rdn = OU=users # Group settings - use the Windows login name for the group (sAMAccountname) groupname = group groupattr = sAMAccountName groupmember = member groupmemberisdn = true # Use Windows login name for user uidattr = sAMAccountName # NEW FOR PATCH: # Attributes on the user object from which full name and email address will be read user_fullname_attr = displayName user_email_attr = mail # Our tree is readonly, but you might want to enable this manage_groups = false
Attachments (1)
Change History (10)
Changed 15 years ago by
comment:1 Changed 15 years ago by
I replaced LdapPlugin api.py with attached file. User can successfully login trac system. But there is a warning: Warning: <acct_mgr.web_ui.MessageWrapper object at 0xb7a3d12c>
And error: WIKI_VIEW privileges are required to perform this operation on WikiStart
All trac links are forbidden. I think it was caused by loginned usr not gotten permission.
comment:2 Changed 14 years ago by
Hello,
I am using OpenLDAP under Ubuntu 10.04, to get your api.py patch working I had to do the following modification: replace objectClass=user with objectClass=posixAccount , I think this should be configurable like the 'groupname' parameter.
comment:3 Changed 14 years ago by
I have a couple of other issues:
- The email gets recorded in the trac database, so if I change the email address of the user in the LDAP (that is probably a very rare use case), then it won't get updated in trac, if that user used trac before his email changed in LDAP.
- I use unicode characters for the name, that causes this error in trac "UnicodeDecodeError: 'ascii' codec can't decode byte 0xd8 in position 0: ordinal not in range(128)
", hence I had to comment the line:
req.sessionname? = name
This is the error traceback:
Trac detected an internal error:
Most recent call last:
- File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 450, in _dispatch_request
Code fragment:
- try:
- if not env and env_error:
- raise HTTPInternalError(env_error)
- try:
- dispatcher = RequestDispatcher(env)
- dispatcher.dispatch(req)
- except RequestDone:
- pass
- resp = req._response or []
- except HTTPException, e:
- File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 217, in dispatch
Code fragment:
- # Give the session a chance to persist changes
- req.session.save()
- req.display(template, content_type or 'text/html')
- else: # Genshi
- template, data, content_type = \
- self._post_process_request(req, *resp)
- if 'hdfdump' in req.args:
- req.perm.require('TRAC_ADMIN')
- # debugging helper - no need to render first
- from pprint import pprint
- out = StringIO()
- File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 309, in _post_process_request
Code fragment:
- # Trac 0.10, only filters with same arity gets passed real values.
- # Errors will call all filters with None arguments,
- # and results will not be not saved.
- extra_arg_count = arity(f.post_process_request) - 2
- if extra_arg_count == nbargs:
- resp = f.post_process_request(req, *resp)
- elif nbargs == 0:
- f.post_process_request(req, *(None,)*extra_arg_count)
- return resp
- File "/usr/local/lib/python2.6/dist-packages/LdapPlugin-0.6.0dev-py2.6.egg/ldapplugin/api.py", line 87, in post_process_request
Code fragment:
- # Info isn't already in the session
- uid = req.remote_user.lower()
- if uid in self._cache:
- # We have something in cache, so let's stick it in the session.
- lut, groups, mail, name = self._cache[uid]
- req.sessionname? = name
- req.sessionemail? = mail 89.
- return template, data, content_type
- # IPermissionProvider interface
- File "/usr/lib/python2.6/dist-packages/trac/web/session.py", line 46, in setitem
Code fragment:
- self.get_session(sid, authenticated=True)
- else:
- self.authenticated = False
- def setitem(self, key, value):
- dict.setitem(self, key, unicode(value))
- def get_session(self, sid, authenticated=False):
- self.env.log.debug('Retrieving session for ID %r', sid)
- db = self.env.get_db_cnx()
File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 450, in _dispatch_request
dispatcher.dispatch(req)
File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 217, in dispatch
self._post_process_request(req, *resp)
File "/usr/lib/python2.6/dist-packages/trac/web/main.py", line 309, in _post_process_request
resp = f.post_process_request(req, *resp)
File "/usr/local/lib/python2.6/dist-packages/LdapPlugin-0.6.0dev-py2.6.egg/ldapplugin/api.py", line 87, in post_process_request
req.sessionname? = name
File "/usr/lib/python2.6/dist-packages/trac/web/session.py", line 46, in setitem
dict.setitem(self, key, unicode(value))
comment:4 Changed 14 years ago by
comment:5 Changed 14 years ago by
Trying to get this to work with Trac 0.12.1, and openldap. Compiles fine and all that.
Looks like it's working, however it doesn't appear to be populating the "Full name" and "Email" under Preferences. I should note that this is the only functionality I'm looking for, just fullname and email from ldap.
I edited api.py
and enabled some debugging. I can see it pulling in the correct information, it's just not populating it.
2011-01-06 16:11:29,006 Trac[session] DEBUG: Retrieving session for ID u'dennisr' 2011-01-06 16:11:29,032 Trac[api] DEBUG: Searching for user dennisr with filter (uid=dennisr) at basedn ou=people,dc=wi,dc=mit,dc=edu 2011-01-06 16:11:29,034 Trac[api] DEBUG: {'mail': ['dennisr@wi.mit.edu'], 'displayName': ['Dennis Ristuccia']}
and ldap settings from our trac.ini:
[ldap] # enable LDAP support for Trac enable = true # enable TLS support use_tls = false # LDAP directory host host = 18.157.1.65 # LDAP directory port (default port for LDAPS/TLS connections is 636) port = 389 # BaseDN basedn = dc=wi,dc=mit,dc=edu # Relative DN for users (defaults to none) user_rdn = ou=People # Relative DN for group of names (defaults to none) group_rdn = # objectclass for groups groupname = # dn entry in a groupname #groupmember = # attribute name for a group groupattr = cn # attribute name for a user uidattr = uid # attribute name to store trac permission #permattr = # filter to search for dn with 'permattr' attributes #permfilter = # time, in seconds, before a cached entry is purged out of the local cache. cache_ttl = 900 # maximum number of entries in the cache cache_size = 100 # whether to perform an authenticated bind for group resolution group_bind = false # whether to perform an authenticated bind for permision store operations store_bind = false # user for authenticated connection to the LDAP directory #bind_user = dennisr # password for authenticated connection #bind_passwd = # global permissions (vs. per-environment permissions) global_perms = false # group permissions are managed as addition/removal to the LDAP directory groups manage_groups = false # whether a group member contains the full dn or a simple uid groupmemberisdn = true # NEW FOR PATCH: # Attributes on the user object from which full name and email address will be read user_fullname_attr = displayName user_email_attr = mail # Our tree is readonly, but you might want to enable this manage_groups = false
comment:6 follow-up: 7 Changed 13 years ago by
I replaced api.py with the one of this ticket, but it just doesn't work and ends up in this error:
Traceback (most recent call last): File "build\bdist.win32\egg\trac\web\main.py", line 511, in _dispatch_request dispatcher.dispatch(req) File "build\bdist.win32\egg\trac\web\main.py", line 237, in dispatch resp = chosen_handler.process_request(req) File "build\bdist.win32\egg\trac\admin\web_ui.py", line 80, in process_request panels, providers = self._get_panels(req) File "build\bdist.win32\egg\trac\admin\web_ui.py", line 163, in _get_panels p = list(provider.get_admin_panels(req) or []) File "build\bdist.win32\egg\tickettemplate\ttadmin.py", line 137, in get_admin_panels if 'TT_ADMIN' in req.perm: File "build\bdist.win32\egg\trac\perm.py", line 553, in has_permission return self._has_permission(action, resource) File "build\bdist.win32\egg\trac\perm.py", line 567, in _has_permission check_permission(action, perm.username, resource, perm) File "build\bdist.win32\egg\trac\perm.py", line 454, in check_permission perm) File "build\bdist.win32\egg\trac\perm.py", line 286, in check_permission get_user_permissions(username) File "build\bdist.win32\egg\trac\perm.py", line 372, in get_user_permissions for perm in self.store.get_user_permissions(username) or []: File "build\bdist.win32\egg\trac\perm.py", line 173, in get_user_permissions subjects.update(provider.get_permission_groups(username) or []) File "build\bdist.win32\egg\ldapplugin\api.py", line 125, in get_permission_groups self._ldap = LdapConnection(self.env.log, self.config, bind, **self._ldapcfg)
comment:7 follow-up: 8 Changed 13 years ago by
Replying to falkb: copy'n'paste error. I forgot the last line:
... File "build\bdist.win32\egg\ldapplugin\api.py", line 125, in get_permission_groups self._ldap = LdapConnection(self.env.log, self.config, bind, **self._ldapcfg) TypeError: __init__() keywords must be strings
comment:8 Changed 13 years ago by
Replying to falkb:
Replying to falkb: copy'n'paste error. I forgot the last line:
... File "build\bdist.win32\egg\ldapplugin\api.py", line 125, in get_permission_groups self._ldap = LdapConnection(self.env.log, self.config, bind, **self._ldapcfg) TypeError: __init__() keywords must be strings
Umm... later I read there is already #6183 fixing that error!
After applying attachment:ticket:6183:v070trac012.diff I got another runtime error but that could be fixed by adding entries for user_fullname_attr
and user_email_attr
to trac.ini.
Next on login I got another error grumbling about an unicode issue with German umlauts. Don't know what to do then but as workaround it helps to use
user_fullname_attr = initials
instead of user_fullname_attr = displayName
.
Now everything seems to work fine here... at least the first 15 minutes... ;)
comment:9 Changed 6 years ago by
Keywords: | active directory removed |
---|
Updated version