Spring REST Service Certificate auth

Я написал контроллер Spring. Это получает запросы от клиентов. Это просто стиль REST.

Это очень хорошо. Но мне нужна аутентификация сертификата. Только клиенты должны иметь доступ к сервису rest (spring controller), у которого есть клиентские сертификаты с ключом (другими словами, клиент должен иметь хранилище ключей с ключом).

Как настроить эту безопасность на spring? Не могли бы вы привести мне пример или ссылку, где это написано?

Спасибо

Ответ 1

То, что вы ищете, называется Взаимная аутентификация.

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

Для Spring безопасности я бы рекомендовал изучить X.509 Authentication. Этот тип аутентификации довольно прост в использовании и расширяется по мере необходимости.

ИЗМЕНИТЬ

Итак, вот несколько ссылок, которые показывают примеры того, что вы спрашиваете:

http://whiteycode.blogspot.com/2012/04/part-3-x509-authentication-with-spring.html

Предупреждение о формате PDF

http://www.promixis.com/pdfs/SpringSecurityAndX509ClientCertificates.pdf

Этот пример действительно хорош в объяснении того, как настроить сертификаты и создать собственный личный центр сертификации (Certificate Authority). Предупреждение: способ показать сертификат клиента - это просто A WAY, а не способ. Ваш клиент (веб-браузер IE или клиент java-клиента httpclient) должен определить, каким образом создать сертификат клиента. Java любит использовать свое хранилище java, и браузеры, как правило, похожи на стиль p12 в сертификатах.

Заключительный совет/предупреждение... Я не знаю вашего уровня знаний с сертификатами, но... Взаимная аутентификация - это все о том, кто кому доверяет. Ответственность severs заключается в том, что вам нужно, чтобы вы аутентифицировали себя с сертификатом, и вот список поставщиков сертификатов, которым я доверяю. Тогда клиенты должны ответить сертификатом, подписанным одним из этих доверенных поставщиков сертификатов. Ответственность за приложения теперь сказать, доверяю ли я этому человеку на основе их имени внутри сертификата? Если и когда все начинает идти не так, подумайте о том, кто и чем не доверяет кому.

Один отличный инструмент использует -Djavax.net.debug = ssl для вашего приложения. Он покажет все рукопожатие ssl и то, что запрашивается, и каковы конкретные ответы. Этот параметр немного подробный, но приятно иметь при необходимости.

EDIT X 2

Вот как включить взаимную аутентификацию на Tomcat 7.

В вашем конфигурационном файле server.xml для SSL-коннектора вы увидите примерно следующее:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           clientAuth="want" sslProtocol="TLS"
           keystoreFile="C:\Java\Certs\localhost.jks"
           keystorePass="changeit"
           URIEncoding="UTF-8" />

Важным значением, которое следует отметить, является значение clientAuth.

Настройка clientAuth на "хочет" указывает клиенту на отправку подписанного клиентского сертификата ssl из списка сертификатов, которым доверяет сервер, если он у вас есть. Если нет, сделайте свой запрос как обычно.

Настройка clientAuth на "true" сообщает клиенту, что им нужно отправить подписанный клиентский сертификат ssl из списка сертификатов, которым доверяет сервер. Если у вас нет сертификата, подписанного списком сертификатов, которым доверяет сервер, клиенту НЕ разрешено делать запрос.

Список сертификатов, которые доверяет сервер, поступает из доверительного хранилища java по умолчанию или может быть установлен с помощью опции -Djavax.net.ssl.trustStore="C:\Java\Certs\jssecacerts1" VM.

Как правило, при наличии специального сертификата CA, которому вы доверяете, которого нет в доверенном хранилище Java по умолчанию, копия по умолчанию используется для копирования, новый сертификат ЦС импортируется в скопированное доверительное хранилище, а затем используется с указанным выше параметром VM.

Внимание

Очень важно НЕ менять сервер доверия по умолчанию на месте. Если вы это сделаете, все приложения Java по умолчанию на этом компьютере будут использовать новый обновленный магазин доверия. Не всегда то, что хотят люди, и может привести к угрозам безопасности.

Ответ 2

Я создал проект на 100% понятный пример со всем, что нужно для установки приложения Spring Boot с конечной точкой REST, защищенной сертификатом клиента, и тестовой программой с RestTemplate, которая настроена на использование сертификата клиента для связи с защищенный сервер: https://github.com/jonashackt/spring-boot-rest-clientcertificate

Он также содержит все шаги, необходимые для создания файлов .key, .crt и .jks. Просто отрегулируйте шаги соответственно, если вы не хотите использовать самозаверяющий сертификат.

RestTemplate настроен следующим образом:

package de.jonashackt.restexamples;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;

@Configuration
public class RestClientCertTestConfiguration {

    private String allPassword = "allpassword";

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
                .loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
                .build();

        HttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        return builder
                .requestFactory(new HttpComponentsClientHttpRequestFactory(client))
                .build();
    }
}

Затем вы можете использовать его так же, как вы использовали с аннотацией @Autowired внутри вашего Test.class.