java - WebSocket 服务器在 Open 上获取客户端证书

标签 java ssl websocket wildfly x509certificate

我有一个在 WildFly 10 上运行的简单 ServerEndpoint,它配置为具有相互 TLS 的 wss,因此需要客户端证书。我在连接到端点时没有任何问题,因此相互身份验证已正确完成,但我无法在 onOpen 方法中访问客户端证书。我尝试使用 getUserPrincipal() 来执行此操作,但总是得到 null

我需要获取客户端证书以进行授权。

import java.io.IOException;
import java.security.Principal;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value = "/test", configurator = GetHttpSessionConfigurator.class)
public class TestWebSocketEndPoint {

    private Session wsSession;
    private HttpSession httpSession;

    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        this.wsSession = session;
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        Principal userPrincipal = session.getUserPrincipal();
        System.out.println(session.getId() + " has opened a connection"); 
        try {
            session.getBasicRemote().sendText("Connection Established");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * When a user sends a message to the server, this method will intercept the message
     * and allow us to react to it. For now the message is read as a String.
     */
    @OnMessage
    public void onMessage(String message, Session session){
        System.out.println("Message from " + session.getId() + ": " + message);
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * The user closes the connection.
     * 
     * Note: you can't send messages to the client from this method
     */
    @OnClose
    public void onClose(Session session){
        System.out.println("Session " +session.getId()+" has ended");
    }
}

获取HttpSessionConfigurator:

import java.security.Principal;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig config, 
                                HandshakeRequest request, 
                                HandshakeResponse response)
    {
        HttpSession httpSession = (HttpSession)request.getHttpSession();
        Map<String, List<String>> map = request.getParameterMap();
        Principal principal = request.getUserPrincipal();
        config.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}

请求监听器:

import java.security.Principal;
import java.security.cert.X509Certificate;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class RequestListener implements ServletRequestListener {

    public void requestDestroyed(ServletRequestEvent sre) {
        // TODO Auto-generated method stub

    }

    public void requestInitialized(ServletRequestEvent sre) {
        ((HttpServletRequest) sre.getServletRequest()).getSession();
        Principal p = ((HttpServletRequest) sre.getServletRequest()).getUserPrincipal();

        boolean secure = ((HttpServletRequest) sre.getServletRequest()).isSecure();
        String authType = ((HttpServletRequest) sre.getServletRequest()).getAuthType();

        X509Certificate[] certs = (X509Certificate[]) ((HttpServletRequest) sre.getServletRequest()).getAttribute("javax.servlet.request.X509Certificate");
    }

}

websocket 客户端是一个使用 TooTallNate/java-websocket 并安全连接的独立应用程序:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Enumeration;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.java_websocket.WebSocketImpl;

public class TestClient {

    private static final Log log = LogFactory.getLog(TestClient.class);

    public static void main(String[] args) throws URISyntaxException {
        WebSocketImpl.DEBUG = true;

        WSRAClient wsRaClient = new WSRAClient(new URI("wss://localhost:8443/TestWebSocket-0.0.1-SNAPSHOT/test"));

        String keystoreFile = "keystore.p12";
        String keystorePassword = "keystore";

        String truststoreFile = "truststore.jks";
        String truststorePassword = "truststore";


        try {
            SSLContext ssl = SSLContext.getInstance("TLSv1.2");

            log.info("Configuring SSL keystore");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
            KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
            log.debug("Loading keystore");
            store.load(new FileInputStream(keystoreFile), keystorePassword.toCharArray());
            log.debug("Number of keystore certificates: " + store.size());
            Enumeration<String> enumeration = store.aliases();
            while(enumeration.hasMoreElements()) {
                String alias = enumeration.nextElement();
                log.debug("alias name: " + alias);
                Certificate certificate = store.getCertificate(alias);
                log.debug(certificate.toString());
            }
            kmf.init(store, keystorePassword.toCharArray());
            KeyManager[] keyManagers = new KeyManager[1];
            keyManagers = kmf.getKeyManagers();

            log.info("Configuring SSL truststore");
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
            log.debug("Loading truststore");
            truststore.load(new FileInputStream(truststoreFile), truststorePassword.toCharArray());
            log.debug("Number of truststore certificates: " + truststore.size());
            enumeration = truststore.aliases();
            while(enumeration.hasMoreElements()) {
                String alias = (String)enumeration.nextElement();
                log.debug("alias name: " + alias);
                Certificate certificate = truststore.getCertificate(alias);
                log.debug(certificate.toString());
            }
            tmf.init(truststore);
            TrustManager[] trustManagers = tmf.getTrustManagers();

            ssl.init(keyManagers, trustManagers, new SecureRandom());

            SSLSocketFactory factory = ssl.getSocketFactory();// (SSLSocketFactory) SSLSocketFactory.getDefault();

            wsRaClient.setSocket(factory.createSocket());

            wsRaClient.connectBlocking();

            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while ( true ) {
                String line = reader.readLine();
                if(line.equals("close")) {
                    wsRaClient.close();
                } else {
                    wsRaClient.send(line);
                }
            }

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (KeyStoreException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (CertificateException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (KeyManagementException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error(e);
            System.exit(0);
        }

    }

}

最佳答案

参见:Accessing HttpServletRequest properties within a WebSocket @ServerEndpoint

  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

关于java - WebSocket 服务器在 Open 上获取客户端证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45780224/

相关文章:

java - Mule ESB(Groovy 脚本): How would I check a value and add a new key value mapping to a java. util.LinkedList

java - 实现二分查找的问题

php Ratchet websocket SSL连接?

node.js - 你能从 Stud > HAProxy > nginx 获取 X-forwarded-for 吗?

perl - IO::Socket::SSL 似乎忽略了 SSL_VERIFY_NONE

php - 什么是长轮询、Websocket、服务器发送事件 (SSE) 和 Comet?

java - 无法使用jdbc以Windows身份验证模式连接到ms sql server 2005

java - Android:如何拥有 ArrayList<HashMap<String, String>> 类型的数组

node.js - React - 仅在 HTTPS 上发送 POST 请求时出现网络错误

java - GlassFish 连接到 SLL Web 服务