com.myJava.file.driver.remote.ftp.SecuredSocketFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.myJava.file.driver.remote.ftp.SecuredSocketFactory.java

Source

package com.myJava.file.driver.remote.ftp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;

import org.apache.commons.net.DefaultSocketFactory;
import org.apache.commons.net.SocketClient;
import org.apache.commons.net.SocketFactory;
import org.apache.commons.net.ftp.FTPConnectionClosedException;

import com.myJava.configuration.FrameworkConfiguration;
import com.myJava.ssl.NoCheckX509TrustManager;
import com.myJava.util.log.Logger;

/**
 * SocketFactory implementation that creates Secured Sockets suitable for the FTPSClient class.
 * <BR>
 * @author Olivier PETRUCCI
 * <BR>
 *
 */

/*
Copyright 2005-2015, Olivier PETRUCCI.
    
This file is part of Areca.
    
Areca is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
    
Areca is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Areca; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    
*/
public class SecuredSocketFactory implements SocketFactory {

    private static TrustManager[] NO_CHECK_TM = new TrustManager[] { new NoCheckX509TrustManager() };
    public static String[] PROTECTIONS = new String[] { "P", "C" };
    private static String KEY_ALGORITHM = "SunX509";
    private static String KEY_TYPE = "JKS";

    private DefaultSocketFactory unsecuredSocketFactory = new DefaultSocketFactory();
    private SSLContext sslContext = null;
    private String protocol = null;
    private String protection;
    private FTPSClient client;
    private boolean implicit = false;

    public SecuredSocketFactory(String protocol, String protection, boolean checkServerCertificate,
            boolean implicit, InputStream certificateInputStream, String certificatePassword, FTPSClient client) {
        Logger.defaultLogger().info("Initializing secured socket factory ...");
        acceptProtocol(protocol);
        this.protocol = protocol;
        this.protection = protection;

        if (protection == null || (!protection.equals("C") && !protection.equals("P"))) {
            throw new IllegalArgumentException(
                    "Illegal protection method : [" + protection + "]. Only \"C\" and \"P\" are accepted.");
        }

        this.implicit = implicit;
        this.client = client;

        TrustManager tm[] = null;
        KeyManager km[] = null;

        // Init the keyStore if needed
        if (certificateInputStream != null) {
            try {
                Logger.defaultLogger().info("Loading certificate ...");
                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEY_ALGORITHM);
                KeyStore ks = KeyStore.getInstance(KEY_TYPE);
                char[] pwdChars = (certificatePassword == null ? null : certificatePassword.toCharArray());
                ks.load(certificateInputStream, pwdChars);
                kmf.init(ks, pwdChars);
                km = kmf.getKeyManagers();
            } catch (Exception e) {
                Logger.defaultLogger().error(e);
            }
        }

        // Init the trustmanager if needed
        if (!checkServerCertificate) {
            Logger.defaultLogger().info("Disabling server identification ...");
            tm = NO_CHECK_TM;
        }

        try {
            sslContext = SSLContext.getInstance(protocol);
            sslContext.init(km, tm, null);
        } catch (NoSuchAlgorithmException e) {
            Logger.defaultLogger().error(e);
        } catch (KeyManagementException e) {
            Logger.defaultLogger().error(e);
        }
    }

    private void acceptProtocol(String protocol) {
        String[] protocols = FrameworkConfiguration.getInstance().getSSEProtocols();
        for (int i = 0; i < protocols.length; i++) {
            if (protocols[i].trim().equalsIgnoreCase(protocol.trim())) {
                Logger.defaultLogger().info(protocol + " protocol validated.");
                return;
            }
        }
        throw new IllegalArgumentException("Protocol not supported : " + protocol);
    }

    public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
        SSLServerSocket serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory()
                .createServerSocket(port, backlog, bindAddr);
        initServerSocket(serverSocket);
        return serverSocket;
    }

    public ServerSocket createServerSocket(int port, int backlog) throws IOException {
        SSLServerSocket serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory()
                .createServerSocket(port, backlog);
        initServerSocket(serverSocket);
        return serverSocket;
    }

    public ServerSocket createServerSocket(int port) throws IOException {
        SSLServerSocket serverSocket = (SSLServerSocket) sslContext.getServerSocketFactory()
                .createServerSocket(port);
        initServerSocket(serverSocket);
        return serverSocket;
    }

    public Socket createSocket(InetAddress address, int port, InetAddress localAddr, int localPort)
            throws IOException {
        throw new UnsupportedOperationException();
    }

    public Socket createSocket(InetAddress address, int port) throws IOException {
        throw new UnsupportedOperationException();
    }

    public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
            throws UnknownHostException, IOException {
        throw new UnsupportedOperationException();
    }

    public Socket createSocket(String host, int port) throws UnknownHostException, IOException {
        if (implicit) {
            return createImplicitSocket(host, port);
        } else {
            return createExplicitSocket(host, port);
        }
    }

    public Socket createImplicitSocket(String host, int port) throws UnknownHostException, IOException {
        if (client.hasBeenNegociated()) {
            return (SSLSocket) sslContext.getSocketFactory().createSocket(host, port);
        } else {
            Logger.defaultLogger().info("Opening an implicit SSL connection on remote host");
            SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(host, port);
            init(socket);

            readReply(socket);
            this.sendCommand("PBSZ 0", socket, true);
            this.sendCommand("PROT " + protection, socket, false);

            return socket;
        }
    }

    public Socket createExplicitSocket(String host, int port) throws UnknownHostException, IOException {
        if (client.hasBeenNegociated()) {
            return (SSLSocket) sslContext.getSocketFactory().createSocket(host, port);
        } else {
            Logger.defaultLogger().info("Opening an explicit SSL connection on remote host");
            Socket unsecured = unsecuredSocketFactory.createSocket(host, port);
            readReply(unsecured);
            this.sendCommand("AUTH " + protocol, unsecured, true);

            SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(unsecured, host, port, true);
            init(socket);

            this.sendCommand("PBSZ 0", socket, true);
            this.sendCommand("PROT " + protection, socket, false);

            return socket;
        }
    }

    private void init(SSLSocket socket) throws IOException {
        socket.setEnableSessionCreation(true);
        socket.setUseClientMode(true);
        socket.startHandshake();
        client.setNegociated();
    }

    private void initServerSocket(SSLServerSocket socket) throws IOException {
        socket.setUseClientMode(true);
    }

    private void sendCommand(String command, Socket socket, boolean readReply) throws IOException {
        Logger.defaultLogger().info("Sending FTP command : " + command);

        // Send Command
        BufferedWriter out = new BufferedWriter(
                new OutputStreamWriter(socket.getOutputStream(), client.getControlEncoding()));
        out.write(command + SocketClient.NETASCII_EOL);
        out.flush();

        if (readReply) {
            readReply(socket);
        }
    }

    private void readReply(Socket socket) throws IOException {
        // Read response
        BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream(), client.getControlEncoding()));
        String line = in.readLine();
        StringBuffer sb = new StringBuffer(line);
        int length = line.length();
        if (length > 3 && line.charAt(3) == '-') {
            do {
                line = in.readLine();
                sb.append(" / ").append(line);

                if (line == null) {
                    throw new FTPConnectionClosedException("Connection closed without indication.");
                }
            } while (!(line.length() >= 4 && line.charAt(3) != '-' && Character.isDigit(line.charAt(0))));
        }
        Logger.defaultLogger().info("Received FTP server response : " + sb.toString());
    }
}