Skip to content

FTPES with TLS Session Reuse for FileZilla Server (need also BouncyCastle and a subclass). #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,30 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
</site>
</distributionManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.32</version>
<scope>test</scope>
</dependency>
<!--<dependency>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this comment block.

<groupId>org.burningwave</groupId>
<artifactId>tools</artifactId>
<version>0.26.2</version>
<scope>test</scope>
</dependency>-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bctls-debug-jdk18on</artifactId>
<version>1.79</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down Expand Up @@ -204,16 +228,47 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${skipUnitTests}</skipTests>
<excludes>
<exclude>**/*FunctionalTest.java</exclude>
<exclude>**/POP3*Test.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IT.java</exclude>
</excludes>
<environmentVariables>
<TRACE_CALLS>${commons.net.trace_calls}</TRACE_CALLS>
<ADD_LISTENER>${commons.net.add_listener}</ADD_LISTENER>
</environmentVariables>
</configuration>
</plugin>
<!-- Plugin Failsafe for integration-tests -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to state what a plugin is.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<!-- Lancer avant la phase verify -->
<execution>
<id>integration-tests</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify-tests</id>
<phase>verify</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Exécute uniquement les classes commençant ou terminant par IT -->
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
Expand Down Expand Up @@ -384,6 +439,55 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
<enableRulesSummary>false</enableRulesSummary>
</configuration>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.45.1</version>
<configuration>
<images>
<image>
<name>mguichar/filezilla-server</name>
<run>
<ports>
<port>21:21</port>
<port>14148:14148</port>
<port>49152:49152</port>
<port>49153:49153</port>
<port>49154:49154</port>
<port>49155:49155</port>
<port>49156:49156</port>
<port>49157:49157</port>
<port>49158:49158</port>
<port>49159:49159</port>
<port>49160:49160</port>
</ports>
<volumes>
<bind>
<volume>target/test-classes/org/apache/commons/net/test-data:/usr/test</volume>
<volume>target/test-classes/org/apache/commons/net/filezillaserver/conf:/opt/filezilla-server/etc</volume>
</bind>
</volumes>
</run>
</image>
</images>
</configuration>
<executions>
<execution>
<id>start-docker-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-docker-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
Expand Down
56 changes: 29 additions & 27 deletions src/main/java/org/apache/commons/net/ftp/FTPSClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public FTPSClient(final boolean isImplicit) {
* {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param isImplicit The security mode(Implicit/Explicit).
* @param context A pre-configured SSL Context
* @param context A pre-configured SSL Context
*/
public FTPSClient(final boolean isImplicit, final SSLContext context) {
this(DEFAULT_PROTOCOL, isImplicit);
Expand Down Expand Up @@ -213,7 +213,7 @@ public FTPSClient(final String protocol) {
* Constructor for FTPSClient allowing specification of protocol and security mode. If isImplicit is true, the port is set to {@link #DEFAULT_FTPS_PORT}
* i.e. 990. The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param protocol the protocol
* @param protocol the protocol
* @param isImplicit The security mode(Implicit/Explicit).
*/
public FTPSClient(final String protocol, final boolean isImplicit) {
Expand Down Expand Up @@ -250,9 +250,9 @@ protected void _connectAction_() throws IOException {
* Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The int representation of the FTP command to send.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
* @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
* initialization of the connection.
* initialization of the connection.
* @throws IOException If there is any problem with the connection.
* @see FTPClient#_openDataConnection_(int, String)
* @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead
Expand All @@ -269,17 +269,16 @@ protected Socket _openDataConnection_(final int command, final String arg) throw
* Returns a socket of the data connection. Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The textual representation of the FTP command to send.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no arguments.
* @return corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the establishment and
* initialization of the connection.
* initialization of the connection.
* @throws IOException If there is any problem with the connection.
* @see FTPClient#_openDataConnection_(int, String)
* @since 3.2
*/
@Override
protected Socket _openDataConnection_(final String command, final String arg) throws IOException {
final Socket socket = openDataSecureConnection(command, arg);
_prepareDataSocket_(socket);
if (socket instanceof SSLSocket) {
final SSLSocket sslSocket = (SSLSocket) socket;

Expand Down Expand Up @@ -332,7 +331,7 @@ private boolean checkPROTValue(final String prot) {
/**
* Close open sockets.
*
* @param socket main socket for proxy if enabled
* @param socket main socket for proxy if enabled
* @param sslSocket ssl socket
* @throws IOException closing sockets is not successful
*/
Expand Down Expand Up @@ -398,7 +397,7 @@ public int execADAT(final byte[] data) throws IOException {
* Sends the AUTH command.
*
* @throws SSLException If the server reply code equals neither "234" nor "334".
* @throws IOException If an I/O error occurs while either sending the command.
* @throws IOException If an I/O error occurs while either sending the command.
*/
protected void execAUTH() throws SSLException, IOException {
final int replyCode = sendCommand(CMD_AUTH, auth);
Expand Down Expand Up @@ -496,7 +495,7 @@ public int execMIC(final byte[] data) throws IOException {
*
* @param pbsz Protection Buffer Size.
* @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending the command.
* @throws IOException If an I/O error occurs while sending the command.
* @see #parsePBSZ(long)
*/
public void execPBSZ(final long pbsz) throws SSLException, IOException {
Expand All @@ -522,7 +521,7 @@ public void execPBSZ(final long pbsz) throws SSLException, IOException {
*
* @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}.
* @throws SSLException If the server reply code does not equal {@code 200}.
* @throws IOException If an I/O error occurs while sending the command.
* @throws IOException If an I/O error occurs while sending the command.
*/
public void execPROT(String prot) throws SSLException, IOException {
if (prot == null) {
Expand All @@ -548,7 +547,7 @@ public void execPROT(String prot) throws SSLException, IOException {
* Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
*
* @param prefix the prefix to find
* @param reply where to find the prefix
* @param reply where to find the prefix
* @return the remainder of the string after the prefix, or null if the prefix was not present.
*/
private String extractPrefixedData(final String prefix, final String reply) {
Expand Down Expand Up @@ -649,8 +648,8 @@ protected String getProtocol() {
}

/**
* Gets the protocol versions. The {@link #getEnabledProtocols()} method gets the value from the socket while
* this method gets its value from this instance's config.
* Gets the protocol versions. The {@link #getEnabledProtocols()} method gets the value from the socket while this method gets its value from this
* instance's config.
* @since 3.11.0
* @return a clone of the protocols, may be null
*/
Expand All @@ -659,8 +658,8 @@ protected String[] getProtocols() {
}

/**
* Gets the cipher suites. The {@link #getEnabledCipherSuites()} method gets the value from the socket while
* this method gets its value from this instance's config.
* Gets the cipher suites. The {@link #getEnabledCipherSuites()} method gets the value from the socket while this method gets its value from this instance's
* config.
* @since 3.11.0
* @return a clone of the suites, may be null
*/
Expand Down Expand Up @@ -714,8 +713,8 @@ private void initSslContext() throws IOException {
}

/**
* Gets the use client mode flag. The {@link #getUseClientMode()} method gets the value from the socket while
* this method gets its value from this instance's config.
* Gets the use client mode flag. The {@link #getUseClientMode()} method gets the value from the socket while this method gets its value from this
* instance's config.
* @since 3.11.0
* @return True If the socket should start its first handshake in "client" mode.
*/
Expand Down Expand Up @@ -754,8 +753,8 @@ protected boolean isImplicit() {
}

/**
* Gets the need client auth flag. The {@link #getNeedClientAuth()} method gets the value from the socket while
* this method gets its value from this instance's config.
* Gets the need client auth flag. The {@link #getNeedClientAuth()} method gets the value from the socket while this method gets its value from this
* instance's config.
* @since 3.11.0
* @return True if enabled, false if not.
*/
Expand All @@ -764,8 +763,8 @@ protected boolean isNeedClientAuth() {
}

/**
* Gets the want client auth flag. The {@link #getWantClientAuth()} method gets the value from the socket while
* this method gets its value from this instance's config.
* Gets the want client auth flag. The {@link #getWantClientAuth()} method gets the value from the socket while this method gets its value from this
* instance's config.
* @since 3.11.0
* @return True if enabled, false if not.
*/
Expand All @@ -779,9 +778,9 @@ protected boolean isWantClientAuth() {
* mode connections also cause a local PORT command to be issued.
*
* @param command The text representation of the FTP command to send.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
* @param arg The arguments to the FTP command. If this parameter is set to null, then the command is sent with no argument.
* @return A Socket corresponding to the established data connection. Null is returned if an FTP protocol error is reported at any point during the
* establishment and initialization of the connection.
* establishment and initialization of the connection.
* @throws IOException If an I/O error occurs while either sending a command to the server or receiving a reply from the server.
* @since 3.1
*/
Expand Down Expand Up @@ -831,6 +830,8 @@ private Socket openDataSecureConnection(final String command, final String arg)
}
socket = server.accept();

_prepareDataSocket_(socket);

// Ensure the timeout is set before any commands are issued on the new socket
if (soTimeoutMillis >= 0) {
socket.setSoTimeout(soTimeoutMillis);
Expand Down Expand Up @@ -871,6 +872,8 @@ private Socket openDataSecureConnection(final String command, final String arg)
socket = _socketFactory_.createSocket();
}

_prepareDataSocket_(socket);

if (getReceiveDataSocketBufferSize() > 0) {
socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
}
Expand Down Expand Up @@ -938,7 +941,7 @@ public byte[] parseADATReply(final String reply) {
*
* @param pbsz Protection Buffer Size.
* @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending the command.
* @throws IOException If an I/O error occurs while sending the command.
* @return the negotiated value.
* @see #execPBSZ(long)
* @since 3.0
Expand All @@ -964,7 +967,7 @@ public long parsePBSZ(final long pbsz) throws SSLException, IOException {
*
* @param command The FTP command.
* @return server reply.
* @throws IOException If an I/O error occurs while sending the command.
* @throws IOException If an I/O error occurs while sending the command.
* @throws SSLException if a CCC command fails
* @see org.apache.commons.net.ftp.FTP#sendCommand(String)
*/
Expand Down Expand Up @@ -1130,4 +1133,3 @@ protected void sslNegotiation() throws IOException {
}
}
}

Loading
Loading