跳到主要内容
版本:7.0.2

附录

DeepSeek V3 中英对照 Appendices

附录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

首先是客户端,它有时指客户端计算机,但在大多数情况下,它指的是坐在计算机前并试图访问资源的实际用户。然后是用户试图访问的资源。在这个例子中,它是一个Web服务器。

接下来是密钥分发中心KDC。在 Windows 环境中,这通常是一个域控制器KDC 是将所有组件真正整合在一起的关键,因此它是您环境中最为关键的组件。正因如此,它也被视为一个单点故障。

最初设置Kerberos环境并将域用户主体创建到数据库时,也会生成加密密钥。这些加密密钥基于共享密钥(即用户密码),且实际密码绝不会以明文形式保存。实际上,KDC拥有自己的密钥以及域用户的其他密钥。

有趣的是,在认证过程中,resourceKDC 之间并没有通信。

drawio kerb cc2

当客户端需要向某个资源进行身份验证时,它首先需要与KDC通信。客户端将构建一个特殊的包,其中包含加密部分和未加密部分。未加密部分包含诸如用户信息等内容,而加密部分则包含协议所需的其他信息。客户端将使用自己的密钥对包数据进行加密。

KDC从客户端接收到此认证包时,它会检查客户端在未加密部分中声称的身份,并基于该信息使用其数据库中已有的客户端解密密钥。如果解密成功,KDC即可确认该客户端确实是其所声称的身份。

KDC返回给客户端的是一种名为Ticket Granting Ticket的票据,该票据由KDC自身的私钥签名。随后,当客户端将此票据发回时,KDC会尝试解密它;如果解密成功,KDC便知道这是自己最初签名并颁发给客户端的票据。

drawio kerb cc3

当客户端想要获取一张可用于向服务进行身份验证的票据时,TGT 会被发送到 KDC,随后 KDC 使用服务自身的密钥对服务票据进行签名。此时,客户端服务 之间的信任关系便建立起来。这张服务票据包含的数据只有 服务 自身能够解密。

drawio kerb cc4

client向服务进行身份验证时,它会将先前收到的服务票据发送给服务。此时服务会认为:"我对这个用户一无所知,但他给了我一个身份验证票据"。接下来,service可以尝试解密该票据。如果解密成功,服务就能确认:唯一掌握我(服务)凭证的另一方是KDC。由于我信任KDC,因此也可以相信这个client确实是其所声称的身份。

附录 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/M@EXAMPLE.ORG'
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/admin@EXAMPLE.ORG 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/admin@EXAMPLE.ORG with password.

kadmin.local: listprincs
K/M@EXAMPLE.ORG
kadmin/admin@EXAMPLE.ORG
kadmin/changepw@EXAMPLE.ORG
kadmin/cypher@EXAMPLE.ORG
krbtgt/EXAMPLE.ORG@EXAMPLE.ORG

kadmin.local: addprinc root/admin@EXAMPLE.ORG
WARNING: no policy specified for root/admin@EXAMPLE.ORG; defaulting to
no policy
Enter password for principal "root/admin@EXAMPLE.ORG":
Re-enter password for principal "root/admin@EXAMPLE.ORG":
Principal "root/admin@EXAMPLE.ORG" 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 user1@EXAMPLE.ORG; defaulting to no
policy
Enter password for principal "user1@EXAMPLE.ORG":
Re-enter password for principal "user1@EXAMPLE.ORG":
Principal "user1@EXAMPLE.ORG" created.

让我们创建第二个用户 user2 并导出一个 keytab 文件。

kadmin:  addprinc user2
WARNING: no policy specified for user2@EXAMPLE.ORG; defaulting to no
policy
Enter password for principal "user2@EXAMPLE.ORG":
Re-enter password for principal "user2@EXAMPLE.ORG":
Principal "user2@EXAMPLE.ORG" created.

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

让我们为Tomcat创建一个服务票据,并将凭据导出到名为tomcat.keytab的keytab文件中。

kadmin:  addprinc -randkey HTTP/neo.example.org@EXAMPLE.ORG
WARNING: no policy specified for HTTP/neo.example.org@EXAMPLE.ORG;
defaulting to no policy
Principal "HTTP/neo.example.org@EXAMPLE.ORG" created.

kadmin: ktadd -k /tmp/tomcat.keytab HTTP/neo.example.org@EXAMPLE.ORG
Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/tmp/tomcat2.keytab.
Entry for principal HTTP/neo.example.org@EXAMPLE.ORG with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/tmp/tomcat2.keytab.

设置 Windows 域控制器

此测试基于 Windows Server 2012 R2 进行。

提示

网络上有很多关于如何设置 Windows AD 的优秀文章和视频,但以下两个资源非常实用:RackspaceMicrosoft Technet

  • 已完成常规域控制器和活动目录的设置。

  • 使用了 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

我将密钥表文件导出并复制到了运行Tomcat的Linux服务器上。

PS C:\> ktpass /out c:\tomcat.keytab /mapuser tomcat@EXAMPLE.ORG /princ HTTP/neo.example.org@EXAMPLE.ORG /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域时,很容易混淆。

这是一个具体示例,展示了使用 Kerberos 认证通过 ldapsearch 查询 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

让我们使用该配置和密钥表来获取初始凭据。

$ env KRB5_CONFIG=/path/to/krb5.ini kinit -kt tomcat.keytab HTTP/neo.example.org@EXAMPLE.ORG

$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: HTTP/neo.example.org@EXAMPLE.ORG

Valid starting Expires Service principal
26/03/15 09:04:37 26/03/15 19:04:37 krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
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/neo.example.org@EXAMPLE.ORG

Valid starting Expires Service principal
26/03/15 09:11:03 26/03/15 19:11:03 krbtgt/EXAMPLE.ORG@EXAMPLE.ORG
renew until 27/03/15 09:11:03
26/03/15 09:11:44 26/03/15 19:11:03
ldap/win-ekbo0eq7ts7.example.org@EXAMPLE.ORG
renew until 27/03/15 09:11:03

如上所示,通过查看 Kerberos 票据可以确认查询是否成功。现在,您可以尝试使用更多查询命令,例如,如果您正在使用 KerberosLdapContextSource

$ ldapsearch -H ldap://WIN-EKBO0EQ7TS7.example.org \
-b "dc=example,dc=org" \
"(| (userPrincipalName=user2@EXAMPLE.ORG)
(sAMAccountName=user2@EXAMPLE.ORG))" \
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
}

Internet Explorer

请按照以下步骤操作,确保您的 Internet Explorer 浏览器已启用以执行 Spnego 身份验证。

  • 打开 Internet Explorer。
  • 点击 工具 > Internet 选项 > 安全 选项卡。
  • 本地 Intranet 部分,确保您的服务器是受信任的,例如将其添加到列表中。