Kanboard Documentation

LDAP Configuration Parameters

Requirements

  • PHP LDAP extension enabled
  • LDAP server:
    • OpenLDAP
    • Microsoft Active Directory
    • Novell eDirectory

LDAP Authentication

Workflow

When the LDAP authentication is activated, the login process works like that:

  1. Try first to authenticate the user by using the database
  2. If the user is not found inside the database, a LDAP authentication is performed
  3. If the LDAP authentication is successful, by default a local user is created automatically with no password and marked as LDAP users.

The full name and the email address are automatically fetched from the LDAP server.

Authentication Types

TypeDescription
Proxy UserA specific user is used to browse LDAP directory
UserThe end-user credentials are used for browsing LDAP directory
AnonymousNo authentication is performed for LDAP browsing
The recommended authentication method is Proxy.

Anonymous Mode

define('LDAP_BIND_TYPE', 'anonymous');
define('LDAP_USERNAME', null);
define('LDAP_PASSWORD', null);

This is the default value but some LDAP servers don’t allow anonymous browsing for security reasons.

Proxy Mode

A specific user is used to browse the LDAP directory:

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'my proxy user');
define('LDAP_PASSWORD', 'my proxy password');

User Mode

This method uses the credentials provided by the end-user.

For example, Microsoft Active Directory doesn’t allow anonymous browsing by default and if you don’t want to use a proxy user you can use this method.

define('LDAP_BIND_TYPE', 'user');
define('LDAP_USERNAME', '%s@kanboard.local');
define('LDAP_PASSWORD', null);

In this case, the constant LDAP_USERNAME is used as a pattern to the ldap username, examples:

  • %s@kanboard.local will be replaced by my_user@kanboard.local
  • KANBOARD\\%s will be replaced by KANBOARD\my_user

User LDAP filter

The configuration parameter LDAP_USER_FILTER is used to find users in LDAP directory.

Examples:

  • (&(objectClass=user)(sAMAccountName=%s)) is replaced by (&(objectClass=user)(sAMAccountName=my_username))
  • uid=%s is replaced by uid=my_username

Other examples of filters for Active Directory

Example to filter access to Kanboard:

(&(objectClass=user)(sAMAccountName=%s)(memberOf=CN=Kanboard Users,CN=Users,DC=kanboard,DC=local))

This example allows only people members of the group “Kanboard Users” to connect to Kanboard.

Example for Microsoft Active Directory

Let’s say we have a domain KANBOARD (kanboard.local) and the primary controller is myserver.kanboard.local.

First example with proxy mode:

<?php

// Enable LDAP authentication (false by default)
define('LDAP_AUTH', true);

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'administrator@kanboard.local');
define('LDAP_PASSWORD', 'my super secret password');

// LDAP server hostname
define('LDAP_SERVER', 'myserver.kanboard.local');

// LDAP properties
define('LDAP_USER_BASE_DN', 'CN=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', '(&(objectClass=user)(sAMAccountName=%s))');

Second example with user mode:

<?php

// Enable LDAP authentication (false by default)
define('LDAP_AUTH', true);

define('LDAP_BIND_TYPE', 'user');
define('LDAP_USERNAME', '%s@kanboard.local');
define('LDAP_PASSWORD', null);

// LDAP server hostname
define('LDAP_SERVER', 'myserver.kanboard.local');

// LDAP properties
define('LDAP_USER_BASE_DN', 'CN=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', '(&(objectClass=user)(sAMAccountName=%s))');

Example for OpenLDAP

Our LDAP server is myserver.example.com and all users are stored under ou=People,dc=example,dc=com.

For this example we use the anonymous binding.

<?php

// Enable LDAP authentication (false by default)
define('LDAP_AUTH', true);

// LDAP server hostname
define('LDAP_SERVER', 'myserver.example.com');

// LDAP properties
define('LDAP_USER_BASE_DN', 'ou=People,dc=example,dc=com');
define('LDAP_USER_FILTER', 'uid=%s');

Example for LDAPS (SSL-encryption)

Some LDAP servers are configured for “LDAPS” connectivity only (on port 636). This is different to TLS, which starts off in cleartext (port 389 by default) and then sets up encryption over the same channel.

To tell PHP to use LDAPS, you need to prefix the name of your LDAP server with “ldaps://”, as in the example below:

Our LDAP server is myserver.example.com and is only accessible via LDAPS. Most likely we won’t want to validate the server cert, and we DON’T want TLS.

For this example we use the anonymous binding.

<?php

// Enable LDAP authentication (false by default)
define('LDAP_AUTH', true);

// LDAP server hostname
define('LDAP_SERVER', 'ldaps://myserver.example.com');

// By default, require certificate to be verified for ldaps:// style URL. Set to false to skip the verification
define('LDAP_SSL_VERIFY', false);

// Enable LDAP START_TLS
define('LDAP_START_TLS', false);;

Disable Automatic Account Creation

By default, Kanboard will create a user account automatically if nothing is found.

You can disable this behavior if you prefer to create user accounts manually to restrict Kanboard to only some people.

Change the value of LDAP_USER_CREATION to false:

// Automatically create user account
define('LDAP_USER_CREATION', false);

Synchronization

By default, Kanboard will synchronize all fields (role, name, email…) except the username.

If you would like to change this behavior, use this config parameter:

// This example will not synchronize the fields "username" and "role" from LDAP to Kanboard.
define('EXTERNAL_AUTH_EXCLUDE_FIELDS', 'username,role');

Troubleshooting

SELinux Restrictions

If SELinux is enabled, you have to allow Apache to reach out your LDAP server.

  • You can switch SELinux to the permissive mode or disable it (not recommended)
  • You can allow all network connections, for example setsebool -P httpd_can_network_connect=1 or have a more restrictive rule

In any case, refer to the official Redhat/Centos documentation.

Debug Mode

If you are not able to setup correctly the LDAP authentication, you can enable the debug mode and watch log files.

LDAP Group Synchronization

  • Nested groups are not implemented.

Requirements

  • Have LDAP authentication properly configured
  • Use a LDAP server that supports memberOf or memberUid (PosixGroups)

Define automatically user roles based on LDAP groups

Use these constants in your config file:

  • LDAP_GROUP_ADMIN_DN: Distinguished names for application administrators
  • LDAP_GROUP_MANAGER_DN: Distinguished names for application managers

Example for Active Directory:

define('LDAP_GROUP_ADMIN_DN', 'CN=Kanboard Admins,CN=Users,DC=kanboard,DC=local');
define('LDAP_GROUP_MANAGER_DN', 'CN=Kanboard Managers,CN=Users,DC=kanboard,DC=local');
  • People member of “Kanboard Admins” will have the role “Administrator”
  • People member of “Kanboard Managers” will have the role “Managers”
  • Everybody else will have the role “User”

Example for OpenLDAP with Posix Groups:

define('LDAP_GROUP_BASE_DN', 'ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_USER_FILTER', '(&(objectClass=posixGroup)(memberUid=%s))');
define('LDAP_GROUP_ADMIN_DN', 'cn=Kanboard Admins,ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_MANAGER_DN', 'cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local');

You must define the parameter LDAP_GROUP_USER_FILTER if your LDAP server use memberUid instead of memberOf. All parameters of this example are mandatory.

Automatically load LDAP groups for project permissions

This feature allows you to sync automatically LDAP groups with Kanboard groups. Each group can have a different project role assigned.

On the project permissions page, people can enter groups in the auto-complete field and Kanboard can search for groups with any provider enabled.

If the group doesn’t exist in the local database, it will be automatically synced.

  • LDAP_GROUP_PROVIDER: Enable the LDAP group provider
  • LDAP_GROUP_BASE_DN: Distinguished names to find groups in LDAP directory
  • LDAP_GROUP_FILTER: LDAP filter used to perform the query
  • LDAP_GROUP_ATTRIBUTE_NAME: LDAP attribute used to fetch the group name

Example for Active Directory:

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'CN=Groups,DC=kanboard,DC=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=group)(sAMAccountName=%s*))');

With the filter given as example above, Kanboard will search for groups that match the query. If the end-user enter the text “My group” in the auto-complete box, Kanboard will return all groups that match the pattern: (&(objectClass=group)(sAMAccountName=My group*)).

  • Note 1: The special characters * is important here, otherwise an exact match will be done.
  • Note 2: This feature is only compatible with LDAP authentication configured in “proxy” or “anonymous” mode

More examples of LDAP filters for Active Directory

Example for OpenLDAP with Posix Groups:

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=posixGroup)(cn=%s*))');

LDAP User Profile Photo

Kanboard can download automatically user pictures from the LDAP server.

This feature is enabled only if LDAP authentication is activated and the parameter LDAP_USER_ATTRIBUTE_PHOTO is defined.

In your config.php, you have to set the LDAP attribute used to store the image.

define('LDAP_USER_ATTRIBUTE_PHOTO', 'jpegPhoto');

Usually, the attributes jpegPhoto or thumbnailPhoto are used. The image can be stored in JPEG or PNG format.

To upload the image in the user profile, Active Directory administrators may use software like AD Photo Edit.

The profile image is downloaded at login time only if the user do not already have uploaded an image previously.

To change the user photo, the previous one have to be removed manually in the user profile.

LDAP Configuration Parameters

  • LDAP attributes must be lowercase.
  • Nested groups are not implemented.
ParameterDefault valueDescription
LDAP_AUTHfalseEnable LDAP authentication
LDAP_SERVEREmptyLDAP server hostname
LDAP_PORT389LDAP server port
LDAP_SSL_VERIFYtrueValidate certificate for ldaps:// style URL
LDAP_START_TLSfalseEnable LDAP start TLS
LDAP_USERNAME_CASE_SENSITIVEfalseKanboard lowercase the ldap username to avoid duplicate users (the database is case sensitive)
LDAP_BIND_TYPEanonymousBind type: anonymous, user or proxy
LDAP_USERNAMEnullLDAP username to use with proxy mode or username pattern to use with user mode
LDAP_PASSWORDnullLDAP password to use for proxy mode
LDAP_USER_BASE_DNEmptyLDAP DN for users (Example: CN=Users,DC=kanboard,DC=local)
LDAP_USER_FILTEREmptyLDAP pattern to use when searching for a user account (Example: (&(objectClass=user)(sAMAccount Name=%s)))
LDAP_USER_ATTRIBUTE_USERNAMEuidLDAP attribute for username (Example: samaccountname)
LDAP_USER_ATTRIBUTE_FULLNAMEcnLDAP attribute for user full name (Example: displayname)
LDAP_USER_ATTRIBUTE_EMAILmailLDAP attribute for user email
LDAP_USER_ATTRIBUTE_GROUPSmemberofLDAP attribute to find groups in user profile
LDAP_USER_ATTRIBUTE_PHOTOEmptyLDAP attribute to find user photo (jpegPhoto or thumbnailPhoto)
LDAP_USER_ATTRIBUTE_LANGUAGEEmptyLDAP attribute for user language (preferredlanguage), the accepted language format is fr-FR
LDAP_USER_CREATIONtrueEnable automatic LDAP user creation
LDAP_GROUP_ADMIN_DNEmptyLDAP DN for administrators (Example: CN=Kanboard-Admins,CN=Users,DC=kanboard,DC=local)
LDAP_GROUP_MANAGER_DNEmptyLDAP DN for managers (Example: CN=Kanboard Managers,CN=Users,DC=kanboard,DC =local)
LDAP_GROUP_PROVIDERfalseEnable LDAP group provider for project permissions
LDAP_GROUP_BASE_DNEmptyLDAP Base DN for groups
LDAP_GROUP_FILTEREmptyLDAP group filter (Example: (&(objectClass=group)(sAMAccoun tName=%s\*)))
LDAP_GROUP_USER_FILTEREmptyIf defined, Kanboard will search user groups in LDAP_GROUP_BASE_DN with this filter, it’s useful only for posixGroups (Example: (&(objectClass=posixGroup)(mem berUid=%s)))
LDAP_GROUP_ATTRIBUTE_NAMEcnLDAP attribute for the group name
LDAP_GROUP_USER_ATTRIBUTEusernameLDAP attribute for the user in the group filter

LDAP Configuration Examples

Microsoft Active Directory

  • User authentication
  • Download the user profile picture from Active Directory
  • Set user language from LDAP attribute
  • Kanboard roles are mapped to Active Directory groups
  • LDAP group providers is enabled
define('LDAP_AUTH', true);

define('LDAP_SERVER', 'my-ldap-server');
define('LDAP_PORT', 389);

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'administrator@kanboard.local');
define('LDAP_PASSWORD', 'secret');

define('LDAP_USER_BASE_DN', 'CN=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', '(&(objectClass=user)(sAMAccountName=%s))');

define('LDAP_USER_ATTRIBUTE_USERNAME', 'sAMAccountName');
define('LDAP_USER_ATTRIBUTE_FULLNAME', 'displayname');
define('LDAP_USER_ATTRIBUTE_PHOTO', 'jpegPhoto');
define('LDAP_USER_ATTRIBUTE_LANGUAGE', 'preferredLanguage');

define('LDAP_GROUP_ADMIN_DN', 'CN=Kanboard Admins,CN=Users,DC=kanboard,DC=local');
define('LDAP_GROUP_MANAGER_DN', 'CN=Kanboard Managers,CN=Users,DC=kanboard,DC=local');

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'CN=Users,DC=kanboard,DC=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=group)(sAMAccountName=%s*))');
define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');

OpenLDAP with memberOf overlay

User LDIF example:

dn: uid=manager,ou=Users,dc=kanboard,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: manager
sn: Lastname
givenName: Firstname
cn: Kanboard Manager
displayName: Kanboard Manager
mail: manager@kanboard.local
userPassword: password
memberOf: cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local

Group LDIF example:

dn: cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local
objectClass: top
objectClass: groupOfNames
cn: Kanboard Managers
member: uid=manager,ou=Users,dc=kanboard,dc=local

Kanboard Configuration:

  • User authentication
  • Kanboard roles are mapped to LDAP groups
  • LDAP group providers is enabled
define('LDAP_AUTH', true);

define('LDAP_SERVER', 'my-ldap-server');
define('LDAP_PORT', 389);

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'cn=admin,DC=kanboard,DC=local');
define('LDAP_PASSWORD', 'password');

define('LDAP_USER_BASE_DN', 'OU=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', 'uid=%s');

define('LDAP_GROUP_ADMIN_DN', 'cn=Kanboard Admins,ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_MANAGER_DN', 'cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local');

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=groupOfNames)(cn=%s*))');
define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');

OpenLDAP with Posix groups (memberUid)

User LDIF example:

dn: uid=manager,ou=Users,dc=kanboard,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: manager
sn: Lastname
givenName: Firstname
cn: Kanboard Manager
displayName: Kanboard Manager
uidNumber: 10001
gidNumber: 8000
userPassword: password
homeDirectory: /home/manager
mail: manager@kanboard.local

Group LDIF example:

dn: cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local
objectClass: posixGroup
cn: Kanboard Managers
gidNumber: 5001
memberUid: manager

Kanboard Configuration:

  • User authentication
  • Kanboard roles are mapped to LDAP groups
  • LDAP group providers is enabled
define('LDAP_AUTH', true);

define('LDAP_SERVER', 'my-ldap-server');
define('LDAP_PORT', 389);

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'cn=admin,DC=kanboard,DC=local');
define('LDAP_PASSWORD', 'password');

define('LDAP_USER_BASE_DN', 'OU=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', 'uid=%s');

define('LDAP_GROUP_ADMIN_DN', 'cn=Kanboard Admins,ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_MANAGER_DN', 'cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local');

// This filter is used to find the groups of our user
define('LDAP_GROUP_USER_FILTER', '(&(objectClass=posixGroup)(memberUid=%s))');

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=posixGroup)(cn=%s*))');
define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');

OpenLDAP with groupOfNames

User LDIF example:

dn: uid=manager,ou=Users,dc=kanboard,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: manager
sn: Lastname
givenName: Firstname
cn: Kanboard Manager
displayName: Kanboard Manager
mail: manager@kanboard.local
userPassword: password

Group LDIF example:

dn: cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local
objectClass: top
objectClass: groupOfNames
cn: Kanboard Managers
member: uid=manager,ou=Users,dc=kanboard,dc=local

Kanboard Configuration:

  • User authentication
  • Kanboard roles are mapped to LDAP groups
  • LDAP group providers is enabled
define('LDAP_AUTH', true);

define('LDAP_SERVER', 'my-ldap-server');
define('LDAP_PORT', 389);

define('LDAP_BIND_TYPE', 'proxy');
define('LDAP_USERNAME', 'cn=admin,DC=kanboard,DC=local');
define('LDAP_PASSWORD', 'password');

define('LDAP_USER_BASE_DN', 'OU=Users,DC=kanboard,DC=local');
define('LDAP_USER_FILTER', 'uid=%s');

define('LDAP_GROUP_ADMIN_DN', 'cn=Kanboard Admins,ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_MANAGER_DN', 'cn=Kanboard Managers,ou=Groups,dc=kanboard,dc=local');

// This filter is used to find the groups of our user
define('LDAP_GROUP_USER_FILTER', '(&(objectClass=groupOfNames)(member=uid=%s,ou=Users,dc=kanboard,dc=local))');

define('LDAP_GROUP_PROVIDER', true);
define('LDAP_GROUP_BASE_DN', 'ou=Groups,dc=kanboard,dc=local');
define('LDAP_GROUP_FILTER', '(&(objectClass=groupOfNames)(cn=%s*))');
define('LDAP_GROUP_ATTRIBUTE_NAME', 'cn');