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?

Community
  • 1
  • 1
Giovanni Lovato
  • 2,183
  • 2
  • 29
  • 53

1 Answers1

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;
        }
    
    }
    
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 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… – Giovanni Lovato Mar 24 '16 at 07:45
  • It's implementation specific. That's exactly why "Without hacking" :) – BalusC Mar 24 '16 at 08:17
  • 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.HttpServletRequest`… – Giovanni Lovato Mar 24 '16 at 08:31
  • 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. – BalusC Mar 24 '16 at 08:39
  • 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")`). – Giovanni Lovato Mar 24 '16 at 14:10
  • Post an issue at WS spec guys requesting a new method which accomplishes at least that task: https://java.net/jira/browse/WEBSOCKET_SPEC – BalusC Mar 24 '16 at 14:16
  • 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(...)`. – BalusC Mar 24 '16 at 15:35