Tomcat10内置SPNEGO+Kerberos WebSSO配置异常,请求排查
问题描述
正在为Tomcat 10配置基于Kerberos的内置SPNEGO认证以实现WebSSO,访问应用时弹出HTTP BasicAuth对话框,catalina.out中出现调试日志(见下文)。keytab文件pt6.keytab包含已在AD服务器上注册的主体(通过ktpass.exe和setspn.exe完成)。开启Kerberos调试模式后,无法定位问题,认证流程在出现“Entering logout”后终止,需明确认证终止的环节及原因,同时解决所有机器访问时返回Kerberos令牌的问题。
环境说明:
应用部署在已加入公司域(xxxyyy.com)的本地机器上,同一机器中运行着域控制器(DC)虚拟机(xxx.com)。
已尝试操作:
- 使用主机名而非IP地址访问应用
- 将Tomcat部署到已加入域(xxx.com)的另一虚拟机
- 将
krb5.ini放置在C:/windows目录下
日志及配置文件
CATALINA.OUT
15-Apr-2023 20:45:52.151 FINE [http-nio-8080-exec-1] org.apache.catalina.authenticator.SpnegoAuthenticator.doAuthenticate No authorization header sent by client Debug is true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator true KeyTab is C:/Program Files/Apache Software Foundation/Tomcat 10.0/conf/pt6115.keytab refreshKrb5Config is false principal is HTTP/RANGESH-PT6.XXXYYY.COM@XXX.COM tryFirstPass is false useFirstPass is false storePass is false clearPass is false principal is HTTP/RANGESH-PT6.XXXYYY.COM@XXX.COM Will use keytab Commit Succeeded 15-Apr-2023 20:45:52.311 FINE [http-nio-8080-exec-2] org.apache.catalina.authenticator.SpnegoAuthenticator.doAuthenticate Unable to login as the service principal java.security.PrivilegedActionException: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag) at java.base/java.security.AccessController.doPrivileged(AccessController.java:716) at java.base/javax.security.auth.Subject.doAs(Subject.java:533) at org.apache.catalina.authenticator.SpnegoAuthenticator.doAuthenticate(SpnegoAuthenticator.java:226) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:626) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:870) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1762) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:1589) Caused by: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag) at java.security.jgss/sun.security.jgss.GSSHeader.<init>(GSSHeader.java:97) at java.security.jgss/sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:325) at java.security.jgss/sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:303) at java.security.jgss/sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:903) at java.security.jgss/sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:557) at java.security.jgss/sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:361) at java.security.jgss/sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:303) at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:326) at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:313) at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) ... 17 more [Krb5LoginModule]: Entering logout [Krb5LoginModule]: logged out Subject
KRB5.INI
[libdefaults] default_realm = XXX.COM default_keytab_name = FILE:C:\Program Files\Apache Software Foundation\Tomcat 10.0\conf\pt6.keytab default_tkt_enctypes = rc4-hmac,aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 default_tgs_enctypes = rc4-hmac,aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 forwardable=true [realms] ZOHOR.COM = { kdc = win-971madet2qs.zohor.com admin_server = win-971madet2qs.zohor.com } [domain_realm] .xxx.com = XXX.COM xxx.com = XXX.COM
JAAS.CONF
com.sun.security.jgss.krb5.initiate { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/RANGESH-PT6.XXXYYY.COM@XXX.COM" useKeyTab=true keyTab="C:/Program Files/Apache Software Foundation/Tomcat 10.0/conf/pt6.keytab" storeKey=true debug=true moduleBanner=true; }; com.sun.security.jgss.krb5.accept { com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=true principal="HTTP/RANGESH-PT6.XXXYYY.COM@XXX.COM" useKeyTab=true keyTab="C:/Program Files/Apache Software Foundation/Tomcat 10.0/conf/pt6.keytab" storeKey=true debug=true moduleBanner=true; };
客户端令牌信息
- 本地机器访问时的令牌:
"Negotiate YIGABgYrBgEFBQKgdjB0oDAwLgYKKwYBBAGCNwICCgYJKoZIgvcSAQICBgkqhkiG9xIBAgIGCisGAQQBgjcCAh6iQAQ+TlRMTVNTUAABAAAAl7II4ggACAA2AAAADgAOACgAAAAKAF1YAAAAD1JBTkdFU0gtUFQ2MTE1Wk9IT0NPUlA= Credentials=`��+�v0t�00. +�7 *�H�� *�H�� +�7�@>NTLMSSP���6( ]XRANGESH-PT6XXXYYY"
- 非Tomcat部署机器的虚拟机访问时的令牌:
"Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKAGNFAAAADw=="
解决方案
一、认证终止的原因分析
日志中的GSSException: Defective token detected表明客户端发送的Negotiate令牌不符合Kerberos/SPNEGO规范,具体是GSS头格式错误。结合客户端令牌内容来看:
- 本地机器的令牌包含
NTLMSSP字样,说明客户端优先发送了NTLM令牌而非Kerberos令牌,Tomcat的SPNEGO认证无法解析NTLM格式的令牌,导致认证失败后触发BasicAuth fallback。 - 远程虚拟机的令牌是NTLM协商的初始请求(
TlRMTVNTUAAB是NTLM令牌的标识),同样没有发送Kerberos令牌。 - 认证流程中出现
Entering logout是因为服务端无法处理无效令牌,主动终止了当前的GSS上下文,完成登录模块的注销操作。
二、核心问题解决步骤
1. 修正域配置与SPN一致性
- 检查SPN注册:执行
setspn -L 服务账号,确认AD中存在HTTP/RANGESH-PT6.XXXYYY.COM,且该SPN唯一绑定到生成keytab的服务账号(避免SPN重复导致认证失败)。 - krb5.ini修正:当前
[realms]块中的ZOHOR.COM与实际域XXX.COM不符,替换为正确配置:
补充应用域名的映射规则:[realms] XXX.COM = { kdc = 你的DC虚拟机主机名或IP(如win-971madet2qs.xxx.com) admin_server = 你的DC虚拟机主机名或IP }[domain_realm] .xxxyyy.com = XXX.COM xxxyyy.com = XXX.COM .xxx.com = XXX.COM xxx.com = XXX.COM
2. 强制客户端优先使用Kerberos
- 浏览器配置:
- 打开IE/Edge的Internet选项 → 安全 → 本地Intranet → 站点 → 高级,将应用URL(如
http://RANGESH-PT6.XXXYYY.COM)添加到本地Intranet区域。 - 进入自定义级别 → 用户验证,选择“自动登录当前用户名和密码”。
- 打开IE/Edge的Internet选项 → 安全 → 本地Intranet → 站点 → 高级,将应用URL(如
- 域组策略配置:
- 在DC上配置计算机策略:计算机配置 → 管理模板 → 系统 → Kerberos,启用“允许Kerberos明文身份验证”(若使用RC4-HMAC加密),并配置“指定Kerberos加密类型”包含
aes256-cts-hmac-sha1-96、aes128-cts-hmac-sha1-96和rc4-hmac。 - 配置用户策略:用户配置 → 管理模板 → Windows组件 → Internet Explorer → Internet控制面板 → 安全页面 → 本地Intranet区域,启用“站点到区域分配列表”并添加应用URL到本地Intranet区域。
- 在DC上配置计算机策略:计算机配置 → 管理模板 → 系统 → Kerberos,启用“允许Kerberos明文身份验证”(若使用RC4-HMAC加密),并配置“指定Kerberos加密类型”包含
- DNS/主机文件配置:确保所有客户端能正确解析
RANGESH-PT6.XXXYYY.COM到Tomcat服务器IP,DNS中需存在该主机名的A记录。
3. Tomcat配置优化
- keytab有效性验证:执行
kinit -kt pt6.keytab HTTP/RANGESH-PT6.XXXYYY.COM@XXX.COM,若能成功获取票据则说明keytab配置正确。 - JAAS配置简化:Tomcat作为服务端仅需
accept块,可移除initiate块减少配置复杂度。 - JVM参数设置:在
catalina.bat中添加参数指定配置文件路径:
确保Tomcat进程有读取这些文件的权限。set CATALINA_OPTS=-Djava.security.auth.login.config="C:\Program Files\Apache Software Foundation\Tomcat 10.0\conf\jaas.conf" -Djava.security.krb5.conf="C:\Program Files\Apache Software Foundation\Tomcat 10.0\conf\krb5.ini" -Dsun.security.krb5.debug=true - 禁用BasicAuth fallback:在Tomcat的
context.xml中添加SPNEGO Valve配置,强制拒绝BasicAuth:<Valve className="org.apache.catalina.authenticator.SpnegoAuthenticator" disableBasicAuth="true" />
三、验证步骤
- 在客户端执行
klist purge清除本地票据缓存,重新访问应用。 - 检查catalina.out日志,若出现
Successfully authenticated user字样则认证成功。 - 查看客户端发送的Negotiate令牌,开头为
YIG则说明是正确的Kerberos令牌。
内容的提问来源于stack exchange,提问作者rangesh a
相关产品推荐
相关产品推荐

