“检测到GSSException有缺陷的令牌"; -尝试使用Kerberos对Windows上运行的Tomcat进行身份验证时

问题描述:

在Windows 2012上运行时,我正在努力向Java Web容器进行身份验证(我已经尝试过Tomcat和Jetty).

I am struggling to authenticate to a Java web container (I've tried both Tomcat and Jetty) when running on Windows 2012.

每次尝试协商身份验证"方案时,都会出现错误:org.ietf.jgss.GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)

Every time I try the Negotiate auth scheme I get an error: org.ietf.jgss.GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)

复制步骤

Steps to reproduce

首先设置Windows Server 2012或2016实例并安装活动目录域服务.

Start out by setting up a Windows Server 2012 or 2016 instance and install active directory domain services.

在我的示例中,我创建了:

In my example, I created:

  • NETBIOS域: NICKIS

Dns域: nickis.life

Dns domain: nickis.life

在Active Directory上创建kerberos主题用户

Create the kerberos subject user on Active Directory

重要提示:请确保名字,姓氏和名字相同!

IMPORTANT: MAKE SURE THAT THE FIRST NAME, LAST NAME AND FULL NAME ARE THE SAME!

在我的情况下,新用户是:

The new user in my case is:

DN = CN=kerberos500,CN=Users,DC=nickis,DC=life

登录+域 = kerberos500@nickis.life

NETBIOS \ samAccountName = NICKIS\kerberos500

从Windows Active Directory服务器运行setspn命令

Run the setspn command from the Windows Active Directory Server

setspn -A HTTP/nickis.life@NICKIS.LIFE kerberos500

示例输出:

C:\Users\Administrator>setspn -A HTTP/nickis.life kerberos500
Checking domain DC=nickis,DC=life 
Registering ServicePrincipalNames for CN=kerberos500,CN=Users,DC=nickis,DC=life
        HTTP/kerberos500.nickis.life
Updated object

从Windows Active Directory服务器运行ktpass命令

Run the ktpass command from the Windows Active Directory Server

ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass XXXXpasswordforkerberos500userXXXX -crypto DES-CBC-MD5 -pType KRB5_NT_PRINCIPAL +DesOnly

示例输出:

C:\Users\Administrator>ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass xxxxxxxx -crypto DES-CBC-MD5 -pType KRB5_NT_PRINCIPAL +DesOnly
Targeting domain controller: WIN-OVV6VHBGIB8.nickis.life
Using legacy password setting method
Successfully mapped HTTP/kerberos500.nickis.life to kerberos500.
Key created.
Output keytab to c:\Users\Administrator\kerberos500.keytab:
Keytab version: 0x502
keysize 71 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x3 (DES-CBC-MD5) keylength 8 (0xcd07200bea625d20)
Account kerberos500 has been set for DES-only encryption.

此时,您将拥有一个密钥表文件:

At this point, you will now have a keytab file:

c:\Users\Administrator\kerberos500.keytab

以及用户主体:

HTTP/kerberos500.nickis.life@NICKIS.LIFE

这些是提供给GSSApi以获得Kerberos单点登录所需的2个输入.

These are the 2 inputs that are needed to provide to the GSSApi to get single sign on with Kerberos.

因此,我将这些输入部署到了Hadoop安全模块中Web容器的kerberos安全领域.

So I deployed those inputs to my web container's kerberos security realm in the Hadoop security module.

卷曲测试,我尝试使用curl进行测试失败:

Curl test I tried unsuccessfully to use curl to test it:

curl --negotiate -u : http://nickis.life:8080/my/webapp

Internet Explorer测试,我也尝试过使用Internet Explorer.我将nickis.life域添加到Internet Explorer中的受信任的角色"中.然后,我在Internet Explorer中启动该网站: http://nickis.life:8080

Internet Explorer test I also tried using Internet Explorer. I added nickis.life domain to the Trusted Roles in Internet Explorer. Then I launch the site in internet explorer: http://nickis.life:8080

无论哪种方式,我都会看到以下错误:

Either way, I get the error below:

org.apache.hadoop.security.authentication.client.AuthenticationException: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
    at org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.authenticate(KerberosAuthenticationHandler.java:398) ~[hadoop-auth-2.7.1.jar:?]

...

Caused by: org.ietf.jgss.GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
    at sun.security.jgss.GSSHeader.<init>(Unknown Source) ~[?:1.8.0_131]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source) ~[?:1.8.0_131]
    at sun.security.jgss.GSSContextImpl.acceptSecContext(Unknown Source) ~[?:1.8.0_131]
    at org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler$2.run(KerberosAuthenticationHandler.java:365) ~[hadoop-auth-2.7.1.jar:?]
    at org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler$2.run(KerberosAuthenticationHandler.java:347) ~[hadoop-auth-2.7.1.jar:?]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_131]
    at javax.security.auth.Subject.doAs(Unknown Source) ~[?:1.8.0_131]
    at org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.authenticate(KerberosAuthenticationHandler.java:347) ~[hadoop-auth-2.7.1.jar:?]

我很困惑.注意:我在这里和那里发现了几个链接,但是它们没有像我在这里总结的那样在所遵循的步骤中包含所有内容,并且提供的任何解决方案都不适合我.

I am stumped. NOTE: I have found several links around here and there but none of them were all inclusive on the steps that were followed like I have summed up here, and none of the solutions provided within worked for me.

  • 我正在尝试从域上与服务器运行所在的计算机不同的机器上进行kerberos登录
  • 我尝试了各种不同的keytab生成变体组合.
  • 没有重复的SPN.
  • 我尝试将域服务器中的DNS设置为A记录.
  • 我想知道是否有一些kerberos Windows服务器设置步骤,并且Microsoft员工已验证在这里不是这种情况:
  • I am attempting kerberos login from a different machine on the domain than the server is running on
  • I have tried all sorts of combinations of keytab generation variations none have worked.
  • There is no duplicate SPN.
  • I tried setting up the DNS in the domain server as an A record.
  • I wonder maybe if there's some kerberos windows server setup steps and Microsoft employee verified that this should not be the case here: https://social.msdn.microsoft.com/Forums/sharepoint/en-US/db15ad96-e269-436e-952f-fe9dfb39da8a/setting-up-a-test-windows-server-active-directory-for-kerberos-testing?forum=winserverDS

任何人都可以追踪到我在这里搞砸了吗?

Can anyone trace what I am screwing up here?

更新:

  • 我有域设置为fusionis.life的AD服务器,而AD服务器是WIN-OVV6VHBGIB8.fusionis.life
  • 我将tomcat服务器移到了域中的另一台Windows计算机上. DESKTOP-VTPBE99.fusionis.life
  • 我打开了dnsmgmt.msc,并添加了一个带有"kerberos500.nickis.life"的"Forward Lookup Zone",并将HOST设置为DESKTOP-VTPBE99.fusionis.life框的IP.
  • 我删除了AD帐户,重新创建了该帐户,然后再次根据票证上的答案之一中的建议重新生成了密钥表.
  • I have AD server with domain set to fusionis.life, and the AD server is WIN-OVV6VHBGIB8.fusionis.life
  • I moved the tomcat server to another windows machine in the domain. DESKTOP-VTPBE99.fusionis.life
  • I opened dnsmgmt.msc and added a "Forward Lookup Zone" with "kerberos500.nickis.life" with A HOST set to the IP of the DESKTOP-VTPBE99.fusionis.life box.
  • I deleted the AD account, recreated it, then re-generated the keytab again as suggested in one of the answers on the ticket.

C:\Users\Administrator>ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/kerberos500.nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass xxxxxxxxx -crypto ALL -pType KRB5_NT_PRINCIPAL Targeting domain controller: WIN-OVV6VHBGIB8.fusionis.life Using legacy password setting method Successfully mapped HTTP/kerberos500.nickis.life to kerberos500. Key created. Key created. Key created. Key created. Key created. Output keytab to c:\Users\Administrator\kerberos500.keytab: Keytab version: 0x502 keysize 67 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x1 (DES-CBC-CRC) keylength 8 (0x04e30b9183ba8389) keysize 67 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x3 (DES-CBC-MD5) keylength 8 (0x04e30b9183ba8389) keysize 75 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x17 (RC4-HMAC) keylength 16 (0xe39a141de38abd8750bf9c0bf49fd1c5) keysize 91 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x12 (AES256-SHA1) keylength 32 (0xe368a1b060cfe4816f522c1c5f62ca07fe201ed96c6d018054dfbd5b86251892) keysize 75 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x11 (AES128-SHA1) keylength 16 (0x1b1a548fa2893a78c6f4c7f9c482b614)

C:\Users\Administrator>ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/kerberos500.nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass xxxxxxxxx -crypto ALL -pType KRB5_NT_PRINCIPAL Targeting domain controller: WIN-OVV6VHBGIB8.fusionis.life Using legacy password setting method Successfully mapped HTTP/kerberos500.nickis.life to kerberos500. Key created. Key created. Key created. Key created. Key created. Output keytab to c:\Users\Administrator\kerberos500.keytab: Keytab version: 0x502 keysize 67 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x1 (DES-CBC-CRC) keylength 8 (0x04e30b9183ba8389) keysize 67 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x3 (DES-CBC-MD5) keylength 8 (0x04e30b9183ba8389) keysize 75 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x17 (RC4-HMAC) keylength 16 (0xe39a141de38abd8750bf9c0bf49fd1c5) keysize 91 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x12 (AES256-SHA1) keylength 32 (0xe368a1b060cfe4816f522c1c5f62ca07fe201ed96c6d018054dfbd5b86251892) keysize 75 HTTP/kerberos500.nickis.life@NICKIS.LIFE ptype 1 (KRB5_NT_PRINCIPAL) vno 4 etype 0x11 (AES128-SHA1) keylength 16 (0x1b1a548fa2893a78c6f4c7f9c482b614)

  • 我将密钥表更新文件保存在服务器上,然后将服务主体更新为HTTP/kerberos500.nickis.life@NICKIS.LIFE

我以域用户身份登录tomcat机器,并添加了 http://kerberos500.nickis.life 到受信任的站点,然后导航到 http://kerberos500.nickis.life:8764

I logged into tomcat machine as a domain user, added http://kerberos500.nickis.life to the trusted sites, then navigated to http://kerberos500.nickis.life:8764

我检查了kerberos500 AD帐户"选项卡中所有加密复选框的组合.

I checked all combinations of the encryption check boxes in the kerberos500 AD "account" tab.

现在我遇到了新的错误...

Now i'm getting a new error...

GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos credentails)

更新:

终于解决了.我遇到了最后一个错误,因为我需要fusionis.lifenickis.life

Resolved finally. I got this final error because I needed fusionis.life to be on the same host as nickis.life

错误检测到缺陷令牌"可能意味着 ntlm 令牌.如果的问题,这就是协商机制在流行的Web浏览器中使用的方式>失败-否则Web服务器未指示时.在操作系统的问题上,可以使用IE Web浏览器(和Firefox,如果配置正确)基本上是说,如果您不使用Kerberos,我将向您发送一个NTLM令牌.服务器回复没有办法",我什至都不知道NTLM,所以我称您发送给我的内容有缺陷.由于您似乎是第一次进行此设置,因此当Kerberos失败时,您很可能未配置任何后备机制(例如NTLM),因此该错误消息.我们通过了解Kerberos为什么会失败来解决此问题.我想我在两个地方看到了您的问题失败的原因,这与SPN和受信任的站点有关.即使您解决了这两项,也存在与加密有关的第三个原因和第四个原因,为什么它可能继续失败.

The error "Defective token detected" likely means that an ntlm token was detected. That’s what the Negotiate mechanism uses inside popular web browsers if kerberos fails - when not instructed by the web server otherwise.  On windows operating systems, the IE web browser on it (and Firefox, if configured correctly) basically says, if you won’t do Kerberos, I’m going to send you an NTLM token.  And the server replies "no way" I don’t even know NTLM so I’m calling what you sent me defective.  Since you seem to be setting this up for the first time, you likely did not configure any fallback mechanism (such as NTLM) for when Kerberos fails, therefore, that error message. We solve this by understanding why Kerberos is failing.  I think I see the reason for the failure in your question, in two places, related to SPNs and Trusted Sites. Even if you resolve those two items, there is a third reason and fourth reason why it could continue to fail, related to encryption.

  1. 用于HTTP服务的的问题不会匹配浏览器输入的URL.这些需要匹配,否则Kerberos将失败.要正常工作,浏览器应使用: http://kerberos500.nickis.life:8080 ,而不是 http://nickis.life:8080 .我说的是根据我在您的的问题中看到的内容创建语法.在此过程中,您已经对SPN进行了编码:HTTP/kerberos500.nickis.life@NICKIS.LIFE.因此,您需要使用 http://kerberos500.nickis.life:8080 .当您告诉浏览器访问 http://nickis.life:8080时,浏览器将不知道如何访问您的Web服务. .使用该*URL,浏览器假定它需要找到在您的Active Directory上运行的Web服务.(假设只有nickis.life的任何内容都可以在域控制器上运行).出于安全考虑,DC永远不要运行Web服务器.
  2. 您需要在IE设置下将 http://kerberos500.nickis.life 添加为受信任的站点" .另外,*.nickis.life也可以工作. (实际上称为受信任的站点",您称之为受信任的角色").
  3. 您将Kerberos加密类型限制为DES-CBC-MD5.从Windows Server 2008 Active Directory R2开始,默认情况下禁用DES.如今,DES是一种过时且通常不安全的加密类型.使用AES128更好,甚至使用AES256更好.您可以按照下面的示例重新生成密钥表来解决此问题.
  4. 在AD用户帐户kerberos500中,转到帐户"标签,滚动到底部,然后选中DES,AES 128和AES 256的所有复选框,然后确定您离开了对话框.即使您已完成上述所有操作,也必须选中这些框,否则Kerberos身份验证仍将失败.
  1. The spn for the HTTP service does not match the URL entered by the browser. These need to match, otherwise Kerberos will fail. To work, the browser should be using: http://kerberos500.nickis.life:8080, not http://nickis.life:8080. I say that based on what I saw in your keytab creation syntax. In that you’ve coded the SPN as such: HTTP/kerberos500.nickis.life@NICKIS.LIFE. That’s why you need to use http://kerberos500.nickis.life:8080. The browser won’t know how to get to your web service when you tell it to go to http://nickis.life:8080. With that top URL, the browser assumes it needs to find a web service running on your Active Directorydomaincontroller (anything with just nickis.life is assumed to run on the Domain Controller). DCs should never run web servers for security reasons.
  2. You’ll need to add http://kerberos500.nickis.life as a Trusted Site under IE settings. Alternatively, *.nickis.life would work as well. (You called it Trusted Roles, when it’s actually called Trusted Sites).
  3. You are restricting the Kerberos encryption type to DES-CBC-MD5. Starting with Windows Server 2008 Active Directory R2, DES is disabled by default. DES is an outdated and generally insecure encryption type these days. Much better to use AES128 or even better, AES256. You can fix that by re-generating the keytab per my example below.
  4. In the AD user account kerberos500, go to the Account tab, scroll to the bottom, and check all the boxes for DES, AES 128, and AES 256, and OK you’re way out of the dialog boxes. You must check these boxes even if you did everything right above, or else Kerberos authentication will still fail.

如何正确地重新生成密钥表:每当您计划制作与该用户帐户相关联的密钥表时,均不应运行setspn -a命令将SPN添加到AD用户.原因是因为keytab创建命令将SPN作为命令的一部分添加到了用户帐户中.如果按照我的上述建议后您的方案仍然无法使用,则需要通过setpn -D删除SPN,如下所示:

How to properly re-generate the keytab: You should not run the setspn -a command to add an SPN to an AD user whenever you are planning to make a keytab associated with that user account.  The reason why is because the keytab creation command adds the SPN to the user account as part of the command.  If your scenario doesn’t work after following my advice above, then you’ll need to remove the SPN via setspn -D like below:

setspn -D HTTP/nickis.life@NICKIS.LIFE kerberos500

然后重新生成密钥表,我唯一的变化是我告诉它使用所有加密类型.客户端和服务器将在身份验证过程中就最强的通用协议达成一致.

And the re-generate the keytab afterwards, my only change is that I told it to use all encryption types. The client and server will agree on the strongest common one during the authentication process. 

ktpass -out c:\Users\Administrator\kerberos500.keytab -princ HTTP/nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass XXXXpasswordforkerberos500userXXXX -crypto ALL -pType KRB5_NT_PRINCIPAL


然后将旧的密钥表替换为新的密钥表.有关密钥表的其他深入信息,您可以从我的技术文章中阅读更多有关如何创建Kerberos密钥表的信息:


Then replace the old keytab with the new one. For additional in-depth information on keytabs, you can read more from my technical article on how to create Kerberos keytabs here: Kerberos Keytabs – Explained. I frequently go back and edit it based on questions I see here in this forum.

顺便说一句, HTTP/kerberos500.nickis.life 是服务主体,而不是您在问题中所写的用户主体.我只使用网络浏览器在这种HTTP场景中测试Kerberos,而不使用cURL.

By the way, HTTP/kerberos500.nickis.life is a service principal, not a user principal as you wrote in your question. I only use web browsers to test Kerberos in HTTP scenarios like this one, I don’t use cURL.

如果您认真地完成了上面提到的所有四点,那么我很肯定,您将解决此问题.

I am positive if you diligently go through all four points I’ve highlighted above, you will resolve this problem.

EDIT1 :此答案假定您在具有完全限定域名kerberos500.nickis.life的主机上运行HTTP服务.如果您没有这样的主机名,我的回答将略有变化.请让我知道.

This answer assumes you have an HTTP service running on a host with the fully-qualified domain name of kerberos500.nickis.life. If you don't have such a host with that name, my answer will slightly change. Please let me know if any.

EDIT2 :要使用 http://nickis.life的URL来实现身份验证的目的:8080 ,那么您可以继续使用已经创建的相同密钥表.

To achieve the objective of authentication using the URL of http://nickis.life:8080, then you may keep on using the same keytab you already created.

在AD帐户NICKIS \ kerberos500上,转到帐户"选项卡,滚动到底部,然后选中为此帐户使用Kerberos DES加密类型"框.

On the AD account NICKIS\kerberos500, go to the Account tab, scroll to the bottom, and check the box for "Use Kerberos DES encryption types for this account".

然后通过组策略在AD域级别启用DES加密本身.为此,请执行以下操作:

Then enable DES encryption itself at the AD domain level via Group Policy. To do that, conduct the following:

  1. 打开组策略管理控制台(GPMC).
  2. 编辑默认域策略GPO. (创建新的域级GPO并进行编辑比较安全,但这取决于您).
  3. 导航到计算机配置">策略">"Windows设置">安全性设置">本地策略">安全性选项">网络安全性:配置Kerberos允许的加密类型",并选中DES_CBC_MD5和DES_CBC_MD5的两个复选框.重要说明:在同一组策略中,还要确保还选中了RC4,AES128和AES256的复选框.这些加密类型不会用于您的网站票证,但会用于域中的其他所有票证.单击确定,然后退出对话框并关闭GPMC.
  4. 在DC服务器和客户端上都运行'gpupdate/force'命令.
  5. 在客户端上运行"klist清除"以清除所有Kerberos票证.
  6. 在网络浏览器中,清除缓存并删除所有cookie.
  7. 确保DC服务器允许端口8080 TCP入站.
  8. 再试一次.

参考: Kerberos支持的加密类型的Windows配置

避免在

EDIT 3: Avoid running Kerberos KDC (the DC), client and server on the same machine. That is a classic recipe for getting the "Defective token error" even if you've done everything else right.

编辑4 :(经过OP验证的最终更新):查看了新的ktpass keytab创建输出,并且我看到了:定位域控制器:WIN-OVV6VHBGIB8.fusionis.life.现在,密钥表中定义的SPN是HTTP/kerberos500.nickis.life. AD域名与您定义的SPN不同,因此,除非您在这些域之间建立了某种信任关系,否则它将无法正常工作.如果没有信任关系,则需要使用HTTP/kerberos500.fusionis.life的SPN.

EDIT 4: (Final update which was verified by the OP): Looked at the new ktpass keytab creation output, and I saw this: Targeting domain controller: WIN-OVV6VHBGIB8.fusionis.life. Now, the defined SPN in the keytab is HTTP/kerberos500.nickis.life. The AD domain name is different from the SPN you defined, so this is not going to work unless you have some kind of trust setup between these domains. If you don't have a trust, you need to use an SPN of HTTP/kerberos500.fusionis.life instead.