Java 类型2响应后NTLM身份验证失败

Java 类型2响应后NTLM身份验证失败,java,ntlm,Java,Ntlm,我有一个带有SSO的站点,它使用NTLM身份验证,到目前为止它在XP和Win7(32位)上运行得非常好,但最近我的公司决定也使用Win7(64位)计算机。在这些PC上,握手在type 2消息之后结束,tomcat返回401。我不知道如何调查,也许这里有人能给我一些建议 这在servlet的doPost方法中: try { // NTLM Handshake // 1: Client --> Server | GET ... /

我有一个带有SSO的站点,它使用NTLM身份验证,到目前为止它在XP和Win7(32位)上运行得非常好,但最近我的公司决定也使用Win7(64位)计算机。在这些PC上,握手在type 2消息之后结束,tomcat返回401。我不知道如何调查,也许这里有人能给我一些建议

这在servlet的doPost方法中:

        try {
        // NTLM Handshake
        // 1: Client --> Server | GET ...
        // 2: Client <-- Server | 401 Unauthorized/WWW-Authenticate: NTLM

        String auth = request.getHeader("Authorization");
        if (auth == null) {
            response.setStatus(response.SC_UNAUTHORIZED);
            response.setHeader("WWW-Authenticate", "NTLM");
            response.flushBuffer();
            return;
        }
        if (auth.startsWith("NTLM ")) {
            byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth
                    .substring(5));
            int off = 0, length, offset;

            // 3: Client --> Server | GET .../Authorization: NTLM
            // <base64-encoded type-1-message>
            if (msg[8] == 1) {
                // 4: Client <-- Server | 401 Unauthorized/WWW-Authenticate:
                // NTLM <base64-encoded type-2-message>
                byte z = 0;
                byte[] msg1 = { (byte) 'N', (byte) 'T', (byte) 'L',
                        (byte) 'M', (byte) 'S', (byte) 'S', (byte) 'P', z,
                        (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z,
                        (byte) 1, (byte) 130, z, z, z, (byte) 2, (byte) 2,
                        (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z };

                response.setHeader("WWW-Authenticate", "NTLM "
                        + new sun.misc.BASE64Encoder().encodeBuffer(msg1));
                //response.sendError(response.SC_UNAUTHORIZED);
                response.setStatus(response.SC_UNAUTHORIZED);
                response.flushBuffer();
                return;
            }
            // 5: Client --> Server | GET .../Authorization: NTLM
            // <base64-encoded type-3-message>
            else if (msg[8] == 3) {
                off = 30;

                length = msg[off + 17] * 256 + msg[off + 16];
                offset = msg[off + 19] * 256 + msg[off + 18];
                String remoteHost = new String(msg, offset, length);

                length = msg[off + 1] * 256 + msg[off];
                offset = msg[off + 3] * 256 + msg[off + 2];
                String domain = new String(msg, offset, length);

                for (int i = 0; i < domain.length(); i += 2)
                    loginDomain += domain.charAt(i);

                length = msg[off + 9] * 256 + msg[off + 8];
                offset = msg[off + 11] * 256 + msg[off + 10];
                String username = new String(msg, offset, length);

                for (int i = 0; i < username.length(); i += 2)
                    loginUser += username.charAt(i);
            }
        }
    } catch (Exception se) {
        log.error(loginUser + ", NTLM handshake exception:", se);
    }
试试看{
//NTLM握手
//1:客户端-->服务器|获取。。。
//2:客户端服务器|获取…/授权:NTLM
// 
如果(消息[8]==1){
//4:客户端服务器|获取…/授权:NTLM
// 
否则如果(消息[8]==3){
关=30;
长度=msg[off+17]*256+msg[off+16];
偏移量=msg[off+19]*256+msg[off+18];
String remoteHost=新字符串(消息、偏移量、长度);
长度=msg[off+1]*256+msg[off];
偏移量=msg[off+3]*256+msg[off+2];
字符串域=新字符串(消息、偏移量、长度);
对于(int i=0;i
这是64位PC上的一个政策问题,因为NTLMv2是强制的。解决方案是在安全策略中禁用这些设置

•运行“secpol.msc”这将打开一个名为“本地安全策略”的窗口

•安全设置>本地策略>安全选项>“网络安全:基于NTLM SSP的最低会话安全…”

有两个类似的条目是这样开始的,分别是open和uncheck“requirentlmv2sessionsecurity”


至少我们使用的是NTLMv1:|

大多数公司网络将转移到NTLMv2。我们不久前遇到了这个问题,并从中获得了Jespa。只要您有一个Servlet堆栈,它就可以正常工作。如果您使用的是非Java EE堆栈(如Play),我不知道除了拒绝对NTLMv1的支持之外还有什么解决方案。

如果您仍然想坚持使用JCIFS,请尝试这些链接以克服“无效参数错误”和“无法与合适的域控制器协商”。 它与NTLM配合使用,但不能保证与NTLMv2配合使用时更安全

“无效参数”

“无法与适当的域控制器协商” 试试这个

使用以下代码启用NTLM扩展安全性

byte[] msg1 = {
  (byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M',
  (byte) 'S', (byte) 'S', (byte) 'P',
  z, (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z,
  (byte) 1, (byte) 130, **(byte) 8**, z, z, (byte) 2, (byte) 2,
  (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z 
};

你说的是“验证”,但你并没有真正检查这里的密码。。。!?!似乎你真的只想从NTLM消息中获取用户名?@EdwardThomson NTLM auth不需要密码。NTLM是一个质询/响应协议。@MatthiasHerlitzius是的,但客户端使用密码来形成质询。因此,服务器实际上应该查看响应以进行身份验证,而不仅仅是假设因为您得到了一些响应,所以它必须是有效的响应。这里没有身份验证。@EdwardThomson你说得对,问题是我只想得到用户名。Ntlm分3步提供给您,但在我们的win 7 64位PC上,过程在第2步后停止,没有第3步请求。如果您实际使用提供的用户名执行任何有意义的操作,则上述代码是一个巨大的安全漏洞。任何人都可以用他们想要的任何用户名构建并提交NTLM type 3消息。需要使用AD域控制器的NETLOGON服务验证类型3消息的代码。否则,这里不会进行身份验证。这只是一扇没有锁的门。当我调查这个问题时,我及时检查了Jespa,但由于您必须购买它,所以这不是一个选项,我的经理告诉我找到一个免费的解决方案。:)不管怎么说,大多数链接都指向这个解决方案,所以我想如果有人认真对待这个NTLM,最终会得到它。欢迎来到Stack Overflow!我刚刚改进了你文章中的一些拼写。最好包括网站上的相关信息,以防万一,而不是仅仅发布链接。您可以编辑您的答案以包含相关信息吗?这会增加任何安全漏洞吗?是的,有更多最新的SSO解决方案(如kerberos),但是如果您有一个复杂的、需要更改的web应用程序正在使用NTLM1,您可以进行风险分析,无论是否值得启用NTLM1或投入开发。假装NTLM握手并不是一件小事,没有多少用户具备这样做的技能。所以不要将其用于财务解决方案,但您可以将其用于网站,例如网球场预订。谢谢!我曾使用类似于海报问题的代码在java webapp中提取用户用户名。它停止了与运行windows 10的机器的工作。您的更改(在(字节)130之后使用(字节)8)修复了问题。你能解释一下你到底是如何找到这个解决方案的吗?我一直在探索为什么我发布的类似于OP的代码对一些用户不起作用,这也解决了我的问题。正如@user467257所说,很高兴知道这个解决方案是如何产生的以及为什么它是必要的。