Alternatives for JCIFS NTLM library
Asked Answered
H

7

19

Are there any alternatives for JCIFS NTLM library?

Hawkes answered 23/2, 2009 at 8:0 Comment(1)
Please see my suggestions in my answer to this question.Forewoman
B
11

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

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

Balling answered 21/5, 2010 at 11:6 Comment(0)
G
3

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.

Goddord answered 18/7, 2009 at 22:11 Comment(2)
NTLM is not a "legacy" mechanism. NTLM is required if the client cannot get a Kerberos ticket which unfortunately happens all too easily. In fact, Kerberos is rather fragile and difficult to use by comparison. And NTLMv2 is just as secure (128 bit RC4 vs. 256 bit AES really doesn't matter much). If you need to do client-side NTLM, JCIFS is fully functional (albeit it is not fully documented - ask on the mailing list). If you need server-side NTLM such as for HTTP SSO, Jespa is the way to go.Selfeffacement
Note that Jespa is not free software.Varicella
O
3

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());
    }
}
Ostrander answered 14/12, 2015 at 21:0 Comment(0)
B
2

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.

Badtempered answered 4/11, 2009 at 16:31 Comment(0)
C
1

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

Charmer answered 27/5, 2009 at 16:51 Comment(0)
Z
1

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.

Zymolysis answered 9/1, 2010 at 11:1 Comment(0)
S
1

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.

Spectroradiometer answered 1/6, 2010 at 11:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.