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

Jes*_*sse 11 java iis ntlm httpclient digest

我正在尝试使用Apache/Jakarta HttpClient 4.1.1使用给定的凭据连接到任意网页.为了测试这一点,我在运行的dev机器上安装了最少的IIS 7.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());
Run Code Online (Sandbox Code Playgroud)

我在Fiddler中注意到的一件事是Firefox和HttpClient发送的哈希值不同,这让我觉得IIS 7.5可能比HttpClient提供更强的哈希值?有任何想法吗?如果我能够验证这适用于NTLM,那就太棒了.摘要也会很好,但如果有必要,我可以不用它.

小智 9

我不是这方面的专家,但在使用http组件的NTLM身份验证期间,我看到客户端需要3次尝试才能连接到我的情况下的NTML端点.这里有针对Spnego的描述,但NTLM身份验证有点不同.

对于第一次尝试的NTLM,客户端将发出请求,Target auth state: UNCHALLENGEDWeb服务器返回HTTP 401状态和标头:WWW-Authenticate: NTLM

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

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

第三次尝试客户端将使用WWW-Authenticate: NTLM 标头中的信息,并将使用包含服务器更多信息Target auth state: HANDSHAKE的授权标头进行最终请求Authorization: NTLM.

在我的情况下,我收到了一个HTTP/1.1 200 OK.

为了避免在第4.7.1章中的每个请求文档中的所有这些,必须使用相同的执行令牌来进行逻辑相关的请求.对我来说它没有用.

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

        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();
Run Code Online (Sandbox Code Playgroud)

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

            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);
Run Code Online (Sandbox Code Playgroud)

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

             this.httpclient.close();
Run Code Online (Sandbox Code Playgroud)


Moh*_*tur 5

我遇到了与HttpClient4.1.X相同的问题.将它升级到HttpClient 4.2.6后,它就像魅力一样.以下是我的代码

DefaultHttpClient httpclient = new DefaultHttpClient();
        HttpContext localContext = new BasicHttpContext();
        HttpGet httpget = new HttpGet("url"); 
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(AuthScope.ANY,
                new NTCredentials("username", "pwd", "", "domain"));
                    List<String> authtypes = new ArrayList<String>();
            authtypes.add(AuthPolicy.NTLM);      
            httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF,authtypes);

        localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
        HttpResponse response = httpclient.execute(httpget, localContext);
        HttpEntity entity=response.getEntity();
Run Code Online (Sandbox Code Playgroud)