附录
附录 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 速成课程
在任何身份验证过程中,通常都涉及三个参与方。
首先是 `客户端`,有时是客户端计算机,但在大多数情况下,它是坐在计算机上并试图访问资源的实际用户。然后是用户试图访问的 `资源`。在本例中,它是一个 Web 服务器。
然后是 `密钥分发中心` 或 `KDC`。在 Windows 环境中,这将是 `域控制器`。`KDC` 是真正将所有内容整合在一起的组件,因此是环境中最重要的组件。正因为如此,它也被认为是单点故障。
最初,当 `Kerberos` 环境设置好并将域用户主体创建到数据库中时,也会创建加密密钥。这些加密密钥基于共享密钥(即用户密码),并且实际密码永远不会以明文形式保存。`KDC` 有自己的密钥以及域用户的其他密钥。
有趣的是,在身份验证过程中,`资源` 和 `KDC` 之间没有通信。
当客户端想要使用 `资源` 进行身份验证时,它首先需要与 `KDC` 通信。`客户端` 将创建一个特殊的包,其中包含加密和未加密的部分。未加密的部分包含例如用户信息,加密部分包含协议的一部分的其他信息。`客户端` 将使用其自己的密钥加密包数据。
当 `KDC` 从客户端收到此身份验证包时,它会从未加密部分检查此 `客户端` 声称的身份,并根据该信息使用其数据库中已有的 `客户端` 解密密钥。如果此解密成功,则 `KDC` 知道此 `客户端` 就是它声称的身份。
`KDC` 返回给客户端的是一张称为 `票据授予票据 (Ticket Granting Ticket)` 的票据,该票据由 KDC 的私钥签名。稍后,当 `客户端` 发送回此票据时,它可以尝试解密它,如果该操作成功,则它知道这是它自己最初签名并提供给 `客户端` 的票据。
当客户端想要获取可用于向服务进行身份验证的票据时,`TGT` 将发送到 `KDC`,然后 `KDC` 使用服务的密钥签署服务票据。这是 `客户端` 和 `服务` 之间建立信任的时刻。此服务票据包含只有 `服务` 本身才能解密的数据。
当 `客户端` 向服务进行身份验证时,它会将先前收到的服务票据发送到服务,然后服务会认为我不知道这个家伙是谁,但他给了我一张身份验证票据。`服务` 接下来可以做的是尝试解密该票据,如果该操作成功,则它知道唯一知道我凭据的另一方是 `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#`。
我最终还将所有虚拟机的 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 导出的 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
出现混乱,使用了错误的配置。您可以像使用kinit
一样,通过KRB5_CONFIG
环境变量告诉ldapsearch
使用不同的配置。您也可以使用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
目录读取策略文件。
{
"AuthServerWhitelist" : "*.example.org",
"AuthNegotiateDelegateWhitelist" : "*.example.org",
"DisableAuthNegotiateCnameLookup" : true,
"EnableAuthNegotiatePort" : true
}