Accessing HttpServletRequest properties within a WebSocket @ServerEndpoint
Asked Answered
S

1

3

I need to access the HttpServletRequest properties to get the javax.servlet.request.X509Certificate which contains the X509Certificate array of certificates for TLS requests.

From a JAX-RS ContainerRequestFilter I can easily extract this from the ContainerRequestContext.getProperty(String property) method, but I can't find a way to get it from the WebSocket Session nor the HandshakeRequest, from which I can access the HttpSession instance but not the HttpServletRequest one.

Note: this is not a duplicate of Accessing HttpSession from HttpServletRequest in a Web Socket @ServerEndpoint since I need accesso to the HttpServletRequest (or equivalent to extract the TLS certificates), not HttpSession.

Since WebSocket is a superset of HTTP, I guess it should be possibile and hope the Java team had thought of a way to access the servlet properties, but I really couldn't find one. Anyone knows if this is possible at all?

Shumpert answered 23/3, 2016 at 17:2 Comment(0)
P
6

Without hacking:

  1. Create servlet filter on URL pattern matching websocket handshake request.
  2. In filter, get request attribute of interest and put it in session before continuing chain.
  3. Finally get it from the session which is in turn just available via handshake request.

With hacking:

  1. Use reflection to find ServletRequest field in handshake request instance.
  2. Get its javax.servlet.request.X509Certificate attribute.

    In other words:

    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;
        }
    
    }
    
Ptolemaist answered 23/3, 2016 at 19:49 Comment(7)
Thank you @BalusC, this could work. I'd rather like not to use HttpSession, if possibile. I wonder if WebSocket actually use HttpServeltRequest and just doesn't expose it in its API or doesn't use it at all…Shumpert
It's implementation specific. That's exactly why "Without hacking" :)Ptolemaist
You're right! I'm on WildFly/Undertow btw. If the WebSocket JSR exposes javax.servlet.http.HttpSession in the HandshakeRequest API, I really don't see why it doesn't expose javax.servlet.http.HttpServletRequestShumpert
WS handshake is not per definition triggered by a HTTP servlet request. So it cannot be exposed in API (otherwise, extreme tight coupling and unreusable API). Basically, it should have exposed kind of getAttribute()/getAttributeMap() orso.Ptolemaist
Right again. I mean just that since WebSocket are accessibile via TLS (wss://) the API should expose a path to get info about the secure connection, such as the client X509 certificates (as in HttpServletRequest, i.e. X509Certificate[] certs = (X509Certificate[]) request.getProperty("javax.servlet.request.X509Certificate")).Shumpert
Post an issue at WS spec guys requesting a new method which accomplishes at least that task: java.net/jira/browse/WEBSOCKET_SPECPtolemaist
It'd been easier if you post the requirement in Servlet API perspective, not in JAX-RS API perspective as WebSockets does not use JAX-RS API under the covers, but just Servlet API. I.e. HttpServletRequest.getAttribute(...).Ptolemaist

© 2022 - 2024 — McMap. All rights reserved.