Content

LDAP authentication

LDAP

How to configure LDAP authentication

Overview
Declaring the LDAP authentication mode
On the fly user creation
Group-based LDAP login
Troubleshooting

 

Overview

LDAP (Lightweight Directory Access Protocol) is a software protocol for enabling anyone to locate organizations, individuals, and other resources such as files and devices in a network, whether on the public Internet or on a corporate intranet. LDAP is a "lightweight" (smaller amount of code) version of Directory Access Protocol (DAP), which is part of X.500, a standard for directory services in a network. LDAP is lighter because in its initial version it did not include security features. Easy Redmine natively supports LDAP authentication using one or multiple LDAP directories. The supported directory service types include Active Directory, OpenLDAP, eDirectory, Sun Java System Directory Server as well as other compatible directory services.

An LDAP directory is organized in a simple "tree" hierarchy consisting of the following levels:

  1. The root directory (the starting place or the source of the tree), which branches out to
  2. Countries, each of which branches out to
  3. Organizations, which branch out to
  4. Organizational units (divisions, departments, and so forth), which branches out to (includes an entry for)
  5. Individuals (which includes people, files, and shared resources such as printers)

 

Declaring the LDAP authentication mode

Go to Administration and click "LDAP authentication" in the menu. Here you find the list of all existing LDAP authentication modes including the options to test or delete any. To create a new one, click on the "New authentication mode" green button in the top right corner.

Easy Redmine 2018 LDAP 01.jpg

The LDAP service provider uses a URL to configure the connection to the directory server. To generate the LDAP connection URL, the following fields should be specified:

  • Name: An arbitrary name for the directory.
  • Host: The LDAP host name (test server).
  • Port: The LDAP port (default is 389).
  • LDAPS: Check this if you want or need to use LDAPS to access the directory.
  • Account: Enter a username that has read access to the LDAP , otherwise leave this field empty if your LDAP can be read anonymously (Active Directory servers generally do not allow anonymous access).
  • Password: Password for the account.
  • Base DN: The top level DN of your LDAP directory tree (example: dc=example,dc=com).
  • LDAP filter: Filters can be used to restrict the numbers of users or groups that are permitted to access an application. In essence the filter limits what part of the LDAP tree the application syncs from. A filter can and should be written for both user and group membership. This ensures that you are not flooding your application with users and groups that do not need access.
     

    Sample filters

    (warning) These filters are written for Active Directory. In order to use them for something such as OpenLDAP the attributes will need to be changed.

    This will only synchronise users in the 'CaptainPlanet' group - this should be applied to the User Object Filter:

    (&(objectCategory=Person)(sAMAccountName=*)(memberOf=cn=CaptainPlanet,ou=users,dc=company,dc=com))

    And this will search for users that are a member of this group, either directly or via nesting:

    (&(objectCategory=Person)(sAMAccountName=*)(memberOf:1.2.840.113556.1.4.1941:=cn=CaptainPlanet,ou=users,dc=company,dc=com))

    (info) Important for Active Directory to have memberOf:1.2.840.113556.1.4.1941 if you want to find nested groups (do not replace the numeric string) inside CaptainPlanet group.

    This will search for users who are a member of any or all the 4 groups (fire, wind,water,heart)

    (&(objectCategory=Person)(sAMAccountName=*)(|(memberOf=cn=fire,ou=users,dc=company,dc=com)(memberOf=cn=wind,ou=users,dc=company,dc=com)(memberOf=cn=water,ou=users,dc=company,dc=com)(memberOf=cn=heart,ou=users,dc=company,dc=com)))
  • Timeout (in seconds): If the LDAP provider doesn't get an LDAP response within the specified period, it aborts the read attempt. The integer should be greater than zero. An integer less than or equal to zero means no read timeout is specified which is equivalent to waiting for the response infinitely until it is received which defaults to the original behavior. If this property is not specified, the default is to wait for the response until it is received.
  • On-the-fly user creation: By checking this, any LDAP user will have his Easy Redmine account automatically created the first time he logs into Easy Redmine. Otherwise, you will have to manually create the user in Easy Redmine for each LDAP user who wants to log in.

Attributes (examples):

  • Login attribute: The login name under which a user logs in and is authenticated.
  • Firstname attribute: Attribute for first name.
  • Lastname attribute: Attribute for last name.
  • Email attribute: Attribute for email address.

Easy Redmine 2018 LDAP 02.jpg

Easy Redmine users should now be able to authenticate using their LDAP username and password if their accounts are set to use the LDAP for authentication (check "Authentication mode" setting when editing the user's profile).

To test this, create an Easy Redmine user with a login that matches his LDAP account (normally, Easy Redmine will advise you by looking up the LDAP data), select the newly created LDAP in the Authentication mode drop-down list (this field is visible on the account screen only if a LDAP is declared) and leave his password empty. Try to log in into Easy Redmine using the LDAP username and password.

Easy Redmine 2018 LDAP 03.jpg

 

On the fly user creation

By checking on-the-fly user creation, any LDAP user will have his Easy Redmine account automatically created the first time he logs into Easy Redmine.
For that, you have to specify the LDAP attributes name (firstname, lastname, email) that will be used to create their Easy Redmine accounts.

Here is an typical example using Active Directory:

Name     = My Directory
Host     = host.domain.org
Port     = 389
LDAPS    = no
Account  = MyDomain\UserName (or UserName@MyDomain depending on AD server)
Password = <password>
Base DN  = CN=users,DC=host,DC=domain,DC=org

On-the-fly user creation = yes
Attributes
  Login     = sAMAccountName
  Firstname = givenName
  Lastname  = sN
  Email     = mail

Here is another example for Active Directory with a compartmentalized intranet:

Name     = Just a description for the auth modes page
Host     = DepartmentName.OrganizationName.local
Port     = 389
LDAPS    = no
Account  = DepartmentName\UserName (or UserName@MyDomain depending on AD server or bind DN uid=Manager,cn=users,dc=MyDomain,dc=com)
Password = <password>
Base DN  = DC=DepartmentName,DC=OrganizationName,DC=local

On-the-fly user creation = yes
Attributes
  Login     = sAMAccountName
  Firstname = givenName
  Lastname  = sN
  Email     = mail

Note that LDAP attribute names are case sensitive.

Dynamic Bind Account

The above setup would need a special account on the directory server which Easy Redmine uses to pre-authenticate. It is possible to use the keyword $login in the account field which then would be replaced by the current login. The password can be left empty in this case, for example:

Account: $login@COMPANY.DOMAIN.NAME

or

Account: company\$login

Base DN variants

Although it's quite possible that the Base DN above is standard for Active Directory, the Active Directory at my employer's site does not use the Users container for standard users, so those instructions sent me down a long and painful path. I recommend also trying just "DC=host,DC=domain,DC=org" if login fail swith the settings there.

 

Group based LDAP login

If you want to just allow logins to users that belongs to a particular LDAP group you should follow below instructions. They are based on OpenLDAP LDAP server and Easy Redmine.

1. (OpenLDAP server) Enable memberof overlay

1.1. Create a file:

vim ~/memberof_add.ldif

With below content:

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: memberof

1.2. Create a file:

vim ~/memberof_config.ldif

With below content:

dn: olcOverlay=memberof,olcDatabase={1}hdb,cn=config
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: olcConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf

1.3. Load them. It will depend on your OpenLDAP configuration, so we will propose some possibilities:

sudo ldapadd -c -Y EXTERNAL -H ldapi:/// -f memberof_add.ldif
sudo ldapadd -c -Y EXTERNAL -H ldapi:/// -f memberof_config.ldif

Or:

ldapadd -D cn=admin,cn=config -w "password" -H ldapi:/// -f memberof_add.ldif
ldapadd -D cn=admin,cn=config -w "password" -H ldapi:/// -f memberof_config.ldif

A restart is NOT needed if you use dynamic runtime configuration engine (slapd-config).

1.4. (Optional) Test it:

ldapsearch -D cn=admin,dc=example,dc=com -x -W -b 'dc=example,dc=com' -H 'ldap://127.0.0.1:389/' '(&(objectClass=posixAccount)(memberOf=cn=ldapeasyredmine,ou=groups,dc=example,dc=com))'

2. (OpenLDAP server) Create the group. In this example the user is "ldap_user_1" and the group is "ldapeasyredmine":

dn: cn=ldapeasyredmine,ou=groups,dc=example,dc=com
cn: ldapeasyredmine
description: Staff members allowed to login to Easy Redmine ticketing system
member: cn=ldap_user_1,ou=people,dc=example,dc=com
objectclass: groupOfNames
objectclass: top

Adjust "dn" and "cn"s to fit to your DIT structure

3. (Easy Redmine) Edit the LDAP authentication mode. In my case "ldap_user_1" is a "posixAccount" objectclass:

Base DN: dc=example,dc=com
Filter: (&(objectClass=posixAccount)(memberOf=cn=ldapeasyredmine,ou=groups,dc=example,dc=com))

 

Troubleshooting

If you want to use on-the-fly user creation, make sure that Easy Redmine can fetch from your LDAP all the required information to create a valid user.
For example, on-the-fly user creation won't work if you don't have valid email adresses in your directory (you will get an 'Invalid username/password' error message when trying to log in).
(This is not true with newer Easy Redmine versions; the user creation dialog is populated with everything it can find from the LDAP server, and asks the new user to fill in the rest.)

Also, make sure you don't have any custom field marked as required for user accounts. These custom fields would prevent user accounts from being created on the fly.

Errors in the login system are not reported with any real information in the Easy Redmine logs, which makes troubleshooting difficult. However, you can found most of the information you need using Wireshark between your Easy Redmine host and the LDAP server. Note that this only works if you have permissions to read network traffic between those two hosts.

You can also use the tool 'ldapsearch' to test if your settings are correct. Log into the Linux machine hosting your Easy Redmine (and possibly install ldaputils) and run this:

ldapsearch -x -b  "dc=example,dc=com" -H ldap://hostname/ -D "DOMAIN\USER" -w mypassword [searchterm]

If succesful, you will get a listing of the contents of the AD, matching your search query. Then, you will know what how to fill out the fields in the LDAP config in Easy Redmine.

Alternative ways to verify the functionality

  • Try removing LDAP filters that, if they are incorrectly set, can delete the users you want to find.
  • Next to the "Login attribute" is a book icon. If it you click on it and the LDAP is set correctly, the "usual attributes" are automatically pre-filled by the actual LDAP server. Instead of text fields, select boxes appear for a case that the user wants to change the settings. In most cases, the user does not have to fill this up at all. If this works, then everything else is likely to work.
  • For connection issues, you can use the "Test" button on the LDAP server listing. Beware, this only serves to test whether you can connect to LDAP. The common problem is that administrators do not fill the LDAP system user even when LDAP settings are still protected. In this case, the test will run OK because the connection works but no users can be added because the LDAP does not "see" any.
  • To test whether LDAP really works, the "Available users" number can also be used - if its value is 0, LDAP does not return any data and is probably incorrectly set. If there is a number, you can click it to expand and see what the LDAP shows (and adjust the filters accordingly).

Account value format

The username for the bind credentials might need to be specified as a DN rather than as a UPN(user@domain.com) or as domain\user, as pointed out by this comment in source:trunk/vendor/plugins/ruby-net-ldap-0.0.4/lib/net/ldap.rb:

  # As described under #bind, most LDAP servers require that you supply a complete DN
  # as a binding-credential, along with an authenticator such as a password.

Therefore user with MyDomain\MyUserName or MyUserName@MyDomain.com username might enter only MyUserName as a Easy Redmine login name.

Slow LDAP authentification

If LDAP authentification is slow and you have an AD cluster, try to specify in Host field one of the AD physical servers. It may help.

OpenDS

If you are using the OpenDS server, you might have issues with the request control "Paged results" sent with the initial query searching for the user by the specified login attribute. This request control 1.2.840.113556.1.4.319 is not allowed for anonymous users by default, thus preventing Easy Redmine from finding the user in the directory even before the binding takes place.

Add a global ACI like this

./dsconfig -h SERVER_IP -p 4444 -D cn="Directory Manager" -w PASSWORD -n set-access-control-handler-prop --trustAll 
--add global-aci:\(targetcontrol=\"1.2.840.113556.1.4.319\"\)\ \(version\ 3.0\;\ acl\ 
\"Anonymous\ control\ access\ to\ 1.2.840.113556.1.4.319\"\;\ allow\ \(read\)\ userdn=\"ldap:///anyone\"\;\)

Note: Enter the command on one line, use the escaping exactly as indicated (the \ after "acl" is meant to be "\ " for space).

Some users are unable to log in

Problem: A specific OU of users is unable to log in (invalid user or password) while all others are. The users are in a remote site, but users in the other OUs at the same site don't get this error.

Solution: The problem is most probably not relating to incorrect settings but rather an Active Directory (AD) issue. The users that were unable to connect had the "Logon to" field set to a certain PC in the Properties of the AD user (AD administration). After changing it to "Logon from everywhere", it should work. More specifically, this field must be set to: AD User -> Properties -> Account -> Logon from everywhere.

Issues with logging-in when using LDAPS without a valid certificate

You may come across issues with logging-in when using LDAPS without a valid certificate. In Redmine 4, LDAPS certificate is always validated. With an invalid certificate, users will not be able to log in. Of course, the correct and long term solution is to use a valid certificate. But until you achieve this, the temporary solution is to go to Administration >> LDAP authentication >> Edit respective auth mode.

Change the setting to LDAPS (without certificate check).

Easy Redmine 2019 LDAP 04.jpg

With Easy Redmine Server solution you can change it in bulk from rails console
rails r "AuthSource.update_all(verify_peer: false)" -e production

or via SQL
UPDATE auth_sources set verify_peer = 0;

Easy Redmine 2019 Free Trial

Full-featured, 30 Days, SSL protected, Daily Backups, In your Geo Location

or