Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HttpClient 4.1.1在使用NTLM进行身份验证时返回401,浏览器工作正常_Java_Iis_Httpclient_Ntlm_Digest - Fatal编程技术网

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

Java HttpClient 4.1.1在使用NTLM进行身份验证时返回401,浏览器工作正常,java,iis,httpclient,ntlm,digest,Java,Iis,Httpclient,Ntlm,Digest,我试图使用Apache/Jakarta HttpClient 4.1.1使用给定的凭据连接到任意网页。为了测试这一点,我在我的dev机器上安装了一个最小的iis7.5,在这个机器上,一次只有一个身份验证模式处于活动状态。基本身份验证工作正常,但无论何时尝试登录,Digest和NTLM都会返回401条错误消息。这是我的密码: DefaultHttpClient httpclient = new DefaultHttpClient(); HttpContext localContex

我试图使用Apache/Jakarta HttpClient 4.1.1使用给定的凭据连接到任意网页。为了测试这一点,我在我的dev机器上安装了一个最小的iis7.5,在这个机器上,一次只有一个身份验证模式处于活动状态。基本身份验证工作正常,但无论何时尝试登录,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());
DefaultHttpClient-httpclient=newdefaulthttpclient();
HttpContext localContext=新的BasicHttpContext();
HttpGet HttpGet=新的HttpGet(“http://localhost/"); 
CredentialsProvider credsProvider=新的BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
新的NTC凭据(“用户”、“密码”、“本地主机”);
如果(!new File(System.getenv(“windir”)+“\\krb5.ini”).exists()){
List authtypes=new ArrayList();
添加(AuthPolicy.NTLM);
添加(AuthPolicy.DIGEST);
添加(AuthPolicy.BASIC);
httpclient.getParams().setParameter(AuthPNames.PROXY\u AUTH\u PREF,
作者类型);
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,
作者类型);
}
setAttribute(ClientContext.CREDS\u PROVIDER,credsProvider);
HttpResponse response=httpclient.execute(httpget,localContext);
System.out.println(“响应代码:+Response.getStatusLine());

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

我发现解决这种情况的最简单方法是。这是一把非常大的锤子,但它确实会向你展示一切。安装它,确保您的服务器在另一台机器上(不能与Localhost一起工作),然后开始日志记录

运行失败的请求,运行有效的请求。然后,通过http进行过滤(只需将http放入过滤器字段),找到第一个GET请求,找到另一个GET请求并进行比较。识别有意义的差异,您现在可以在code/net中搜索特定的关键字或问题。如果还不够,请缩小到第一次TCP对话,并查看完整的请求/响应。另一个也一样

我用这种方法解决了大量令人难以置信的问题。Wireshark是非常有用的工具。许多超级先进的功能,使您的网络调试更容易


您还可以在客户端或服务器端运行它。任何东西都会显示两个请求,以便您进行比较。

我终于找到了答案。摘要身份验证要求,如果在请求中使用完整URL,则代理还需要使用完整URL。我没有将代理代码留在示例中,但它被定向到“localhost”,这导致它失败。将其更改为127.0.0.1使其工作。

我在HttpClient 4.1.2中遇到了类似的问题。对我来说,通过恢复到HttpClient 4.0.3解决了这个问题。无论是使用内置实现还是使用JCIFS,我都无法让NTLM使用4.1.2

在升级到HttpClient4.1.X之后,我也遇到了同样的问题 HttpClient 4.2.6它运行起来就像一个魅力。下面是我的代码

DefaultHttpClient-httpclient=newdefaulthttpclient();
HttpContext localContext=新的BasicHttpContext();
HttpGet HttpGet=新的HttpGet(“url”);
CredentialsProvider credsProvider=新的BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
新的NTC凭据(“用户名”、“pwd”、“域”);
List authtypes=new ArrayList();
添加(AuthPolicy.NTLM);
httpclient.getParams().setParameter(AuthPNames.TARGET\u AUTH\u PREF,authtypes);
setAttribute(ClientContext.CREDS\u PROVIDER,credsProvider);
HttpResponse response=httpclient.execute(httpget,localContext);
HttpEntity=response.getEntity();

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

对于第一次尝试中的NTLM,客户端将发出一个带有
Target auth state:UNCHALLENGED
的请求,Web服务器返回HTTP 401状态和一个头:
WWW Authenticate:NTLM

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

第二次尝试时,客户端将发出一个带有
目标身份验证状态:challected
的请求,并将发送一个带有以base64格式编码的令牌的授权头:
授权:NTLM tlrmtvtuaabaaayiogaaaaaaaaaaaaaaaaacgaaafasgkaadw=
服务器再次返回HTTP 401状态,但标题:
WWW-Authenticate:NTLM
现在已填充编码信息

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

在我的例子中,我收到一个
HTTP/1.1200ok

为了避免所有这些情况,第4.7.1章中的每个请求都规定,必须对逻辑相关的请求使用相同的执行令牌。对我来说,它不起作用

我的代码: 我在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();
<
             this.httpclient.close();