Are there any alternatives for JCIFS NTLM library?
Waffle - https://github.com/dblock/waffle
Has filters, authenticators, supports spring-security, etc. Windows-only, but doesn't require native DLLs.
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.
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());
}
}
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.
jespa www.ioplex.com is the only one I've come across. Never used it though
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.
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.
来源:https://stackoverflow.com/questions/576850/alternatives-for-jcifs-ntlm-library