Настройка 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
            }
          }
        ]