Упреждающая аутентификация с помощью DefaultHttpClient

Я хочу реализовать упреждающую аутентификацию для DefaultHttpClient с помощью NTLM. Я нашел библиотеку от Dan Hounshell, которая отлично работает для нормальная аутентификация.

Но я не могу понять, как заставить это работать с упреждающей аутентификацией. Я нашел вопрос 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=...

Я думаю, что первый запрос абсолютно бесполезен.


person rekire    schedule 12.12.2012    source источник


Ответы (2)


Мое решение здесь:

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..., который пропускает первоначальный запрос. После первого использования этого заголовка этот заголовок удаляется, чтобы этот фиктивный заголовок не переопределял реальный процесс аутентификации. Это работает для меня.

person rekire    schedule 13.12.2012

Проверка подлинности NTLM не может выполняться упреждающе. Это сложная схема, которая включает несколько (3) обменов сообщениями.

person ok2c    schedule 12.12.2012
comment
Но первый звонок действительно бесполезен, нет ответа на вызов или что-то в этом роде. Смотрите мое обновление. - person rekire; 12.12.2012
comment
Рукопожатие всегда инициируется сервером NTLM путем вызова клиента. Не стесняйтесь обращаться к спецификации. - person ok2c; 12.12.2012
comment
Ну, я не читал спецификацию, но я вижу сообщение и, основываясь на этом знании, я думаю, что клиент начинает с своего рода соли, которая используется для аутентификации ответа chellange. Пока я думаю, что могу пропустить часть, где Сервер сообщает, что он поддерживает NTLM. - person rekire; 12.12.2012
comment
Учитывая, что NTLM — это схема с отслеживанием состояния, попытка «оптимизировать» ее таким причудливым способом, скорее всего, ни к чему не приведет, но попытка не повредит. - person ok2c; 12.12.2012
comment
Я нашел способ увидеть мой собственный ответ :-) - person rekire; 13.12.2012