Как на сервере Jetty получить сертификат клиента, используемый, когда требуется проверка подлинности клиента?

Настроить встроенный сервер Jetty, запрашивающий аутентификацию клиента, очень просто: достаточно добавить оператор SslContextFactory.setNeedClientAuth (true); в контекст ssl при настройке сервера. Любой клиент, имеющий сертификат в хранилище доверенных сертификатов сервера, сможет установить TLS-соединение с сервером.

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


person Brian Reinhold    schedule 18.11.2013    source источник


Ответы (2)


Обновлено в августе 2019 г .: для Jetty 9.4.20.v20190813.

Сертификаты добавляются в Запрос объекты (например, HttpServletRequest ) с помощью HttpConfiguration Настройщик .

В частности, SecureRequestCustomizer .

Ваш код для использования этого будет следующим (прокрутите вниз) ...

Server server = new Server();

// === HTTP Configuration ===
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(8443);
http_config.setOutputBufferSize(32768);
http_config.setRequestHeaderSize(8192);
http_config.setResponseHeaderSize(8192);
http_config.setSendServerVersion(true);
http_config.setSendDateHeader(false);

// === Add HTTP Connector ===
ServerConnector http = new ServerConnector(server,
    new HttpConnectionFactory(http_config));
http.setPort(8080);
http.setIdleTimeout(30000);
server.addConnector(http);

// === Configure SSL KeyStore, TrustStore, and Ciphers ===
SslContextFactory sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath("/path/to/keystore");
sslContextFactory.setKeyStorePassword("changeme");
sslContextFactory.setKeyManagerPassword("changeme");
sslContextFactory.setTrustStorePath("/path/to/truststore");
sslContextFactory.setTrustStorePassword("changeme");
// OPTIONAL - for client certificate auth (both are not needed)
// sslContextFactory.getWantClientAuth(true)
// sslContextFactory.setNeedClientAuth(true)

// === SSL HTTP Configuration ===
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer()); // <-- HERE

// == Add SSL Connector ===
ServerConnector sslConnector = new ServerConnector(server,
    new SslConnectionFactory(sslContextFactory,"http/1.1"),
    new HttpConnectionFactory(https_config));
sslConnector.setPort(8443);
server.addConnector(sslConnector);

С помощью этого SecureRequestCustomizer вы можете получить доступ к различным частям SSL-соединения из вызовов HttpServletRequest.getAttribute(String), используя следующие имена атрибутов.

javax.servlet.request.X509Certificate

массив java.security.cert.X509Certificate []

javax.servlet.request.cipher_suite

Строковое имя набора шифров. (то же, что и то, что возвращается из _ 6_)

javax.servlet.request.key_size

Целое число используемой длины ключа

javax.servlet.request.ssl_session_id

Строковое представление (шестнадцатеричное) активного идентификатора сеанса SSL

person Joakim Erdfelt    schedule 18.11.2013
comment
Возвращает ли javax.servlet.request.X509Certificate список сертификатов X509 в хранилище доверенных сертификатов или цепочку сертификатов для этого соединения? Если первое, как мне найти сертификат, используемый этим подключением? Если второе, то как указана сеть? Является ли элемент [0] сертификатом в хранилище доверенных сертификатов, а оставшийся элемент представляет собой цепочку к ЦС? - person Brian Reinhold; 19.11.2013
comment
Это сработало с небольшой оговоркой. Импорт X509Certificate должен быть java.security.cert.X509Certificate, а НЕ javax.security.cert.X509Certificate, даже если в атрибуте передается строка javax. Если я импортирую сертификат javax, я получаю исключение приведения. Также кажется (из комментария ниже), что первый сертификат в списке является сертификатом для текущего сеанса. На данный момент это сложно сказать, так как в моем хранилище доверенных сертификатов только один сертификат. - person Brian Reinhold; 19.11.2013
comment
"javax.servlet.*" - это просто имя атрибута для чего-то, что диктуется спецификацией сервлета, это имя не имеет корреляции с классом, который вы должны преобразовать / использовать. - person Joakim Erdfelt; 19.11.2013
comment
@JoakimErdfelt, как использовать HttpServletRequest? Любой указатель был бы полезен. - person devd; 01.02.2021

Есть стандартное свойство запроса сервлета: javax.servlet.request.X509Certificate

Он возвращает массив X509Certificates.

Мы используем это, чтобы получить имя и найти DN в сертификате:

x509Cert[0].getSubjectX500Principal().getName()
person Will Hartung    schedule 18.11.2013
comment
Это помогло мне использовать приведенный выше ответ, чтобы предположить, что такое возвращенный список сертификатов. - person Brian Reinhold; 19.11.2013