實現 tomcat 熱加載證書

以前一篇中說了如何 創建 https 通訊的完整流程,其中涉及了java web容器 tomcat,關於它的配置是: java

<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啓動時一次性加載到內存中的。 web

大多數的場景這就夠了,可是若是 要構建一個 基於https、受信任證書的 權限驗證體系,像上邊的那樣 一次性加載 keyStore 就算 咱們從鍵庫中刪除某個證書,程序是沒辦法探知的。我急需一種熱加載 keyStore的技術。 apache

咱們修改對應的配置爲 瀏覽器

<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"/>

這裏 本身的私鑰鍵庫是不須要也是不能從新加載的,關鍵在與證書鍵庫,咱們建立了一個在自定義的類叫 tomcat

MyTrustManager 用來管理受信任證書,他須要實現接口 X509TrustManager 並提供一個無參的構造函數。 ide

而後將其打包成jar後,部署到tomcat的lib目錄(注意connector是在tomcat啓動時構建的,因此代碼不能放在你本身的web項目裏,由於當時tomcat尚未classLoad你的類呢)下邊是參考代碼 函數


public class MyTrustManager implements X509TrustManager {

    public MyTrustManager(){}

    @Override
    public 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();
    }

    @Override
    public 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();
        }
    }

    @Override
    public 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。 spa


綜上所述,你能夠實現一個經過添加信任證書的方式來對請求方進行控制的系統了。 .net

注意:https爲了性能在創建了SSL-SESSION以後容許再也不進行證書驗證,你在瀏覽器裏訪問作實驗須要關閉瀏覽器後從新訪問纔會看到keyStore更新生效,你也能夠經過代碼設法銷燬SSL-SESSION讓每次https請求都從新握手驗證。參考:http://blog.csdn.net/ibznphone/article/details/7846879

相關文章
相關標籤/搜索