JCIFS NTLM 库的替代方案

发布于 2024-07-14 18:59:30 字数 26 浏览 9 评论 0原文

JCIFS NTLM 库有其他选择吗?

Are there any alternatives for JCIFS NTLM library?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

箹锭⒈辈孓 2024-07-21 18:59:30

Waffle - https://github.com/dblock/waffle

具有过滤器、验证器、支持 spring-security等。仅限 Windows,但不需要本机 DLL。

Waffle - https://github.com/dblock/waffle

Has filters, authenticators, supports spring-security, etc. Windows-only, but doesn't require native DLLs.

呢古 2024-07-21 18:59:30

说实话,你不应该寻找一个。 为了满足您的 SSO 需求,您应该使用适当的 kerberos / SPNEGO 而不是旧版 NTLM。

对于这些东西,您不需要特殊的库,因为 JVM 已经可以自动执行此操作。 您所要做的就是正确配置应用程序和 JVM 安全策略。 Sun 的官方文档应该为您提供所需的所有详细信息,只需浏览“安全 API”部分即可。

To be honest, you should not look for one. For your SSO needs you should use proper kerberos / SPNEGO instead of the legacy NTLM.

For that stuff you need no special libraries as JVMs are already enabled for doing that automatically. All you have to do is to configure your application and JVM security policies properly. The official documentation from Sun should give you all the details you need, just browse the "security APIs" section.

吖咩 2024-07-21 18:59:30

实际上 jcifs 很好,您可以轻松测试 4 次握手 在本地与 Windows IIS 和保持活动的 java 套接字。

这个 2004 Apache 伪代码对于使用 generateType1Msg()generateType3Msg() 构建 jcifs 算法非常有用,甚至 Apache 也推出了 示例 作为 HttpClient 的替代方案。

2004 年的旧 Apache 代码可以工作,但身份验证不稳定,您经常会收到 HTTP/1.1 401 Unauthorized ,还有这个 来自 Luigi Dragone 的非常旧的代码不再工作了。 另一方面,Apache 的 HttpClient 运行平稳,但握手是在幕后完成的(仅供参考。HttpClient 需要 new NTCredentials() 来定义用户的身份验证)。

下面是在 IIS 上本地测试握手的示例,端口 81 上没有域。 您需要适当地更改 hostportuserpassword 以及 HTTP 标头,最终 WWW -如果您不使用 IIS,请进行身份验证

HTTP/1.1 200 OK 表示身份验证正确,否则您将得到 HTTP/1.1 401 Unauthorized

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import jcifs.ntlmssp.NtlmFlags;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.util.Base64;

import org.apache.http.impl.auth.NTLMEngineException;

public class TestNTLM {

    public static void main(String[] args) throws UnknownHostException, IOException, NTLMEngineException {
        Socket s = new Socket("127.0.0.1", 81);
        s.setKeepAlive(true);
        InputStream is = s.getInputStream();
        OutputStream os = s.getOutputStream();
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os));

        String host = "127.0.0.1:81";
        String hostDomain = "";
        String user = "My_Windows_Username";
        String password = "My_Windows_Password";

        w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
        w.write("Host: 127.0.0.1:81\n");
        w.write("Authorization: NTLM " + TestNTLM.generateType1Msg(hostDomain, host) + "\n\n");
        System.out.println("[First Message Sent]");
        w.flush();

        String resp = "", line = "";
        int contentLength = 0;
        while((line = r.readLine()) != null){
            if(line.length() == 0)
                break;
            System.out.println(line);
            if(line.startsWith("Content-Length"))
                contentLength = Integer.parseInt(line.substring(line.indexOf(":") + 1).trim());
            else if(line.startsWith("WWW-Authenticate"))
                resp = line.substring(line.indexOf(":") + 1).trim();
        }
        r.skip(contentLength);

        System.out.println("\n[Second Message Received]");
        System.out.println("Proxy-Authenticate: " + resp);
        resp = resp.substring(resp.indexOf(" ")).trim();

        w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
        w.write("Host: 127.0.0.1:81\n");
        w.write("Authorization: NTLM " + TestNTLM.generateType3Msg(user, password, hostDomain, host, new String(resp)) + "\n\n");

        w.flush();
        System.out.println("\n[Third Message Sent]");

        while((line = r.readLine()) != null){
            System.out.println(line);
            if(line.length() == 0)
                break;
        }
    }

    private static final int TYPE_1_FLAGS = 
            NtlmFlags.NTLMSSP_NEGOTIATE_56 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_128 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | 
            NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public static String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return Base64.encode(type1Message.toByteArray());
    }

    public static String generateType3Msg(final String username, final String password,
            final String domain, final String workstation, final String challenge)
                    throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, password, domain,
                username, workstation, type3Flags);
        return Base64.encode(type3Message.toByteArray());
    }
}

Actually jcifs is good and you can test easily the 4-way handshake locally with Windows IIS and a keep alive java Socket.

This 2004 Apache pseudo code is useful to build the algorithm with jcifs using generateType1Msg() and generateType3Msg(), even Apache promotes an example as an alternative to HttpClient.

The old Apache code from 2004 works but authentication is unstable, you get HTTP/1.1 401 Unauthorized frequently, also this really old code from Luigi Dragone does not work anymore. On the other hand Apache's HttpClient runs smoothly but the handshake is done behind the scene (fyi. HttpClient requires new NTCredentials() to define user's authentication).

Here's an example to test the handshake locally on IIS, on port 81 without a domain. You need to change the host, port, user and password and HTTP headers appropriately, eventually WWW-Authenticate if you are not using IIS.

HTTP/1.1 200 OK means the authentication is correct, otherwise you get HTTP/1.1 401 Unauthorized.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import jcifs.ntlmssp.NtlmFlags;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.util.Base64;

import org.apache.http.impl.auth.NTLMEngineException;

public class TestNTLM {

    public static void main(String[] args) throws UnknownHostException, IOException, NTLMEngineException {
        Socket s = new Socket("127.0.0.1", 81);
        s.setKeepAlive(true);
        InputStream is = s.getInputStream();
        OutputStream os = s.getOutputStream();
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(os));

        String host = "127.0.0.1:81";
        String hostDomain = "";
        String user = "My_Windows_Username";
        String password = "My_Windows_Password";

        w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
        w.write("Host: 127.0.0.1:81\n");
        w.write("Authorization: NTLM " + TestNTLM.generateType1Msg(hostDomain, host) + "\n\n");
        System.out.println("[First Message Sent]");
        w.flush();

        String resp = "", line = "";
        int contentLength = 0;
        while((line = r.readLine()) != null){
            if(line.length() == 0)
                break;
            System.out.println(line);
            if(line.startsWith("Content-Length"))
                contentLength = Integer.parseInt(line.substring(line.indexOf(":") + 1).trim());
            else if(line.startsWith("WWW-Authenticate"))
                resp = line.substring(line.indexOf(":") + 1).trim();
        }
        r.skip(contentLength);

        System.out.println("\n[Second Message Received]");
        System.out.println("Proxy-Authenticate: " + resp);
        resp = resp.substring(resp.indexOf(" ")).trim();

        w.write("GET http://127.0.0.1:81/ HTTP/1.1\n");
        w.write("Host: 127.0.0.1:81\n");
        w.write("Authorization: NTLM " + TestNTLM.generateType3Msg(user, password, hostDomain, host, new String(resp)) + "\n\n");

        w.flush();
        System.out.println("\n[Third Message Sent]");

        while((line = r.readLine()) != null){
            System.out.println(line);
            if(line.length() == 0)
                break;
        }
    }

    private static final int TYPE_1_FLAGS = 
            NtlmFlags.NTLMSSP_NEGOTIATE_56 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_128 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 | 
            NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | 
            NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public static String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return Base64.encode(type1Message.toByteArray());
    }

    public static String generateType3Msg(final String username, final String password,
            final String domain, final String workstation, final String challenge)
                    throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, password, domain,
                username, workstation, type3Flags);
        return Base64.encode(type3Message.toByteArray());
    }
}
一个人的夜不怕黑 2024-07-21 18:59:30

我认为 NTLM 已被弃用,取而代之的是 Kerberos/SPNEGO。 查看 SPNEGO HTTP Servlet Filter 项目,看看它是否适合您的需求。

I think NTLM is being deprecated in favor of Kerberos/SPNEGO. Take a look at the SPNEGO HTTP Servlet Filter project to see if it might fit your needs.

⒈起吃苦の倖褔 2024-07-21 18:59:30

jespa www.ioplex.com 是我遇到的唯一一个。
虽然没用过

jespa www.ioplex.com is the only one I've come across.
Never used it though

兰花执着 2024-07-21 18:59:30

Java 开源单点登录 (JOSSO) 位于 http://www.josso.org/
他们有一个关于 NTLM 的页面,尽管我不确定它的效果如何。

Java Opensource Single Sign On (JOSSO) is at http://www.josso.org/
They have a page on NTLM, although I'm not sure how well it works.

抽个烟儿 2024-07-21 18:59:30

如果您不介意商业包装产品,请查看:Quest Single Sign On for Java,提供对 SPNEGO/Kerberos(包括站点和 S4U 协议)以及 NTLM 的支持。

If you don't mind a commercially packaged product then take a look at: Quest Single Sign On for Java which provides support for SPNEGO/Kerberos (including sites and S4U protocols) as well as NTLM.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文