Для начала немного терминологии:
Интеграция приложения с LDAP (Lightweight Directory Access Protocol) может быть полезна по нескольким причинам. Вот некоторые из них:
1. Централизованная аутентификация
LDAP часто используется для хранения учетных данных пользователей, таких как имена пользователей и пароли. Интегрируя приложение с LDAP, можно обеспечить централизованную систему аутентификации, которая будет управлять доступом ко всем приложениям через единый источник. Это упрощает управление пользователями и их правами доступа.
2. Управление доступом (Access Control)
С помощью интеграции с LDAP можно легко контролировать права доступа пользователей к различным ресурсам и функциям внутри приложения. LDAP поддерживает группы и роли, что позволяет назначать пользователям определенные привилегии на основе их принадлежности к той или иной группе.
3. Синхронизация данных
Интеграция с LDAP позволяет синхронизировать данные между различными системами. Например, изменения в учетной записи пользователя в одной системе могут автоматически обновляться в другой системе, использующей ту же базу данных LDAP.
4. Уменьшение административных затрат
Централизация управления пользователями и их данными в одном месте снижает административную нагрузку. Администраторы могут управлять всеми учетными записями и разрешениями из единого интерфейса, что уменьшает вероятность ошибок и повышает эффективность работы.
5. Безопасность
Использование LDAP для аутентификации и авторизации улучшает безопасность системы, поскольку все учетные данные хранятся в защищенном центральном хранилище. Это также облегчает внедрение политик безопасности, таких как использование сложных паролей, регулярная смена паролей и другие меры защиты.
6. Масштабируемость
LDAP хорошо масштабируется, позволяя добавлять новые пользователи и ресурсы без значительных изменений в инфраструктуре. Это особенно полезно для крупных организаций с большим количеством сотрудников и приложений.
7. Совместимость с другими системами
Многие корпоративные системы уже используют LDAP для управления пользователями и ресурсами. Интеграция нового приложения с существующей системой LDAP обеспечивает совместимость и упрощает интеграцию с другими сервисами организации.
Примеры использования:
- Корпоративные порталы: Аутентификация и управление доступом к внутренним системам компании.
- CRM-системы: Управление доступом клиентов и партнеров к различным функциональным возможностям.
- Облачные сервисы: Обеспечение безопасного доступа к облачным ресурсам и данным.
- Образовательные платформы: Управление учётными записями студентов и преподавателей, контроль доступа к учебным материалам.
Таким образом, интеграция с LDAP предоставляет множество преимуществ, связанных с безопасностью, управлением пользователями и эффективностью работы информационных систем.
Начнет с того что нам нужно запустить LDAP сервер.
Для этого будем использовать LLDAP — Light LDAP implementation for authentication https://github.com/lldap/lldap
Воспользуемся docker compose
. Создадим файл docker-compose.yaml
volumes:
lldap-data:
services:
lldap:
image: lldap/lldap:stable
ports:
- 3890:3890
- 17170:17170
volumes:
- lldap-data:/data
environment:
- LLDAP_JWT_SECRET=secret
- LLDAP_KEY_SEED=seed
- LLDAP_LDAP_BASE_DN=dc=example,dc=com
- LLDAP_LDAP_USER_PASS=adminPassword
Запустим наш LDAP сервер с помощью команды docker compose up -d
WEB интерфейс будет доступен по адресу http://localhost:17170

Для подключения к LDAP будем использовать библиотеку https://github.com/dlampsi/adc которая в свою очередь является оберткой над библиотекой https://github.com/go-ldap/ldap
Создадим проект для нашего приложения

Добавим зависимости
go get github.com/dlampsi/adc
Ниже приведем код для функции main
package main
import (
"fmt"
"github.com/dlampsi/adc"
)
func main() {
cfg := &adc.Config{
URL: "ldap://localhost:3890",
Bind: &adc.BindAccount{
DN: "uid=admin,ou=people,dc=example,dc=com",
Password: "adminPassword",
},
SearchBase: "DC=example,DC=com",
}
cl := adc.New(cfg)
if err := cl.Connect(); err != nil {
fmt.Println(err)
return
}
err := cl.CheckAuthByDN("uid=test,ou=people,dc=example,dc=com", "12345678")
if err != nil {
fmt.Println(err)
return
}
user, err := cl.GetUser(adc.GetUserArgs{
Dn: "test",
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(user)
}
Перед запуском я создал тестового пользователя test
с паролем 12345678

Проверяем как выполнится код нашего тестового приложения
go run main.go
В результате код вывел данные нашего тестового пользователя
&{uid=test,ou=people,dc=example,dc=com map[givenName:Test mail:test@example.com sn:User] []}
Теперь немного о том, что происходит в коде.
Сначала кратко что такое LDAP и на каких правилах основан этот протокол.
Всякая запись в каталоге LDAP состоит из одного или нескольких атрибутов и обладает уникальным именем (DN — англ. Distinguished Name). Уникальное имя может выглядеть, например, следующим образом: «cn=Иван Петров,ou=Сотрудники,dc=example,dc=com»[1]. Уникальное имя состоит из одного или нескольких относительных уникальных имён (RDN — англ. Relative Distinguished Name), разделённых запятой. Относительное уникальное имя имеет вид ИмяАтрибута=значение. На одном уровне каталога не может существовать двух записей с одинаковыми относительными уникальными именами. В силу такой структуры уникального имени записи в каталоге LDAP можно легко представить в виде дерева.
Запись может состоять только из тех атрибутов, которые определены в описании класса записи (object class), которые, в свою очередь, объединены в схемы (schema). В схеме определено, какие атрибуты являются для данного класса обязательными, а какие — необязательными. Также схема определяет тип и правила сравнения атрибутов. Каждый атрибут записи может хранить несколько значений.
Мы используем lldap — приложение предназначено для аутентификации и авторизации. BaseDN мы указали в docker-compose.yaml файле с помощью переменной окружения LLDAP_LDAP_BASE_DN=dc=example,dc=com
Из README к lldap все пользователи создаются в OU=people, DN администратора по умолчанию cn=admin,ou=people,dc=example,dc=com
, пароль для администратора мы задали в переменной окружения LLDAP_LDAP_USER_PASS=adminPassword
Эти параметры мы используем для конфигурации adc:
cfg := &adc.Config{
URL: "ldap://localhost:3890",
Bind: &adc.BindAccount{
DN: "uid=admin,ou=people,dc=example,dc=com",
Password: "adminPassword",
},
SearchBase: "DC=example,DC=com",
}
Далее мы создаем клиент и проверяем подключение:
cl := adc.New(cfg)
if err := cl.Connect(); err != nil {
fmt.Println(err)
return
}
Теперь мы можем аутентифицировать тестовго пользователя:
err := cl.CheckAuthByDN("uid=test,ou=people,dc=example,dc=com", "12345678")
if err != nil {
fmt.Println(err)
return
}
Если пользователь найден, то идем дальше и получаем информацию о пользователе:
user, err := cl.GetUser(adc.GetUserArgs{
Dn: "test",
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(user)
В зависимости от того какие атрибуты установлены для пользователя или в какой группе находится пользователь мы можем разрешать те или иные действия в приложении. Таким образом можно реализовать авторизацию.
Нужно учитывать что если вам требуется более гибкое управление процессом, то стоит обратить внимание на библиотеку https://github.com/go-ldap/ldap
Так же обратите внимание что библиотека https://github.com/dlampsi/adc предназначена для работы с MS Active Directory и реализует некоторые особенности для работы именно с AD.
Всем спасибо, с вами была команда it-story.ru