View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.ftp;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.ByteArrayOutputStream;
25  import java.io.File;
26  import java.io.IOException;
27  import java.nio.charset.StandardCharsets;
28  import java.nio.file.Files;
29  import java.nio.file.Path;
30  import java.nio.file.Paths;
31  import java.time.Instant;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import org.apache.commons.io.FileUtils;
36  import org.apache.ftpserver.FtpServer;
37  import org.apache.ftpserver.FtpServerFactory;
38  import org.apache.ftpserver.ftplet.Authority;
39  import org.apache.ftpserver.ftplet.FtpException;
40  import org.apache.ftpserver.ftplet.UserManager;
41  import org.apache.ftpserver.listener.Listener;
42  import org.apache.ftpserver.listener.ListenerFactory;
43  import org.apache.ftpserver.usermanager.Md5PasswordEncryptor;
44  import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
45  import org.apache.ftpserver.usermanager.impl.BaseUser;
46  import org.apache.ftpserver.usermanager.impl.WritePermission;
47  import org.junit.jupiter.api.AfterEach;
48  import org.junit.jupiter.api.BeforeEach;
49  import org.junit.jupiter.params.ParameterizedTest;
50  import org.junit.jupiter.params.provider.ValueSource;
51  
52  public class FTPClientTransferModeTest {
53  
54      private static final class FtpServerAndPort {
55  
56          private final int port;
57          private final FtpServer ftpServer;
58  
59          FtpServerAndPort(final FtpServer ftpServer, final int port) {
60              this.port = port;
61              this.ftpServer = ftpServer;
62          }
63      }
64  
65      @FunctionalInterface
66      interface Runner {
67          void run(int port, String user, String password) throws Exception;
68      }
69  
70      private static final String DEFAULT_HOME = "ftp_root/";
71  
72      private static UserManager initUserManager(final String username, final String password) throws FtpException {
73  
74          final PropertiesUserManagerFactory propertiesUserManagerFactory = new PropertiesUserManagerFactory();
75          // TODO Update to SHA512
76          propertiesUserManagerFactory.setPasswordEncryptor(new Md5PasswordEncryptor());
77          final UserManager userManager = propertiesUserManagerFactory.createUserManager();
78          final BaseUser user = new BaseUser();
79          user.setName(username);
80          user.setPassword(password);
81  
82          final List<Authority> authorities = new ArrayList<>();
83          authorities.add(new WritePermission());
84          user.setAuthorities(authorities);
85  
86          new File(DEFAULT_HOME).mkdirs();
87          user.setHomeDirectory(DEFAULT_HOME);
88          userManager.save(user);
89          return userManager;
90      }
91  
92      private static void runWithFTPserver(final Runner runner) throws Exception {
93          final String userName = "test";
94          final String password = "test";
95          final FtpServerAndPort ftpServerAndPort = setupPlainFTPserver(userName, password);
96          try {
97              runner.run(ftpServerAndPort.port, userName, password);
98          } finally {
99              ftpServerAndPort.ftpServer.stop();
100         }
101     }
102 
103     private static FtpServerAndPort setupPlainFTPserver(final String username, final String password) throws FtpException {
104         final FtpServerFactory serverFactory = new FtpServerFactory();
105 
106         // Init user
107         serverFactory.setUserManager(initUserManager(username, password));
108 
109         final ListenerFactory factory = new ListenerFactory();
110         // Automatically assign port.
111         factory.setPort(0);
112 
113         // replace the default listener
114         final Listener listener = factory.createListener();
115         serverFactory.addListener("default", listener);
116 
117         // start the server
118         final FtpServer server = serverFactory.createServer();
119         server.start();
120 
121         return new FtpServerAndPort(server, listener.getPort());
122     }
123 
124     @BeforeEach
125     protected void setUp() throws IOException {
126         FileUtils.deleteDirectory(new File(DEFAULT_HOME));
127     }
128 
129     @AfterEach
130     protected void tearDown() throws Exception {
131         FileUtils.deleteDirectory(new File(DEFAULT_HOME));
132     }
133 
134     @ParameterizedTest
135     @ValueSource(ints = {FTP.DEFLATE_TRANSFER_MODE})
136     public void testRetrievingFiles(final int transferMode) throws Exception {
137         new File(DEFAULT_HOME).mkdirs();
138         final String filename = "test_download.txt";
139         final String fileContent = "Created at " + Instant.now();
140         Files.write(Paths.get(DEFAULT_HOME).resolve(filename), fileContent.getBytes(StandardCharsets.UTF_8));
141 
142         runWithFTPserver((port, user, password) -> {
143             final FTPClient client = new FTPClient();
144             try {
145                 client.connect("localhost", port);
146                 client.login(user, password);
147                 assertTrue(client.setFileTransferMode(transferMode));
148 
149                 final FTPFile[] files = client.listFiles();
150                 assertEquals(1, files.length);
151 
152                 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
153                 assertTrue(client.retrieveFile(files[0].getName(), bos));
154                 assertEquals(fileContent, new String(bos.toByteArray(), StandardCharsets.UTF_8));
155             } finally {
156                 client.logout();
157             }
158         });
159     }
160 
161     @ParameterizedTest
162     @ValueSource(ints = {FTP.DEFLATE_TRANSFER_MODE})
163     public void testStoringFiles(final int transferMode) throws Exception {
164         runWithFTPserver((port, user, password) -> {
165             final FTPClient client = new FTPClient();
166             try {
167                 client.connect("localhost", port);
168                 client.login(user, password);
169                 assertTrue(client.setFileTransferMode(transferMode));
170 
171                 final FTPFile[] filesBeforeUpload = client.listFiles();
172                 assertEquals(0, filesBeforeUpload.length);
173 
174                 final String fileName = "test_upload.txt";
175                 final String fileContent = "Created at " + Instant.now();
176                 assertTrue(client.storeFile(fileName, new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8))));
177 
178                 final FTPFile[] filesAfterUpload = client.listFiles();
179                 assertEquals(1, filesAfterUpload.length);
180 
181                 final Path p = Paths.get(DEFAULT_HOME, fileName);
182                 assertEquals(fileContent, new String(Files.readAllBytes(p), StandardCharsets.UTF_8));
183             } finally {
184                 client.logout();
185             }
186         });
187     }
188 
189 }