«1. Обзор

В Spring Security 4 можно было хранить пароли в виде обычного текста, используя аутентификацию в памяти.

Серьезный пересмотр процесса управления паролями в версии 5 представил более безопасный механизм по умолчанию для кодирования и декодирования паролей. Это означает, что если ваше приложение Spring хранит пароли в виде простого текста, обновление до Spring Security 5 может вызвать проблемы.

В этом коротком уроке мы опишем одну из этих потенциальных проблем и продемонстрируем решение.

2. Spring Security 4

Мы начнем с демонстрации стандартной конфигурации безопасности, обеспечивающей простую аутентификацию в памяти (действительно для Spring 4):

@Configuration
public class InMemoryAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password("secret")
          .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/private/**")
          .authenticated()
          .antMatchers("/public/**")
          .permitAll()
          .and()
          .httpBasic();
    }
}

Эта конфигурация определяет аутентификацию для всех /private/ сопоставленные методы и публичный доступ ко всему в /public/.

Если мы используем ту же конфигурацию в Spring Security 5, мы получим следующую ошибку:

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

Ошибка говорит нам о том, что данный пароль не может быть декодирован, поскольку для нашего in -аутентификация памяти.

3. Spring Security 5

Мы можем исправить эту ошибку, определив DelegatingPasswordEncoder с классом PasswordEncoderFactories.

Мы используем этот кодировщик для настройки нашего пользователя с помощью AuthenticationManagerBuilder:

@Configuration
public class InMemoryAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password(encoder.encode("secret"))
          .roles("USER");
    }
}

Теперь, с этой конфигурацией, мы сохраняем наш пароль в памяти с помощью BCrypt в следующем формате:

{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS

Хотя мы можем определить собственный набор кодировщиков паролей, рекомендуется придерживаться кодировщиков по умолчанию, предоставленных в PasswordEncoderFactories.

3.2. NoOpPasswordEncoder

Если по какой-либо причине мы не хотим кодировать настроенный пароль, мы можем использовать NoOpPasswordEncoder.

Для этого мы просто добавляем перед фразой-паролем, которую мы предоставляем методу password(), идентификатор {noop}:

@Configuration
public class InMemoryNoOpAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password("{noop}secret")
          .roles("USER");
    }
}

Таким образом, Spring Security будет использовать NoOpPasswordEncoder под капотом при сравнении пароля предоставленный пользователем с тем, который мы настроили выше.

Обратите внимание, однако, что мы никогда не должны использовать этот подход в рабочем приложении! Как говорится в официальной документации, NoOpPasswordEncoder устарел, чтобы указать, что это устаревшая реализация, и ее использование считается небезопасным.

3.3. Миграция существующих паролей

Мы можем обновить существующие пароли до рекомендуемых стандартов Spring Security 5 следующим образом:

    Обновление сохраненных паролей в виде простого текста с закодированным значением:
String encoded = new BCryptPasswordEncoder().encode(plainTextPassword);
    Добавление префикса к хэшированным сохраненным паролям с их известным идентификатором кодировщика: ~ ~~
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
    Запрос пользователей на обновление своих паролей, когда механизм кодирования для сохраненных паролей неизвестен

4. Заключение

В этом кратком примере мы обновили действующую конфигурацию аутентификации Spring 4 в памяти до Spring 5, используя новый механизм хранения паролей.

Как всегда, вы можете найти исходный код в проекте GitHub.