Перейти к основному содержимому

Весенний обзор LDAP

· 4 мин. чтения

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».