<style> .red { color: red; } </style> # 架設CAS Server and Client Tomcat SSL 設定 ###### tags: `CAS`, `Tomcat Server SSL Setting`, `keytool` ## 前言: 這篇算是在實作SSO時在設定Tomcat ssl時遇到一些問題及找到的相關資料,做個彙整。 此篇文章默認電腦系統已經安裝java環境,及設定好環境變數等等,關於java環境安裝不在此多描述。 其實一般在設定憑證,會向信任的第三方憑證公司(通常都要$$)發出簽署請求(CSR),之後第三方憑證公司會發中繼憑證給自己,再把中繼憑證設定在server上,但如果只是為了開發用途,為了省麻煩和省經費,選擇自己簽發信任憑證。 有一篇關於ssl的相關名詞解釋、概念以及一些相關流程,在學習時給予我很大的幫助,若跟我一樣一開始對ssl觀念不是很清楚,推薦優先服用這篇文: [[SSL 基礎]私有金鑰、CSR 、CRT 與 中繼憑證](https://haway.30cm.gg/ssl-key-csr-crt-pem/)[1] ## 大致流程: * 先自己簽發ssl所需要的證書 * 將憑證匯入到java sdk or java jre的cacert證書庫裡面 * 到Tomcat內部設定私鑰(或憑證)存放位置以及設定私鑰密碼 -------------------------------------------------- ## 產生私鑰及簽發ssl憑證 #### 1. 產生私鑰: 一般簽發憑證可以透過兩種工具達成,一種是java內建的keytool,另一種是openssl。這邊直接選擇java內建工具keytool完成,為了產生私鑰,請下指令: ``` keytool -genkey -alias 私鑰名稱 -keyalg RSA -storepass 憑證密碼 -keystore 憑證檔名 ``` ![](https://i.imgur.com/f2XI0Kh.png) * 私鑰名稱<span class="red">(test)</span>: 這邊輸入的名稱可以看做只是私鑰的別名而已,若後續有需要去私鑰檔案尋找憑證,可以透過alias尋找。 * 私鑰密碼<span class="red">(123456)</span>: 自己設定的私鑰密碼,會要求要6碼以上。 * 私鑰檔名<span class="red">(test.keystore)</span>: 產出的私鑰檔案名稱,通常我會習慣用.keystore當結尾,一開始在找教學文時有些也是會用.key或.jks當結尾,一開始以為會有什麼差別,但其實都沒什麼差。 打完指令後,會要你輸入圖片上呈現的一些資訊,<span class="red">請注意,這邊最重要的其實大概就第一行,這邊輸入的資訊必須和自己網站網域(domain name)的名稱相同</span>,像是xxx.test.com之類的,如果不一致的話,在訪問server做ssl handshake時就會出錯了...剩下的資訊不是很重要,可以隨便打。 -------------------------------------------------- #### 2. 產生憑證: 接著需要透過私鑰導出憑證,請下指令[2]: ``` keytool -export -alias 憑證名稱 -file 憑證檔名 -keystore 私鑰檔名 ``` ![](https://i.imgur.com/sjnV1pk.png) * 憑證名稱<span class="red">(test)</span>: 跟私鑰名稱一樣,都只是別名。 * 憑證檔名<span class="red">(test.crt)</span>: 要導出的憑證檔案名稱,個人習慣.crt結尾,有些教學文件習慣用.cer結尾,一樣沒什麼差異。 * 私鑰檔名<span class="red">(test.keystore)</span>: 請輸入剛剛產生的私鑰檔案位置。 產出時需要輸入剛剛在私鑰設定的密碼,成功後會產生.crt檔案。 -------------------------------------------------- #### 3. 將自簽憑證匯入java jdk or jre的cacerts: 由於java訪問ssl網站時,會從jdk的keystore(也就是cacerts)取出對應可信任憑證進行驗證,如果找不到就會出現 `PKIX:unable to find valid certification path to requested target`的問題,請下指令: ``` keytool -import -trustcacerts -alias test -file test.crt -keystore "C:\Program Files\Java\jdk-11.0.6\lib\security\cacerts" -storepass changeit ``` ![](https://i.imgur.com/NOjcUpq.png) 上述為一般教學文件手動指定cacerts位置的寫法,但其實輸入後可以發現有跳出提示: <span class="red">Warning: use -cacerts option to access cacerts keystore</span> 的字樣,所以其實可以不用這麼麻煩,以下指令也可以: ``` keytool -import -alias test -file test.crt -cacerts ``` ![](https://i.imgur.com/LDrwPYL.png) 輸入完後會需要輸入密碼,cacerts的密碼固定為changeit,你也可以在後面補上`-storepass changeit`也可以,輸入完後選擇加入即可。 -------------------------------------------------- ## Tomcat SSL設定及配置 #### 請到Tomcat Server安裝位置底下找到`conf\server.xml`並設定如下: ```xml= <Connector SSLEnabled="true" defaultSSLHostConfigName="sso.server.com" maxThreads="150" port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"> <SSLHostConfig hostName="sso.server.com"> <Certificate certificateKeystoreFile="....\ssodemo.keystore" certificateKeystorePassword="123456" type="RSA"/> </SSLHostConfig> <SSLHostConfig hostName="sso.client1.com"> <Certificate certificateKeystoreFile="....\casclient1.keystore" certificateKeystorePassword="123456" type="RSA"/> </SSLHostConfig> <SSLHostConfig hostName="sso.client2.com"> <Certificate certificateKeystoreFile="....\casclient2.keystore" certificateKeystorePassword="123456" type="RSA"/> </SSLHostConfig> </Connector> ``` 這邊有些情境需要說明一下,由於在實作CAS機制的關係,Tomcat總共架了三台,所以其實要設定的xml總共有兩份,其中一台擔任Server(domain name: `sso.server.com`),兩台擔任Client1、Client2(domain name: `sso.client1.com、sso.client2.com`)。 <span class="red">因為都是連內部local的關係,需要先去 `C:\Windows\System32\drivers\etc` 底下配置域名和ip的位子</span>。 以目前來說,我是將`sso.server.com、sso.client1.com、sso.client2.com` 全部和127.0.0.1 mapping,並且將Server的keystore配置在<span class="red">Client1和Client2的兩台Tomcat上</span>,這樣基本上ssl就算設定完成了。 <span class="red">但是!! 就是這個but!!</span> 一般教學在寫cas server配置的相關文章只會寫到這邊,那為什麼這邊會列出3個keystore在xml裡面呢? 這邊就需要提到一些關於CAS的機制,一般基本上在實作SSO時,是由Client會向Server發出認證和驗證的request,所以許多教學文只會要你將Server的keystore配到Client上,這是沒問題,但許多人會卡在為什麼在做單一登出(Single Logout)的時候會失敗? 這是因為CAS機制在實作Single Logout(SLO)時,CAS Server會發logout request給CAS Client,如果Server沒有配置Client的keystore,發出request時ssl handshake就會失敗,所以如果有多台Client需要配置,那麼<span class="red">Server就應該包含全部Client的keystore</span>。 ##### Note: 配置多個keystore時需要注意`defaultSSLHostConfigName`這個屬性應該根據自身的域名下去配置,這邊只是以CAS Server當舉例,CAS Client的配置請自行替換,如果只配一個keystore,那這屬性可移除。 CAS相關部分有興趣的請閱讀[SSO 技術實踐: CAS整合JWT](https://hackmd.io/328QeSlORYeg8tsmPDfLIQ) > [name=夜雨] 其實說穿了也是自己對於ssl機制的不熟悉,自己的理解是如果誰發出請求,那麼對方應該要包含自己的私鑰,當初卡了很久才發現slo request handshake failed,希望這篇能幫上實作時卡在SLO的小夥伴們~ 所以最後應該是: Server有Client1、Client2的keystore Client1、Client2有Server的keystore 只是我通常還會習慣再配上自己本身的keystore預防萬一,其實應該是可以不用,有興趣的可以拔掉實驗看看,應該也是會成功~ ## Referece: [1] [[SSL 基礎]私有金鑰、CSR 、CRT 與 中繼憑證](https://haway.30cm.gg/ssl-key-csr-crt-pem/) [2] [使用 keytool 公用程式產生憑證](https://docs.oracle.com/cd/E19900-01/820-0848/ablrb/index.html)