Configuring an LDAP authentication provider

Configuring an LDAP provider

To configure an LDAP provider, you need to create a configuration for connection to an LDAP server and user attribute mapping.

Main configuration parameters

{
    slug: 'openldap',                  // Unique provider ID
    title: 'OpenLDAP',                 // Displayed provider name
    type: 'ldap',                      // Provider type (use 'ldap')
    defaultRole: 'datalens.visitor',   // Default role for new users
    config: {
        // LDAP server connection parameters
        url: 'ldap://localhost:8389',  // LDAP server URL
        bindDN: 'cn=admin,dc=example,dc=org',  // DN for the administrative connection
        bindCredentials: 'admin',      // Administrative connection password
        bindProperty: 'dn',            // Administrative connection attribute

        // User search parameters
        searchBase: 'ou=users,dc=example,dc=org',  // User search base
        searchFilter: '(uid={{username}})',        // User search filter
        searchScope: 'sub',                        // Search area: 'base', 'one', or 'sub'

        // Group search parameters (optional)
        groupSearchBase: 'ou=groups,dc=example,dc=org',  // Group search base
        groupSearchFilter: '(&(objectClass=groupOfNames)(member={{dn}}))',  // Group search filter
        groupDnProperty: 'dn',                           // Group DN attribute
        groupSearchScope: 'sub',                         // Group search area

        // User attribute mapping (optional)
        userAttributes: {
            userId: 'uid',       // User ID attribute ('uid' by default)
            login: 'uid',        // User login attribute ('uid' by default)
            email: 'mail',       // User email address attribute ('mail' by default)
            firstName: 'givenName', // User first name attribute ('givenName' by default)
            lastName: 'sn',      // User last name attribute ('sn' by default)
        },

        // Group attribute mapping (optional)
        groupAttributes: {
            groupId: 'dn',       // Group ID attribute ('dn' by default)
            title: 'cn',         // Group name attribute ('cn' by default)
        },

        // Mapping of DataLens roles for LDAP groups (optional)
        roleToGroupId: {
            'datalens.admin': 'cn=datalensadmin,ou=groups,dc=example,dc=org',
            'datalens.creator': 'cn=datalenscreator,ou=groups,dc=example,dc=org',
            'datalens.visitor': 'cn=datalensvisitor,ou=groups,dc=example,dc=org',
        },

        // Additional settings
        syncUserRoles: true,     // Synchronizing user roles at each log-in (true by default)
        syncUserGroups: true,    // Synchronizing user groups at each log-in (true by default)
    }
}

Detailed description of parameters

Basic parameters

  • slug: Unique provider ID used in URLs and internal IDs.
  • title: Provider name displayed in the interface.
  • type: Provider type; for LDAP, use ldap.
  • defaultRole: Role assigned to the user if unable to define a role according to LDAP groups.

LDAP server connection parameters

  • url: LDAP server URL, e.g., ldap://localhost:389 or ldaps://ldap.example.com:636.
  • bindDN: Unique Distinguished Name (DN) for the administrative LDAP server connection.
  • bindCredentials: Administrative connection password.
  • bindProperty: User’s LDAP object attribute used for password checking as a bind property, e.g., name, email. The default value is dn.

User search parameters

  • searchBase: User search base in LDAP, e.g., ou=users,dc=example,dc=org.

  • searchFilter: User search filter. Use the {{username}} template to substitute the login entered by the user.

  • searchScope: Search area:

    • base: Search in the specified base only.
    • one: Search in the base and one level below.
    • sub: Recursive search in all subtrees.

Group search parameters (optional)

  • groupSearchBase: Group search base in LDAP, e.g., ou=groups,dc=example,dc=org.
  • groupSearchFilter: Group search filter. Use {{dn}} to substitute the DN of the found user.
  • groupDnProperty: User object attribute used to interpolate {{dn}} for groupSearchFilter (dn by default).
  • groupSearchScope: Group search area (similar to searchScope).

// User attribute mapping

Allows you to set up the mapping between the LDAP user attributes and the user’s fields in the system:

  • userId: User ID attribute (uid by default).
  • login: User login attribute (uid by default).
  • email: User email address attribute (mail by default).
  • firstName: User first name attribute (givenName by default).
  • lastName: User last name attribute (sn by default).

Group attribute mapping

Allows you to set up the mapping between the LDAP groups' attributes and the groups' fields in the system:

  • groupId: Group ID attribute (dn by default).
  • title: Group name attribute (cn by default).

Mapping of LDAP group roles

Allows you to set up the mapping between DataLens roles and LDAP groups.

Algorithm of synchronization between groups and roles:

  1. A search for the user's LDAP groups is performed.
  2. For each group, a search is performed in roleToGroupId based on the group ID (an attribute from groupAttributes). Once a group is found in roleToGroupId, a relevant role will be assigned to the user.

For example:

roleToGroupId: {
    'datalens.admin': 'cn=datalensadmin,ou=groups,dc=example,dc=org',
    'datalens.creator': 'cn=datalenscreator,ou=groups,dc=example,dc=org',
    'datalens.visitor': 'cn=datalensvisitor,ou=groups,dc=example,dc=org',
}

Where:

  • 'cn=datalensadmin,ou=groups,dc=example,dc=org', 'cn=datalenscreator,ou=groups,dc=example,dc=org', and 'cn=datalensvisitor,ou=groups,dc=example,dc=org': Group IDs and the search base (ou=groups,dc=example,dc=org) in LDAP.
  • 'datalens.admin', 'datalens.creator', and 'datalens.visitor': DataLens roles.

If the user is a member of the cn=datalensadmin group, the datalens.admin role will be assigned.

Additional settings

  • syncUserRoles: When set to true (default value), user roles will be synchronized at each log-in.
  • syncUserGroups: When set to true (default value), user groups will be synchronized at each log-in.

Aspects of role and group synchronization

User roles and groups are synchronized the moment the user logs in to the system. If the user is a member of a group specified in the configuration, the relevant role will be assigned to the user, and the group will appear in DataLens and will be available in the access permissions. If the user is not a group member, the default role will be assigned. If there are more than 100 groups, synchronization will be skipped. If you need to synchronize more groups, set up regular group synchronization using a synchronization script.

Example of an OpenLDAP configuration

const ldapConfig = {
    slug: 'openldap',
    title: 'OpenLDAP',
    type: 'ldap',
    defaultRole: 'datalens.visitor',
    config: {
        url: 'ldap://ldap.example.com:389',
        bindDN: 'cn=admin,dc=example,dc=org',
        bindCredentials: 'admin_password',
        searchBase: 'ou=users,dc=example,dc=org',
        searchFilter: '(uid={{username}})',
        groupSearchBase: 'ou=groups,dc=example,dc=org',
        groupSearchFilter: '(&(objectClass=groupOfNames)(member={{dn}}))',
        groupDnProperty: 'dn',
        searchScope: 'sub',
        groupSearchScope: 'sub',

        userAttributes: {
            userId: 'uid',
            login: 'uid',
            email: 'mail',
            firstName: 'givenName',
            lastName: 'sn',
        },

        groupAttributes: {
            groupId: 'dn',
            title: 'cn',
        },

        roleToGroupId: {
            'datalens.admin': 'cn=datalensadmin,ou=groups,dc=example,dc=org',
            'datalens.creator': 'cn=datalenscreator,ou=groups,dc=example,dc=org',
        },

        syncUserRoles: true,
        syncUserGroups: true,
    },
};

Example of an ldif file for an OpenLDAP configuration

## base

dn: ou=users,dc=example,dc=org
changetype: add
ou: users
objectClass: organizationalUnit
description: Org group for users.

dn: ou=groups,dc=example,dc=org
changetype: add
ou: groups
objectClass: organizationalUnit
description: Org group for groups.

## users

dn: uid=bob,ou=users,dc=example,dc=org
changetype: add
uid: bob
cn: Bob Smith
givenName: Bob
sn: Smith
objectClass: inetOrgPerson
userPassword: bob
mail: bob@example.org

dn: uid=al,ou=users,dc=example,dc=org
changetype: add
uid: al
cn: Al Brown
givenName: Al
sn: Brown
objectClass: inetOrgPerson
userPassword: al
mail: al@example.org

dn: uid=carl,ou=users,dc=example,dc=org
changetype: add
uid: carl
cn: Carl Snow
givenName: Carl
sn: Snow
objectClass: inetOrgPerson
userPassword: carl
mail: carl@example.org

## groups
dn: cn=someusers,ou=groups,dc=example,dc=org
changetype: add
objectclass: groupofnames
cn: someusers
description: Some Group
member: uid=al,ou=users,dc=example,dc=org
member: uid=bob,ou=users,dc=example,dc=org

## groups-roles
dn: cn=datalensadmin,ou=groups,dc=example,dc=org
changetype: add
objectclass: groupofnames
cn: datalensadmin
description: Group datalens.admin role
member: uid=bob,ou=users,dc=example,dc=org

dn: cn=datalenscreator,ou=groups,dc=example,dc=org
changetype: add
objectclass: groupofnames
cn: datalenscreator
description: Group datalens.creator role
member: uid=al,ou=users,dc=example,dc=org

ldapsearch

We recommend you to start by testing the configuration with the ldapsearch utility:

# Search for the user
ldapsearch \
  -H ldap://ldap.example.com:389 \
  -x \
  -D cn=admin,dc=example,dc=org \
  -w admin \
  -b ou=users,dc=example,dc=org \
  "(uid=bob)"

# ldapsearch \
#  -H ldap://ldap.example.com:389 \ # config.url
#  -x \
#  -D cn=admin,dc=example,dc=org \  # config.bindDN
#  -w admin \                       # config.bindCredentials
#  -b ou=users,dc=example,dc=org \  # config.searchBase
#  "(uid=bob)"                      # config.searchFilter with {{username}} (user login when logging in to the DL) substituted into the template string

# LDAP response:
# dn: uid=bob,ou=users,dc=example,dc=org
# uid: bob
# cn: Bob Smith
# givenName: Bob
# sn: Smith
# objectClass: inetOrgPerson
# userPassword:: ...
# mail: bob@example.org

# Search for the user's groups
ldapsearch \
  -H ldap://ldap.example.com:389 \
  -x \
  -D cn=admin,dc=example,dc=org \
  -w admin \
  -b ou=groups,dc=example,dc=org \
  "(&(objectClass=groupOfNames)(member=uid=bob,ou=users,dc=example,dc=org))"

# ldapsearch \
#  -H ldap://ldap.example.com:389 \ # config.url
#  -x \
#  -D cn=admin,dc=example,dc=org \  # config.bindDN
#  -w admin \                       # config.bindCredentials
#  -b ou=groups,dc=example,dc=org \ # config.groupSearchBase
#  "(&(objectClass=groupOfNames)(member=uid=bob,ou=users,dc=example,dc=org))"  # config.groupSearchFilter
#  Above, we got the `bob` user and substituted their dn into the template string {{dn}}: (&(objectClass=groupOfNames)(member={{dn}})) according to config.groupDnProperty

# LDAP response:
# someusers, groups, example.org
# dn: cn=someusers,ou=groups,dc=example,dc=org
# objectClass: groupOfNames
# cn: someusers
# description: Some Group
# member: uid=bob,ou=users,dc=example,dc=org
# member: uid=al,ou=users,dc=example,dc=org

# datalensadmin, groups, example.org
# dn: cn=datalensadmin,ou=groups,dc=example,dc=org
# objectClass: groupOfNames
# description: Group datalens.admin role
# member: uid=bob,ou=users,dc=example,dc=org
# cn: datalensadmin

Example of an Active Directory configuration

const adConfig = {
    slug: 'active-directory',
    title: 'Active Directory',
    type: 'ldap',
    defaultRole: 'datalens.visitor',
    config: {
        url: 'ldap://ad.example.com:389',
        bindDN: 'CN=Service Account,OU=Service Accounts,DC=example,DC=com',
        bindCredentials: 'service_account_password',
        searchBase: 'OU=Users,DC=example,DC=com',
        searchFilter: '(&(objectClass=user)(sAMAccountName={{username}}))',
        groupSearchBase: 'OU=Groups,DC=example,DC=com',
        groupSearchFilter: '(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{dn}}))',
        groupDnProperty: 'dn',
        searchScope: 'sub',
        groupSearchScope: 'sub',

        userAttributes: {
            userId: 'sAMAccountName',
            login: 'sAMAccountName',
            email: 'mail',
            firstName: 'givenName',
            lastName: 'sn',
        },

        groupAttributes: {
            groupId: 'dn',
            title: 'cn',
        },

        roleToGroupId: {
            'datalens.admin': 'CN=DatalensAdmins,OU=Groups,DC=example,DC=com',
            'datalens.creator': 'CN=DatalensCreators,OU=Groups,DC=example,DC=com',
        },

        syncUserRoles: true,
        syncUserGroups: true,
    },
};

Using a configuration

Configuration via the AUTH_PROVIDERS_CONFIG environment variable

To configure authentication providers, the application uses the AUTH_PROVIDERS_CONFIG environment variable. This variable contains a JSON string with an array of configurations of all authentication providers. Currently, only the LDAP provider is supported; however, other provider types will be added in future as well.

Example of the AUTH_PROVIDERS_CONFIG environment variable:

[
  {
    "slug": "openldap",
    "title": "OpenLDAP",
    "type": "ldap",
    "defaultRole": "datalens.visitor",
    "config": {
      "url": "ldap://ldap.example.com:389",
      "bindDN": "cn=admin,dc=example,dc=org",
      "bindCredentials": "admin_password",
      "searchBase": "ou=users,dc=example,dc=org",
      "searchFilter": "(uid={{username}})",
      "groupSearchBase": "ou=groups,dc=example,dc=org",
      "groupSearchFilter": "(&(objectClass=groupOfNames)(member={{dn}}))",
      "groupDnProperty": "dn",
      "searchScope": "sub",
      "groupSearchScope": "sub",
      "roleToGroupId": {
        "datalens.admin": "cn=datalensadmin,ou=groups,dc=example,dc=org",
        "datalens.creator": "cn=datalenscreator,ou=groups,dc=example,dc=org"
      },
      "syncUserRoles": true,
      "syncUserGroups": true
    }
  }
]