Настройка LDAP-провайдера аутентификации

Конфигурация LDAP-провайдера

Чтобы настроить LDAP-провайдер, нужно создать конфигурацию с необходимыми параметрами для подключения к LDAP-серверу и маппинга пользовательских атрибутов.

Основные параметры конфигурации

{
    slug: 'openldap',                  // Уникальный идентификатор провайдера
    title: 'OpenLDAP',                 // Отображаемое название провайдера
    type: 'ldap',                      // Тип провайдера (должен быть 'ldap')
    defaultRole: 'datalens.visitor',   // Роль по умолчанию для новых пользователей
    config: {
        // Параметры подключения к LDAP-серверу
        url: 'ldap://localhost:8389',  // URL LDAP-сервера
        bindDN: 'cn=admin,dc=example,dc=org',  // DN для административного подключения
        bindCredentials: 'admin',      // Пароль для административного подключения
        bindProperty: 'dn',            // Атрибут для административного подключения

        // Параметры поиска пользователей
        searchBase: 'ou=users,dc=example,dc=org',  // База поиска пользователей
        searchFilter: '(uid={{username}})',        // Фильтр поиска пользователей
        searchScope: 'sub',                        // Область поиска: 'base', 'one' или 'sub'

        // Параметры поиска групп (опционально)
        groupSearchBase: 'ou=groups,dc=example,dc=org',  // База поиска групп
        groupSearchFilter: '(&(objectClass=groupOfNames)(member={{dn}}))',  // Фильтр поиска групп
        groupDnProperty: 'dn',                           // Атрибут DN группы
        groupSearchScope: 'sub',                         // Область поиска групп

        // Маппинг атрибутов пользователя (опционально)
        userAttributes: {
            userId: 'uid',       // Атрибут для идентификатора пользователя (по умолчанию 'uid')
            login: 'uid',        // Атрибут для логина пользователя (по умолчанию 'uid')
            email: 'mail',       // Атрибут для адреса электронной почты пользователя (по умолчанию 'mail')
            firstName: 'givenName', // Атрибут для имени пользователя (по умолчанию 'givenName')
            lastName: 'sn',      // Атрибут для фамилии пользователя (по умолчанию 'sn')
        },

        // Маппинг атрибутов группы (опционально)
        groupAttributes: {
            groupId: 'dn',       // Атрибут для идентификатора группы (по умолчанию 'dn')
            title: 'cn',         // Атрибут для названия группы (по умолчанию 'cn')
        },

        // Маппинг ролей DataLens на группы LDAP (опционально)
        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',
        },

        // Дополнительные настройки
        syncUserRoles: true,     // Синхронизировать роли пользователя при каждом входе (по умолчанию true)
        syncUserGroups: true,    // Синхронизировать группы пользователя при каждом входе (по умолчанию true)
    }
}

Детальное описание параметров

Основные параметры

  • slug — уникальный идентификатор провайдера, используется в URL и внутренних идентификаторах;
  • title — название провайдера, отображаемое в интерфейсе;
  • type — тип провайдера, для LDAP должно быть значение ldap;
  • defaultRole — роль, назначаемая пользователю, если не удалось определить роль по группам LDAP.

Параметры подключения к LDAP-серверу

  • url — URL LDAP-сервера, например, ldap://localhost:389 или ldaps://ldap.example.com:636;
  • bindDN — уникальное имя Distinguished Name (DN) для административного подключения к LDAP-серверу;
  • bindCredentials — пароль для административного подключения;
  • bindProperty — атрибут объекта пользователя LDAP, используемый при привязке для проверки пароля. Например, name, email. По умолчанию: dn.

Параметры поиска пользователей

  • searchBase — база поиска пользователей в LDAP, например, ou=users,dc=example,dc=org;

  • searchFilter — фильтр поиска пользователей. Используйте шаблон {{username}} для подстановки введенного пользователем логина;

  • searchScope — область поиска:

    • base — поиск только в указанной базе;
    • one — поиск в базе и на один уровень ниже;
    • sub — рекурсивный поиск во всех поддеревьях.

Параметры поиска групп (опционально)

  • groupSearchBase — база поиска групп в LDAP, например, ou=groups,dc=example,dc=org;
  • groupSearchFilter — фильтр поиска групп. Используйте {{dn}} для подстановки DN найденного пользователя;
  • groupDnProperty — атрибут объекта пользователя, используемый в интерполяции {{dn}} для groupSearchFilter (по умолчанию dn);
  • groupSearchScope — область поиска групп (аналогично searchScope).

Маппинг атрибутов пользователя

Позволяет настроить соответствие между атрибутами пользователя LDAP и полями пользователя в системе:

  • userId — атрибут для идентификатора пользователя (по умолчанию uid);
  • login — атрибут для логина пользователя (по умолчанию uid);
  • email — атрибут для адреса электронной почты пользователя (по умолчанию mail);
  • firstName — атрибут для имени пользователя (по умолчанию givenName);
  • lastName — атрибут для фамилии пользователя (по умолчанию sn).

Маппинг атрибутов группы

Позволяет настроить соответствие между атрибутами групп LDAP и полями групп в системе:

  • groupId — атрибут для идентификатора группы (по умолчанию dn);
  • title — атрибут для названия группы (по умолчанию cn).

Маппинг ролей на группы LDAP

Позволяет настроить соответствие между ролями в DataLens и группами LDAP.

Алгоритм синхронизации групп и ролей:

  1. Выполняется поиск групп пользователя в LDAP.
  2. Для каждой группы выполняется поиск в roleToGroupId по идентификатору группы (аттрибуту из groupAttributes). При нахождении группы в roleToGroupId, пользователю будет назначена соответствующая роль.

Например:

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',
}

Где:

  • 'cn=datalensadmin,ou=groups,dc=example,dc=org', 'cn=datalenscreator,ou=groups,dc=example,dc=org', 'cn=datalensvisitor,ou=groups,dc=example,dc=org' — идентификаторы групп и база для поиска (ou=groups,dc=example,dc=org) в LDAP;
  • 'datalens.admin', 'datalens.creator', 'datalens.visitor' — роли в DataLens.

Так, если пользователь состоит в группе cn=datalensadmin, ему будет назначена соответствующая роль — datalens.admin.

Дополнительные настройки

  • syncUserRoles — при значении true (по умолчанию), роли пользователя будут синхронизироваться при каждом входе;
  • syncUserGroups — при значении true (по умолчанию), группы пользователя будут синхронизироваться при каждом входе.

Особенности синхронизации ролей и групп

Синхронизация групп и ролей пользователя происходит в момент входа пользователя в систему. Если пользователь состоит в группе, указанной в конфигурации, ему будет назначена соответствующая роль, а также группа будет заведена в DataLens и будет доступна в правах доступа. Если пользователь не состоит в группе, ему будет назначена роль по умолчанию. Если групп больше, чем 100, то синхронизация будет пропущена. Если нужно синхронизировать больше групп, то необходимо настроить периодическую синхронизацию групп с помощью скрипта синхронизации.

Пример конфигурации для OpenLDAP

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,
    },
};

Пример ldif файла для конфигурации OpenLDAP

## 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

Рекомендуем предварительно проверить работу конфигурации утилитой ldapsearch:

# поиск юзера
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 с подставленным в шаблонную строку {{username}} логин пользователя при заходе в DL

# Ответ из LDAP:
# 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

# поиск групп пользователя
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
#  Выше мы получили пользователя bob и подставили в шаблонную строку {{dn}}: (&(objectClass=groupOfNames)(member={{dn}})) его dn согласно config.groupDnProperty

# Ответ из LDAP:
# 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

Пример конфигурации для Active Directory

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,
    },
};

Использование конфигурации

Настройка через переменную окружения AUTH_PROVIDERS_CONFIG

Для настройки провайдеров аутентификации в приложении используется переменная окружения AUTH_PROVIDERS_CONFIG. Эта переменная содержит JSON-строку с массивом конфигураций всех провайдеров аутентификации. В настоящее время поддерживается только LDAP-провайдер, но в будущем планируется добавление других типов провайдеров.

Пример значения переменной окружения AUTH_PROVIDERS_CONFIG:

[
  {
    "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
    }
  }
]