View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.ftp.simpleimpl.config;
21  
22  import io.netty.handler.traffic.AbstractTrafficShapingHandler;
23  import org.dom4j.Document;
24  import org.dom4j.DocumentException;
25  import org.dom4j.Node;
26  import org.waarp.common.file.AbstractDir;
27  import org.waarp.common.file.FileParameterInterface;
28  import org.waarp.common.file.filesystembased.FilesystemBasedFileParameterImpl;
29  import org.waarp.common.file.filesystembased.specific.FilesystemBasedDirJdkAbstract;
30  import org.waarp.common.logging.WaarpLogger;
31  import org.waarp.common.logging.WaarpLoggerFactory;
32  import org.waarp.common.xml.XmlUtil;
33  import org.waarp.ftp.core.config.FtpConfiguration;
34  import org.waarp.ftp.core.control.BusinessHandler;
35  import org.waarp.ftp.core.data.handler.DataBusinessHandler;
36  import org.waarp.ftp.simpleimpl.file.SimpleAuth;
37  
38  import java.io.File;
39  import java.io.IOException;
40  import java.util.List;
41  import java.util.concurrent.ConcurrentHashMap;
42  
43  /**
44   * FtpConfiguration based on a XML file
45   */
46  public class FileBasedConfiguration extends FtpConfiguration {
47    /**
48     * Internal Logger
49     */
50    private static final WaarpLogger logger =
51        WaarpLoggerFactory.getLogger(FileBasedConfiguration.class);
52  
53    /**
54     * SERVER PASSWORD (shutdown)
55     */
56    private static final String XML_SERVER_PSSWD = "/config/serverpasswd";
57  
58    /**
59     * SERVER PORT
60     */
61    private static final String XML_SERVER_PORT = "/config/serverport";
62    /**
63     * SERVER ADDRESS if any
64     */
65    private static final String XML_SERVER_ADDRESS = "/config/serveraddress";
66    /**
67     * Base Directory
68     */
69    private static final String XML_SERVER_HOME = "/config/serverhome";
70  
71    /**
72     * Default number of threads in pool for Server.
73     */
74    private static final String XML_SERVER_THREAD = "/config/serverthread";
75  
76    /**
77     * Default number of threads in pool for Client.
78     */
79    private static final String XML_CLIENT_THREAD = "/config/clientthread";
80  
81    /**
82     * Limit per session
83     */
84    private static final String XML_LIMITSESSION = "/config/sessionlimit";
85  
86    /**
87     * Limit global
88     */
89    private static final String XML_LIMITGLOBAL = "/config/globallimit";
90  
91    /**
92     * Nb of milliseconds after connection is in timeout
93     */
94    private static final String XML_TIMEOUTCON = "/config/timeoutcon";
95  
96    /**
97     * Should a file be deleted when a Store like command is aborted
98     */
99    private static final String XML_DELETEONABORT = "/config/deleteonabort";
100 
101   /**
102    * Should a file MD5 SHA1 be computed using NIO
103    */
104   private static final String XML_USENIO = "/config/usenio";
105 
106   /**
107    * Should a file MD5 be computed using FastMD5
108    */
109   private static final String XML_USEFASTMD5 = "/config/usefastmd5";
110 
111   /**
112    * Size by default of block size for receive/sending files. Should be a
113    * multiple of 8192 (maximum = 64K due to
114    * block limitation to 2 bytes)
115    */
116   private static final String XML_BLOCKSIZE = "/config/blocksize";
117 
118   /**
119    * RANGE of PORT for Passive Mode
120    */
121   private static final String XML_RANGE_PORT_MIN = "/config/rangeport/min";
122 
123   /**
124    * RANGE of PORT for Passive Mode
125    */
126   private static final String XML_RANGE_PORT_MAX = "/config/rangeport/max";
127 
128   /**
129    * Authentication
130    */
131   private static final String XML_AUTHENTIFICATION_FILE = "/config/authentfile";
132 
133   /**
134    * Authentication Fields
135    */
136   private static final String XML_AUTHENTIFICATION_BASED = "/authent/entry";
137 
138   /**
139    * Authentication Fields
140    */
141   private static final String XML_AUTHENTIFICATION_USER = "user";
142 
143   /**
144    * Authentication Fields
145    */
146   private static final String XML_AUTHENTIFICATION_PSSWD = "passwd";
147 
148   /**
149    * Authentication Fields
150    */
151   private static final String XML_AUTHENTIFICATION_ACCOUNT = "account";
152 
153   /**
154    * Authentication Fields
155    */
156   private static final String XML_AUTHENTIFICATION_ADMIN = "admin";
157 
158   /**
159    * RANGE of PORT for Passive Mode
160    */
161   private CircularIntValue rangePort;
162 
163   /**
164    * All authentications
165    */
166   private final ConcurrentHashMap<String, SimpleAuth> authentications =
167       new ConcurrentHashMap<String, SimpleAuth>();
168 
169   /**
170    * @param classtype
171    * @param businessHandler class that will be used for
172    *     BusinessHandler
173    * @param dataBusinessHandler class that will be used for
174    *     DataBusinessHandler
175    * @param fileParameter the FileParameter to use
176    */
177   public FileBasedConfiguration(final Class<?> classtype,
178                                 final Class<? extends BusinessHandler> businessHandler,
179                                 final Class<? extends DataBusinessHandler> dataBusinessHandler,
180                                 final FileParameterInterface fileParameter) {
181     super(classtype, businessHandler, dataBusinessHandler, fileParameter);
182     computeNbThreads();
183   }
184 
185   /**
186    * Initiate the configuration from the xml file
187    *
188    * @param filename
189    *
190    * @return True if OK
191    */
192   public final boolean setConfigurationFromXml(final String filename) {
193     Document document;
194     // Open config file
195     try {
196       document = XmlUtil.getNewSaxReader().read(filename);
197     } catch (final DocumentException e) {
198       logger.error("Unable to read the XML Config file: " + filename + ": {}",
199                    e.getMessage());
200       return false;
201     }
202     if (document == null) {
203       logger.error("Unable to read the XML Config file: " + filename);
204       return false;
205     }
206     Node nodebase;
207     Node node;
208     node = document.selectSingleNode(XML_SERVER_PSSWD);
209     if (node == null) {
210       logger.error("Unable to find Password in Config file: " + filename);
211       return false;
212     }
213     final String passwd = node.getText();
214     setPassword(passwd);
215     node = document.selectSingleNode(XML_SERVER_PORT);
216     int port = 21;
217     if (node != null) {
218       port = Integer.parseInt(node.getText());
219     }
220     setServerPort(port);
221     node = document.selectSingleNode(XML_SERVER_ADDRESS);
222     String address = null;
223     if (node != null) {
224       address = node.getText();
225     }
226     setServerAddress(address);
227     node = document.selectSingleNode(XML_SERVER_HOME);
228     if (node == null) {
229       logger.error("Unable to find Home in Config file: " + filename);
230       return false;
231     }
232     final String path = node.getText();
233     final File file = new File(path);
234     try {
235       setBaseDirectory(AbstractDir.normalizePath(file.getCanonicalPath()));
236     } catch (final IOException e1) {
237       logger.error("Unable to set Home in Config file: " + filename);
238       return false;
239     }
240     if (!file.isDirectory()) {
241       logger.error("Home is not a directory in Config file: " + filename);
242       return false;
243     }
244     node = document.selectSingleNode(XML_SERVER_THREAD);
245     if (node != null) {
246       setServerThread(Integer.parseInt(node.getText()));
247     }
248     node = document.selectSingleNode(XML_CLIENT_THREAD);
249     if (node != null) {
250       setClientThread(Integer.parseInt(node.getText()));
251     }
252     if (getServerThread() == 0 || getClientThread() == 0) {
253       computeNbThreads();
254     }
255     node = document.selectSingleNode(XML_LIMITGLOBAL);
256     if (node != null) {
257       serverGlobalReadLimit = Long.parseLong(node.getText());
258       if (serverGlobalReadLimit <= 0) {
259         serverGlobalReadLimit = 0;
260       }
261       serverGlobalWriteLimit = serverGlobalReadLimit;
262       logger.warn("Global Limit: {}", serverGlobalReadLimit);
263     }
264     node = document.selectSingleNode(XML_LIMITSESSION);
265     if (node != null) {
266       serverChannelReadLimit = Long.parseLong(node.getText());
267       if (serverChannelReadLimit <= 0) {
268         serverChannelReadLimit = 0;
269       }
270       serverChannelWriteLimit = serverChannelReadLimit;
271       logger.warn("SessionInterface Limit: {}", serverChannelReadLimit);
272     }
273     delayLimit = AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL;
274     node = document.selectSingleNode(XML_TIMEOUTCON);
275     if (node != null) {
276       setTimeoutCon(Integer.parseInt(node.getText()));
277     }
278     node = document.selectSingleNode(XML_DELETEONABORT);
279     if (node != null) {
280       setDeleteOnAbort(Integer.parseInt(node.getText()) == 1);
281     }
282     node = document.selectSingleNode(XML_USENIO);
283     if (node != null) {
284       FilesystemBasedFileParameterImpl.useNio =
285           Integer.parseInt(node.getText()) == 1;
286     }
287     node = document.selectSingleNode(XML_BLOCKSIZE);
288     if (node != null) {
289       setBlocksize(Integer.parseInt(node.getText()));
290     }
291     node = document.selectSingleNode(XML_RANGE_PORT_MIN);
292     int min = 100;
293     if (node != null) {
294       min = Integer.parseInt(node.getText());
295     }
296     node = document.selectSingleNode(XML_RANGE_PORT_MAX);
297     int max = 65535;
298     if (node != null) {
299       max = Integer.parseInt(node.getText());
300     }
301     final CircularIntValue circularIntValue = new CircularIntValue(min, max);
302     setRangePort(circularIntValue);
303     // We use Apache Commons IO
304     FilesystemBasedDirJdkAbstract.ueApacheCommonsIo = true;
305     node = document.selectSingleNode(XML_AUTHENTIFICATION_FILE);
306     if (node == null) {
307       logger.error(
308           "Unable to find Authentication file in Config file: " + filename);
309       return false;
310     }
311     final String fileauthent = node.getText();
312     document = null;
313     try {
314       document = XmlUtil.getNewSaxReader().read(fileauthent);
315     } catch (final DocumentException e) {
316       logger.error(
317           "Unable to read the XML Authentication file: " + fileauthent + ": {}",
318           e.getMessage());
319       return false;
320     }
321     if (document == null) {
322       logger.error(
323           "Unable to read the XML Authentication file: " + fileauthent);
324       return false;
325     }
326     final List<Node> list = document.selectNodes(XML_AUTHENTIFICATION_BASED);
327     for (final Node value : list) {
328       nodebase = value;
329       node = nodebase.selectSingleNode(XML_AUTHENTIFICATION_USER);
330       if (node == null) {
331         continue;
332       }
333       final String user = node.getText();
334       node = nodebase.selectSingleNode(XML_AUTHENTIFICATION_PSSWD);
335       if (node == null) {
336         continue;
337       }
338       final String userpasswd = node.getText();
339       node = nodebase.selectSingleNode(XML_AUTHENTIFICATION_ADMIN);
340       boolean isAdmin = false;
341       if (node != null) {
342         isAdmin = "1".equals(node.getText());
343       }
344       final List<Node> listaccount =
345           nodebase.selectNodes(XML_AUTHENTIFICATION_ACCOUNT);
346       String[] account = null;
347       if (!listaccount.isEmpty()) {
348         account = new String[listaccount.size()];
349         int i = 0;
350         for (final Node item : listaccount) {
351           node = item;
352           account[i] = node.getText();
353           // logger.debug("User: {} Acct: {}", user, account[i])
354           i++;
355         }
356       }
357       final SimpleAuth auth = new SimpleAuth(user, userpasswd, account);
358       auth.setAdmin(isAdmin);
359       authentications.put(user, auth);
360     }
361     return true;
362   }
363 
364   /**
365    * @param user
366    *
367    * @return the SimpleAuth if any for this user
368    */
369   public final SimpleAuth getSimpleAuth(final String user) {
370     return authentications.get(user);
371   }
372 
373   /**
374    * @see FtpConfiguration#getNextRangePort()
375    */
376   @Override
377   public final int getNextRangePort() {
378     return rangePort.getNext();
379   }
380 
381   /**
382    * @param rangePort the range of available ports for Passive
383    *     connections
384    */
385   private void setRangePort(final CircularIntValue rangePort) {
386     this.rangePort = rangePort;
387   }
388 
389   @Override
390   public final void inShutdownProcess() {
391     // nothing to do
392   }
393 }