Authenticating Logins Using Active Directory¶
I have a Redmine installation which the clients wanted to have Redmine authenticate its users from their Windows 2003 Active Directory. Redmine has LDAP authentication so this should be a walk in the park, right? It largely was, too.
The “Account” needs to be the windows domain and account of any account you would like to allow to do the initial bind to the directory to perform the search for the username trying to log in. I think by default, Windows does not allow anonymous searches (which is a good thing) so give a user/pass that you are comfortable using. Any domain user should work, but I think ideally it should be an account that has no ability to actually log in to a workstation.
the “Base DN” is another tricky part. I’m not a Windows admin, much less an AD guru. There are ways to obtain valid base DNs for a given LDAP server but I found the easiest was to use one of any number of free or free-to-try LDAP client applications. You will need to be able to provide login credentials (the account/password above) but it should give you one of several base DNs that are valid for the server. Usually you will use the DN of the actual AD machine. If the computer’s name is MYSERVER for example, the base DN is probably “dc=myserver,dc=local”.
I didn’t worry about additional filtering or a timeout. Redmine appends its own filter to look for users (instead of machines or anything else in the directory) but I expect if you have a huge directory it may be prudent to add a filter to try and pare the list down.
The attributes section should be copied verbatim. These are the attributes in Active Directory which correspond to the login elements that Redmine uses.
Nothing to do here.
How it Works¶
Redmine will bind the AD server with the account/password given, and try to look up the Login Attribute with the username provided by the person trying to log in. If a result is given, Redmine will re-bind the AD server with the full distinctive name information that was returned by the AD server when the first query was run. If this succeeds, the login is considered valid.
Where it can go Wrong¶
There are a bunch of different things that can screw this up. Having the incorrect initial user/pass to bind AD will prevent it from being able to search for the user who wants to log in. Having the wrong base DN can return no results because the information is not part of that base DN or the base DN does not exist in the directory. Incorrect attributes can either return no or invalid data which would prevent the login process from succeeding.
There is one other thing that can cause trouble. This client had a user account that they wanted on Redmine but which was restricted to logging in to one workstation. I thought it would be enough to add Samba to the Redmine server and make Samba part of the AD group and then configuring the AD user to allow logins from the Redmine machine as well, but this was not working. Adding the machine to AD by configuring Samba and Kerberos was simple enough, but the Redmine logins were still failing.
Turning on event auditing on the AD server and then going through the logs after a connection attempt showed the initial (search) LDAP connection working, but then a connection attempt for the machine “localhost”. Ok, so I added “localhost” to the list of allowed machines (it’s just a list of strings, no actual checking that the machine name is part of AD is done), but this didn’t work yet. I continued looking at the event log and noticed that for whatever reason, the second bind (the one with the username of the person trying to log in to Redmine) was being authenticated to log in to the name of the AD server, not the Redmine server!
I checked the packet traces of the LDAP “conversation” and nowhere in there does Redmine mention the AD server’s name in the query (or anywhere else for that matter). It seems that Win2k3 is defaulting to its own name. If I add the AD server’s name to the list of machines that this user can log in from, everything works. This is far from ideal.
At this point in time I don’t know how to get the Redmine server to say “for the machine named $foo”.
Finding Out What Went Wrong¶
I don’t know why Redmine doesn’t report the error in its log, but if you use
tcpdump to track the interaction between Redmine and the LDAP server and then use
strings on the binary capture you can oftentimes see what’s wrong. The string you’re looking for looks something like this:
LDAP: error code 49 - 80090308: LdapErr: DSID-0Cxxxxxx, comment: AcceptSecurityContext error, data xxx, vece
xxx, vece” is the important part. The code gives the reason for the failure. I don’t know if this is an exhaustive list but it covers all the big reasons. This list comes from here:
|525||user not found|
|530||not permitted to logon at this time|
|531||not permitted to logon at this workstation|
|773||user must reset password|
|775||user account locked|
The specific code I was getting was