我的客户的Java代码(胖客户端(需要通过网络代理访问web服务。网络代理需要身份验证。客户希望将静默身份验证作为当前Windows用户(单次登录,无密码提示!(。我做了很多研究,似乎大多数人在服务器端使用NTLMv2或Kerberos。但我需要在客户端进行网络代理身份验证。
我看到Java似乎支持开箱即用的Kerberos——这在这里看起来不错(但事实并非如此——我没有当前用户的密码(。
Java似乎也支持开箱即用的NTLM——这个和这个看起来很有趣。
不幸的是,这两种解决方案都需要我的代码提供用户名和密码。我不知道密码。我必须提示用户,但我不能这样做——根据规范,必须是静音。到目前为止,我发现的两种解决方案都不是沉默的!不过,我肯定需要静音单点登录。
因此,我想知道,我是否可以以某种方式使用Waffle或任何其他本机(=>JNA(lib来解决基于NTLMv2和Kerberos的代理身份验证的问题(需要user+pw(。如果这样的lib可以省去我们编写kerberos配置文件的工作,那也会很酷。
但我在华夫饼干的文档中没有发现这样的东西。华夫饼是我迄今为止发现的唯一一个本地库。我假设它必须是本机代码,因为其他任何东西都应该有安全屏障,阻止它获得当前用户的Kerberos票证(或NTLMv2中的类似令牌(。但是本机代码应该IMHO能够访问这样的身份验证令牌,因为本机OS-lib可以访问Windows-API,而Windows-API仅将当前用户的NTLM/Kerberos-token分发给当前用户。
AFAIK IE和其他本机程序能够通过NTLM/Kerberos保护的代理访问web服务。因此,这一定是可能的。
关于如何使用网络代理进行静默身份验证,有什么提示吗?
如果还没有现成的东西,也许你可以给我一些提示,如何使用Waffle或任何其他(本机,JNI/JNA(lib实现解决方案?
如果真的还没有解决方案,我甚至会使用JNA或JNI自己实现一个解决方案——你能给我一些正确方向的提示吗?我是一个GNU/Linux-guy,我不得不承认,我甚至不知道从哪里开始在Windows-API-文档中搜索这个。
Btw。我已经在华夫饼社区问过这个问题,但还没有得到任何答案。也许华夫饼不是最好的解决方案?也许还有更好的方法?
你写了很多,很少有实质性的东西。让我为你分解一下。
Java似乎也支持开箱即用的NTLM——这和这看起来很有趣。
这是错误的。这是专门为HttpUrlConnection
使用SSPI的专用实现。两者皆忘。
忘记NTLM吧,它是基于连接的,并且是专有的。使用Kerberos!
我不知道你在使用什么HTTP库,但方法很简单,你不需要Waffle,只需要JNA:
import java.io.IOException;
import java.util.Base64;
import org.apache.commons.io.HexDump;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import com.sun.jna.platform.win32.Secur32;
import com.sun.jna.platform.win32.Sspi;
import com.sun.jna.ptr.IntByReference;
public class SspiAuth {
public static void main(String[] args)
throws ArrayIndexOutOfBoundsException, IllegalArgumentException, IOException {
Sspi.CredHandle cred = new Sspi.CredHandle();
int status = Secur32.INSTANCE.AcquireCredentialsHandle(null, "Negotiate",
Sspi.SECPKG_CRED_OUTBOUND, null, null, null, null, cred, null);
System.out.println(status);
Sspi.CtxtHandle ctxt = new Sspi.CtxtHandle();
Sspi.SecBufferDesc bufferDesc = new Sspi.SecBufferDesc(Sspi.SECBUFFER_TOKEN,
Sspi.MAX_TOKEN_SIZE);
IntByReference ctxtAttrs = new IntByReference();
status = Secur32.INSTANCE.InitializeSecurityContext(cred, null,
"HTTP/<fqdn of the proxy>",
Sspi.ISC_REQ_MUTUAL_AUTH, 0, Sspi.SECURITY_NATIVE_DREP, null, 0, ctxt, bufferDesc,
ctxtAttrs, null);
System.out.println(status);
HexDump.dump(bufferDesc.getBytes(), 0, System.out, 0);
HttpClientBuilder builder = HttpClientBuilder.create();
try (CloseableHttpClient httpClient = builder.build()) {
HttpGet method = new HttpGet("https://deblndw024v.ad001.siemens.net:8444/manager/html");
method.addHeader("Authorization",
"Negotiate " + Base64.getEncoder().encodeToString(bufferDesc.getBytes()));
CloseableHttpResponse response = httpClient.execute(method);
EntityUtils.consumeQuietly(response.getEntity());
response.close();
System.out.println(response.getStatusLine());
String responseToken = response.getFirstHeader("WWW-Authenticate").getValue()
.substring(10);
System.out.println(responseToken);
byte[] rawResponseToken = Base64.getDecoder().decode(responseToken);
Sspi.SecBufferDesc bufferDesc2 = new Sspi.SecBufferDesc(Sspi.SECBUFFER_TOKEN,
rawResponseToken);
Sspi.CtxtHandle ctxt2 = new Sspi.CtxtHandle();
Sspi.SecBufferDesc bufferDesc3 = new Sspi.SecBufferDesc(Sspi.SECBUFFER_TOKEN,
Sspi.MAX_TOKEN_SIZE);
status = Secur32.INSTANCE.InitializeSecurityContext(cred, ctxt,
"HTTP/<fqdn of the proxy>",
Sspi.ISC_REQ_MUTUAL_AUTH, 0, Sspi.SECURITY_NATIVE_DREP, bufferDesc2, 0, ctxt2,
bufferDesc3, ctxtAttrs, null);
System.out.printf("0x%x%n", status);
}
}
}
考虑释放句柄以避免内存泄漏!