java - HttpClient 4.1.1 在使用 NTLM 进行身份验证时返回 401,浏览器工作正常

标签 java iis httpclient ntlm digest

我正在尝试使用 Apache/Jakarta HttpClient 4.1.1 使用给定的凭据连接到任意网页。为了对此进行测试,我在我的开发机器上安装了 IIS 7.5,一次只有一种身份验证模式处于 Activity 状态。基本身份验证工作正常,但每当我尝试登录时,Digest 和 NTLM 都会返回 401 错误消息。这是我的代码:

    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpGet httpget = new HttpGet("http://localhost/"); 
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(AuthScope.ANY,
            new NTCredentials("user", "password", "", "localhost"));
    if (!new File(System.getenv("windir") + "\\krb5.ini").exists()) {
        List<String> authtypes = new ArrayList<String>();
        authtypes.add(AuthPolicy.NTLM);
        authtypes.add(AuthPolicy.DIGEST);
        authtypes.add(AuthPolicy.BASIC);
        httpclient.getParams().setParameter(AuthPNames.PROXY_AUTH_PREF,
                authtypes);
        httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,
                authtypes);
    }
    localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
    HttpResponse response = httpclient.execute(httpget, localContext);
    System.out.println("Response code: " + response.getStatusLine());

我在 Fiddler 中注意到的一件事是 Firefox 与 HttpClient 发送的散列不同,这让我觉得 IIS 7.5 可能期望比 HttpClient 提供的散列更强?有任何想法吗?如果我能验证这适用于 NTLM,那就太好了。摘要也不错,但如果有必要,我可以没有它。

最佳答案

我不是该主题的专家,但在使用 http 组件进行 NTLM 身份验证期间,我发现客户端需要 3 次尝试才能连接到我的 NTML 端点。有点描述here对于 Spnego,但对于 NTLM 身份验证有点不同。

对于 NTLM,在第一次尝试中,客户端将使用 Target auth state: UNCHALLENGED 发出请求,Web 服务器返回 HTTP 401 状态和 header :WWW-Authenticate: NTLM

客户端将检查配置的身份验证方案,NTLM 应在客户端代码中配置。

第二次尝试,客户端将使用Target auth state: CHALLENGED 发出请求,并将发送一个带有以 base64 格式编码的 token 的授权 header :Authorization: NTLM TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw== 服务器再次返回 HTTP 401 状态,但 header :WWW-Authenticate: NTLM 现在填充了编码信息。

第三次尝试客户端将使用来自 WWW-Authenticate: NTLM header 的信息,并将使用 Target auth state: HANDSHAKE 和授权 header 发出最终请求授权:NTLM,其中包含服务器的更多信息。

在我的例子中,之后我收到一个 HTTP/1.1 200 OK

为了在每个请求中避免这一切documentation在第 4.7.1 章指出,相同的执行 token 必须用于逻辑相关的请求。对我来说它没有用。

我的代码: 我在 EJB 的 @PostConstruct 方法中初始化客户端一次

        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(18);
        cm.setDefaultMaxPerRoute(6);

        RequestConfig requestConfig = RequestConfig.custom()
        .setSocketTimeout(30000)
        .setConnectTimeout(30000)
        .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM))
        .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
        .build();

        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new NTCredentials(userName, password, hostName, domainName));

        // Finally we instantiate the client. Client is a thread safe object and can be used by several threads at the same time. 
        // Client can be used for several request. The life span of the client must be equal to the life span of this EJB.
         this.httpclient = HttpClients.custom()
        .setConnectionManager(cm)
        .setDefaultCredentialsProvider(credentialsProvider)
        .setDefaultRequestConfig(requestConfig)
        .build();

在每个请求中使用相同的客户端实例:

            HttpPost httppost = new HttpPost(endPoint.trim());            
            // HttpClientContext is not thread safe, one per request must be created.
            HttpClientContext context = HttpClientContext.create();    
            response = this.httpclient.execute(httppost, context);

在我的 EJB 的 @PreDestroy 方法中释放资源并将连接返回给连接管理器:

             this.httpclient.close();

关于java - HttpClient 4.1.1 在使用 NTLM 进行身份验证时返回 401,浏览器工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5917356/

相关文章:

java - 无法获取 Facebook ID 和电子邮件

asp.net - (405) 不允许的方法。 WCF网络服务

c# - 如何在同一URL下托管多个.NET Core应用

.net - WCF 服务卡在 SendResponse 中

java - Android HttpUrlConnection 不支持摘要身份验证?

android - Android 中 HttpUrlConnection 的编码问题

java - Maven 最佳实践 : including timestamps for snapshot releases or not?

java - 使用流遍历列表时如何获取元素索引?

java - 突然无法通过亚马逊SES发送电子邮件 - 无法连接smtp主机

android - 如何在我登录 Activity 后开始 Activity