---
# System prepended metadata

title: 架設CAS Server and Client Tomcat SSL 設定
tags: [Tomcat Server SSL Setting, CAS, keytool]

---

<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)