1. Обзор
Серверы каталогов LDAP представляют собой иерархические хранилища данных, оптимизированные для чтения. Как правило, они используются для хранения информации о пользователе, необходимой для аутентификации и авторизации пользователя.
В этой статье мы рассмотрим API Spring LDAP для аутентификации и поиска пользователей, а также для создания и изменения пользователей на сервере каталогов. Тот же набор API можно использовать для управления любыми другими типами записей в LDAP.
2. Зависимости Maven
Начнем с добавления необходимой зависимости Maven:
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
Последнюю версию этой зависимости можно найти по адресу spring-ldap-core .
3. Подготовка данных
Для целей этой статьи давайте сначала создадим следующую запись LDAP:
ou=users,dc=example,dc=com (objectClass=organizationalUnit)
В этом узле мы будем создавать новых пользователей, изменять существующих пользователей, аутентифицировать существующих пользователей и искать информацию.
4. API-интерфейсы Spring LDAP
4.1. Определение компонента ContextSource
и LdapTemplate
ContextSource
используется для создания LdapTemplate
. Мы увидим использование ContextSource
во время аутентификации пользователя в следующем разделе:
@Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(env.getRequiredProperty("ldap.url"));
contextSource.setBase(
env.getRequiredProperty("ldap.partitionSuffix"));
contextSource.setUserDn(
env.getRequiredProperty("ldap.principal"));
contextSource.setPassword(
env.getRequiredProperty("ldap.password"));
return contextSource;
}
LdapTemplate
используется для создания и изменения записей LDAP:
@Bean
public LdapTemplate ldapTemplate() {
return new LdapTemplate(contextSource());
}
4.2. Использование весенней загрузки
Когда мы работаем над проектом Spring Boot, мы можем использовать зависимость Spring Boot Starter Data Ldap , которая автоматически будет использовать для нас LdapContextSource
и LdapTemplate
.
Чтобы включить автоконфигурацию, нам нужно убедиться, что у нас есть spring-boot-starter-data-ldap
Starter или spring-ldap-core
, определенные как зависимость в нашем pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
Для подключения к LDAP нам необходимо указать параметры подключения в application.properties:
spring.ldap.url=ldap://localhost:18889
spring.ldap.base=dc=example,dc=com
spring.ldap.username=uid=admin,ou=system
spring.ldap.password=secret
Затем все готово для внедрения автоматически сконфигурированного шаблона LdapTemplate
в требуемый класс обслуживания.
@Autowired
private LdapTemplate ldapTemplate;
4.3. Аутентификация пользователя
Давайте теперь реализуем простую логику для аутентификации существующего пользователя:
public void authenticate(String username, String password) {
contextSource
.getContext(
"cn=" +
username +
",ou=users," +
env.getRequiredProperty("ldap.partitionSuffix"), password);
}
4.4. Создание пользователя
Далее давайте создадим нового пользователя и сохраним SHA-хэш пароля в LDAP.
Во время аутентификации сервер LDAP генерирует хэш SHA предоставленного пароля и сравнивает его с сохраненным:
public void create(String username, String password) {
Name dn = LdapNameBuilder
.newInstance()
.add("ou", "users")
.add("cn", username)
.build();
DirContextAdapter context = new DirContextAdapter(dn);
context.setAttributeValues(
"objectclass",
new String[]
{ "top",
"person",
"organizationalPerson",
"inetOrgPerson" });
context.setAttributeValue("cn", username);
context.setAttributeValue("sn", username);
context.setAttributeValue
("userPassword", digestSHA(password));
ldapTemplate.bind(context);
}
дайджестSHA()
— это пользовательский метод, который возвращает закодированную в Base64 строку хэша SHA предоставленного пароля.
Наконец, метод bind()
из LdapTemplate
используется для создания записи на сервере LDAP.
4.5. Модификация пользователя
Мы можем изменить существующего пользователя или запись следующим методом:
public void modify(String username, String password) {
Name dn = LdapNameBuilder.newInstance()
.add("ou", "users")
.add("cn", username)
.build();
DirContextOperations context
= ldapTemplate.lookupContext(dn);
context.setAttributeValues
("objectclass",
new String[]
{ "top",
"person",
"organizationalPerson",
"inetOrgPerson" });
context.setAttributeValue("cn", username);
context.setAttributeValue("sn", username);
context.setAttributeValue("userPassword",
digestSHA(password));
ldapTemplate.modifyAttributes(context);
}
Метод lookupContext()
используется для поиска указанного пользователя.
4.6. Поиск пользователя
Мы можем искать существующих пользователей с помощью поисковых фильтров:
public List<String> search(String username) {
return ldapTemplate
.search(
"ou=users",
"cn=" + username,
(AttributesMapper<String>) attrs -> (String) attrs.get("cn").get());
}
AttributesMapper используется для получения желаемого значения атрибута
из найденных записей. Внутри Spring LdapTemplate
вызывает AttributesMapper
для всех найденных записей и создает список значений атрибутов.
5. Тестирование
spring-ldap-test
предоставляет встроенный сервер LDAP на основе ApacheDS 1.5.5. Чтобы настроить встроенный сервер LDAP для тестирования, нам нужно настроить следующий bean-компонент Spring:
@Bean
public TestContextSourceFactoryBean testContextSource() {
TestContextSourceFactoryBean contextSource
= new TestContextSourceFactoryBean();
contextSource.setDefaultPartitionName(
env.getRequiredProperty("ldap.partition"));
contextSource.setDefaultPartitionSuffix(
env.getRequiredProperty("ldap.partitionSuffix"));
contextSource.setPrincipal(
env.getRequiredProperty("ldap.principal"));
contextSource.setPassword(
env.getRequiredProperty("ldap.password"));
contextSource.setLdifFile(
resourceLoader.getResource(
env.getRequiredProperty("ldap.ldiffile")));
contextSource.setPort(
Integer.valueOf(
env.getRequiredProperty("ldap.port")));
return contextSource;
}
Давайте протестируем наш метод поиска пользователей с помощью JUnit:
@Test
public void
givenLdapClient_whenCorrectSearchFilter_thenEntriesReturned() {
List<String> users = ldapClient
.search(SEARCH_STRING);
assertThat(users, Matchers.containsInAnyOrder(USER2, USER3));
}
6. Заключение
В этой статье мы представили API-интерфейсы Spring LDAP и разработали простые методы для аутентификации пользователей, поиска пользователей, создания и изменения пользователей на сервере LDAP.
Как всегда, полный исходный код доступен в этом проекте Github . Тесты создаются в профиле Maven «вживую» и, следовательно, могут запускаться с использованием опции «-P live».