Доступ к свойствам HttpServletRequest в WebSocket @ServerEndpoint

Мне нужно получить доступ к свойствам HttpServletRequest, чтобы получить javax.servlet.request.X509Certificate, который содержит массив X509Certificate сертификатов для запросов TLS.

Из JAX-RS ContainerRequestFilter я могу легко извлечь это из метода ContainerRequestContext.getProperty(String property), но я не могу найти способ получить его из WebSocket Session или HandshakeRequest, из которого я могу получить доступ к экземпляру HttpSession, но не к экземпляру HttpServletRequest.

Примечание. Это не дубликат Доступ к HttpSession из HttpServletRequest в веб-сокете @ServerEndpoint, поскольку мне нужен доступ к HttpServletRequest (или эквивалентному для извлечения сертификатов TLS), а не HttpSession.

Поскольку WebSocket является расширенным набором HTTP, я думаю, что это должно быть возможно, и надеюсь, что команда Java придумала способ доступа к свойствам сервлета, но я действительно не мог его найти. Кто-нибудь знает, возможно ли это вообще?


person Giovanni Lovato    schedule 23.03.2016    source источник


Ответы (1)


Без взлома:

  1. Создайте фильтр сервлета для шаблона URL, соответствующего запросу рукопожатия веб-сокета.
  2. В фильтре получите интересующий атрибут запроса и поместите его в сеанс перед продолжением цепочки.
  3. Наконец, получите его из сеанса, который, в свою очередь, доступен только через запрос рукопожатия.

Со взломом:

  1. Используйте отражение, чтобы найти поле ServletRequest в экземпляре запроса на рукопожатие.
  2. Получите его атрибут javax.servlet.request.X509Certificate.

    Другими словами:

    public class ServletAwareConfigurator extends Configurator {
    
        @Override
        public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
            ServletRequest servletRequest = getField(request, ServletRequest.class);
            X509Certificate[] certificates = (X509Certificate[]) servletRequest.getAttribute("javax.servlet.request.X509Certificate");
            // ...
        }
    
        private static <I, F> F getField(I instance, Class<F> fieldType) {
            try {
                for (Class<?> type = instance.getClass(); type != Object.class; type = type.getSuperclass()) {
                    for (Field field : type.getDeclaredFields()) {
                        if (fieldType.isAssignableFrom(field.getType())) {
                            field.setAccessible(true);
                            return (F) field.get(instance);
                        }
                    }
                }
            } catch (Exception e) {
                // Handle?
            }
    
            return null;
        }
    
    }
    
person BalusC    schedule 23.03.2016
comment
Спасибо @BalusC, это может сработать. Я бы предпочел не использовать HttpSession, если это возможно. Интересно, действительно ли WebSocket использует HttpServeltRequest и просто не раскрывает его в своем API или вообще не использует… - person Giovanni Lovato; 24.03.2016
comment
Это зависит от реализации. Именно поэтому Без взлома :) - person BalusC; 24.03.2016
comment
Ты прав! Я на WildFly/Undertow, кстати. Если WebSocket JSR предоставляет javax.servlet.http.HttpSession в API HandshakeRequest, я действительно не понимаю, почему он не предоставляет javax.servlet.http.HttpServletRequest - person Giovanni Lovato; 24.03.2016
comment
Рукопожатие WS не по определению инициируется запросом сервлета HTTP. Таким образом, он не может быть выставлен в API (в противном случае чрезвычайно тесная связь и непригодный для использования API). По сути, он должен был выставлять вид getAttribute()/getAttributeMap() или около того. - person BalusC; 24.03.2016
comment
Снова правильно. Я имею в виду только то, что, поскольку WebSocket доступен через TLS (wss://), API должен предоставить путь для получения информации о безопасном соединении, например сертификаты клиента X509 (как в HttpServletRequest, т.е. X509Certificate[] certs = (X509Certificate[]) request.getProperty("javax.servlet.request.X509Certificate")). - person Giovanni Lovato; 24.03.2016
comment
Опубликуйте вопрос у ребят из спецификации WS с просьбой о новом методе, который выполняет хотя бы эту задачу: java.net/jira/ просмотреть/WEBSOCKET_SPEC - person BalusC; 24.03.2016
comment
Было бы проще, если бы вы разместили требование в перспективе API сервлета, а не в перспективе API JAX-RS, поскольку WebSockets не использует API JAX-RS под прикрытием, а только API сервлета. т.е. HttpServletRequest.getAttribute(...). - person BalusC; 24.03.2016