最近产品中需要在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连接.
整个配置过程结束,成功连接.