附錄

附錄 A:本文檔中使用的材料

範例中使用的虛擬 UserDetailsService,因為我們沒有真實的使用者來源。

public class DummyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        return new User(username, "notUsed", true, true, true, true,
                AuthorityUtils.createAuthorityList("ROLE_USER"));
    }

}

附錄 B:Kerberos 快速入門

在任何身份驗證過程中,通常都涉及三個參與方。

drawio kerb cc1

首先是用戶端,有時是用戶端電腦,但在大多數情況下,它是坐在電腦前並嘗試存取資源的實際使用者。然後是用戶嘗試存取的資源。在本例中,它是一台網路伺服器。

然後是金鑰發放中心KDC。在 Windows 環境中,這將是網域控制器KDC 是真正將所有事物整合在一起的角色,因此也是您環境中最關鍵的組件。因此,它也被視為單點故障。

最初,當 Kerberos 環境設定完成並將網域使用者主體建立到資料庫中時,也會建立加密金鑰。這些加密金鑰基於共享密碼(即使用者密碼),而實際密碼永遠不會以明文形式保存。實際上,KDC 擁有自己的金鑰和其他網域使用者的金鑰。

有趣的是,在身份驗證過程中,資源KDC 之間沒有任何通訊。

drawio kerb cc2

當用戶端想要向 資源 驗證自身身份時,它首先需要與 KDC 通訊。用戶端 將製作一個特殊封包,其中包含加密和未加密的部分。未加密的部分包含例如有關使用者的資訊,而加密部分包含協定一部分的其他資訊。用戶端 將使用自己的金鑰加密封包資料。

KDC 從用戶端收到此身份驗證封包時,它會從未加密的部分檢查此 用戶端 聲稱是誰,並根據該資訊,它會使用已在其資料庫中擁有的 用戶端 解密金鑰。如果此解密成功,KDC 知道此 用戶端 就是它聲稱的身份。

KDC 返回給用戶端的是一個稱為 票證授予票證 的票證,該票證由 KDC 自己的私鑰簽署。稍後,當 用戶端 發回此票證時,它可以嘗試解密它,如果該操作成功,它就知道這是一個票證,是它自己最初簽署並給予 用戶端 的。

drawio kerb cc3

當用戶端想要取得可用於向服務驗證身份的票證時,TGT 會被發送到 KDC,然後 KDC 使用服務自己的金鑰簽署服務票證。這是建立 用戶端服務 之間信任的時刻。此服務票證包含只有 服務 本身才能解密的資料。

drawio kerb cc4

用戶端 向服務進行身份驗證時,它會將先前收到的服務票證發送到服務,然後服務會認為我不了解這個人,但他給了我一張身份驗證票證。服務 接下來可以做的是嘗試解密該票證,如果該操作成功,它就知道唯一知道我的憑證的另一方是 KDC,並且因為我信任他,所以我也可以信任這個用戶端是他聲稱的身份。

附錄 C:設定 Kerberos 環境

Kerberos 環境的生產設定超出本文檔的範圍,但此附錄提供了一些幫助,讓您開始設定開發所需的組件。

設定 MIT Kerberos

第一個動作是設定新的 realm 和資料庫。

# kdb5_util create -s -r EXAMPLE.ORG
Loading random data
Initializing database '/var/lib/krb5kdc/principal' for realm 'EXAMPLE.ORG',
master key name 'K/[email protected]'
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.
Enter KDC database master key:
Re-enter KDC database master key to verify:

kadmin 命令可用於管理 Kerberos 環境,但您還不能使用它,因為資料庫中沒有管理員使用者。

root@neo:/etc/krb5kdc# kadmin
Authenticating as principal root/[email protected] with password.
kadmin: Client not found in Kerberos database while initializing
kadmin interface

讓我們使用 kadmin.local 命令來建立一個。

root@neo:/etc/krb5kdc# kadmin.local
Authenticating as principal root/[email protected] with password.

kadmin.local:  listprincs
K/[email protected]
kadmin/[email protected]
kadmin/[email protected]
kadmin/[email protected]
krbtgt/[email protected]

kadmin.local:  addprinc root/[email protected]
WARNING: no policy specified for root/[email protected]; defaulting to
no policy
Enter password for principal "root/[email protected]":
Re-enter password for principal "root/[email protected]":
Principal "root/[email protected]" created.

然後透過修改 kadm5.acl 檔案並重新啟動 Kerberos 服務來啟用管理員。

# cat /etc/krb5kdc/kadm5.acl
# This file Is the access control list for krb5 administration.
*/admin *

現在您可以使用先前建立的 root/admin 主體來使用 kadmin。讓我們建立我們的第一個使用者 user1

kadmin:  addprinc user1
WARNING: no policy specified for [email protected]; defaulting to no
policy
Enter password for principal "[email protected]":
Re-enter password for principal "[email protected]":
Principal "[email protected]" created.

讓我們建立我們的第二個使用者 user2 並匯出 keytab 檔案。

kadmin:  addprinc user2
WARNING: no policy specified for [email protected]; defaulting to no
policy
Enter password for principal "[email protected]":
Re-enter password for principal "[email protected]":
Principal "[email protected]" created.

kadmin:  ktadd -k /tmp/user2.keytab [email protected]
Entry for principal [email protected] with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/user2.keytab.
Entry for principal [email protected] with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/tmp/user2.keytab.
Entry for principal [email protected] with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/tmp/user2.keytab.
Entry for principal [email protected] with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/tmp/user2.keytab.

讓我們為 tomcat 建立一個服務票證,並將憑證匯出到名為 tomcat.keytab 的 keytab 檔案。

kadmin:  addprinc -randkey HTTP/[email protected]
WARNING: no policy specified for HTTP/[email protected];
defaulting to no policy
Principal "HTTP/[email protected]" created.

kadmin:  ktadd -k /tmp/tomcat.keytab HTTP/[email protected]
Entry for principal HTTP/[email protected] with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/[email protected] with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/[email protected] with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/[email protected] with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/tmp/tomcat2.keytab.

設定 Windows 網域控制器

這是使用 Windows Server 2012 R2 測試的

網路上有很多關於如何設定 Windows AD 的好文章和影片,但這兩篇相當有用 RackspaceMicrosoft Technet

  • 已完成正常的網域控制器和 Active Directory 設定。

  • 使用的 dns 網域 example.org 和 Windows 網域 EXAMPLE

  • 我建立了各種網域使用者,例如 user1user2user3tomcat,並將密碼設定為 Password#

我最終還將我所有虛擬機器的 IP 新增到 AD 的 dns 伺服器,以避免造成任何問題。

Name: WIN-EKBO0EQ7TS7.example.org
Address: 172.16.101.135

Name: win8vm.example.org
Address: 172.16.101.136

Name: neo.example.org
Address: 172.16.101.1

服務主體名稱 (SPN) 需要使用 HTTP 和伺服器名稱 neo.example.org 進行設定,其中執行 tomcat servlet 容器。這與 tomcat 網域使用者一起使用,其 keytab 然後用作服務憑證。

PS C:\> setspn -A HTTP/neo.example.org tomcat

我匯出了 keytab 檔案,該檔案被複製到執行 tomcat 的 Linux 伺服器。

PS C:\> ktpass /out c:\tomcat.keytab /mapuser [email protected] /princ HTTP/[email protected] /pass Password# /ptype KRB5_NT_PRINCIPAL /crypto All
 Targeting domain controller: WIN-EKBO0EQ7TS7.example.org
 Using legacy password setting method
 Successfully mapped HTTP/neo.example.org to tomcat.

附錄 D:疑難排解

本附錄提供關於疑難排解錯誤和問題的通用資訊。

如果您認為環境和設定已正確設定,請仔細檢查並請其他人檢查可能的明顯錯誤或錯字。Kerberos 設定通常非常脆弱,並且並不總是很容易偵錯問題所在。

找不到適當類型的金鑰來解密
GSSException: Failure unspecified at GSS-API level (Mechanism level:
Invalid argument (400) - Cannot find key of appropriate type to
decrypt AP REP - RC4 with HMAC)

如果您看到指示缺少金鑰類型的錯誤,則會在兩種不同的用例中發生這種情況。首先,您的 JVM 可能不支援適當的加密類型,或者它在您的 krb5.conf 檔案中被停用。

default_tkt_enctypes = rc4-hmac
default_tgs_enctypes = rc4-hmac

第二種情況不太明顯且難以追蹤,因為它會導致相同的錯誤。如果您根本沒有所需的加密金鑰,也會拋出此特定的 GSSException,這可能是由於您的 Kerberos 伺服器中的錯誤設定或主體中的簡單錯字造成的。

使用錯誤的 Kerberos 設定


在大多數系統中,所有命令和程式庫都會從預設位置或特殊位置(例如 JDK)搜尋 Kerberos 設定。很容易混淆,尤其是在從 Unix 系統(可能已經具有與 MIT Kerberos 配合使用的預設設定)轉向 Windows 網域時。

這是一個具體的範例,說明 ldapsearch 嘗試使用 Kerberos 身份驗證查詢 Windows AD 時會發生什麼情況。

$ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"
SASL/GSSAPI authentication started
ldap_sasl_interactive_bind_s: Local error (-2)
  additional info: SASL(-1): generic failure: GSSAPI Error:
  Unspecified GSS failure.  Minor code may provide more information
  (No Kerberos credentials available)

這看起來不太好,並且簡單地表明我沒有有效的 Kerberos 票證,如下所示。

$ klist
klist: Credentials cache file '/tmp/krb5cc_1000' not found

我們已經有一個從 Windows AD 匯出的 keytab 檔案,用於在 Linux 上執行的 tomcat。讓我們嘗試使用它向 Windows AD 進行身份驗證。

您可以擁有一個專用的設定檔,該設定檔通常可以透過系統屬性與原生 Linux 命令和 JVM 一起使用。

$ cat krb5.ini
[libdefaults]
default_realm = EXAMPLE.ORG
default_keytab_name = /tmp/tomcat.keytab
forwardable=true

[realms]
EXAMPLE.ORG = {
  kdc = WIN-EKBO0EQ7TS7.example.org:88
}

[domain_realm]
example.org=EXAMPLE.ORG
.example.org=EXAMPLE.ORG

讓我們使用該設定檔和 keytab 來取得初始憑證。

$ env KRB5_CONFIG=/path/to/krb5.ini kinit -kt tomcat.keytab HTTP/[email protected]

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: HTTP/[email protected]

Valid starting     Expires            Service principal
26/03/15 09:04:37  26/03/15 19:04:37  krbtgt/[email protected]
  renew until 27/03/15 09:04:37

讓我們看看如果我們現在嘗試對 Windows AD 進行簡單查詢會發生什麼情況。

$ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"
SASL/GSSAPI authentication started
ldap_sasl_interactive_bind_s: Local error (-2)
  additional info: SASL(-1): generic failure: GSSAPI Error:
  Unspecified GSS failure.  Minor code may provide more information
  (KDC returned error string: PROCESS_TGS)

這可能僅僅是因為 ldapsearch 感到困惑並且只是使用了錯誤的設定。您可以告訴 ldapsearch 使用不同的設定,透過 KRB5_CONFIG 環境變數,就像我們對 kinit 所做的那樣。您也可以使用 KRB5_TRACE=/dev/stderr 來取得有關原生程式庫正在執行的操作的更詳細輸出。

$ env KRB5_CONFIG=/path/to/krb5.ini ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org -b "dc=example,dc=org"

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: HTTP/[email protected]

Valid starting     Expires            Service principal
26/03/15 09:11:03  26/03/15 19:11:03  krbtgt/[email protected]
  renew until 27/03/15 09:11:03
  26/03/15 09:11:44  26/03/15 19:11:03
  ldap/[email protected]
    renew until 27/03/15 09:11:03

在上面您可以看到如果查詢透過查看 Kerberos 票證而成功會發生什麼情況。現在您可以嘗試進一步的查詢命令,例如,如果您使用 KerberosLdapContextSource

$ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org \
-b "dc=example,dc=org" \
"(| ([email protected])
([email protected]))" \
dn

...
# test user, example.org
dn: CN=test user,DC=example,DC=org

附錄 E:設定瀏覽器以進行 Spnego 協商

Firefox

完成以下步驟以確保您的 Firefox 瀏覽器已啟用以執行 Spnego 身份驗證。

  • 開啟 Firefox。

  • 在網址欄位中,輸入 about:config

  • 在篩選器/搜尋中,輸入 negotiate

  • 參數 network.negotiate-auth.trusted-uris 可能設定為預設值 https://,這對您不起作用。一般來說,如果需要 Kerberos 委派,則必須將此參數替換為伺服器位址。

  • 建議對所有通訊使用 https

Chrome

使用 Google Chrome,您通常需要設定命令列參數順序,以將伺服器列入白名單,Chrome 將與之協商。

  • 在 Windows 機器(用戶端)上:Chrome 與 Internet Explorer 共享設定,因此如果所有變更都已應用於 IE(如 E.3 中所述),則無需透過命令列參數傳遞任何內容。

  • 在 Linux/Mac OS 機器(用戶端)上:只有在需要 Kerberos 委派時才應使用命令列參數 --auth-negotiate-delegate-whitelist(否則請勿設定此參數)。

  • 建議對所有通訊使用 https

--auth-server-whitelist="*.example.com"
--auth-negotiate-delegate-whitelist="*.example.com"

您可以透過在 Chrome 的網址列中輸入 chrome://policy/ 來查看啟用了哪些策略。

使用 Linux Chrome 也會從 /etc/opt/chrome/policies/managed 目錄讀取策略檔案。

mypolicy.json
{
  "AuthServerWhitelist" : "*.example.org",
  "AuthNegotiateDelegateWhitelist" : "*.example.org",
  "DisableAuthNegotiateCnameLookup" : true,
  "EnableAuthNegotiatePort" : true
}

Internet Explorer

完成以下步驟以確保您的 Internet Explorer 瀏覽器已啟用以執行 Spnego 身份驗證。

  • 開啟 Internet Explorer。

  • 點擊 工具 > 網際網路選項 > 安全性 索引標籤。

  • 近端網路 區段中,確保您的伺服器受到信任,例如將其新增到清單中。