Java 通过NTLMv2和Kerberos进行静默代理身份验证

Java 通过NTLMv2和Kerberos进行静默代理身份验证,java,single-sign-on,kerberos,http-proxy,ntlmv2,Java,Single Sign On,Kerberos,Http Proxy,Ntlmv2,我客户的Java代码(胖客户机)需要通过网络代理访问web服务。网络代理需要身份验证。客户希望作为当前Windows用户进行静默身份验证(单点登录,无密码提示!)。我做了很多研究,似乎大多数人在服务器端使用NTLMv2或Kerberos。但我需要它在客户端进行网络代理身份验证 我看到Java似乎开箱即用地支持Kerberos——看起来不错(但不是——我没有当前用户的密码) Java似乎还支持开箱即用的NTLM——看起来很有趣 不幸的是,这两种解决方案都要求我的代码提供用户名和密码。我不知道密码。

我客户的Java代码(胖客户机)需要通过网络代理访问web服务。网络代理需要身份验证。客户希望作为当前Windows用户进行静默身份验证(单点登录,无密码提示!)。我做了很多研究,似乎大多数人在服务器端使用NTLMv2或Kerberos。但我需要它在客户端进行网络代理身份验证

我看到Java似乎开箱即用地支持Kerberos——看起来不错(但不是——我没有当前用户的密码)

Java似乎还支持开箱即用的NTLM——看起来很有趣

不幸的是,这两种解决方案都要求我的代码提供用户名和密码。我不知道密码。我必须提示用户,但我不能这样做——根据规范,它必须是静默的。到目前为止,我找到的两种解决方案都不是沉默的!不过,我确实需要无声单点登录

因此,我想知道,我是否可以以某种方式使用或任何其他本机(=>JNA)库来解决我的问题(需要用户+pw)以进行基于NTLMv2和Kerberos的代理身份验证。如果这样的库可以节省编写kerberos配置文件的工作,那也会很酷

但我在华夫饼文件里没有找到类似的东西。华夫饼干是目前为止我发现的唯一的本地库。我假设它必须是本机代码,因为其他任何东西都应该有安全屏障,阻止它为当前用户获取Kerberos票证(或NTLMv2中的类似令牌)。但是本机代码应该能够访问这样的身份验证令牌,因为本机OS库可以访问Windows API,该API只向当前用户分发当前用户的NTLM/Kerberos令牌

AFAIK IE和其他本机程序能够通过NTLM/Kerberos保护的代理访问web服务。因此,这一定是可能的

有关于如何使用网络代理进行静默身份验证的提示吗

如果还没有现成的解决方案,也许您可以给我一些提示,如何使用Waffle或任何其他(本机,JNI/JNA)lib实现解决方案

如果真的没有解决方案,我甚至会自己使用JNA或JNI实现一个——你能给我一些关于正确方向的提示吗?我是一个GNU/Linux的家伙,不得不承认我甚至不知道从哪里开始在WindowsAPI文档中搜索它


顺便说一句,我已经知道了,但还没有得到任何答案。也许华夫饼干不是最好的解决方案?也许有更好的方法吗?

你写了很多,很少有实质性的东西。让我为你把事情分解一下

Java似乎还支持开箱即用的NTLM——这个和这个看起来很有趣

那是错误的。这是一个专用于
HttpUrlConnection
使用SSPI的私有实现。两者都忘了

忘记NTLM吧,它是基于连接的、专有的。使用Kerberos

我不知道您使用的是什么HTTP库,但这种方法非常简单,您不需要华夫格,只需要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);
    }

  }

}
import java.io.IOException;
导入java.util.Base64;
导入org.apache.commons.io.hextump;
导入org.apache.http.client.methods.CloseableHttpResponse;
导入org.apache.http.client.methods.HttpGet;
导入org.apache.http.impl.client.CloseableHttpClient;
导入org.apache.http.impl.client.HttpClientBuilder;
导入org.apache.http.util.EntityUtils;
导入com.sun.jna.platform.win32.Secur32;
导入com.sun.jna.platform.win32.Sspi;
导入com.sun.jna.ptr.IntByReference;
公共类SspiAuth{
公共静态void main(字符串[]args)
抛出ArrayIndexOutOfBoundsException、IllegalArgumentException、IOException{
Sspi.CredHandle cred=新的Sspi.CredHandle();
int status=Secur32.INSTANCE.AcquireCredentialsHandle(null,“协商”,
Sspi.SECPKG\u CRED\u出站,null,null,null,null,CRED,null);
系统输出打印项次(状态);
Sspi.CtxtHandle ctxt=新的Sspi.CtxtHandle();
Sspi.SecBufferDesc bufferDesc=新的Sspi.SecBufferDesc(Sspi.SECBUFFER_令牌,
Sspi.最大令牌大小);
IntByReference ctxtAttrs=新的IntByReference();
status=Secur32.INSTANCE.InitializeSecurityContext(cred,null,
“HTTP/”,
Sspi.ISC_REQ_MUTUAL_AUTH,0,Sspi.SECURITY_NATIVE_DREP,null,0,ctxt,bufferDesc,
ctxtAttrs,空);
系统输出打印项次(状态);
dump(bufferDesc.getBytes(),0,System.out,0);
HttpClientBuilder=HttpClientBuilder.create();
try(CloseableHttpClient-httpClient=builder.build()){
HttpGet方法=新的HttpGet(“https://deblndw024v.ad001.siemens.net:8444/manager/html");
方法addHeader(“授权”,
“协商”+Base64.getEncoder().encodeToString(bufferDesc.getBytes());
CloseableHttpResponse response=httpClient.execute(方法);
EntityUtils.consumer(response.getEntity());
response.close();
System.out.println(response.getStatusLine());
字符串responseToken=response.getFirstHeader(“WWW-Authenticate”).getValue()
.子串(10);
系统输出打印LN(响应肯);
字节[]rawResponseToken=Base64.getDecoder().decode(responseToken);
Sspi.SecBufferDesc bufferDesc2=新的Sspi.SecBufferDesc(Sspi.SECBUFFER_令牌,
罗维特肯);
Sspi.CtxtHandle ctxt2=新的Sspi.CtxtHandle();
Sspi.SecBufferDesc bufferdesc 3=新的Sspi.SecBufferDesc(Sspi.SECBUFFER_令牌,
Sspi.最大令牌大小);
status=Secur32.INSTANCE.InitializeSecurityContext(cred,ctxt,
“HTTP/”,
Sspi.ISC\u请求\u相互\u身份验证,0,Sspi.SECURITY\u NATIVE\u DREP,bufferDesc2,0,ctxt2,
bufferDesc3,ctxtAttrs,null);
System.out.printf(“0x%x%n”,状态);
}
}
}

考虑释放句柄以避免内存泄漏

你写了很多,很少有实质性的东西。让我为你把事情分解一下

Java似乎还支持开箱即用的NTLM——这个和这个外观