Реализация 2 способа SSL с использованием spring boot

Я создаю некоторые веб-службы restful и использую Spring-Boot для создания встроенного контейнера tomcat.

одним из требований является то, что это реализует 2 способа SSL. Я смотрел на объект HttpSecurity и могу заставить его запускать веб-службы только по каналу SSL, используя это: -

@Override
protected void configure(HttpSecurity http) throws Exception {

    System.out.println("CONFIGURED");

    http
        // ...
        .requiresChannel()
            .anyRequest().requiresSecure();
}

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

У меня только базовые знания SSL, поэтому даже общий указатель в правильном направлении будет оценен.

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

2 ответов


вы можете настроить clientAuth=want см. Справочник По Конфигурации Apache Tomcat 8:

значение true Если вы хотите, чтобы стек SSL требовал от клиента действительной цепочки сертификатов перед принятием соединения. Значение want Если вы хотите, чтобы стек SSL запрашивал сертификат клиента, но не терпел неудачу, если он не представлен. А false значение (которое является значением по умолчанию) не требует цепочки сертификатов, если клиент не запрашивает ресурс, защищенный ограничение безопасности, использующее CLIENT-CERT проверка подлинности.

а затем прочитайте сертификат клиента с Spring Security-X. 509 Аутентификация:

вы также можете использовать SSL с "взаимной аутентификацией"; сервер затем запросит действительный сертификат от клиента как часть SSL-рукопожатия. Сервер будет проверять подлинность клиента, проверяя, что его сертификат подписан приемлемым органом. Если действительный сертификат при условии, что он может быть получен через API сервлета в приложении. Модуль Spring Security X. 509 извлекает сертификат с помощью фильтра. Он сопоставляет сертификат пользователю приложения и загружает набор предоставленных полномочий этого пользователя для использования со стандартной инфраструктурой безопасности Spring.

и

clientAuth также можно установить в want Если вы все еще хотите, чтобы SSL-соединения были успешными, даже если клиент не предоставляет сертификат. Клиенты, которые не предоставляют сертификат, не смогут получить доступ к объектам, защищенным Spring Security, если вы не используете механизм проверки подлинности, отличный от X. 509, например проверку подлинности формы.


я столкнулся с подобной проблемой и подумал, что поделюсь решением, с которым пришел.

во-первых, вам нужно понять, что аутентификация SSL-сертификата будет обрабатываться на стороне вашего веб-сервера (cfr. объяснение дура с настройкой "clientAuth=want"). Затем ваше веб-приложение должно быть настроено для обработки предоставленного (и разрешенного) сертификата, сопоставления его пользователю и т. д.

небольшая разница у меня с тобой, что я упаковки моей весна загрузки приложение в военный архив, который затем развертывается на существующем сервере приложений Tomcat.

мой котяра по.файл конфигурации xml определяет соединитель HTTPS следующим образом:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
    keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks"
    keystorePass=“some-complex-password“
    clientAuth="want" sslProtocol="TLS"
    truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks"
    truststorePass=“some-other-complex-password” />

небольшой комментарий, чтобы избежать путаницы: keystoreFile содержит пару сертификат / закрытый ключ, используемый для SSL (только), в то время как truststoreFile содержит разрешенные сертификаты CA для аутентификации SSL клиента (обратите внимание, что вы также можете добавить сертификаты клиента непосредственно в это trust-store).

если вы используете встроенный контейнер tomcat с приложением spring boot, вы должны иметь возможность настроить эти параметры в файле свойств вашего приложения, используя следующий ключ/значения свойств:

server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks
server.ssl.key-store-password=some-complex-password
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks
server.ssl.trust-store-password=some-other-complex-password
server.ssl.client-auth=want

затем в моем веб-приложении я объявляю определенную конфигурацию SSL следующим образом:

@Configuration
@EnableWebSecurity
//In order to use @PreAuthorise() annotations later on...
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter {

    @Value("${allowed.user}")
    private String ALLOWED_USER;

    @Value("${server.ssl.client.regex}")
    private String CN_REGEX;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure (final HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests()
                .antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication...
            .and()
                .x509() //... and that x509 authentication is enabled
                    .subjectPrincipalRegex(CN_REGEX)
                    .userDetailsService(userDetailsService);
    }

    @Autowired
    //Simplified case, where the application has only one user...
    public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
        //... whose username is defined in the application's properties.
        auth
            .inMemoryAuthentication()
                .withUser(ALLOWED_USER).password("").roles("SSL_USER");
    }

}

затем мне нужно объявить компонент UserDetailsService (например, в основном классе моего приложения):

@Value("${allowed.user}")
private String ALLOWED_USER;

@Bean
public UserDetailsService userDetailsService () {

    return new UserDetailsService() {

        @Override
        public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
            if (username.equals(ALLOWED_USER)) {
                final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER"));
                return user;
            }
            return null;
        }
    };
}

и это все! Я затем можно добавить аннотации @PreAuthorize("hasRole(‘ROLE_SSL_USER’)") к методам, которые я хочу защитить.

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

  1. пользователь предоставляет сертификат SSL ;
  2. Tomcat проверяет свой trust-store;
  3. пользовательский WebSecurityConfigurerAdapter извлекает "имя пользователя" из CN сертификата;
  4. приложение аутентифицирует пользователя, связанного с полученные имя пользователя ;
  5. на уровне метода, если аннотировать с @PreAuthorize ("hasRole ('SSL_USER')"), приложение будет проверять, имеет ли пользователь требуемую роль.