【问题标题】:Preemptive authentication with DefaultHttpClient使用 DefaultHttpClient 进行抢先式身份验证
【发布时间】:2012-12-12 13:40:22
【问题描述】:

我想使用 NTLM 为 DefaultHttpClient 实施抢先式身份验证。我从Dan Hounshell 中找到了一个库,它适用于正常的身份验证。

但我无法弄清楚如何使用抢先式身份验证进行这项工作。我用这个很酷的answer找到了问题Preemptive Basic authentication with Apache HttpClient 4

UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, password);
HttpRequest request = ...
request.addHeader(new BasicScheme().authenticate(creds, request));

不适合我的问题,但一个好主意。所以我尝试使用NTLMSchemeFactory 创建AuthScheme 的新实例,并提供authenticate 函数。

NTCredentials ntc = new NTCredentials("example.com/user:pwd");
httpPost.addHeader(new NTLMScheme(new JCIFSEngine()).authenticate(ntc, httpPost));

当这个函数被调用时,我会得到一个异常:

org.apache.http.auth.AuthenticationException:意外状态:UNINITIATED

我该如何解决这个问题?

POST /login/ HTTP/1.1
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
Host: example.com
Connection: Keep-Alive
data=...

HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Wed, 12 Dec 2012 14:36:26 GMT
Content-Length: 1344

Much data...

POST /login/ HTTP/1.1
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
Host: example.com
Connection: Keep-Alive
Authorization: NTLM AAABBBCCC...FFF==
data=...

我认为第一个请求绝对没用。

【问题讨论】:

    标签: android authorization ntlm apache-httpclient-4.x preemptive


    【解决方案1】:

    我的解决方案是:

    public class PreemptiveNTLMHeader implements Header {
        private HttpRequest request;
        private NTCredentials ntc;
    
        public PreemptiveNTLMHeader(HttpRequest request, NTCredentials ntc) {
            this.request = request;
            this.ntc = ntc;
        }
    
        /* (non-Javadoc)
         * @see org.apache.http.Header#getName()
         */
        public String getName() {
            return "Authorization";
        }
    
        /* (non-Javadoc)
         * @see org.apache.http.Header#getValue()
         */
        public String getValue() {
            request.removeHeader(this);
            try {
                return "NTLM " + new JCIFSEngine().generateType1Msg(ntc.getDomain(), ntc.getWorkstation());
            } catch(NTLMEngineException e) {
                return "Failed";
            }
        }
    
        /* (non-Javadoc)
         * @see org.apache.http.Header#getElements()
         */
        public HeaderElement[] getElements() throws ParseException {
            return null;
        }
    }
    

    这种用法:

    NTCredentials ntc = new NTCredentials("example.com/user:password");
    httpPost.addHeader(new PreemptiveNTLMHeader(httpPost, ntc));
    

    DefaultHttpClient 也会发送一个跳过初始请求的Authorization: NTLM AAA... 标头。在第一次使用此标头后,此标头会自行删除,以避免此虚拟标头覆盖真正的身份验证过程。这对我有用。

    【讨论】:

      【解决方案2】:

      不能抢先执行 NTLM 身份验证。这是一个复杂的方案,涉及多 (3) 次消息交换。

      【讨论】:

      • 但是第一个电话真的没用,没有挑战响应之类的。查看我的更新。
      • 握手总是由 NTLM 服务器通过挑战客户端来发起的。随意查阅规范。
      • 好吧,我没有阅读规范,但我看到了通信,基于这些知识,我认为客户端从一种用于 chellange 响应身份验证的盐开始。到目前为止,我想我可以跳过服务器告诉他支持 NTLM 的部分。
      • 鉴于 NTLM 是一个有状态的方案,尝试以这种奇怪的方式“优化”它可能会让你一事无成,但尝试并没有什么坏处。
      • 我找到了一种方法来查看我自己的答案:-)
      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 2011-10-24
      • 1970-01-01
      相关资源
      最近更新 更多