实现 tomcat 热加载证书
原文地址:https://my.oschina.net/u/157514/blog/395238
之前一篇中說了如何 建立 https 通信的完整流程,其中涉及了java web容器 tomcat,關于它的配置是:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true"clientAuth="true" sslProtocol="TLS" keystoreFile="D:\ssl\server.keystore" keystorePass="123456" truststoreFile="D:\ssl\server.keystore" truststorePass="123456"/>
對應的keyStore(包括私鑰庫和受信任證書庫)是在tomcat啟動時一次性加載到內存中的。
大多數的場景這就夠了,但是如果 要構建一個 基于https、受信任證書的 權限驗證體系,像上邊的那樣 一次性加載 keyStore 就算 我們從鍵庫中刪除某個證書,程序是沒辦法探知的。我急需一種熱加載 keyStore的技術。
我們修改對應的配置為
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"maxThreads="150" scheme="https" secure="true"clientAuth="true" sslProtocol="TLS" keystoreFile="d:/ssl/server.keystore" keystorePass="123456" trustManagerClassName="MyTrustManager"/>
這里 自己的私鑰鍵庫是不需要也是不能重新加載的,關鍵在與證書鍵庫,我們創建了一個在自定義的類叫
MyTrustManager 用來管理受信任證書,他需要實現接口?X509TrustManager 并提供一個無參的構造函數。
然后將其打包成jar后,部署到tomcat的lib目錄(注意connector是在tomcat啟動時構建的,所以代碼不能放在你自己的web項目里,因為當時tomcat還沒有classLoad你的類呢)下邊是參考代碼
public class MyTrustManager implements X509TrustManager {public MyTrustManager(){}@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {System.out.println("check");if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException();KeyStore store=getKeyStore();boolean pass=false;try {for(X509Certificate certificate:x509Certificates){certificate.checkValidity();String theAlias = store.getCertificateAlias(certificate);if(theAlias!=null)pass=true;}} catch (KeyStoreException e) {e.printStackTrace();}System.out.println("pass "+pass);if(!pass)throw new CertificateException();}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException();for(X509Certificate certificate:x509Certificates){certificate.checkValidity();}}@Overridepublic X509Certificate[] getAcceptedIssuers() {ArrayList<X509Certificate> trusts=new ArrayList<X509Certificate>();try {KeyStore store=getKeyStore();Enumeration<String> alias = store.aliases();while (alias.hasMoreElements()){String name = alias.nextElement();if(store.isCertificateEntry(name)){X509Certificate trust = (X509Certificate) store.getCertificate(name);trusts.add(trust);}}} catch (Exception e) {e.printStackTrace();}X509Certificate[] trustsArr = trusts.toArray(new X509Certificate[0]);System.out.println("return trust array "+trustsArr.length);return trustsArr;}private KeyStore getKeyStore() throws CertificateException {try {KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());store.load(new FileInputStream("D:/ssl/server.keystore"),"123456".toCharArray());return store;} catch (Exception e) {e.printStackTrace();throw new CertificateException();}} }getAcceptedIssuers 返回server端的所有信任的證書,這樣client (比如瀏覽器)才知道應該挑選哪些它所擁有的證書來詢問你,證書必須是雙方都認識的。
checkClientTrusted ?是對client提交過來的證書進行驗證,certificate.checkValidity();驗證證書是否過期,store.getCertificateAlias(certificate)從自己的鍵庫中尋找對應的證書,不存在返回null,發現驗證不通過 就自己手動拋出一個異常CertificateException,這樣容器就知道如何處理了。
getKeyStore中是加載鍵庫,由于每次驗證時才加載鍵庫,所以就實現了熱加載。當然為了性能你可以把keyStore放到某個全局變量里,在需要的時候對其進行reload。
綜上所述,你可以實現一個通過添加信任證書的方式來對請求方進行控制的系統了。
注意:https為了性能在建立了SSL-SESSION之后允許不再進行證書驗證,你在瀏覽器里訪問做實驗需要關閉瀏覽器后重新訪問才會看到keyStore更新生效,你也可以通過代碼設法銷毀SSL-SESSION讓每次https請求都重新握手驗證。參考:http://blog.csdn.net/ibznphone/article/details/7846879
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的实现 tomcat 热加载证书的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HTML常遇问题
- 下一篇: Qomolangma实现篇(三):兼容层