make Rhodecode support user login via LDAP

Issue #60 resolved
TK Soh
created an issue

We use LDAP at work. With this support, then we can manage the users better. BTW, our LDAP authenticate in two-pass manner (first auth to access LDAP server, then auth user).

Comments (24)

  1. Mike Matz

    I would also love to see LDAP support. I would expect to use RhodeCode's internal mechanisms for access control, but use LDAP to authenticate users.

  2. Marcin Kuzminski repo owner

    Implemented this into web interface, with ldap conf under admin->permissions. Have to write some tests, and docs + toottip helpers,

    But i believe ldap is usable in 1.1

  3. TK Soh reporter

    I managed to get 1.1 running, but not sure how to setup the LDAP. Any doc on this?

    In Apache, I use these directives to connect to our proxy server:

    AuthLDAPBindDN 
    AuthLDAPBindPassword 
    AuthLDAPURL
    

    How to I map them to those settings in Rhodecode?

  4. TK Soh reporter

    I tried to install ldap-python per setup.rst but received this error:

    	# easy_install ldap-python
    	Searching for ldap-python
    	Reading http://www.pylonshq.com/download/
    	Reading http://pypi.python.org/simple/ldap-python/
    	Couldn't find index page for 'ldap-python' (maybe misspelled?)
    	Scanning index of all packages (this may take a while)
    	Reading http://pypi.python.org/simple/
    	No local packages or download links found for ldap-python
    	Best match: None
    	Traceback (most recent call last):
    	  File "/py25vir/bin/easy_install", line 8, in <module>
    	    load_entry_point('setuptools==0.6c11', 'console_scripts', 'easy_install')()
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/command/easy_install.py", line 1712, in main
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/command/easy_install.py", line 1700, in with_ei_usage
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/command/easy_install.py", line 1716, in <lambda>
    	  File "/usr/lib/python2.5/distutils/core.py", line 151, in setup
    	    dist.run_commands()
    	  File "/usr/lib/python2.5/distutils/dist.py", line 974, in run_commands
    	    self.run_command(cmd)
    	  File "/usr/lib/python2.5/distutils/dist.py", line 994, in run_command
    	    cmd_obj.run()
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/command/easy_install.py", line 211, in run
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/command/easy_install.py", line 434, in easy_install
    	  File "/py25vir/lib/python2.5/site-packages/setuptools-0.6c11-py2.5.egg/setuptools/package_index.py", line 475, in fetch_distribution
    	AttributeError: 'NoneType' object has no attribute 'clone'
    

    Have I missed anything?

  5. TK Soh reporter

    Just found out 'easy_install python-ldap' has no problem. It's a typo in setup.rst, or that's a different package from the one needed by rhodecode?

  6. TK Soh reporter

    No problem. BTW, I tried the LDAP support, but it doesn't seem to work for our two-pass process. Based on the sample python code from our IT, it seems that the LDAP access has to be done via the search() call. I have done some hacking, but can't quite figure out who to make it work, since I am not familiar with LDAP.

    The only way I can think right now is to somehow patch auth_ldap.py to slot in the code from our IT's sample. But this might not be a long term fix.

  7. TK Soh reporter

    One more thing. I notice this line in auth_ldap.py at line 87:

                    server.simple_bind_s(self.AUTH_DN % (self.LDAP_BIND_DN,
                                                    self.BASE_DN),
                                                    self.LDAP_BIND_PASS)
    

    Is the first param simple_bind_s() to correctly constructed this way? Looks a bit strange to me. In any case, I am probably not qualified to ask this question ;-)

  8. TK Soh reporter

    Just a quick update. I manage to get LDAP work with the following patch:

    diff -r 0520bc083d88 rhodecode/lib/auth_ldap.py
    --- a/rhodecode/lib/auth_ldap.py	Mon Nov 22 09:00:42 2010 +0800
    +++ b/rhodecode/lib/auth_ldap.py	Mon Nov 22 17:05:12 2010 +0800
    @@ -55,7 +55,7 @@
                                                    self.LDAP_SERVER_PORT)
     
             self.BASE_DN = base_dn
    -        self.AUTH_DN = "uid=%s,%s"
    +        self.AUTH_DN = "motguid=%s,%s"
     
         def authenticate_ldap(self, username, password):
             """Authenticate a user via LDAP and return his/her LDAP properties.
    @@ -75,7 +75,7 @@
             if "," in username:
                 raise LdapUsernameError("invalid character in username: ,")
             try:
    -            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, '/etc/openldap/cacerts')
    +            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
                 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
                 server = ldap.initialize(self.LDAP_SERVER)
                 if self.ldap_version == 2:
    @@ -84,9 +84,7 @@
                     server.protocol = ldap.VERSION3
     
                 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
    -                server.simple_bind_s(self.AUTH_DN % (self.LDAP_BIND_DN,
    -                                                self.BASE_DN),
    -                                                self.LDAP_BIND_PASS)
    +                server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
     
                 server.simple_bind_s(dn, password)
                 properties = server.search_s(dn, ldap.SCOPE_SUBTREE)
    
    

    Somehow our LDAP resort to using a custom field name rather than the usual 'uid'. I am not sure how to workaround this problem custom patching on the code.

    Comment?

  9. Marcin Kuzminski repo owner

    I'm not and LDAP expert myself, but from what I have seen so far no other systems had customizable AUTH_DN uid string template. For example redmine, is very mature project and they don't have this. If Your company is using non standard ldap authentication probably You should patch the code for Your needs. But on the other hand putting this setting in current configuration wouldn't be complicated, i have to think about this.

  10. TK Soh reporter

    Right now I am still don't want to say our practice is "non standard", especially since I can make it work for Apache without any special hack. I wonder how Apache manages.

  11. Marcin Kuzminski repo owner

    I think good solution would be to extend the DN template to something like this:

    uid=%(user),cn=enabled,ou=groups,dc=example,dc=com

    That way You could specify Your own custom AUTH_DN, and the template variable would just be replaced by the username server side.

  12. TK Soh reporter

    Interesting solution. Be great if you can do that.

    BTW, are the other patches on OPT_X_TLS_CACERTFILE and simple_bind_s() valid bug fixes? If so, feel free to break down and applies. Or let me know if you me to handle it.

  13. Anonymous

    FYI, LDAP support is working great for us. Thank you! If I had a another wish, I'd set a template for the emails (username@mydomain.com instead of @ldap.server).

  14. Marcin Kuzminski repo owner
    • changed milestone to 1.1

    Is Your ldap not working without setting OPT_X_TLS_CACERTDIR ? One more thing is that, the i cannot find how the two pass authentication should look like, i thought it's simple_bind_s called with the same bind string just different username,

    Did you have to apply all your patches to make ldap work in two way pass ? or is it just really the 'motgui' that makes the difference ?

  15. TK Soh reporter

    I had to apply all three patches for it to work. FYI, I changed OPT_X_TLS_CACERTFILE to OPT_X_TLS_CACERTDIR as I noticed the /etc/openldap/cacerts is a directory, and that helped fix the "SERVER DOWN" error too.

  16. Marcin Kuzminski repo owner

    Ok, so I'll change it to: ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')

    the case of uid i think will be moved out to config as a template,and also move the whole ldap page from permissions. and the biggest problem is with the change You did in simple_bind_s(), what is that You pass as LDAP_BIND_DN how this string is build ?

  17. TK Soh reporter

    I am not sure I can share the bind DN with you since it's company info, but it's of similar syntax to the base DN, with 'cn=my_ldap_account'.

  18. Marcin Kuzminski repo owner

    fixes in rev >=832 implemented custom uid in base templates now the whole string is passed for example uid=%(user)s,dc=people,dc=company,dc=org also moved ldap to it's own admin section

  19. Log in to comment