LDAP Authentication

Added by Martin Eckhardt over 13 years ago

Hello everybody,

I am trying to get Redmine authentication to work with LDAP / Active Directory groups. At the moment authentication with organization units is fine but Active Directory groups is not. Everytime I try to add a group I recieve Invalid user or password error message. Instead of adding a group I need to add every single OU so Redmine authenticates successfully. This is quiet annoying for maintenance and even worse the user who wants to login is frustrated.

My idea is to add a AD group redmine and add every OU to this group that should be able to login into Redmine or even better to add an existing group with all our employees.

So my question is, what do I need to so that Redmine authenticates also with LDPA groups.

Greetings
--
Martin Eckhardt
IDG Communications and Media AG
Germany

Replies (15)

RE: LDAP Authentication - Added by Jürgen Walter over 13 years ago

Hi Martin,

when you add a "OU", you really add a search base from your AD/LDAP directory. What that means is, that - when Redmine performs the authentication for a user, it really only "looks" in that particular partition of your directory. For example, a typical LDAP structure could look like this:

ou=sales,o=mycompany.com
uid=john.doe,ou=sales,mycompany.com
ou=accounting,o=mycompany.com
uid=jane.doe,ou=accounting,o=mycompany.com
....
cn=groups,o=mycompany.com
cn=admins,cn=groups,o=mycompany.com
cn=assistants,cn=groups,o=mycompany.com
...

Now, if you configure an authentication provider in Redmine, you specify the so called "search base" for that authentication provider as well. Of course, if you specify "ou=sales,o=mycompany.com" as the search base from our example above, Redmine will find the user with uid "john.doe" - but not the user "jane.doe" (because she is under a different search base). Does that make sense so far?

Now, the area of groups is something totally different, because users (typically do not and should not) be "physically" located underneath a group, they are still in the directory only once, underneath the organizational unit (ou) that they belong to (e.g. uid=john.doe,ou=sales,o=mycompany.com).

When you add a user to a group (or even a group to a group (or even a ou to a group (not sure if this is possible, I am not an expert with AD and cannot verify that right now))), the search that Redmine performs with not yield any result, because it does not "ask" the directory for a group membership of a particular user, but only if a user is physically located under a particular search base, such as ou=sales,o=mycompany.com

In order for a group membership to work, the query that Redmine performs needs to be different (this is called the LDAP search filter): it needs to specifically ask the directory server (AD in your case), if a user belongs to (or is "member of" a particular group). But that is currently not implemented. Make sense so far?

Now, why even do all this search base vs. group membership thing? This is for two reasons: limit the search scope (performance, load on server) to a particular subset (many directories are organized by region as opposed to functional groups), but also to limit the search (and result of course) to a particular subset of the directory population (e.g. everbody from ou=germany,o=mycompany.com, or ou=sales,o=mycompany.com)

Now, for your solution: you could try to specify "o=mycompany.com" as the search scope in Redmine, then all users in that directory can be found and will be authenticated by Redmine; the only issue is that they seem to have at least read privileges for all configured projects - that is something, we should try to change in the Redmine authorization system though.

That would require a more sophisticated LDAP subsystem implementation - probably a couple of days worth of effort including testing (in order to accommodate the major LDAP servers, like AD, openLDAP, SUN One, Novell eDirectory, etc.).

For now, an ugly hack in order to get it to work for your situation could be to modify the file "<redmine-home>/app/models/auth_source_ldap.rb" and replace the line

object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )

with

object_filter = Net::LDAP::Filter.construct( "(&(objectClass=*)(memberOf=ou=redmine))" )

Again, this works only with AD and hard coded group "redmine". Note: maybe you have to specify the full dn for the group, something like "ou=redmine,cn=groups,o=mycompany.com" - I cannot test this right now, since I do not have an AD avail.

Good luck and let me know if you had success. Thanks, Jürgen

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

Thanks Jürgen I'm going to try this :)

BB

RE: LDAP Authentication - Added by Anders Gustafsson over 13 years ago

Any progress on this issue, Martin?

I needed the same functionality, so i added something similar like Jürgen suggested.
If you are interested, i made a patch for Redmine 0.8.1.

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

Anders Gustafsson wrote:

Any progress on this issue, Martin?

I needed the same functionality, so i added something similar like Jürgen suggested.
If you are interested, i made a patch for Redmine 0.8.1.

Hi Anders,

unfortunately I made no progress on this topic.

And yes, I would appreciate this very much. The provided version also fits with our installation.

Greetings,
Martin

RE: LDAP Authentication - Added by Anders Gustafsson over 13 years ago

Ok, what i did is that i added another settings field in "Administration->Settings->Authentication->LDAP Authentication" that says "Member of".

In that field you enter something like "CN=group,CN=Users,DC=domain,DC=com" and save.

When the user then logins, he will be matched against both the base-dn and the member of values.

To get the whole thing to work, you have to add another column in the database table "auth_sources" called "memberof".
That column should be a varchar with a size that will fit your memberof-string (i put 60) and be able to be null.
I am not 100% sure, but you might have to add a line to "db/schema.rb" aswell:

t.string  "memberof" 

This should be under the "create_table 'auth_soruces'".

After this is done, you should apply the attached patch file and it should work.
Please try this on a development server, not you precious production Redmine site! I don't want you to mess something important up!!!

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

Ofcourse not production. Some guys word be really pissed about that here :)

Thanks for the patch I'm going to test that immediately.

Greetings,
Martin

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

Hey Anders,

I've applied your patch file and made the changes to database and schema. I have done the migrations and loaded the defaults to redmine.

I have added the LDAP authentication server, checked the on the fly creation and left the Base DN field blank. I added CN=redmine_all1,CN=Users,DC=domain,DC=com to the member of field where I am the only user in.

But no luck :|

Have I missed something?

Greetings,
Martin

RE: LDAP Authentication - Added by Anders Gustafsson over 13 years ago

The base DN field should not be blank.
In your case it would contain "CN=Users,DC=domain,DC=com".

Hope it helps.

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

OK I'll try this tomorrow.

Greetings

RE: LDAP Authentication - Added by Martin Eckhardt over 13 years ago

Nope, this does not work for me :|

redmine_ldap_auth.png - LDAP authentication (170 KB)

RE: LDAP Authentication - Added by Anders Gustafsson over 13 years ago

Hmm really strange, i am using the same like you against a W2003 servers Active Directory LDAP.

Can you somehow query the user you try to login as in the LDAP-server?
Just to determine that the "memberOf" variable really looks like the one you wrote in the Member of field in Redmine.

RE: LDAP Authentication - Added by Reynier Perez Mira over 13 years ago

Hi:
I have a similar situation. I got this structure:
OU = Principal Domain
OU = First Group
OU = Second Group
OU = Another Group

So my Base DN looks like this: CN=Principal Domain, DC=domain,DC=com

When I test the connection this message is returned: Successful connection so it goes OK. When I logout from admin account and try domain account I can't login. Why? What I'm doing wrong? I'm working with the latest Redmine release 0.8.2
Cheers and thanks in advance

RE: LDAP Authentication - Added by teru t over 12 years ago

I did that:

- created column named memberof in table auto_sources.
- added the line 't.string "memberof"' into db/shema.rb.
- patched with redmine-0.8.1_add_ldap_group_auth.patch

after that, I can not login. Just showed error

---
Internal error
An error occurred on the page you were trying to access.
If you continue to experience problems please contact your redMine administrator for assistance.

Back
---

My environment are:
Windows Server 2003
Redmine offered by Bitnami all-in-one installer

I'd really appreciate it if you help me.

below is log I got that time.
(C:\Program Files\BitNami Redmine Stack\apps\redmine\log\pruduction.log)

---
Processing AccountController#login (for xxx.xxx.xxx.xxx at 2009-12-03 09:31:16) [POST]
Session ID: ab255654ad5578c3ef39b8bd89fb3f63
Parameters: {"action"=>"login", "username"=>"xxxxxxxx", "controller"=>"account", "password"=>"[FILTERED]", "login"=>"繝ュ繧ー繧、繝ウ ツサ"}

NoMethodError (undefined method `empty?' for nil:NilClass):
/app/models/auth_source_ldap.rb:42:in `authenticate'
/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:173:in `send'
/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:173:in `method_missing'
/app/models/user.rb:93:in `try_to_login'
/app/controllers/account_controller.rb:53:in `login'
/vendor/rails/actionpack/lib/action_controller/base.rb:1166:in `send'
/vendor/rails/actionpack/lib/action_controller/base.rb:1166:in `perform_action_without_filters'
/vendor/rails/actionpack/lib/action_controller/filters.rb:579:in `call_filters'
/vendor/rails/actionpack/lib/action_controller/filters.rb:572:in `perform_action_without_benchmark'
/vendor/rails/actionpack/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/1.8/benchmark.rb:293:in `measure'
/vendor/rails/actionpack/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
/vendor/rails/actionpack/lib/action_controller/rescue.rb:201:in `perform_action_without_caching'
/vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb:13:in `perform_action'
/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:33:in `cache'
/vendor/rails/activerecord/lib/active_record/query_cache.rb:8:in `cache'
/vendor/rails/actionpack/lib/action_controller/caching/sql_cache.rb:12:in `perform_action'
/vendor/rails/actionpack/lib/action_controller/base.rb:529:in `send'
/vendor/rails/actionpack/lib/action_controller/base.rb:529:in `process_without_filters'
/vendor/rails/actionpack/lib/action_controller/filters.rb:568:in `process_without_session_management_support'
/vendor/rails/actionpack/lib/action_controller/session_management.rb:130:in `process'
/vendor/rails/actionpack/lib/action_controller/base.rb:389:in `process'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:149:in `handle_request'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:107:in `dispatch'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:104:in `synchronize'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:104:in `dispatch'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:120:in `dispatch_cgi'
/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:35:in `dispatch'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/rails.rb:76:in `process'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/rails.rb:74:in `synchronize'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/rails.rb:74:in `process'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:159:in `process_client'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:158:in `each'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:158:in `process_client'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:285:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:285:in `initialize'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:285:in `new'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:285:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:268:in `initialize'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:268:in `new'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel.rb:268:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/configurator.rb:282:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/configurator.rb:281:in `each'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/configurator.rb:281:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:128:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/../lib/mongrel/command.rb:212:in `run'
C:/Program Files/BitNami Redmine Stack/ruby/lib/ruby/gems/1.8/gems/mongrel-1.1.5-x86-mswin32-60/bin/mongrel_rails:281
C:/Program Files/BitNami Redmine Stack/ruby/bin/mongrel_rails:19:in `load'
C:/Program Files/BitNami Redmine Stack/ruby/bin/mongrel_rails:19

Rendering C:/Program Files/BitNami Redmine Stack/apps/redmine/public/500.html (500 Internal Server Error)

RE: LDAP Authentication - Added by teru t over 12 years ago

Hi,
I just locked out the account for connection to Active Directory.
Problems have been solved. It works fine with the varchar(200) for memberof column particuraly our environment.

Thanks.

(1-15/15)