Кастомная аутентификация LDAP через LoginView — не срабатывает провайдер

Добрый день!

Столкнулся с проблемой при реализации кастомного подключения и аутентификации к LDAP-серверу. Готовые возможности аддона JMiX LDAP мне не подходят, поэтому я пишу свою логику.

Что мне нужно:
Аутентификация должна проходить через стандартный экран LoginView в Vaadin Flow, но этого не получается.

Что я уже сделал:

  1. Создал своего провайдера, имплементировав AuthenticationProvider.

  2. Создал конфигурацию безопасности, унаследованную от FlowuiVaadinWebSecurity.

  3. В методе configure(HttpSecurity http) добавил своего провайдера.

Результат:
Ничего не происходит, просто падает ошибка BadCredentialsException.

Буду благодарен за любую подсказку. По запросу могу предоставить фрагменты кода.

Спасибо.

Добрый день, Егор!

Похоже, проблема может быть в том, куда именно подключается ваш AuthenticationProvider.

Стандартный LoginView в Jmix Flow UI — это не обычный Spring Security form-login. При нажатии на кнопку входа он использует LoginViewSupport.authenticate(…), а дальше аутентификация проходит через AuthenticationManager с UsernamePasswordAuthenticationToken.

Поэтому я бы в первую очередь проверил две вещи.

  1. Провайдер должен поддерживать UsernamePasswordAuthenticationToken:

    @Override
    public boolean supports(Class<?> authentication) {
    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

  2. Если провайдер добавлен только в HttpSecurity, например так:

    http.authenticationProvider(myProvider);

то он может не попасть в тот AuthenticationManager, который используется LoginViewSupport.

Для LoginView лучше подключать провайдер в общий AuthenticationManager Jmix. Например, можно зарегистрировать свой AddonAuthenticationManagerSupplier и добавить туда ваш LDAP-провайдер вместе со стандартными провайдерами Jmix:

@Configuration
public class MyAuthenticationConfiguration {

    @Bean
    @Order(100)
    public AddonAuthenticationManagerSupplier myAuthenticationManagerSupplier(
            StandardAuthenticationProvidersProducer providersProducer,
            ApplicationEventPublisher publisher,
            MyLdapAuthenticationProvider myLdapAuthenticationProvider) {

        return () -> {
            List<AuthenticationProvider> providers =
                    new ArrayList<>(providersProducer.getStandardProviders());

            providers.add(0, myLdapAuthenticationProvider);

            ProviderManager providerManager = new ProviderManager(providers);
            providerManager.setAuthenticationEventPublisher(
                    new DefaultAuthenticationEventPublisher(publisher)
            );

            return providerManager;
        };
    }
}

Также проверьте, что в вашей security configuration, унаследованной от FlowuiVaadinWebSecurity, вызывается стандартная конфигурация Jmix:

@Override
protected void configure(HttpSecurity http) throws Exception {
    super.configure(http);
}

Ещё важный момент: после успешной проверки пользователя в LDAP провайдер должен вернуть уже аутентифицированный Authentication. При этом principal должен быть пользователем Jmix / UserDetails, у которого есть нужные роли для входа в UI.

Например:

return new UsernamePasswordAuthenticationToken(
        userDetails,
        null,
        userDetails.getAuthorities()
);

То есть обычно схема такая: LDAP используется для проверки логина и пароля, а затем пользователь загружается или синхронизируется в Jmix, после чего возвращается Authentication с authorities.

Если после этого ваш AuthenticationProvider всё равно не вызывается, приложите, пожалуйста, фрагменты кода:

  • ваш AuthenticationProvider;
  • security configuration;
  • LoginView, если он был изменён.

Тогда будет проще понять, на каком этапе теряется вызов.

С уважением,
Дмитрий