【问题标题】:Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407" via https无法通过代理进行隧道传输。代理通过 https 返回“HTTP/1.1 407”
【发布时间】:2013-02-11 00:03:07
【问题描述】:

我尝试通过需要身份验证的 https 连接到服务器。此外,我在中间有一个 http 代理,也需要身份验证。我使用 ProxyAuthSecurityHandler 对代理进行身份验证,使用 BasicAuthSecurityHandler 对服务器进行身份验证。

接收 java.io.IOException:无法通过代理进行隧道传输。

Proxy returns "HTTP/1.1 407 Proxy Auth Required"

at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1525)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect (AbstractDelegateHttpsURLConnection.java:164)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at org.apache.wink.client.internal.handlers.HttpURLConnectionHandler.processRequest(HttpURLConnectionHandler.java:97)

我注意到 ProxyAuthSecurityHandler 的实现需要响应代码 407,但是,在调试期间,由于抛出 IOException,我们从未进入第二部分。

代码快照:

ClientConfig configuration = new ClientConfig();
configuration.connectTimeout(timeout);

MyBasicAuthenticationSecurityHandler basicAuthProps = new MyBasicAuthenticationSecurityHandler();
basicAuthProps.setUserName(user);
basicAuthProps.setPassword(password);
configuration.handlers(basicAuthProps);

if ("true".equals(System.getProperty("setProxy"))) {
    configuration.proxyHost(proxyHost);
    if ((proxyPort != null) && !proxyPort.equals("")) {
        configuration.proxyPort(Integer.parseInt(proxyPort));
    }

    MyProxyAuthSecurityHandler proxyAuthSecHandler =
            new MyProxyAuthSecurityHandler();
    proxyAuthSecHandler.setUserName(proxyUser);
    proxyAuthSecHandler.setPassword(proxyPass);
    configuration.handlers(proxyAuthSecHandler);
}

restClient = new RestClient(configuration);
// create the createResourceWithSessionCookies instance to interact with

Resource resource = getResource(loginUrl);

// Request body is empty
ClientResponse response = resource.post(null); 

尝试使用 wink 客户端版本 1.1.2 和 1.2.1。这个问题在两者中都重复。

【问题讨论】:

    标签: authentication https proxy apache-wink http-tunneling


    【解决方案1】:

    我发现当尝试使用 https url 通过代理时,我们首先发送 CONNECT,然后才尝试发送请求。代理服务器无法读取我们附加到请求的任何标头,因为它没有解密流量的密钥。 这意味着 CONNECT 应该已经让用户/传递给代理以通过此阶段。 这是我使用的代码快照 - 对我有用:

    import sun.misc.BASE64Encoder;
    import java.io.*;
    import java.net.*;
    
    public class ProxyPass {
        public ProxyPass(String proxyHost, int proxyPort, final String userid, final String password, String url) {
    
            try {
            /* Create a HttpURLConnection Object and set the properties */
                URL u = new URL(url);
                Proxy proxy =
                new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
                HttpURLConnection uc = (HttpURLConnection)u.openConnection(proxy);
    
                Authenticator.setDefault(new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                if (getRequestorType().equals(RequestorType.PROXY)) {
                return new PasswordAuthentication(userid, password.toCharArray());
                }
                return super.getPasswordAuthentication();
                }
                });
    
                uc.connect();
    
                /* Print the content of the url to the console. */
                showContent(uc);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void showContent(HttpURLConnection uc) throws IOException {
            InputStream i = uc.getInputStream();
            char c;
            InputStreamReader isr = new InputStreamReader(i);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    
        public static void main(String[] args) {
    
            String proxyhost = "proxy host";
            int proxyport = port;
            String proxylogin = "proxy username";
            String proxypass = "proxy password";
            String url = "https://....";
            new ProxyPass(proxyhost, proxyport, proxylogin, proxypass, url);
    
        }
        }
    

    如果您使用 wink - 就像我一样,您需要在 ClientConfig 中设置代理,然后在将其传递给 RestClient 之前设置默认身份验证器。

    ClientConfig configuration = new ClientConfig();
        configuration.connectTimeout(timeout);
    
        BasicAuthenticationSecurityHandler basicAuthProps = new BasicAuthenticationSecurityHandler();
        basicAuthProps.setUserName(user);
        basicAuthProps.setPassword(password);
        configuration.handlers(basicAuthProps);
    
        if (proxySet()) {
            configuration.proxyHost(proxyHost);
            if ((proxyPort != null) && !proxyPort.equals("")) {
                configuration.proxyPort(Integer.parseInt(proxyPort));
            }
            Authenticator.setDefault(new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    if (getRequestorType().equals(RequestorType.PROXY)) {
                        return new PasswordAuthentication(proxyUser), proxyPass.toCharArray());
                    }
                    return super.getPasswordAuthentication();
                }
            });
        }
    
        restClient = new RestClient(configuration);
        Resource resource = getResource(loginUrl);
    
        // Request body is empty
        ClientResponse response = resource.post(null);
        if (response.getStatusCode() != Response.Status.OK.getStatusCode()) {
            throw new RestClientException("Authentication failed for user " + user);
        }
    

    【讨论】:

      【解决方案2】:

      如果 Ilana Platonovanswer 不起作用,请尝试编辑变量:

      jdk.http.auth.tunneling.disabledSchemes  
      jdk.http.auth.proxying.disabledSchemes
      

      【讨论】:

        猜你喜欢
        • 2013-07-01
        • 1970-01-01
        • 2017-08-11
        • 1970-01-01
        • 2020-04-18
        • 2018-01-14
        • 1970-01-01
        • 2013-05-08
        相关资源
        最近更新 更多