You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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�@&gt;NTLMSSP���6( ]XRANGESH-PT6XXXYYY"
  • 非Tomcat部署机器的虚拟机访问时的令牌:
"Negotiate TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKAGNFAAAADw=="

解决方案

一、认证终止的原因分析

日志中的GSSException: Defective token detected表明客户端发送的Negotiate令牌不符合Kerberos/SPNEGO规范,具体是GSS头格式错误。结合客户端令牌内容来看:

  1. 本地机器的令牌包含NTLMSSP字样,说明客户端优先发送了NTLM令牌而非Kerberos令牌,Tomcat的SPNEGO认证无法解析NTLM格式的令牌,导致认证失败后触发BasicAuth fallback。
  2. 远程虚拟机的令牌是NTLM协商的初始请求(TlRMTVNTUAAB是NTLM令牌的标识),同样没有发送Kerberos令牌。
  3. 认证流程中出现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区域。
    • 进入自定义级别 → 用户验证,选择“自动登录当前用户名和密码”。
  • 域组策略配置:
    • 在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区域。
  • 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中添加参数指定配置文件路径:
    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
    
    确保Tomcat进程有读取这些文件的权限。
  • 禁用BasicAuth fallback:在Tomcat的context.xml中添加SPNEGO Valve配置,强制拒绝BasicAuth:
    <Valve className="org.apache.catalina.authenticator.SpnegoAuthenticator"
           disableBasicAuth="true" />
    

三、验证步骤

  1. 在客户端执行klist purge清除本地票据缓存,重新访问应用。
  2. 检查catalina.out日志,若出现Successfully authenticated user字样则认证成功。
  3. 查看客户端发送的Negotiate令牌,开头为YIG则说明是正确的Kerberos令牌。

内容的提问来源于stack exchange,提问作者rangesh a

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:14:54