我想在我的Java应用程序中使用Windows NTLM身份验证来透明地验证Intranet用户。如果使用浏览器(单点登录),用户不应该注意任何身份验证。
我找到了一些支持NTLM的库,但不知道使用哪一个:
有什么建议从哪里开始?
答案 0 :(得分:10)
在上面的列表中,只有ntlmv2-auth和Jespa支持NTLMv2。 Jespa是可行但商业化的。 ntlmv2-auth我还没有尝试,但它基于Liferay的代码,我以前见过它。
'ntlm-authentication-in-java'只是NTLMv1,它是旧的,不安全的,并且随着人们升级到较新的Windows版本而在不断减少的环境中工作。 JCIFS曾经有一个NTLMv1 HTTP身份验证过滤器,但它在以后的版本中被删除,因为它的实现方式相当于对不安全协议的中间人攻击。 (“ntlm-authentication-in-java”也是如此。)
'spnego'项目是Kerberos而不是NTLM。如果要在IIS执行时复制完整的IWA,则需要同时支持NTLMv2和Kerberos('NTLM'auth,'Negotiate'auth,NTLMSSP-in-SPNego auth和NTLM-masquerading-as-Negotiate auth)。
答案 1 :(得分:3)
Luigi Dragone的剧本很老,似乎总是失败。
如果您添加库jcifs,HttpURLConnection可以与NTLM一起使用,此示例适用于最新的jcifs-1.3.18:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.impl.auth.NTLMEngineException;
public class TestNTLMConnection {
public static void main(String[] args) throws UnknownHostException, IOException, NTLMEngineException {
// Method 1 : authentication in URL
jcifs.Config.registerSmbURLHandler();
URL urlRequest = new URL("http://domain%5Cuser:pass@127.0.0.1/");
// or Method 2 : authentication via System.setProperty()
// System.setProperty("http.auth.ntlm.domain", "domain");
// System.setProperty("jcifs.smb.client.domain", "domain");
// System.setProperty("jcifs.smb.client.username", "user");
// System.setProperty("jcifs.smb.client.password", "pass");
// Not verified // System.setProperty("jcifs.netbios.hostname", "host");
// System.setProperty("java.protocol.handler.pkgs", "jcifs");
// URL urlRequest = new URL("http://127.0.0.1:8180/simulate_get.php");
HttpURLConnection conn = (HttpURLConnection) urlRequest.openConnection();
StringBuilder response = new StringBuilder();
try {
InputStream stream = conn.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String str = "";
while ((str = in.readLine()) != null) {
response.append(str);
}
in.close();
System.out.println(response);
} catch(IOException err) {
System.out.println(err);
} finally {
Map<String, String> msgResponse = new HashMap<String, String>();
for (int i = 0;; i++) {
String headerName = conn.getHeaderFieldKey(i);
String headerValue = conn.getHeaderField(i);
if (headerName == null && headerValue == null) {
break;
}
msgResponse.put(headerName == null ? "Method" : headerName, headerValue);
}
System.out.println(msgResponse);
}
}
}
如果您对每次握手的内容感到好奇,可以在thread上找到另一个使用jcifs和Socket的示例。
答案 2 :(得分:0)
相对于你给出的清单,我会选择JCIFS。 图书馆很成熟,文档很好。 最重要的是,他们有相当规律的发布,最后一个是2011年11月。
Personal Experience
:与我尝试的其他人(spnego和ntmv2auth)相比,开始起来相当容易
答案 3 :(得分:0)
参考:https://jcifs.samba.org/src/docs/faq.html#ntlmv2
问:jCIFS是否支持NTLMv2?
A:是的。从1.3.0开始,JCIFS完全支持NTLMv2并默认使用它。
注意:以前包含在JCIFS中的NTLM HTTP SSO过滤器不支持NTLMv2。
答案 4 :(得分:0)
最近不得不在工作中实现这一点,因此这里是使用 Spring 的 RestTemplate 更新的解决方案:
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
public class Runner {
public static void main(String[] args) {
var credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new NTCredentials("username", "password", "", "someDomain"));
try (var client = HttpClients.custom()
.setDefaultCredentialsProvider(credentialsProvider)
.build();) {
var requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(client);
RestTemplate restTemplate = new RestTemplate(requestFactory);
ResponseEntity<String> stringResponseEntity = restTemplate.postForEntity("url", new HttpEntity<>("yourDtoObject"), String.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}
需要的依赖是:spring-web
和 org.apache.httpcomponents
ps:输入不带域的用户名很重要,否则它不起作用。就像您的域是 companyName/username 通常人们只是输入整个内容作为用户名,您应该做的是分别输入它们,其中 domain="companyName" 和 username="username"