JCIFS NTLM库的替代品

时间:2009-02-23 08:00:35

标签: java ntlm jcifs josso

JCIFS NTLM库有其他选择吗?

7 个答案:

答案 0 :(得分:11)

华夫饼 - https://github.com/dblock/waffle

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

答案 1 :(得分:3)

说实话,你不应该找一个。对于您的SSO需求,您应该使用适当的kerberos / SPNEGO而不是传统的NTLM。

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

答案 2 :(得分:3)

实际上jcifs很好,您可以使用Windows IIS和保持活动的Java Socket在本地轻松测试4-way handshake

这个2004年的Apache pseudo code对于使用generateType1Msg()generateType3Msg()的jcifs构建算法非常有用,甚至Apache也会提升example作为HttpClient的替代。

2004年的旧Apache代码可以运行,但身份验证不稳定,频繁得到HTTP/1.1 401 Unauthorized,Luigi Dragone的这个really old代码也不再有效。另一方面,Apache的HttpClient运行顺利,但握手是在场景后完成的(fyi .HttpClient需要new NTCredentials()来定义用户的身份验证)。

这是一个在没有域的端口81上在IIS上本地测试握手的示例。如果您不使用IIS,则需要适当更改hostportuserpassword以及HTTP标头,最终WWW-Authenticate

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());
    }
}

答案 3 :(得分:2)

我认为NTLM正在被弃用,而有利于Kerberos / SPNEGO。看看SPNEGO HTTP Servlet Filter项目,看看它是否符合您的需求。

答案 4 :(得分:1)

jespa www.ioplex.com是我遇到过的唯一一个。 从未使用过它

答案 5 :(得分:1)

Java开源单点登录(JOSSO)位于http://www.josso.org/ 他们在NTLM上有一个页面,虽然我不确定它有多好用。

答案 6 :(得分:1)

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