有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在使用MTL和WSS时提取客户端证书信息

我有一个java应用程序在Tomcat中运行。我在8443端口上添加了https侦听器,如下所述:

https://docs.spring.io/spring-boot/docs/2.2.x/reference/pdf/spring-boot-reference.pdf(9.3.13.使用Tomcat启用多个连接器)

此外,我还配置了侦听器,让客户机提供证书(双向TLS/双向TLS),并拥有一个包含可信条目的信任库。所有这些都有效,我可以在日志中看到整个TLS握手,以及提供的客户端证书

我有一个WebSocket服务器端点(@javax.websocket.server.ServerEndpoint),当客户机通过“”连接时,它确实会被调用wss://.....“在安全tls隧道建立之后,会调用@OnOpen方法,它有javax.websocket.Session对象。因此,http(s)升级到ws是可行的

我的问题:在执行TLS握手后(在我的情况下由WSS:ws over https触发),我需要提取客户端证书(X509)信息(主题/颁发者等)并在@OnOpen方法中提供。我正在搜索一些拦截器或其他方法来访问和提取证书数据,并在升级到ws后使其可用。有没有办法通过@OnOpenwebsocket处理方法访问HttpServletRequest?谢谢你的帮助


共 (1) 个答案

  1. # 1 楼答案

    经过进一步研究,我终于做到了

    第一步:点击修改握手(…)方法并获取ServletRequest对象,HttpSession将不执行此任务。学分归this StackOverflow answer

    package example.com;
    
    import java.lang.reflect.Field;
    import java.security.cert.X509Certificate;
    import javax.security.auth.x500.X500Principal;
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpSession;
    import javax.websocket.HandshakeResponse;
    import javax.websocket.server.HandshakeRequest;
    import javax.websocket.server.ServerEndpointConfig;    
    
    public class InjectAttributesIntoWebSocketConfigurator extends ServerEndpointConfig.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");
        // certificates[0] is client certificate
        // do null/error/empty array handling here
        config.getUserProperties().put("clientcert", certificates[0]);
      }
    
      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;
      }
    }
    

    第2步:将WS配置为使用上面的configurator,并从Session对象中读取任何参数(必须在modifyHandshake()metod中添加这些参数)

    @ServerEndpoint(
            value = "/some/endpoint/here",
            configurator = InjectAttributesIntoWebSocketConfigurator.class
    )
    

    第3步:完成:)。现在,WS-endpoint拥有客户机证书,用来建立底层HTTPS连接的TLS(在我的例子中是双向TLS)