Como se conectar ao servidor FTPS com conexão de dados usando a mesma sessão TLS?

Ambiente: estou usando o Sun Java JDK 1.8.0_60 no Windows 7 de 64 bits, usando o Spring Integration 4.1.6 (que internamente parece usar o Apache Commons Net 3.3 para acesso ao FTPS).

Estou tentando integrar com nosso aplicativo um download automático do servidor FTPS do nosso cliente. Fiz isso com êxito com servidores SFTP usando o Spring Integration sem problemas para outros clientes sem problemas, mas é a primeira vez que um cliente exige que usemos o FTPS, e fazer com que ele se conecte tem sido muito intrigante. Enquanto no meu aplicativo real, estou configurando o Spring Integration usando beans XML, para tentar entender o que não está funcionando, estou usando o seguinte código de teste (embora eu esteja anonimando o host / nome de usuário / senha reais aqui):

final DefaultFtpsSessionFactory sessionFactory = new DefaultFtpsSessionFactory();
sessionFactory.setHost("XXXXXXXXX");
sessionFactory.setPort(990);
sessionFactory.setUsername("XXXXXXX");
sessionFactory.setPassword("XXXXXXX");
sessionFactory.setClientMode(2);
sessionFactory.setFileType(2);
sessionFactory.setUseClientMode(true);
sessionFactory.setImplicit(true);
sessionFactory.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
sessionFactory.setProt("P");
sessionFactory.setProtocol("TLSv1.2");
sessionFactory.setProtocols(new String[]{"TLSv1.2"});
sessionFactory.setSessionCreation(true);
sessionFactory.setCipherSuites(new String[]{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"});

final FtpSession session = sessionFactory.getSession();
//try {
    final FTPFile[] ftpFiles = session.list("/");
    logger.debug("FtpFiles: {}", (Object[]) ftpFiles);
//} catch (Exception ignored ) {}
session.close();

Estou executando este código com-Djavax.net.debug=all para obter todas as informações de depuração do TLS impressas.

A conexão principal de "controle" com o servidor FTPS funciona bem, mas quando ele tenta abrir a conexão de dados da lista (ou qualquer outra conexão de dados que eu tentei), recebo umjavax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake, causado porjava.io.EOFException: SSL peer shut down incorrectly. Se eu descomentar as exceções da deglutição, pegue um bloco nosession.list comando, posso ver (através da saída javax.net.debug) que o servidor enviou a seguinte mensagem após rejeitar o handshake SSL da conexão de dados:

main, READ: TLSv1.2 Application Data, length = 129
Padded plaintext after DECRYPTION:  len = 105
0000: 34 35 30 20 54 4C 53 20   73 65 73 73 69 6F 6E 20  450 TLS session 
0010: 6F 66 20 64 61 74 61 20   63 6F 6E 6E 65 63 74 69  of data connecti
0020: 6F 6E 20 68 61 73 20 6E   6F 74 20 72 65 73 75 6D  on has not resum
0030: 65 64 20 6F 72 20 74 68   65 20 73 65 73 73 69 6F  ed or the sessio
0040: 6E 20 64 6F 65 73 20 6E   6F 74 20 6D 61 74 63 68  n does not match
0050: 20 74 68 65 20 63 6F 6E   74 72 6F 6C 20 63 6F 6E   the control con
0060: 6E 65 63 74 69 6F 6E 0D   0A                       nection..

O que parece estar acontecendo (e esta é a minha primeira vez que lida com FTPS, embora já tenha lidado com FTP simples) é que a maneira como o servidor garante autenticação e criptografia nas conexões de controle e de dados é que após um "normal" A conexão TLS para estabelecer a conexão de controle e a autenticação acontece lá, cada conexão de dados exige que o cliente se conecte com a mesma sessão TLS. Isso faz sentido para mim como deve funcionar, mas a implementação do Apache Commons Net FTPS não parece estar fazendo isso. Parece estar tentando estabelecer uma nova sessão TLS e, portanto, o servidor está rejeitando a tentativa.

Baseado emesta pergunta sobre como retomar sessões SSL em JSSE, parece que o Java assume ou requer uma sessão diferente para cada combinação de host / postagem. Minha hipótese é que, como a conexão de dados FTPS está em uma porta diferente da conexão de controle, ela não está encontrando a sessão existente e está tentando estabelecer uma nova, portanto a conexão falha.

Eu vejo três possibilidades principais:

O servidor não está seguindo o padrão FTPS ao exigir a mesma sessão TLS na porta de dados e na porta de controle. Posso me conectar bem ao servidor (usando o mesmo host / usuário / senha que estou tentando usar no meu código) usando o FileZilla 3.13.1. O servidor se identifica como "FileZilla Server 0.9.53 beta" no login, portanto, talvez essa seja uma espécie de maneira proprietária de fazer o FileZilla, e há algo estranho que preciso fazer para convencer o Java a usar a mesma sessão TLS.O cliente Apache Commons Net, na verdade, não segue o padrão FTPS e permite apenas um subconjunto que não permite a proteção das conexões de dados. Isso parece estranho, pois parece ser a maneira padrão de se conectar ao FTPS a partir do Java.Estou perdendo completamente alguma coisa e diagnosticando isso incorretamente.

Agradeço qualquer orientação que você possa fornecer sobre como se conectar a esse tipo de servidor FTPS. Obrigado.

questionAnswers(3)

yourAnswerToTheQuestion