我有一个在 Tomcat 中运行的 java 应用程序。我在端口 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
),当客户端在建立安全 tls 隧道后通过“wss://.....”连接时,它会被调用,调用 @OnOpen
方法并且它有 javax.websocket.Session 对象。所以 http(s) 升级到 ws 是有效的。
我的问题:执行 TLS 握手后(在我的情况下由 WSS 触发:ws over https),我需要提取客户端证书(X509)信息(主题/颁发者等..)并使其可用在@OnOpen方法中。我正在寻找一些拦截器或其他方式来访问和提取证书数据并使其在升级到 ws 完成后可用。有没有办法从 HttpServletRequest
Web 套接字处理方法访问
@OnOpen
?感谢您的帮助。第1步:点击modifyHandshake(...)方法并获取
ServletRequest
对象,
HttpSession
不会完成这项工作。学分请参阅这个 StackOverflow 答案。
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 以使用上面的配置器,并从
Session
对象读取任何参数(您必须事先在修改Handshake() 方法中添加这些参数)。
@ServerEndpoint(
value = "/some/endpoint/here",
configurator = InjectAttributesIntoWebSocketConfigurator.class
)
第三步:完成:)。现在,WS 端点具有客户端证书,通过该证书建立了 TLS(在我的例子中为 2 路 TLS)底层 HTTPS 连接。