HTTP-прокси с аутентификацией и Java

Как я могу настроить имя пользователя и пароль для аутентификации прокси-сервера http с использованием Java?

Я только что нашел следующие параметры конфигурации:

http.proxyHost=<proxyAddress>
http.proxyPort=<proxyPort>
https.proxyHost=<proxyAddress>
https.proxyPort=<proxyPort>

Но мой прокси-сервер требует аутентификации. Как я могу настроить свое приложение на использование прокси-сервера?

8 ответов

Решение

(РЕДАКТИРОВАТЬ: Как указано OP, использование java.net.Authenticator тоже требуется. Я корректирую свой ответ соответственно для корректности.)

Для аутентификации используйте java.net.Authenticator установить конфигурацию прокси и установить системные свойства http.proxyUser а также http.proxyPassword,

final String authUser = "user";
final String authPassword = "password";
Authenticator.setDefault(
   new Authenticator() {
      @Override
      public PasswordAuthentication getPasswordAuthentication() {
         return new PasswordAuthentication(
               authUser, authPassword.toCharArray());
      }
   }
);

System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);

Вы почти у цели, вам просто нужно добавить:

-Dhttp.proxyUser=someUserName
-Dhttp.proxyPassword=somePassword

http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword говорит:

Другие предлагают использовать собственный Аутентификатор по умолчанию. Но это опасно, потому что это отправит ваш пароль любому, кто попросит.

Это актуально, если некоторые запросы http / https не проходят через прокси (что вполне возможно в зависимости от конфигурации). В этом случае вы отправите свои учетные данные напрямую на какой-либо http-сервер, а не на свой прокси-сервер.

Он предлагает следующее исправление.

// Java ignores http.proxyUser. Here come's the workaround.
Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY) {
            String prot = getRequestingProtocol().toLowerCase();
            String host = System.getProperty(prot + ".proxyHost", "");
            String port = System.getProperty(prot + ".proxyPort", "80");
            String user = System.getProperty(prot + ".proxyUser", "");
            String password = System.getProperty(prot + ".proxyPassword", "");

            if (getRequestingHost().equalsIgnoreCase(host)) {
                if (Integer.parseInt(port) == getRequestingPort()) {
                    // Seems to be OK.
                    return new PasswordAuthentication(user, password.toCharArray());  
                }
            }
        }
        return null;
    }  
});

Я еще не пробовал, но это выглядит хорошо для меня.

Из-за этого я немного изменил исходную версию, чтобы использовать equalsIgnoreCase() вместо equals(host.toLowerCase()): http://mattryall.net/blog/2009/02/the-infamous-turkish-locale-bug и я. добавлено "80" в качестве значения по умолчанию для порта, чтобы избежать NumberFormatException в Integer.parseInt(порт).

Большая часть ответа есть, но для меня не совсем. Это то, что работает для меня с java.net.HttpURLConnection (я проверил все случаи с JDK 7 и JDK 8). Обратите внимание, что вам не нужно использовать класс Authenticator.

Случай 1: Прокси без аутентификации пользователя, доступ к ресурсам HTTP

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport

Случай 2: Прокси с аутентификацией пользователя, доступ к ресурсам HTTP

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Случай 3: Прокси без аутентификации пользователя, доступ к ресурсам HTTPS (SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Случай 4: Прокси с аутентификацией пользователя, доступ к ресурсам HTTPS (SSL)

-Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Случай 5: Прокси-сервер без аутентификации пользователя, доступ к ресурсам HTTP и HTTPS (SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport 

Случай 6: Прокси с аутентификацией пользователя, доступ к ресурсам HTTP и HTTPS (SSL)

-Dhttp.proxyHost=myproxy -Dhttp.proxyPort=myport -Dhttp.proxyUser=myuser -Dhttp.proxyPassword=mypass -Dhttps.proxyHost=myproxy -Dhttps.proxyPort=myport -Dhttps.proxyUser=myuser -Dhttps.proxyPassword=mypass

Вы также можете установить свойства в с помощью System.setProperty("ключ", "значение").

Чтобы получить доступ к HTTPS-ресурсу, вам, возможно, придется довериться ресурсу, загрузив сертификат сервера и сохранив его в хранилище доверенных сертификатов, а затем используя это хранилище доверенных сертификатов. т.е.

 System.setProperty("javax.net.ssl.trustStore", "c:/temp/cert-factory/my-cacerts");
 System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Для Java 1.8 и выше вы должны установить

-Djdk.http.auth.tunneling.disabledSchemes=

сделать прокси с Базовой Авторизацией, работающей с https вместе с Аутентификатором, как указано в принятом ответе

Но, устанавливая только эти параметры, аутентификация не работает.

К этому коду необходимо добавить следующее:

final String authUser = "myuser";
final String authPassword = "secret";

System.setProperty("http.proxyHost", "hostAddress");
System.setProperty("http.proxyPort", "portNumber");
System.setProperty("http.proxyUser", authUser);
System.setProperty("http.proxyPassword", authPassword);

Authenticator.setDefault(
  new Authenticator() {
    public PasswordAuthentication getPasswordAuthentication() {
      return new PasswordAuthentication(authUser, authPassword.toCharArray());
    }
  }
);

Попробуйте этот раннер, который я написал. Это может быть полезно.

import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;

public class ProxyAuthHelper {

    public static void main(String[] args) throws Exception {
        String tmp = System.getProperty("http.proxyUser", System.getProperty("https.proxyUser"));
        if (tmp == null) {
            System.out.println("Proxy username: ");
            tmp = new Scanner(System.in).nextLine();
        }
        final String userName = tmp;

        tmp = System.getProperty("http.proxyPassword", System.getProperty("https.proxyPassword"));
        if (tmp == null) {
            System.out.println("Proxy password: ");
            tmp = new Scanner(System.in).nextLine();
        }
        final char[] password = tmp.toCharArray();

        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                System.out.println("\n--------------\nProxy auth: " + userName);
                return new PasswordAuthentication (userName, password);
            }

         });

        Class<?> clazz = Class.forName(args[0]);
        Method method = clazz.getMethod("main", String[].class);
        String[] newArgs = new String[args.length - 1];
        System.arraycopy(args, 1, newArgs, 0, newArgs.length);
        method.invoke(null, new Object[]{newArgs});
    }

}

Поскольку никто не упомянул об этом, и я видел несколько примеров, когда, это может привести к непреднамеренной утечке вашего имени пользователя и пароля. Вот еще один способ сделать это, я думаю, что это намного чище.

      import java.net.*;
import java.util.Base64;

class JavaFileUtil {
  private String hostname = "hostname";
  private int port = 8000;
  private String username = "username";
  private String password = "password";

  private Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, port));
  private String authHeader = new String(Base64.getEncoder().encode(new String(username + ":" + password).getBytes()));

  public void download(URL url) {
    HttpURLConnection newConnection = null;
    try {
      newConnection = (HttpURLConnection) url.openConnection(proxy);
      newConnection.setRequestProperty("Proxy-Authorization", "Basic " + authHeader);

      //The rest of your code here

    } catch (Exception e) {
      //log some error or handle it
    } finally {
      //Make sure you close the connection
      if (newConnection != null) newConnection.disconnect();
    }
  }

}
Другие вопросы по тегам