java.net.ConnectException: Connection refused: connect for HTTPS connections

7.5k views Asked by At

I've created this class executed as a stand-alone program inside Eclipse that connects with no problem with all the http URLs (e.g.: http://stackoverflow.com), but when I try to connect to a https (e.g. https://en.wikipedia.org/wiki/HTTPS) is not possible

public class TEST4 {

    public static void main(String[] args) throws IOException {

        System.setProperty("http.proxyHost", "147.67.217.33");
        System.setProperty("http.proxyPort", "8022");
        System.setProperty("https.proxyHost", "147.67.217.33");
        System.setProperty("https.proxyPort", "8022");

        Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication("pecador", "9ddjk69t".toCharArray());
        }
      });

        URL url=new URL("https://en.wikipedia.org/wiki/HTTPS");     

        URLConnection uc = url.openConnection ();
        String encoded = new String (base64Encode(new String("pecador:9ddjk69t")));
        uc.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
        uc.connect();

        BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) 
            System.out.println(inputLine);
        in.close();

    }

    public static String userNamePasswordBase64(String username, String password) {
        return "Basic " + base64Encode(username + ":" + password);
    }

    private final static char base64Array[] = { 'A', 'B', 'C', 'D', 'E', 'F',
            'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
            'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
            't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', '+', '/' };

    private static String base64Encode(String string) {
        String encodedString = "";
        byte bytes[] = string.getBytes();
        int i = 0;
        int pad = 0;
        while (i < bytes.length) {
            byte b1 = bytes[i++];
            byte b2;
            byte b3;
            if (i >= bytes.length) {
                b2 = 0;
                b3 = 0;
                pad = 2;
            } else {
                b2 = bytes[i++];
                if (i >= bytes.length) {
                    b3 = 0;
                    pad = 1;
                } else
                    b3 = bytes[i++];
            }
            byte c1 = (byte) (b1 >> 2);
            byte c2 = (byte) (((b1 & 0x3) << 4) | (b2 >> 4));
            byte c3 = (byte) (((b2 & 0xf) << 2) | (b3 >> 6));
            byte c4 = (byte) (b3 & 0x3f);
            encodedString += base64Array[c1];
            encodedString += base64Array[c2];
            switch (pad) {
            case 0:
                encodedString += base64Array[c3];
                encodedString += base64Array[c4];
                break;
            case 1:
                encodedString += base64Array[c3];
                encodedString += "=";
                break;
            case 2:
                encodedString += "==";
                break;
            }
        }
        return encodedString;
    }

}
2

There are 2 answers

4
YoYo On BEST ANSWER

You need to set the https proxy. In your example, only the http proxy is set. Also username and password can be set using an Authenticator. The hope is that proper methods will be selected automatically.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;

public class Play {
    public static void main(String[] args) throws IOException {
      // Method 1 for Proxy
      System.setProperty("http.proxyHost", "147.67.217.33");
      System.setProperty("http.proxyPort", "8022");
      System.setProperty("https.proxyHost", "147.67.217.33");
      System.setProperty("https.proxyPort", "8022");

      URL url=new URL("https://en.wikipedia.org/wiki/HTTPS");   
      URLConnection uc = url.openConnection();
      Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication("pecador", "9ddjk69t".toCharArray());
        }
      });

      uc.connect();

      BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
      String inputLine;
      while ((inputLine = in.readLine()) != null) 
          System.out.println(inputLine);
      in.close();
    }
}

[update]

As this still did not resolve the issue, I think what is going on is that the proxy expects to negotiate in plain text, even for requesting username and password for proxying a https site. At one point the client will expect data encrypted over SSL while the proxy requests BASIC authentication still in plain text. I have found an old article that tries to address this problem: https tunneling.

Also see this blog entry as it seems an interesting topic referring to the same article.

There is a lot of material there to read an learn, a little too much right now for me to grasp and repeat. So forgive me for directly referring you to those two readings. As usual, I hope to read about your experience,and hope you make it to work.

[my eternal wish]

Proxies and authentication are the fabric of a corporate environment, I just don't get it why we didn't get it right with simple to use API's.

0
Mehdi On

This is not recommended in a production environment but you can disable the SSL validation (ex: For development purpose). Add this code to your program before you do a connection using :

TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
       return null;
      }
      @Override
      public void checkClientTrusted(X509Certificate[] arg0, String arg1)
       throws CertificateException {}

      @Override
      public void checkServerTrusted(X509Certificate[] arg0, String arg1)
        throws CertificateException {}

      }
 };

  SSLContext sc=null;
  try {
   sc = SSLContext.getInstance("SSL");
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
  try {
   sc.init(null, trustAllCerts, new java.security.SecureRandom());
  } catch (KeyManagementException e) {
   e.printStackTrace();
  }
  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

  // Create all-trusting host name verifier
  HostnameVerifier validHosts = new HostnameVerifier() {
  @Override
 public boolean verify(String arg0, SSLSession arg1) {
   return true;
  }
  };
  // All hosts will be valid
  HttpsURLConnection.setDefaultHostnameVerifier(validHosts);

In a production environment you have to install the SSL Certificates on the JVM.

Source