Как проверить отозванный сертификат в соединениях на основе SSL с использованием LDAP-сервера в памяти (из UnboundID LDAP SDK для Java)?

В своем приложении я использую библиотеку UnboundID LDAP SDK для Java (https://ldap.com/unboundid-ldap-sdk-for-java/).

Я пытаюсь написать тест, который точно проверит, как соединения LDAPS / StartTLS ведут себя для сертификатов, которые были правильно настроены, но когда запрос к серверу LDAP выполнен, они больше не действительны (например, ключи были скомпрометированы, и мы заменил на другой).

Я хотел проверить это поведение с помощью интеграционных тестов, используя сервер в памяти из UnboundID LDAP SDK - InMemoryDirectoryServer (https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/listener/InMemoryDirectoryServer.html)

Постараюсь пошагово описать, как это выглядит на производстве:

  1. Мы создаем пул подключений к нашему серверу, используя действующий сертификат. У нас есть рабочий и настроенныйLDAPConnectionPoolобъект (https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/LDAPConnectionPool.html). Подключение работает через порт 636 по протоколу LDAPS или через порт 389 по протоколу StartTLS.
  2. На стороне сервера LDAP мы отзываем сертификат, потому что, например, ключи были скомпрометированы. Мы генерируем новый сертификат. Подключение к LDAP на стороне нашего приложения все еще активно.
  3. Когда мы выполняем простой поиск из нашего приложения - ldapConnectionPool.search(someSearchRequest()); мы должны получить LDAPSearchException, сообщая нам, что наше соединение недействительно.

Допустим, опция насмешки LDAPConnectionPool не учитывается.

Конфигурация моего сервера в памяти следующая:

class InMemoryLDAPServer {

    private final static String LDAPS_LISTENER_NAME = "LDAPS";
    private final static String TLS_LISTENER_NAME = "TLS";
    private final static String BASE_DN = "dc=example,dc=com";
    private final static String LDIF_FILENAME = "ldap.ldif";

    private final InMemoryDirectoryServer directoryServer;

    private InMemoryLDAPServer(InMemoryDirectoryServer directoryServer) {
        this.directoryServer = directoryServer;
    }

    static InMemoryLDAPServer newSecureServer(final InMemoryOperationInterceptor interceptor) throws Exception {
        InMemoryDirectoryServerConfig config = createServerConfig(interceptor);
        return getEmbeddedLdapServer(config);
    }

    private static InMemoryLDAPServer getEmbeddedLdapServer(final InMemoryDirectoryServerConfig config) throws LDAPException {
        InMemoryDirectoryServer directoryServer = new InMemoryDirectoryServer(config);
        directoryServer.importFromLDIF(true, ldifFilename());
        directoryServer.startListening();
        return new InMemoryLDAPServer(directoryServer);
    }

    private static InMemoryDirectoryServerConfig createServerConfig(final InMemoryOperationInterceptor interceptor) throws LDAPException, GeneralSecurityException {
        final SSLUtil serverSSLUtil = new SSLUtil(KeyStoreStub.keyStores(), KeyStoreStub.trustStores());
        final SSLUtil clientSSLUtil = new SSLUtil(KeyStoreStub.trustStores());

        InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(BASE_DN);
        config.setSchema(null);
        config.setListenerConfigs(InMemoryListenerConfig.createLDAPSConfig(LDAPS_LISTENER_NAME,
                InetAddress.getLoopbackAddress(), 0, serverSSLUtil.createSSLServerSocketFactory(),
                clientSSLUtil.createSSLSocketFactory()), InMemoryListenerConfig.createLDAPConfig(TLS_LISTENER_NAME, InetAddress.getLoopbackAddress(), 0, serverSSLUtil.createSSLSocketFactory()));
        config.addInMemoryOperationInterceptor(interceptor);
        return config;
    }

    private static String ldifFilename() {
        return getPath(LDIF_FILENAME);
    }

    private static String getPath(final String relativePath) {
        File resourcesDirectory = new File(PATH_NAME + relativePath);
        return resourcesDirectory.getAbsolutePath();
    }
}

Моя идея - изменить возвращаемый результат, используя InMemoryOperationInterceptor(https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/listener/interceptor/InMemoryOperationInterceptor.html). К сожалению, это не совсем так.

Образец теста:

@Test
void shouldReturnEmptyResultWhenConfigurationIsBroken() throws Exception {
    //given
    TestOperationInterceptor testOperationInterceptor = new TestOperationInterceptor();
    InMemoryLDAPServer.newSecureServer(testOperationInterceptor);
    final LdapTestConfiguration testConfiguration = createTestLDAPConfiguration();

    //when
    final List<UserResult> results = ldapSearchService.searchByUsername(testConfiguration.getUsername());

    //then
    assertTrue(results.isEmpty());
}

Образец перехватчика:

class TestOperationInterceptor extends InMemoryOperationInterceptor {

    @Override
    public void processSearchResult(final InMemoryInterceptedSearchResult result) {
        final LDAPSearchException searchException = new LDAPSearchException(ResultCode.NO_SUCH_OBJECT, "Provided keystore is revoked or expired");
        final SearchResult searchResult = new SearchResult(searchException);
        result.setResult(searchResult);
    }
}

У вас есть еще идеи, как решить эту проблему?

0 ответов

Другие вопросы по тегам