附錄
附錄 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 速成課
在任何認證過程中,通常涉及三方。
首先是 client
(客戶端),有時它是一臺客戶端計算機,但在大多數情況下,它是坐在計算機前試圖訪問資源的實際使用者。然後是使用者試圖訪問的 resource
(資源)。在本例中,它是一臺 web 伺服器。
然後是 Key Distribution Center
(金鑰分發中心)或 KDC
。在 Windows 環境中,它將是 Domain Controller
(域控制器)。KDC
是真正將所有事物連線在一起的元件,因此是您環境中最關鍵的元件。正因為如此,它也被認為是單點故障。
最初設定 Kerberos
環境並將域使用者主體建立到資料庫中時,也會建立加密金鑰。這些加密金鑰基於共享秘密(即使用者密碼),實際密碼從不以明文形式儲存。實際上,KDC
擁有自己的金鑰以及用於域使用者的其他金鑰。
有趣的是,在認證過程中,resource
(資源)和 KDC
之間沒有通訊。
當客戶端希望使用 resource
進行自我認證時,它首先需要與 KDC
通訊。Client
將構建一個包含加密和未加密部分的特殊資料包。未加密部分包含使用者資訊,加密部分包含協議中的其他資訊。Client
將使用自己的金鑰對資料包資料進行加密。
當 KDC
從客戶端接收到此認證資料包時,它會檢查未加密部分中的 client
聲稱是誰,並根據該資訊使用其資料庫中已有的 client
解密金鑰。如果解密成功,KDC
就知道此 client
就是它聲稱的身份。
KDC 返回給客戶端的是一個稱為 Ticket Granting Ticket
(票據授予票據)的票據,該票據由 KDC 自己的私鑰簽名。稍後,當 client
將此票據傳送回來時,它可以嘗試解密它,如果操作成功,它就知道這是 KDC 最初自己簽名並提供給 client
的票據。
當客戶端想要獲取可用於向服務進行認證的票據時,會將 TGT
傳送到 KDC
,然後 KDC
使用服務自己的金鑰簽署服務票據。這時,client
和 service
之間建立了信任。此服務票據包含只有 service
本身才能解密的資料。
當 client
向服務進行認證時,它會將之前收到的服務票據傳送給服務,然後服務會想:“我對此人一無所知,但他給了我一個認證票據。” 接下來 service
可以嘗試解密該票據,如果操作成功,它就知道唯一知道我的憑據的另一方是 KDC
,並且由於我信任他,我也可以信任此客戶端就是他聲稱的身份。
附錄 C:設定 Kerberos 環境
Kerberos 生產環境的設定超出了本文件的範圍,但本附錄提供了一些幫助,以便您開始為開發設定所需的元件。
設定 MIT Kerberos
第一步是設定一個新的領域和資料庫。
# 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 的優秀文章和影片,但這兩篇非常有用:Rackspace 和 Microsoft Technet。 |
-
完成了正常的域控制器和活動目錄設定。
-
使用了 dns 域
example.org
和 windows 域EXAMPLE
。 -
我建立了各種域使用者,如
user1
、user2
、user3
、tomcat
,並將密碼設定為Password#
。
我最終還將所有 vm 的 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
需要使用 HTTP
和執行 tomcat servlet 容器的伺服器名稱 neo.example.org
設定服務主體名稱(SPN)。這與 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 伺服器配置錯誤或主體中的簡單拼寫錯誤引起的。
在大多數系統中,所有命令和庫都會從預設位置或 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 匯出用於在 Linux 上執行的 tomcat 的 keytab 檔案。讓我們嘗試使用它來向 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
混淆並使用了錯誤的配置。您可以透過 KRB5_CONFIG
環境變數告訴 ldapsearch
使用不同的配置,就像我們使用 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 機器(客戶端)上:命令列引數
--auth-negotiate-delegate-whitelist
只應在需要 Kerberos 委託時使用(否則不要設定此引數)。 -
建議所有通訊都使用
https
。
--auth-server-whitelist="*.example.com"
--auth-negotiate-delegate-whitelist="*.example.com"
透過在 Chrome 的位址列中輸入 chrome://policy/,您可以檢視哪些策略已啟用。
在 Linux 上,Chrome 還會從 /etc/opt/chrome/policies/managed
目錄讀取策略檔案。
{
"AuthServerWhitelist" : "*.example.org",
"AuthNegotiateDelegateWhitelist" : "*.example.org",
"DisableAuthNegotiateCnameLookup" : true,
"EnableAuthNegotiatePort" : true
}