All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cybozu.kintone.client.connection.SSLSocketFactoryForHttpsProxy Maven / Gradle / Ivy

package com.cybozu.kintone.client.connection;

import java.net.*;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.io.*;
import javax.net.ssl.*;

/**
 * SSLSocket used to tunnel through a SSL-secured proxy
 */
class SSLSocketFactoryForHttpsProxy extends SSLSocketFactory {
    private String proxyHost;
    private int proxyPort;
    private SSLSocketFactory dfactory;
    private String proxyPassword;
    private String proxyUser;
    private boolean socketConnected = false;


    /**
     * Constructor for the SSLSocketFactoryForHttpsProxy object
     *
     * @param dfactory  The socket factory used for setting client certificate
     */
    public SSLSocketFactoryForHttpsProxy(SSLSocketFactory dfactory) {
        System.err.println("creating Socket Factory");
        this.dfactory = dfactory;
    }

    /**
     * Constructor for the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyHost The url of the proxy host
     * @param proxyPort the port of the proxy
     */
    public SSLSocketFactoryForHttpsProxy(String proxyHost, String proxyPort) {
        System.err.println("creating Socket Factory");
        this.proxyHost = proxyHost;
        this.proxyPort = Integer.parseInt(proxyPort);
        this.dfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    }

    /**
     * Constructor for the SSLSocketFactoryForHttpsProxy object
     * 
     * @param dfactory  The socket factory used for setting client certificate
     * @param proxyHost The url of the proxy host
     * @param proxyPort the port of the proxy
     */
    public SSLSocketFactoryForHttpsProxy(SSLSocketFactory dfactory, String proxyHost, String proxyPort) {
        System.err.println("creating Socket Factory");
        this.proxyHost = proxyHost;
        this.proxyPort = Integer.parseInt(proxyPort);
        this.dfactory = dfactory;
    }

    /**
     * Constructor for the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyHost     The url of the proxy host
     * @param proxyPort     the port of the proxy
     * @param proxyUserName username for authenticating with the proxy
     * @param proxyPassword password for authenticating with the proxy
     * 
     */
    public SSLSocketFactoryForHttpsProxy(String proxyHost, String proxyPort, String proxyUserName,
            String proxyPassword) {
        System.err.println("creating Socket Factory with password/username");
        this.proxyHost = proxyHost;
        this.proxyPort = Integer.parseInt(proxyPort);
        this.proxyUser = proxyUserName;
        this.proxyPassword = proxyPassword;
        this.dfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    }

    /**
     * Constructor for the SSLSocketFactoryForHttpsProxy object
     *
     * @param dfactory      The socket factory used for setting client certificate
     * @param proxyHost     The url of the proxy host
     * @param proxyPort     the port of the proxy
     * @param proxyUserName username for authenticating with the proxy
     * @param proxyPassword password for authenticating with the proxy
     * 
     */
    public SSLSocketFactoryForHttpsProxy(SSLSocketFactory dfactory, String proxyHost, String proxyPort,
            String proxyUserName, String proxyPassword) {
        System.err.println("creating Socket Factory with password/username");
        this.proxyHost = proxyHost;
        this.proxyPort = Integer.parseInt(proxyPort);
        this.proxyUser = proxyUserName;
        this.proxyPassword = proxyPassword;
        this.dfactory = dfactory;
    }

    public SSLSocketFactoryForHttpsProxy() {
        this.dfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
    }
    
    /**
     * Sets the proxyHost attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyHost The new proxyHost value
     */
    public void setProxyHost(String proxyHost) {
        this.proxyHost = proxyHost;
    }

    /**
     * Sets the proxyPort attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyPort The new proxyPort value
     */
    public void setProxyPort(int proxyPort) {
        this.proxyPort = proxyPort;
    }

	/**
     * Sets the proxyUserName attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyUserName The new proxyUserName value
     */
    public void setProxyUserName(String proxyUserName) {
        proxyUser = proxyUserName;
    }

    /**
     * Sets the proxyPassword attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @param proxyPassword The new proxyPassword value
     */
    public void setProxyPassword(String proxyPassword) {
        this.proxyPassword = proxyPassword;
    }

    /**
     * Gets the supportedCipherSuites attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @return The supportedCipherSuites value
     */
    public String[] getSupportedCipherSuites() {
        return dfactory.getSupportedCipherSuites();
    }

    /**
     * Gets the defaultCipherSuites attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @return The defaultCipherSuites value
     */
    public String[] getDefaultCipherSuites() {
        return dfactory.getDefaultCipherSuites();
    }

    /**
     * Gets the socketConnected attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @return The socketConnected value
     */
    public synchronized boolean getSocketConnected() {
        return socketConnected;
    }

    /**
     * Creates a new SSL Tunneled Socket
     *
     * @param s         Ignored
     * @param host      destination host
     * @param port      destination port
     * @param autoClose wether to close the socket automaticly
     * @return proxy tunneled socket
     * @exception IOException          raised by an IO error
     * @exception UnknownHostException raised when the host is unknown
     */
    public Socket createSocket(Socket s, String host, int port, boolean autoClose)
            throws IOException, UnknownHostException {
        SSLSocket tunnel = (SSLSocket) dfactory.createSocket(proxyHost, proxyPort);
        doTunnelHandshake(tunnel, host, port);
        SSLSocket result = (SSLSocket) dfactory.createSocket(tunnel, host, port, autoClose);
        result.addHandshakeCompletedListener(new HandshakeCompletedListener() {
            public void handshakeCompleted(HandshakeCompletedEvent event) {
                System.out.println("Handshake Finished!");
                System.out.println("\t CipherSuite :" + event.getCipherSuite());
                System.out.println("\t SessionId: " + event.getSession());
                System.out.println("\t PeerHost: " + event.getSession().getPeerHost());
                setSocketConnected(true);
            }
        });
        return result;
    }

    /**
     * Creates a new SSL Tunneled Socket
     *
     * @param host destination host
     * @param port destination port
     * @return tunneled SSL Socket
     * @exception IOException          raised by IO error
     * @exception UnknownHostException raised when the host is unknown
     */
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return createSocket(null, host, port, true);
    }

    /**
     * Creates a new SSL Tunneled Socket
     *
     * @param host       Destination Host
     * @param port       Destination Port
     * @param clientHost Ignored
     * @param clientPort Ignored
     * @return SSL Tunneled Socket
     * @exception IOException          Raised when IO error occurs
     * @exception UnknownHostException Raised when the destination host is unknown
     */
    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
            throws IOException, UnknownHostException {
        return createSocket(null, host, port, true);
    }

    /**
     * Creates a new SSL Tunneled Socket
     *
     * @param host destination host
     * @param port destination port
     * @return tunneled SSL Socket
     * @exception IOException raised when IO error occurs
     */
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return createSocket(null, host.getHostName(), port, true);
    }

    /**
     * Creates a new SSL Tunneled Socket
     *
     * @param address       destination host
     * @param port          destination port
     * @param clientAddress ignored
     * @param clientPort    ignored
     * @return tunneled SSL Socket
     * @exception IOException raised when IO exception occurs
     */
    public Socket createSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort)
            throws IOException {
        return createSocket(null, address.getHostName(), port, true);
    }

    /**
     * Sets the socketConnected attribute of the SSLSocketFactoryForHttpsProxy object
     *
     * @param b The new socketConnected value
     */
    private synchronized void setSocketConnected(boolean b) {
        socketConnected = b;
    }

    /**
     * Description of the Method
     *
     * @param tunnel tunnel socket
     * @param host   destination host
     * @param port   destination port
     * @exception IOException raised when an IO error occurs
     */
    private void doTunnelHandshake(SSLSocket tunnel, String host, int port) throws IOException {
        OutputStream out = tunnel.getOutputStream();
        // generate connection string
        String msg = "CONNECT " + host + ":" + port + " HTTP/1.1\n" + "User-Agent: " + Connection.userAgent;
        if (proxyUser != null && proxyPassword != null) {
            // add basic authentication header for the proxy
            Encoder enc = Base64.getEncoder();
            String encodedPassword = new String(enc.encode((proxyUser + ":" + proxyPassword).getBytes()));
            msg = msg + "\nProxy-Authorization: Basic " + encodedPassword;
        }
        msg = msg + "\nContent-Length: 0";
        msg = msg + "\nPragma: no-cache";
        msg = msg + "\r\n\r\n";

        System.err.println(msg);
        byte b[];
        try {
            // we really do want ASCII7 as the http protocol doesnt change with locale
            b = msg.getBytes("ASCII7");
        } catch (UnsupportedEncodingException ignored) {
            // If ASCII7 isn't there, something is seriously wrong!
            b = msg.getBytes();
        }
        out.write(b);
        out.flush();

        byte reply[] = new byte[200];
        int replyLen = 0;
        int newlinesSeen = 0;
        boolean headerDone = false;

        InputStream in = tunnel.getInputStream();
        while (newlinesSeen < 2) {
            int i = in.read();
            if (i < 0) {
                throw new IOException("Unexpected EOF from Proxy");
            }
            if (i == '\n') {
                headerDone = true;
                ++newlinesSeen;
            } else if (i != '\r') {
                newlinesSeen = 0;
                if (!headerDone && replyLen < reply.length) {
                    reply[replyLen++] = (byte) i;
                }
            }
        }

        // convert byte array to string
        String replyStr;
        try {
            replyStr = new String(reply, 0, replyLen, "ASCII7");
        } catch (UnsupportedEncodingException ignored) {
            replyStr = new String(reply, 0, replyLen);
        }

        // we check for connection established because our proxy returns http/1.1
        // instead of 1.0
        if (replyStr.toLowerCase().indexOf("200 connection established") == -1) {
            System.err.println(replyStr);
            throw new IOException(
                    "Unable to tunnel through " + proxyHost + ":" + proxyPort + ". Proxy returns\"" + replyStr + "\"");
        }
        // tunneling hanshake was successful
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy