Tomcat 8 和 Windows non-domain 用户的 NTLM 身份验证
Tomcat 8 and Windows NTLM authentication for non-domain user
我们有 Tomcat 8 个应用程序配置了 Windows 身份验证 (IWA),带有 SPNEGO 身份验证器、密钥表和 SPN。
它适用于域用户 - 他们在不使用 Kerberos 提示用户和密码的情况下进行身份验证。
对于 non-domain 用户,我们希望通过使用本机浏览器弹出窗口输入用户名和密码来允许身份验证。看来,tomcat 应该在这种情况下使用 NTLM。
然而,当 non-domain 用户在浏览器弹出窗口中输入登录名和密码时 - 它再次出现并且 tomcat 日志中存在异常:
2017-01-24 05:15:46,910 [http-nio-127.0.0.1-8455-exec-9] DEBUG org.apache.catalina.authenticator.SpnegoAuthenticator- 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.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.catalina.authenticator.SpnegoAuthenticator.authenticate(SpnegoAuthenticator.java:230)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577)
at com.avaya.cas.auth.authenticator.IViewTokenAuthenticator.invoke(IViewTokenAuthenticator.java:212)
at com.avaya.cas.ssl.valves.SSLValve.invoke(SSLValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
at sun.security.jgss.GSSHeader.<init>(GSSHeader.java:97)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:306)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:323)
at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:310)
... 20 more
有一段GSSHeader的代码:
int var2 = decodedHeader.read();
if(var2 != 96) {
throw new GSSException(10, -1, "GSSHeader did not find the right tag");
在我的例子中,var2 是 78('N' 字符)
decodedHeader- 是标准的第一个 NTLM 消息,它是在授权 header 中从浏览器发送的。
在我的例子中是:
授权:协商 TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKADk4AAAADw==
解码后会是'NTLMSSP...binary data...'。
因此,此消息的第一个字节始终是 'N'(78) 而不是 96,正如 Tomcat 的代码所预期的那样。
Tomcat是否支持 NTLM 身份验证?这很奇怪,因为可以对域用户进行身份验证(这意味着 Tomcat 可以使用提供的密钥表解密来自用户的质询)
这里是 SPNEGO 代码的捐赠者。
GSSHeader did not find the right tag
表示客户端没有发送任何SPNEGO token; you receive a pure NTLM token。当 Kerberos 由于某种原因失败时会发生这种情况,这就是您的情况。
NTLM 非常不同并且非常专有。在这种情况下,服务器充当中间人,将哈希值从客户端传递到域控制器。服务器本身不能做任何事情。 Tomcat 无法解密任何内容 without the help of a domain controller。此外,除了 Samba 的内部代码之外,没有已知的 NTLM server-side 实现可作为开源(尤其是 Java 中没有)。
结果:forget about NTLM and do what I recommend here。
注意:有IAKERB这种场景,但只有MIT Kerberos,顶多Heimdal支持
我们有 Tomcat 8 个应用程序配置了 Windows 身份验证 (IWA),带有 SPNEGO 身份验证器、密钥表和 SPN。 它适用于域用户 - 他们在不使用 Kerberos 提示用户和密码的情况下进行身份验证。 对于 non-domain 用户,我们希望通过使用本机浏览器弹出窗口输入用户名和密码来允许身份验证。看来,tomcat 应该在这种情况下使用 NTLM。 然而,当 non-domain 用户在浏览器弹出窗口中输入登录名和密码时 - 它再次出现并且 tomcat 日志中存在异常:
2017-01-24 05:15:46,910 [http-nio-127.0.0.1-8455-exec-9] DEBUG org.apache.catalina.authenticator.SpnegoAuthenticator- 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.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.catalina.authenticator.SpnegoAuthenticator.authenticate(SpnegoAuthenticator.java:230)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577)
at com.avaya.cas.auth.authenticator.IViewTokenAuthenticator.invoke(IViewTokenAuthenticator.java:212)
at com.avaya.cas.ssl.valves.SSLValve.invoke(SSLValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: GSSException: Defective token detected (Mechanism level: GSSHeader did not find the right tag)
at sun.security.jgss.GSSHeader.<init>(GSSHeader.java:97)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:306)
at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:323)
at org.apache.catalina.authenticator.SpnegoAuthenticator$AcceptAction.run(SpnegoAuthenticator.java:310)
... 20 more
有一段GSSHeader的代码:
int var2 = decodedHeader.read();
if(var2 != 96) {
throw new GSSException(10, -1, "GSSHeader did not find the right tag");
在我的例子中,var2 是 78('N' 字符) decodedHeader- 是标准的第一个 NTLM 消息,它是在授权 header 中从浏览器发送的。 在我的例子中是:
授权:协商 TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKADk4AAAADw==
解码后会是'NTLMSSP...binary data...'。 因此,此消息的第一个字节始终是 'N'(78) 而不是 96,正如 Tomcat 的代码所预期的那样。
Tomcat是否支持 NTLM 身份验证?这很奇怪,因为可以对域用户进行身份验证(这意味着 Tomcat 可以使用提供的密钥表解密来自用户的质询)
这里是 SPNEGO 代码的捐赠者。
GSSHeader did not find the right tag
表示客户端没有发送任何SPNEGO token; you receive a pure NTLM token。当 Kerberos 由于某种原因失败时会发生这种情况,这就是您的情况。
NTLM 非常不同并且非常专有。在这种情况下,服务器充当中间人,将哈希值从客户端传递到域控制器。服务器本身不能做任何事情。 Tomcat 无法解密任何内容 without the help of a domain controller。此外,除了 Samba 的内部代码之外,没有已知的 NTLM server-side 实现可作为开源(尤其是 Java 中没有)。
结果:forget about NTLM and do what I recommend here。
注意:有IAKERB这种场景,但只有MIT Kerberos,顶多Heimdal支持