Accessing HttpServletRequest properties within a W

2020-02-13 05:29发布

问题:

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?

回答1:

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;
        }
    
    }