LDAP заявки с Spring Boot LdapTemplate
Наскоро си играех с Active Directory (AD) и се опитах да извлека потребителска информация чрез LDAP заявки. Това определено беше разочароващо преживяване, тъй като не бях много запознат с LDAP. Затова реших да пиша за това, което научих.
Забележка: в момента на писане работя с Spring Boot v2.7.7, Gradle v7.6, Docker-Compose v2.14.0, Docker v20.10.3 и Java v11.
Преглед
Нека започнем с малко фонов контекст. Active Directory (AD) е често използвана директорийна услуга от много компании за управление на потребители и групи, администриране на политики, удостоверяване и т.н. LDAP (Lightweight Directory Access Protocol) е протокол, който можем да използваме за комуникация с LDAP сървърите ( напр. рекламата).
Когато разработваме услуги, можем да удостоверяваме потребителите с LDAP или да извличаме потребителска информация от LDAP сървъра. В тази статия ще се съсредоточа основно върху някои от методите, които използвах за запитване до LDAP сървъра с помощта на LdapTemplate
. LdapTemplate
е набор от готови за използване API за изпълнение на основни LDAP операции като създаване, модифициране, извличане и т.н.
Настройка на LDAP сървър
Преди да започнем, ще трябва да имаме LDAP сървър, за да правим заявки. В тази демонстрация, вместо да настроим цяла Active Directory, ще настроим LDAP сървър с помощта на osixia/docker-openldap
. Това е OpenLDAP докер изображение, което ни позволява лесно да попълваме LDAP базата данни с помощта на LDIF файл.
За да започнем, ще подготвим LDIF файл за стартиране, който съдържа всички данни, с които искаме да заредим LDAP базата данни. За демонстрационни цели ние ще попълним само LDAP базата данни с потребителска информация, както е показано по-долу.
Има 3 потребители (известни също като запис), попълнени в LDAP базата данни с 3 атрибута, които ще извлечем в нашата демонстрация:
uid
: съхранява идентификатора на потребителяdisplayname
: съхранява името на потребителяmail
: съхранява всички имейл адреси на потребителя
Забележка: LDAP запис е колекция от информация за обект. Всеки запис се състои от три основни компонента: отличително име, колекция от атрибути и колекция от класове обекти
За да стартирам OpenLdap сървъра, създадох следния YAML файл за съставяне на докери.
Обърнете внимание, че домейнът е example.org
и LDAP директорията има следната дървовидна структура след зареждане с файла LDIF
, дефиниран по-горе.
Запитване с ldapsearch
Когато OpenLdap сървърът работи, можем да опитаме да изработим някои LDAP заявки, използвайки ldapsearch
, както е показано по-долу.
# Step into the OpenLdap Docker Container Instance docker exec -it openldap /bin/bash # Execute LDAP query ldapsearch -x \ -H ldap://localhost:389 \ -b "dc=example,dc=org" \ -D "cn=admin,dc=example,dc=org" \ -w admin
Опцията -b
показва базата за търсене за заявката и в нашия случай можем да използваме dc=example,dc=org
или ou=Users,dc=example,dc=org
, както е посочено в дървовидната структура на нашата LDAP директория по-горе.
Опцията -D
и -w
показва кое отличително име за обвързване е необходимо за удостоверяване и по подразбиране docker-openldap създава администраторски акаунт с парола admin
.
Забележка: Отличителното име (DN) е името, което уникално идентифицира и описва запис в LDAP сървър.
След като вече знаем как да правим заявки с помощта на ldapsearch
, нека се опитаме да направим същото в Spring Boot с LdapTemplate
.
Създайте Spring Boot Project
Spring Boot предоставя Spring Data LDAP, която е библиотека за просто LDAP програмиране. Това ни позволява лесно да конфигурираме Spring Boot проект за свързване и комуникация с LDAP сървър. Можем да направим това, като импортираме зависимостта spring-boot-starter-data-ldap
към нашия проект.
# Gradle dependencies { implementation("org.springframework.boot:spring-boot-starter-data-ldap") } # Maven <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-ldap</artifactId> </dependency>
След това, за да се свържете със сървъра OpenLdap, ще предоставим следните настройки за връзка в нашия application.yaml
:
spring.ldap: urls: ldap://localhost:389 base: dc=example,dc=org username: cn=admin,dc=example,dc=org password: admin
С това вече сме готови да използваме LdapTemplate
за запитване до OpenLdap сървъра.
Запитване с LdapTemplate
Първо, нека проверим всеки потребителски запис. По-долу е даден пример за потребителски запис.
dn: cn=Amanda,ou=Users,dc=example,dc=org objectclass: inetOrgPerson uid: U0 cn: Amanda sn: Amanda givenname: Amanda displayname: Amanda mail: [email protected] mail: [email protected] userpassword: amanda
Интересуваме се да извлечем атрибутите uid
, displayname
и mail
. Както може би сте забелязали, има повече от 1 стойност за атрибута mail
. Така че нека да видим как можем да извлечем всички тези атрибути с помощта на LdapTemplate
.
#1 Използване на AttributesMapper
Когато търсим с LdapTemplate
, можем да използваме AttributesMapper
за картографиране на стойностите на атрибута. Според „документите“,
Вътрешно
LdapTemplate
итерира всички намерени записи, извиквайки даденияAttributesMapper
за всеки запис и събира резултатите в списък. След това списъкът се връща от метода за търсене.
Ето пример за това как можем да извлечем атрибутите на потребителя с помощта на AttributesMapper.
Забележете, че търсим от директорията ou=Users
в основната директория dc=example,dc=org
, която дефинирахме по-горе. Филтър uid=$userId
също се прилага за намиране на конкретния потребителски запис.
Очакван резултат:
[{ "userId":"U0", "name":"Amanda", "emails":["[email protected]","[email protected]"] }]
Имайте предвид обаче, че има малко ограничение, при което, ако се опитвате да извлечете атрибути, които не съществуват, ще получите NullPointerException
. Освен това няма да можете да извлечете отличителното име (dn
) или схеми с помощта на AttributesMapper
.
#2 Използване на ContextMapper
По подобен начин можем да използваме AbstractContextMapper
за картографиране на атрибутите на запис. Според „документите“,
Всеки път, когато бъде намерен запис в дървото на LDAP, неговите атрибути и отличително име (DN) ще бъдат използвани от Spring LDAP за конструиране на
DirContextAdapter
. Това ни позволява да използвамеContextMapper
за трансформиране на намерените стойности.
Ето пример за това как можем да извлечем атрибутите на потребителя с помощта на AbstractContextMapper
. Операцията за търсене е същата като AttributesMapper
, с изключение на това, че картографът е заменен с AbstractContextmapper
.
Очакван резултат:
[{ "userId":"U0", "name":"Amanda", "emails":["[email protected]","[email protected]"] }]
Предимството на ContextMapper
е, че
- той обработва
NullPointerException
като връща null вместо да хвърля изключения. - той опростява операциите за извличане на атрибути (особено за атрибути с много стойности) с
getStringAttribute()
иgetStringAttributes()
методи. - позволява ви да извличате разграничително име (dn), схеми и класове обекти.
#3 Допълнителни съвети — DefaultIncrementAttributesMapper
Ако знаете отличителното име (dn), можете да използвате DefaultIncrementAttributesMapper
, за да търсите многостойностни атрибути (напр. атрибута mail
). Ето пример как можете да го използвате.
Очакван резултат
["[email protected]","[email protected]"]
Имайте предвид, че dn на потребителя е cn=Amanda,ou=Users,dc=example,dc=org
. Тъй като вече сме дефинирали основната директория да бъде dc=example,dc=org
, няма нужда да включвате dc=example,dc=org
в dn при търсене. Това ще доведе до код за грешка 32, ако е включен.
javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]; remaining name 'cn=Amanda,ou=Users,dc=example,dc=org'
Резюме
Това е! Ако сте запознати с LDAP и Spring Boot, по-голямата част от тази информация може лесно да бъде намерена в съответната документация. Тази статия има за цел да даде обща представа за това как можете да извършите търсене на атрибути с помощта на LdapTemplate
. Надявам се тази статия да ви хареса толкова, колкото ми беше приятно да я напиша :)
За повече информация вижте тези полезни връзки:
- Основни концепции за LDAP
- Пролетен преглед на LDAP
- Пролетна рамка LDAP
- „Създайте изображение на OpenLdap Docker, което се попълва с потребители“
Благодаря за четенето.