Как обойти процесс аутентификации Ldap при доступе к базе данных в памяти

Я разработал страницу входа, где пользователь может быть пользователем из активного каталога (LDAP) или локальным пользователем из файловой базы данных H2 или пользователем из файла конфигурации, учетные данные которого уже сохранены, например, имя пользователя - admin, пароль - admin.

В файле конфигурации приведены параметры для включения или отключения LDAP, аутентификации в памяти и базе данных H2.

Предположим, что все 3 типа аутентификации включены и локальный пользователь из базы данных H2 входит в систему, поэтому, согласно логике, поскольку все 3 типа аутентификации включены, проверка выполняется во всех 3 базах данных, т.е. память и базу данных H2, если пользователь существует или нет, чего следует избегать.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private static final Logger _LOG = LoggerFactory.getLogger(SecurityConfig.class);

private ActiveDirectoryLdapAuthenticationProvider provider;

@Autowired
private DataSource dataSource;

@Autowired
private PasswordEncoder bCryptPasswordEncoder;

@Value("${ldap.auth.enabled}")
private boolean ldapAuthEnabled;

@Value("${database.auth.enabled}")
private boolean databaseAuthEnabled;

@Value("${inMemory.auth.enabled}")
private boolean imMemAuthEnabled;

@Value("${userrole.admin.username}")
private String adminUsername;

@Value("${userrole.admin.password}")
private String adminPassword;

@Value("${ldap.domain}")
private String ldapDomain;

@Value("${ldap.url}")
private String ldapUrl;

@PostConstruct
public void configValuesForApplication() {
    _LOG.info("Ldap Authentication {}", ldapAuthEnabled);
    _LOG.info("In Memory  Authentication {} ", imMemAuthEnabled);
    _LOG.info("Ldap Authentication {}", ldapAuthEnabled);
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http
            .authorizeRequests()
            .antMatchers(
                    "/", "/reg",
                    "/js*//**//**",
                    "/css*//**//**",
                    "/img*//**//**",
                    "/webjars*//**//**").permitAll()
            .antMatchers("/user*//**//**").hasRole("USER")
            .antMatchers("/admin", "/h2_console/**").hasRole("ADMIN")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/index")
            .permitAll()
            .and()
            .logout()
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .logoutSuccessUrl("/login?logout")
            .permitAll()
            .and()
            .exceptionHandling()
            .accessDeniedHandler(accessDeniedHandler);
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    if (imMemAuthEnabled) {
        auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER")
                .and()
                .withUser(adminUsername).password(adminPassword).roles("ADMIN");
    }
    if (databaseAuthEnabled) {
        auth.
                jdbcAuthentication()
                .authoritiesByUsernameQuery("select username, role FROM USER where username=?")
                .usersByUsernameQuery("select username,password, 1 FROM USER where username=?")
                .dataSource(dataSource)
                .passwordEncoder(bCryptPasswordEncoder);
    }
    if (ldapAuthEnabled) {
        provider = new ActiveDirectoryLdapAuthenticationProvider(ldapDomain, ldapUrl);
        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);
        auth.authenticationProvider(provider);
    }
  }
}

Файл login.properties выглядит следующим образом:

ldap.auth.enabled=true
inMemory.auth.enabled=true
database.auth.enabled=true

userrole.admin.username=admin
userrole.admin.password=admin
userrole.user.username=user
userrole.user.password=user

ldap.domain=foo.com
ldap.url=ldap://abcdef12.foo.com.:450/

spring.h2.console.enabled=true
spring.h2.console.path=/h2_console
spring.datasource.url=jdbc:h2:file:~/h2/vehicledb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

Вопрос в том, как избежать проверки в LDAP и базе данных в памяти, если пользователь из базы данных H2 входит в систему и наоборот?

0
0
1 477
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете написать свой собственный поставщик безопасности

Пример доступен здесь:

https://www.baeldung.com/spring-security-multiple-auth-providers

«Если вы зарегистрируете несколько поставщиков аутентификации, он будет проверять только первый в списке». - это неверно в Spring Security v5. Вы можете видеть, что ProviderManager#authenticate выполняет итерацию по всем AuthenticationProviders, и весь процесс аутентификации завершается успешно, если аутентификация в любом провайдере завершается успешно.

Krzysztof Skrzynecki 24.07.2019 10:32

Тогда это новое для весны 5, но, как говорится в вопросе, он хочет полностью игнорировать определенных провайдеров и не хочет перебирать их всех. Это все еще лучшее решение.

Toerktumlare 24.07.2019 10:37

Это моя точка зрения - ProviderManager выполняет итерацию по всем AuthenticationProviders и останавливается, как только любой из них завершается успешно. Поэтому я бы перефразировал «он будет проверять только первый в списке» на «он будет повторять и проверять один за другим и останавливаться, как только любой из них добьется успеха» или что-то в этом роде.

Krzysztof Skrzynecki 24.07.2019 11:13

если вы посмотрите на мой пост, я уже отредактировал ответ, это старый ответ на старый вопрос. Зачем воплощать эти вещи в жизнь?

Toerktumlare 24.07.2019 11:59

Успокойтесь, StackOverflow не отображал ваше редактирование, когда я отвечал. Искал решение своей проблемы и случайно зашел сюда. Нашел проблему, указал и все - я всегда ссылался на первую версию вашего ответа, потому что она вводила в заблуждение, поэтому это была единственная причина, по которой я оставил комментарий - чтобы улучшить ваш пост, поскольку создатель StackOverflow намеревался использовать комментарии - «Используйте комментарии, чтобы запросить дополнительную информацию или уточнить вопрос или ответ».

Krzysztof Skrzynecki 24.07.2019 12:12

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