Повторное использование заголовка авторизации для предотвращения множественных проблем с проверкой подлинности прокси-сервера 407 с помощью Jersey Client

Я использую библиотеку Jersey Client 2.0 (с транспортным соединителем Apache HttpClient v4.2.5) для использования веб-службы RESTful. Мое приложение должно поддерживать соединения через прокси-сервер с любой аутентификацией Basic, Digest или NTLM. Я добавил поддержку всех этих типов прокси-аутентификации, и, по сути, все работает правильно.

Вот как я добавил поддержку базовой и дайджест-аутентификации прокси:

ClientConfig config = new ClientConfig();
config.property(ApacheClientProperties.PROXY_URI, "http://www.proxy.com:5678");
config.property(ApacheClientProperties.PROXY_USERNAME, "proxy_user");
config.property(ApacheClientProperties.PROXY_PASSWORD, "proxy_password");
ApacheConnector connector = new ApacheConnector(config);
config.connector(connector);
Client client = ClientBuilder.newClient(config);

Кроме того, веб-служба RESTful, к которой я подключаюсь, также требует самой простой проверки подлинности, которую я обрабатываю, используя следующее:

client.register( new HttpBasicAuthFilter("user", "password") );

Однако мое приложение ведет себя не так, как я хочу: кажется, что каждый отдельный HTTP-запрос, который я делаю, приводит к ответу на запрос аутентификации 407 от прокси-сервера. Это проблема по двум причинам:

  1. Если я делаю запрос POST или PUT (уже успешно прошедший аутентификацию на прокси-сервере в предыдущем запросе) с телом объекта, предоставленным InputStream, он считается "неповторяющимся" запросом, поэтому при получении запроса 407 У меня следующее исключение:

    org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
    

    Я мог бы обойти эту проблему, буферизовав данные тела объекта из InputStream в строку или массив байтов, чтобы запрос был повторяемым в случае получения запроса 407, но это неэффективно и не решает проблему 2.

  2. Необходимость дублировать каждый запрос, сначала запускать запрос 407, а затем повторять с необходимыми дополнительными заголовками HTTP на месте для проверки подлинности прокси, очень неэффективно. Некоторые из моих клиентских операций включают в себя многочисленные HTTP-запросы к веб-службе RESTful, поэтому этот дополнительный трафик и задержки вызывают сожаление.

Я ожидаю, что после первой успешной аутентификации клиента Jersey на прокси-сервере все последующие запросы, сделанные с использованием того же экземпляра Client, будут автоматически включать в себя необходимый заголовок Proxy-Authorization, чтобы предотвратить дальнейшие проблемы 407. Это кажется стандартным подходом для HTTP 1.1 согласно этой ссылке:

Прокси-сервер отправляет клиенту заголовок Proxy-Authenticate, содержащий запрос, в ответе 407 (Proxy Authentication Required). Затем клиент повторяет первоначальный запрос, но добавляет заголовок Proxy-Authorization, содержащий учетные данные, соответствующие задаче. После успешной аутентификации прокси клиент обычно отправляет тот же заголовок Proxy-Authorization на прокси с каждым последующим запросом, а не ждет повторного запроса.

Итак, мой вопрос: какие настройки конфигурации мне нужно применить к клиенту Jersey или к базовому транспортному уровню Apache HttpClient, чтобы включить такое поведение? Я видел различные другие сообщения, в которых рекомендовалось добавить заголовок Proxy-Authorization вручную, но я бы предпочел избегать этого обходного пути, если это возможно. Я также в идеале ищу решение, которое будет работать со всеми тремя типами прокси-аутентификации, которые я использую (Basic, Digest и NTLM).

Если невозможно предотвратить все эти дополнительные проблемы 407, я также хотел бы получить рекомендации по наилучшему подходу при POSTing или PUTing данных из локальных файлов «повторяемым» способом, чтобы предотвратить проблемы, следующие за проблемой аутентификации прокси-сервера 407.


person Ian Thomas    schedule 30.10.2013    source источник


Ответы (1)


В конце концов, я решил проблему 1, обновив свой проект до Jersey Client v2.6 и настроив клиент для автоматической буферизации всех моих запросов POST / PUT, чтобы они были «повторяемыми» в ответ на любые 407 проблем, которые приходят от прокси. сервер.

Буферизацию запросов можно включить в Jersey Client v2.5 +, установив следующее свойство для объекта ClientConfig, которое изменяет режим обработки объекта запроса с "фрагментированного" (по умолчанию) на "буферизованный":

config.property(ClientProperties.REQUEST_ENTITY_PROCESSING,
                RequestEntityProcessing.BUFFERED);

Теперь это работает для меня со всеми тремя типами прокси-аутентификации, которые я должен поддерживать: Basic, Digest и NTLM. Я включаю этот «буферизованный» режим только тогда, когда пользователь настроил прокси-сервер, так как я считаю, что лучше придерживаться стандартного «фрагментированного» режима, если только это не абсолютно необходимо. Меня беспокоят накладные расходы, связанные с буферизацией больших запросов PUT / POST в памяти, и потенциальная потеря эффективности, если данные не разбиваются на части.

Итак, теперь мое клиентское приложение работает правильно, но мне все равно было бы очень интересно услышать о любых возможных решениях проблемы 2, так как было бы предпочтительнее запускать только один исходный запрос проверки подлинности прокси-сервера 407 для каждого экземпляра Client. Я подозреваю, что любое возможное решение этой проблемы в любом случае будет работать только для обычной проверки подлинности из-за присущих дополнительных сложностей проверки подлинности Digest и NTLM.

person Ian Thomas    schedule 15.03.2014