diff --git a/pom.xml b/pom.xml
index 0a944b47f..3d7df7c24 100644
--- a/pom.xml
+++ b/pom.xml
@@ -142,7 +142,13 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
4.5.0test
-
+
+ org.bouncycastle
+ bctls-debug-jdk18on
+ 1.79
+ test
+
+
clean apache-rat:check javadoc:javadoc checkstyle:check verify japicmp:cmp pmd:check
@@ -199,6 +205,8 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
org.apache.maven.pluginsmaven-surefire-plugin
+
+ ${skip.surefire.tests}**/*FunctionalTest.java**/POP3*Test.java
@@ -209,6 +217,23 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ **/*IT.java
+
+
+
+
+
+ integration-test
+ verify
+
+
+
+ maven-assembly-plugin
@@ -219,6 +244,55 @@ Supported protocols include Echo, Finger, FTP, NNTP, NTP, POP3(S), SMTP(S), Teln
gnu
+
+ io.fabric8
+ docker-maven-plugin
+ 0.48.1
+
+
+
+ linuxserver/filezilla:3.68.1
+
+
+ 21:21
+ 14148:14148
+ 49152:49152
+ 49153:49153
+ 49154:49154
+ 49155:49155
+ 49156:49156
+ 49157:49157
+ 49158:49158
+ 49159:49159
+ 49160:49160
+
+
+
+ target/test-classes/org/apache/commons/net/test-data:/usr/test
+ target/test-classes/org/apache/commons/net/filezillaserver/conf:/opt/filezilla-server/etc
+
+
+
+
+
+
+
+
+ start-docker-container
+ pre-integration-test
+
+ start
+
+
+
+ stop-docker-container
+ post-integration-test
+
+ stop
+
+
+
+ maven-antrun-plugin
diff --git a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
index bd49af4e8..11676a9d2 100644
--- a/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
+++ b/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
@@ -185,7 +185,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);
@@ -214,7 +214,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) {
@@ -251,9 +251,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
@@ -270,9 +270,9 @@ 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
@@ -280,7 +280,6 @@ protected Socket _openDataConnection_(final int command, final String arg) throw
@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;
@@ -392,7 +391,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);
@@ -490,7 +489,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 {
@@ -516,7 +515,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) {
@@ -542,7 +541,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) {
@@ -781,9 +780,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
*/
@@ -829,6 +828,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);
@@ -866,6 +867,8 @@ private Socket openDataSecureConnection(final String command, final String arg)
socket = _socketFactory_.createSocket();
}
+ _prepareDataSocket_(socket);
+
if (getReceiveDataSocketBufferSize() > 0) {
socket.setReceiveBufferSize(getReceiveDataSocketBufferSize());
}
@@ -928,7 +931,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
@@ -954,7 +957,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)
*/
@@ -1120,4 +1123,3 @@ protected void sslNegotiation() throws IOException {
}
}
}
-
diff --git a/src/test/java/org/apache/commons/net/ftp/FTPSClientIT.java b/src/test/java/org/apache/commons/net/ftp/FTPSClientIT.java
new file mode 100644
index 000000000..5c6ab26f6
--- /dev/null
+++ b/src/test/java/org/apache/commons/net/ftp/FTPSClientIT.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.ftp;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.time.Duration;
+import java.util.Properties;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import org.apache.commons.io.output.NullOutputStream;
+import org.apache.commons.net.PrintCommandListener;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.params.ParameterizedClass;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * Tests {@link FTPSClient}.
+ *
+ * To get our test cert to work on Java 11, this test must be run with:
+ *
+ *
+ *
+ * -Djdk.tls.client.protocols="TLSv1.1"
+ *
+ *
+ * This test does the above programmatically.
+ *
+ */
+@ParameterizedClass
+@ValueSource(booleans = { false, true })
+public class FTPSClientIT {
+
+ private static final String FILEZILLA_PROPS_RES = "org/apache/commons/net/filezillaserver/filezillaserver.properties";
+ private static final String LOGGING_PROPS_RES = "logging.properties";
+ private static int FZSocketPort = -1;
+ private static String FZServerHost = "";
+
+ private static boolean UseExtFZServer;
+ private static String ExtFZServerHost = "";
+ private static int ExtFZServerPort = -1;
+
+ private static final boolean ADD_LISTENER = Boolean.parseBoolean(System.getenv("ADD_LISTENER"));
+ private static final boolean TRACE_CALLS = Boolean.parseBoolean(System.getenv("TRACE_CALLS"));
+ private static final long startTime = System.nanoTime();
+ protected static final boolean IMPLICIT = false;
+ private static final Logger LOGGER = Logger.getLogger(FTPSClientIT.class.getPackage().getName());
+ protected static final long TEST_TIMEOUT = 10000; // individual test timeout
+ // Configure java.util.logging for lib bouncy castle
+ // Redirect log to logback via org.slf4j.bridge.SLF4JBridgeHandler
+ // So, we can check log to see if session really resumed
+ static {
+// try {
+// final LogManager logManager = LogManager.getLogManager();
+// final URL logPropsFile = ClassLoader.getSystemClassLoader().getResource(LOGGING_PROPS_RES);
+// logManager.readConfiguration(logPropsFile.openStream());
+// } catch (final IOException exception) {
+// System.out.println("Cannot read configuration file " + LOGGING_PROPS_RES);
+// exception.printStackTrace();
+// }
+ }
+
+ protected static void initFZServer(final String fzPropertiesResource) throws IOException {
+ // Make a try to activate SNI (using a real hostname for control connection)
+ // with docker but don't work.
+// Map hostAliases = new LinkedHashMap<>();
+// hostAliases.put("filezilla-server", "127.0.0.1");
+//
+// // Installing the host resolvers
+// HostResolutionRequestInterceptor.INSTANCE.install(new MappedHostResolver(hostAliases),
+// // This is the system default resolving wrapper
+// DefaultHostResolver.INSTANCE);
+
+ final URL fzPropsResource = ClassLoader.getSystemClassLoader().getResource(fzPropertiesResource);
+ final Properties prop = new Properties();
+ try (InputStream in = fzPropsResource.openStream()) {
+ prop.load(in);
+ }
+ FZSocketPort = Integer.parseInt(prop.getProperty("filezillaserver.port"));
+ FZServerHost = prop.getProperty("filezillaserver.host");
+
+ UseExtFZServer = Boolean.valueOf(prop.getProperty("filezillaserver.external.enable"));
+ if (UseExtFZServer) {
+ ExtFZServerHost = prop.getProperty("filezillaserver.external.host");
+ ExtFZServerPort = Integer.parseInt(prop.getProperty("filezillaserver.external.port"));
+ }
+
+ }
+
+ @BeforeAll
+ public static void setupServer() throws Exception {
+ initFZServer(FILEZILLA_PROPS_RES);
+ }
+
+ public static Boolean[] testConstructurData() {
+ return new Boolean[] { Boolean.FALSE, Boolean.TRUE };
+ }
+
+ protected static void trace(final String msg) {
+ if (TRACE_CALLS) {
+ System.err.println(msg + " " + (System.nanoTime() - startTime));
+ }
+ }
+
+ private final boolean endpointCheckingEnabled;
+
+ public FTPSClientIT(final boolean endpointCheckingEnabled) {
+ this.endpointCheckingEnabled = endpointCheckingEnabled;
+ }
+
+ protected void assertClientCode(final FTPSClient client) {
+ final int replyCode = client.getReplyCode();
+ assertTrue(FTPReply.isPositiveCompletion(replyCode));
+ }
+
+ // Only passive mode tested
+ protected FTPSClient loginClientTo(final String hostname, final int port, final boolean withSSLSessionReuse) throws Exception {
+ trace(">>loginClientTo");
+ LOGGER.fine("Server " + FZServerHost);
+ LOGGER.fine("Port " + FZSocketPort);
+ FTPSClient client = null;
+ if (withSSLSessionReuse) {
+ client = new FTPSClientSSLSessionReuse(IMPLICIT);
+ } else {
+ client = new FTPSClient(IMPLICIT);
+ }
+ if (ADD_LISTENER) {
+ client.addProtocolCommandListener(new PrintCommandListener(System.err));
+ }
+
+ // HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+
+ //
+ client.setControlKeepAliveReplyTimeout(null);
+ assertEquals(0, client.getControlKeepAliveReplyTimeoutDuration().getSeconds());
+ client.setControlKeepAliveReplyTimeout(Duration.ofSeconds(60));
+ assertEquals(60, client.getControlKeepAliveReplyTimeoutDuration().getSeconds());
+ //
+ client.setControlKeepAliveTimeout(null);
+ assertEquals(0, client.getControlKeepAliveTimeoutDuration().getSeconds());
+ client.setControlKeepAliveTimeout(Duration.ofSeconds(61));
+ assertEquals(61, client.getControlKeepAliveTimeoutDuration().getSeconds());
+ //
+ client.setDataTimeout(null);
+ assertEquals(0, client.getDataTimeout().getSeconds());
+ client.setDataTimeout(Duration.ofSeconds(62));
+ assertEquals(62, client.getDataTimeout().getSeconds());
+
+ client.setUseClientMode(true);
+ //
+ client.setEndpointCheckingEnabled(endpointCheckingEnabled);
+ client.connect(hostname, port);
+ //
+ assertClientCode(client);
+ assertEquals(port, client.getRemotePort());
+ //
+ try {
+ // HACK: Without this sleep, the user command sometimes does not reach the ftpserver
+ // This only seems to affect GitHub builds, and only Java 11+
+ Thread.sleep(200); // 100 seems to be not always enough
+ } catch (final InterruptedException ignore) {
+ // ignore
+ }
+ assertTrue(client.login("test", "test"));
+ assertClientCode(client);
+ //
+ client.setFileType(FTP.BINARY_FILE_TYPE);
+ assertClientCode(client);
+ //
+ client.execPBSZ(0);
+ assertClientCode(client);
+ //
+ client.execPROT("P");
+ assertClientCode(client);
+ //
+ // Only passive mode tested
+ client.enterLocalPassiveMode();
+
+ trace("<>loginClientToFZ");
+ assertNotEquals(FZSocketPort, -1, "initFZServer not called");
+ final FTPSClient client = loginClientTo(FZServerHost, FZSocketPort, withSSLSessionReuse);
+ trace("< client.retrieveFile(pathname, NullOutputStream.INSTANCE));
+ }
+ } finally {
+ client.disconnect();
+ }
+ }
+
+ /**
+ * This test is corrected by this Merge Request. It requires an external server. The docker version and its bridge network cannot activate SNI verifications
+ * @throws Exception
+ */
+ @Test
+ @Timeout(TEST_TIMEOUT)
+ public void testExtFileZillaServerForSNI() throws Exception {
+ assumeTrue(UseExtFZServer);
+ trace(">>testExtFileZillaServerForSNI");
+ retrieveFileOnExtServer("/file.txt", true);
+ trace("<>testExtFileZillaServerNoSNI");
+ retrieveFileOnExtServer("/file.txt", false);
+ trace("<>testFileZillaNoTlsResume");
+ final FTPSClient client = loginClientToFZ(false);
+ try {
+ // Do it twice.
+ // Just testing that we are not getting an SSL error (the file MUST be present).
+ final String string = "/file.txt";
+ assertFalse(client.retrieveFile(string, NullOutputStream.INSTANCE), string);
+ assertFalse(client.retrieveFile(string, NullOutputStream.INSTANCE), string);
+ } finally {
+ client.disconnect();
+ }
+ trace("<>testFileZillaTlsResume");
+ retrieveFile("/file.txt", true);
+ trace("< _hostname_);
+
+ }
+
+ private static SSLContext createSSLContext(final String hostname) throws Exception {
+ final SSLContext context = SSLContext.getInstance("TLS", new BouncyCastleJsseProvider());
+ context.init(null, new TrustManager[] { TrustManagerUtils.getValidateServerCertificateTrustManager() }, new SecureRandom());
+ return context;
+ }
+
+ @Override
+ protected void _prepareDataSocket_(final Socket socket) throws IOException {
+ if (_socket_ instanceof BCSSLSocket) {
+ final BCSSLSocket sslSocket = (BCSSLSocket) _socket_;
+ final BCExtendedSSLSession bcSession = sslSocket.getBCSession();
+ if (bcSession != null && bcSession.isValid() && socket instanceof BCSSLSocket) {
+ final BCSSLSocket dataSslSocket = (BCSSLSocket) socket;
+ dataSslSocket.setBCSessionToResume(bcSession);
+ if (needHostForSni) {
+ dataSslSocket.setHost(bcSession.getPeerHost());
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml
new file mode 100644
index 000000000..96fb8906a
--- /dev/null
+++ b/src/test/resources/logback.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/logging.properties b/src/test/resources/logging.properties
new file mode 100644
index 000000000..9f5c93e81
--- /dev/null
+++ b/src/test/resources/logging.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+handlers = org.slf4j.bridge.SLF4JBridgeHandler
+.level=FINEST
diff --git a/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings.xml b/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings.xml
new file mode 100644
index 000000000..7df8d5b2c
--- /dev/null
+++ b/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings.xml
@@ -0,0 +1,202 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+ 9223372036854775807
+
+ 15
+
+ 0
+
+ false
+
+ false
+
+
+
+
+
+
+ 300000
+
+ 0
+
+ 0
+
+
+
+
+ 0
+
+ -1
+
+ -1
+
+
+
+
+ 60000
+
+ 3600000
+
+
+
+
+
+
+ 0.0.0.0
+ 21
+ 2
+
+
+ ::
+ 21
+ 2
+
+
+
+
+
+
+
+
+ true
+
+
+
+ 49152
+
+ 49160
+
+
+
+
+
+
+ -----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIHrmnc8p/0SjT2aZEK2h9hoO0CHadEF8PMt36MhOkv+woAoGCCqGSM49
+AwEHoUQDQgAEhy4e3BORejV3n4lg1I+NeS4zQKhxk7/M9a/8Z5VWC7PJVWtb+Zjq
+J6PQLO9FMgYE0bP4UKkRb0CaGYvwExvX6A==
+-----END EC PRIVATE KEY-----
+
+
+
+ -----BEGIN CERTIFICATE-----
+MIIBSjCB8KADAgECAhTRYlWUGps1ZPgAQ/XJXOtLyxQ0pDAKBggqhkjOPQQDAjAU
+MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjUwMTMxMTAzMzE1WhcNMjYwMjAxMTAz
+ODE1WjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAASHLh7cE5F6NXefiWDUj415LjNAqHGTv8z1r/xnlVYLs8lVa1v5mOono9As
+70UyBgTRs/hQqRFvQJoZi/ATG9fooyAwHjAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0T
+AQH/BAIwADAKBggqhkjOPQQDAgNJADBGAiEA02yK+o42pFyVjDHRKQUiN8zK9hEc
+cTlFYCefw0CrT34CIQC0S07ZLWDSXLLQEMHRfmFVeHRIYP51XxOK+6BWvehE5Q==
+-----END CERTIFICATE-----
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 300000
+
+ 1296000000
+
+ 15000
+
+ 30000
+
+
+
+
+
+
+ 14148
+ true
+
+ 0.0.0.0
+ 14148
+ true
+
+
+ ::
+ 14148
+ true
+
+
+ IVUV2eYKYKRFW2rZX0AEJWuZPp5BeNKX+YEXI8susmo
+ 1b92/rHKRi3Q8utZI8gugyUNKKHFRfdqo9ySdpEu0bs
+ 100000
+
+
+
+
+ -----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAaSQdoEL4PbTqzb4KY3ZOF71mSIrBdFWZx7m9ra4FIDoAoGCCqGSM49
+AwEHoUQDQgAES9fGv8Yp05XUU483Xxnc17VuE7VsHXFd2vdi2NyhMRNLZowT8qlS
+ANnG7LFfhTmcS+vJ7pavBPYV9HdKUfy0og==
+-----END EC PRIVATE KEY-----
+
+
+ -----BEGIN CERTIFICATE-----
+MIIBiDCCAS6gAwIBAgIUoF7wXnXF9PXDHwqZVLPjWedGhUYwCgYIKoZIzj0EAwIw
+MzExMC8GA1UEAxMoZmlsZXppbGxhLXNlcnZlciBzZWxmIHNpZ25lZCBjZXJ0aWZp
+Y2F0ZTAeFw0yNTAxMTcwOTAyNTVaFw0yNjAxMTgwOTA3NTVaMDMxMTAvBgNVBAMT
+KGZpbGV6aWxsYS1zZXJ2ZXIgc2VsZiBzaWduZWQgY2VydGlmaWNhdGUwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAARL18a/xinTldRTjzdfGdzXtW4TtWwdcV3a92LY
+3KExE0tmjBPyqVIA2cbssV+FOZxL68nulq8E9hX0d0pR/LSioyAwHjAOBgNVHQ8B
+Af8EBAMCBaAwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEA6wDLKiIC
+ko0Plie8tYfIsH32JcOnU0Uw0F1ssGQYSOkCIGBe0G7hUEWOZW9X0DEs7E5BGchP
+gAdv9Rivb4uwoBi+
+-----END CERTIFICATE-----
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 604800000
+
+
+
+
+
+
+
diff --git a/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings_filezilla-server.xml b/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings_filezilla-server.xml
new file mode 100644
index 000000000..d91044996
--- /dev/null
+++ b/src/test/resources/org/apache/commons/net/filezillaserver/conf/settings_filezilla-server.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+ 9223372036854775807
+
+ 15
+
+ 0
+
+ false
+
+ false
+
+
+
+
+
+
+ 300000
+
+ 0
+
+ 0
+
+
+
+
+ 0
+
+ -1
+
+ -1
+
+
+
+
+ 60000
+
+ 3600000
+
+
+
+
+
+
+ 0.0.0.0
+ 21
+ 2
+
+
+ ::
+ 21
+ 2
+
+
+
+
+
+
+
+
+ true
+
+
+
+ 49152
+
+ 49160
+
+
+
+
+
+
+ -----BEGIN EC PRIVATE KEY-----
+MHgCAQEEIQD6DEpLcmisEIpl5zh6R2cgPRRUkUGNNFB2hqywH1zxlqAKBggqhkjO
+PQMBB6FEA0IABIWdR7RYqnF6ygAIlj/w/3G/D5hyQ9DCkBkZmauknS6I8JkMvWqk
+7DGF4FmN931V7+/tOWJNzEGfO8rnsErmqso=
+-----END EC PRIVATE KEY-----
+
+
+
+ -----BEGIN CERTIFICATE-----
+MIIBVzCB/qADAgECAhTMl4SxTF8JmJ3F09VSmO+WIuPZ9TAKBggqhkjOPQQDAjAb
+MRkwFwYDVQQDExBmaWxlemlsbGEtc2VydmVyMB4XDTI1MDEyMDE1Mjk0N1oXDTI2
+MDEyMTE1MzQ0N1owGzEZMBcGA1UEAxMQZmlsZXppbGxhLXNlcnZlcjBZMBMGByqG
+SM49AgEGCCqGSM49AwEHA0IABIWdR7RYqnF6ygAIlj/w/3G/D5hyQ9DCkBkZmauk
+nS6I8JkMvWqk7DGF4FmN931V7+/tOWJNzEGfO8rnsErmqsqjIDAeMA4GA1UdDwEB
+/wQEAwIFoDAMBgNVHRMBAf8EAjAAMAoGCCqGSM49BAMCA0gAMEUCIQCFH1HewfMo
+1NMxzYIFPV1uZpT+3qAg9+lBw9a8268MfwIgYg9GGu8lhP5lpMu7jOowJmtcDYeX
+cSfSt2iB8lyLtf0=
+-----END CERTIFICATE-----
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 300000
+
+ 1296000000
+
+ 15000
+
+ 30000
+
+
+
+
+
+
+ 14148
+ true
+
+ 0.0.0.0
+ 14148
+ true
+
+
+ ::
+ 14148
+ true
+
+
+ IVUV2eYKYKRFW2rZX0AEJWuZPp5BeNKX+YEXI8susmo
+ 1b92/rHKRi3Q8utZI8gugyUNKKHFRfdqo9ySdpEu0bs
+ 100000
+
+
+
+
+ -----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAaSQdoEL4PbTqzb4KY3ZOF71mSIrBdFWZx7m9ra4FIDoAoGCCqGSM49
+AwEHoUQDQgAES9fGv8Yp05XUU483Xxnc17VuE7VsHXFd2vdi2NyhMRNLZowT8qlS
+ANnG7LFfhTmcS+vJ7pavBPYV9HdKUfy0og==
+-----END EC PRIVATE KEY-----
+
+
+ -----BEGIN CERTIFICATE-----
+MIIBiDCCAS6gAwIBAgIUoF7wXnXF9PXDHwqZVLPjWedGhUYwCgYIKoZIzj0EAwIw
+MzExMC8GA1UEAxMoZmlsZXppbGxhLXNlcnZlciBzZWxmIHNpZ25lZCBjZXJ0aWZp
+Y2F0ZTAeFw0yNTAxMTcwOTAyNTVaFw0yNjAxMTgwOTA3NTVaMDMxMTAvBgNVBAMT
+KGZpbGV6aWxsYS1zZXJ2ZXIgc2VsZiBzaWduZWQgY2VydGlmaWNhdGUwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAARL18a/xinTldRTjzdfGdzXtW4TtWwdcV3a92LY
+3KExE0tmjBPyqVIA2cbssV+FOZxL68nulq8E9hX0d0pR/LSioyAwHjAOBgNVHQ8B
+Af8EBAMCBaAwDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiEA6wDLKiIC
+ko0Plie8tYfIsH32JcOnU0Uw0F1ssGQYSOkCIGBe0G7hUEWOZW9X0DEs7E5BGchP
+gAdv9Rivb4uwoBi+
+-----END CERTIFICATE-----
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 604800000
+
+
+
+
+
+
+
diff --git a/src/test/resources/org/apache/commons/net/filezillaserver/filezillaserver.properties b/src/test/resources/org/apache/commons/net/filezillaserver/filezillaserver.properties
new file mode 100644
index 000000000..1af2a84bb
--- /dev/null
+++ b/src/test/resources/org/apache/commons/net/filezillaserver/filezillaserver.properties
@@ -0,0 +1,33 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+filezillaserver.port=21
+# Tried to use a hostname (other than localhost) to activate SNI but don't work...
+# Test realised with HostResolutionRequestInterceptor of BurningWave library
+# to give a hostname to docker filezilla server
+# see FTPSClientIntegrationTest.initFZServer()
+# Need another certificate in server configuration (with CN=filezilla-server)
+# Use src\test\resources\org\apache\commons\net\filezillaserver\conf\settings_filezilla-server.xml
+# filezillaserver.host=filezila-server
+filezillaserver.host=localhost
+
+# password is "test"
+filezillaserver.user.test.userpassword=098f6bcd4621d373cade4e832627b4f6
+
+filezillaserver.external.enable=false
+filezillaserver.external.host=
+filezillaserver.external.port=