最近产品中需要在RCP中通过SSL方式来访问Tomcat下的应用,查阅了一些资料经过调试,最终连接成功,整理过程如下

一.使用java的keytool来生成keystore和证书

1、生成服务器证书库


keytool -validity 365 -genkey -v -alias server -keyalg RSA -keystore D:\ssl\server.keystore -dname "CN=127.0.0.1,OU=disoft,O=disoft,L=ChaoYang,ST=Beijing,c=cn" -storepass 123456 -keypass 123456


2、生成客户端证书库


keytool -validity 365 -genkeypair -v -alias client -keyalg RSA -storetype PKCS12 -keystore D:\ssl\client.p12 -dname "CN=client,OU=disoft,O=disoft,L=ChaoYang,ST=Beijing,c=cn" -storepass 123456 -keypass 123456


3、从客户端证书库中导出客户端证书


keytool -export -v -alias client -keystore D:\ssl\client.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\ssl\client.cer


4、从服务器证书库中导出服务器证书


keytool -export -v -alias server -keystore D:\ssl\server.keystore -storepass 123456 -rfc -file D:\ssl\server.cer


5、生成客户端信任证书库(由服务端证书生成的证书库)


keytool -import -v -alias server -file D:\ssl\server.cer -keystore D:\ssl\client.truststore -storepass 123456


6、将客户端证书导入到服务器证书库(使得服务器信任客户端证书)


keytool -import -v -alias client -file D:\ssl\client.cer -keystore D:\ssl\server.keystore -storepass 123456

之后ssl文件夹下会有5个文件,分别是server.keystore,client.p12,client.cer,server.cer,client.truststore

注意:其中的server.keystore既是服务器的证书库,又作为服务器端对客户端的信任证书库.

步骤1中的CN最好使用IP地址,通过这个IP地址对支持SSL的server进行访问.

之后双击client.cer对客户端证书进行导入以支持浏览器的访问

用keytool生成的证书是私人的证书,并不是权威CA机构颁发的证书,但是并不影响开发。

二.配置Tomcat的SSL

Tomcat的server.xml文件需要进行相应的配置,默认这段是注释掉的,启用即可


上面的clientAuth="true"这样的设置是说明需要支持SSL双向认证.keystoreFile和keystorePass配置好自己server的keystore的路径和密码.

启动tomcat,通过 来访问

三.Eclipse RCP中通过SSL连接server

直接上代码

private static SSLContext getSSLContext() {        if (sslcontext == null) {            try {                String keystorePath = System.getProperty(TAC_SSL_SYSTEM_KEY);                String keyStorePass = System.getProperty(TAC_SSL_SYSTEM_PASS);                if (keystorePath == null) {                    // if user does not set the keystore path in the .ini,we need to look for the keystore file under                    // the root dir of product                    String userDir = System.getProperty("user.dir");                    File keystorePathFile = new File(userDir + "/" + TAC_SSL_KEYSTORE);                    keystorePath = keystorePathFile.getAbsolutePath();                }                if (keyStorePass == null) {                    // if user does not set the password in the .ini,we only can make it empty by                    // default,but not sure the ssl can connect                    keyStorePass = "";                }                File keystoreFile = new File(keystorePath);                if (!keystoreFile.canRead()) {                    throw new RuntimeException("Can't find or read the SSL Keystore file at: '" + keystoreFile.getAbsolutePath()                            + "'");                }                sslcontext = SSLContext.getInstance("SSL");                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");                TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");                KeyStore ks = KeyStore.getInstance("JKS");                KeyStore tks = KeyStore.getInstance("JKS");                ks.load(new FileInputStream(keystorePath), keyStorePass.toCharArray());                tks.load(new FileInputStream(keystorePath), keyStorePass.toCharArray());                kmf.init(ks, keyStorePass.toCharArray());                tmf.init(tks);                sslcontext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);            } catch (NoSuchAlgorithmException e) {                e.printStackTrace();            } catch (KeyManagementException e) {                e.printStackTrace();            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        return sslcontext;    }

上述代码是用来初始化SSL上下文,可以将生成的keystore(这里仍然是server.keystore)的路径和密码配置在RCP产品中的*.ini文件(相当于Eclipse中VM Argument的参数配置)里面,使用的时候用系统属性进行读取.

public static String getContent(String adminUrl, String urlString) throws PersistenceException {        StringBuffer buffer = new StringBuffer();        try {            URL url = new URL(adminUrl + urlString);            BufferedReader in = null;            if (adminUrl.startsWith("https://")) {                final SSLSocketFactory socketFactory = getSSLContext().getSocketFactory();                HttpsURLConnection httpsCon = (HttpsURLConnection) url.openConnection();                httpsCon.setSSLSocketFactory(socketFactory);                httpsCon.setHostnameVerifier(new HostnameVerifier() {                    @Override                    public boolean verify(String arg0, SSLSession arg1) {                        return true;                    }                });                httpsCon.connect();                in = new BufferedReader(new InputStreamReader(httpsCon.getInputStream()));            } else {                in = new BufferedReader(new InputStreamReader(url.openStream()));            }            String inputLine;            while ((inputLine = in.readLine()) != null) {                buffer.append(inputLine);            }            in.close();        } catch (Exception e) {            throw new PersistenceException("Unable to access to url : " + adminUrl);        }        return buffer.toString();    }

上述代码用java的HttpsURLConnection来建立SSL连接.

整个配置过程结束,成功连接.