What else does a geek do on Christmas eve? How about some ruby on rails debugging, especially when I don’t really know anything other than the basics of Ruby on Rails. 🙂
So here’s what I’ve done and what I’ve learned, for the great search engine in the sky and the next time I find myself in this pickle.
I’ve installed Redmine on a CentOS box, which worked out really well. I cribbed the install notes from http://blog.itsmine.co.uk/2009/01/22/howto-install-subversion-and-redmine-on-centos5-rhel5/, which is a fantastic walk-through to the process.
So first is getting authentication working with Redmine. It includes a nice LDAPS:// based built-in mechanism, but there’s little detail around configuring it. The best is the wiki page RedmineLDAP on the Redmine wiki. If you’re doing LDAP authentication, you probably want LDAPS – otherwise you’re shipping passwords in clear over the wire. The default port of LDAPS on Active Directory is 636.
The other key thing you need to know is that even though you configure an LDAP connection in the redmine application (under http://YourRedmineHost/auth_sources/list), when you test it – it’ll test positive even if it isn’t binding into Active Directory and returning a result. Why? Now that another story – and one I don’t have clearly nailed.
To start, I enabled debugging in Redmine by editing /var/www/rails/redmine/config/environments/production.rb and inserting the line:
config.log_level = :debug
(the default, if you’re curious, is config.log_level = :info)
Restarted the service and now I’m getting a lot more detail. Turns out the LDAP authentication pieces really only trigger useful logging if the search mechanism that looks for the ID is successful. I found the ruby code doing the lifting at redmine/app/models/auth_source_ldap.rb – and starting adding in additional debugging methods. What I found was that the system wasn’t throwing any exceptions, but the result of a call to ldap_con.search() wasn’t returning any values.
What I haven’t been able to solve is why that search wasn’t returning any values.
Since I’m not super conversant on hacking on ruby (yet – I think I’m about to learn the hard way), I switched to a different tactic to see what was happening: tcpdump.
The command line to watch the LDAP protocol stream in plain-text as it flows is:
tcpdump -l -s 1024 -A -vv port 389
(you’ll need to run that as root, and turn of LDAPS so you can actually see the darned protocol). Wireshark would be a hell of a lot easier, but I’m doing this on a remote RHEL server and didn’t have a GUI to wrap into the darn thing. What I saw from that was a string embedded in the protocol noise:
LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 525, vece.
Why this wasn’t propagating an exception or error in Rails is not clear to me (which is why I think I’m about to learn more rails hacking, the hard way). I’ve tweaked things around to get different exceptions, but what it all amounts to is that I’m not yet getting a good/successful bind on LDAP from which I can do searches.
I’ve managed to get LDAP authentication working from python (and Django) within my environment, so I’m familiar with the proper base DN and some of the attributes that are available for use from our Active Directory – but so far, no love in the ruby world.
When you’re configuring the LDAP, the code is written so that Redmine has to have an account and password that will bind with LDAPS properly and be able to return search results. If you’re doing this against active directory, make sure you include the domain in the account you’re binding (i.e. YOURDOMAINyouraccount). That made the difference in getting a successful bind to LDAP. Using the correct domain is what got me past the bind issue. The fact that it wasn’t successfully binding and not propogating an error seems like a bug – that’s been logged today as issue 4483
(by the way – the time when I want more screen real estate is when I have 5 terminal consoles and two different web browsers open debugging something like the redmine application)
More later… still debugging, but now I’m diving into using ruby script/console to interactively figure out this LDAP code in ruby.
UPDATE: So the final solution was all about having the right configuration entries in the fields to make it work. I ended up using ruby script/console to manually drive values until I had a success, and then the results were really clear as to what I needed to use.
For anyone else coming along and trying to same thing, here’s what worked for me (minus my password…) to learn what attributes were being passed back from LDAP:
ruby script/console
require 'net/ldap' options = { :host => 'my.adhost.com', :port => 389, :encryption => nil, :method => :simple, :username => 'DOMAINjheck', :password => 'mypassword' } ldap_conn = Net::LDAP.new options ldap_conn.open { } ldap_conn.auth('DOMAINjheck','mypassword') ldap_conn.bind filter = Net::LDAP::Filter.eq('sAMAccountName','jheck') ldap_conn.search(:base => 'DC=MYDOMAIN1,DC=MYDOMAIN2', :filter => filter)
A related update/patch submitted to Redmine a few months ago is issue 4283 which solves a quandry I have about needing a separate account to authenticate through LDAP. I’ll be trying out that patch next monday.
Man, thank you so much for this walk-through. I was going mad about my LDAP setup! By using tcpdump I was able to track the issues and fix the LDAP parameters… works like a charm 🙂
LikeLike
Thank you so much!
I already tried several times to get the LDAP authentication working. Up till now without success.
Debugging using the console really made a difference. I couldn’t have found that myself (only basic Linux knowledge and no PHP, Rails and Active Directory experience … it’s close to a miracle I got it working at all 😉 )
In case someone is interested: my Base DN was wrong:
Before debugging, it was: DC=server,DC=companyName,DC=local while it should have been: DC=companyName,DC=local
Thanks again
LikeLike
Hello,
Thank you for your post.
I’m having a similar issue with Redmine which I can make work with LDAP. Sadly, I can’t find any info when I want to debug.
I actually don’t understand how to set up the domain thing in the account setting. My LDAP base DN is something like that:
ou=People,dc=domain,dc=com
And my user is
uid=testUser,ou=People,dc=myDomain,dc=com
(testUser already exists on Redmine and is configured to user LDAP auth)
So I’m using uid to filter the user.
My LDAP admin account is
cn=admin,dc=domain,dc=com
Then, I’ve tried to use admin, cn=admin,dc=domain,dc=com or myDomain/admin or event testUser (he must be able to retrieve his own credential infos), but with none of them I can make work the testUser login into Redmine.
Strangely, I don’t get anything with the tcpdump command, even while my LDAP is working for the PAM and SASL authentications.
Thanks if you can help !
LikeLike
Debugging is one of the truly hard parts in this – the route I took was to adwd debugging statements into the code itself where it was authenticating to the remote system, printing out responses and data to see what was happening. If you dont know your LDAP settings, check to see if anyone else around has done LDAP against AD authentication and go from there. I ended up writing little test scripts to understand our structure and dig around in it to get familiar with ours.
Not much to go on… sorry.
LikeLike
I finally made it work. Actually it was a password problem in my LDAP account. But yes, this debugging problem really make me loose my time as I couldn’t find out what was happening.
And to enable local debugging on LDAP port, I had to add ‘-i lo’ on the tcpdump command.
To answer my question, I finally did not set the account setting in redmine, as the account is used to log in to LDAP to retrieve the DN (which I can do anonymously) and then Redmine log in again to LDAP to check the credential.
LikeLike
Yo thanks!!! I actually had the exact same problem you had, followed the instructions and works like a charm now. Thanks a million. I sent a tip your way. [tiptheweb.org]
LikeLike