Merge "Added support for using oauth token for Kafka"
[nonrtric/plt/ranpm.git] / datafilecollector / src / main / java / org / onap / dcaegen2 / collectors / datafile / ftp / FtpesClient.java
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2018-2019 Nordix Foundation. All rights reserved.
4  * Copyright (C) 2020-2021 Nokia. All rights reserved.
5  * ===============================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7  * in compliance with the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  * ============LICENSE_END========================================================================
16  */
17
18 package org.onap.dcaegen2.collectors.datafile.ftp;
19
20 import java.io.File;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.nio.file.Path;
26 import java.security.GeneralSecurityException;
27 import java.security.KeyStore;
28 import java.security.KeyStoreException;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.UnrecoverableKeyException;
31 import java.security.cert.CertificateException;
32
33 import javax.net.ssl.KeyManager;
34 import javax.net.ssl.KeyManagerFactory;
35 import javax.net.ssl.TrustManager;
36 import javax.net.ssl.TrustManagerFactory;
37
38 import org.apache.commons.net.ftp.FTP;
39 import org.apache.commons.net.ftp.FTPReply;
40 import org.apache.commons.net.ftp.FTPSClient;
41 import org.onap.dcaegen2.collectors.datafile.commons.FileCollectClient;
42 import org.onap.dcaegen2.collectors.datafile.commons.FileServerData;
43 import org.onap.dcaegen2.collectors.datafile.commons.SecurityUtil;
44 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
45 import org.onap.dcaegen2.collectors.datafile.exceptions.NonRetryableDatafileTaskException;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.core.io.FileSystemResource;
49
50 /**
51  * Gets file from PNF with FTPS protocol.
52  *
53  * @author <a href="mailto:martin.c.yan@est.tech">Martin Yan</a>
54  */
55 public class FtpesClient implements FileCollectClient {
56     private static final Logger logger = LoggerFactory.getLogger(FtpesClient.class);
57
58     private static final int DEFAULT_PORT = 21;
59
60     FTPSClient realFtpsClient = new FTPSClient();
61     private final FileServerData fileServerData;
62     private static TrustManager theTrustManager = null;
63     private static KeyManager theKeyManager = null;
64
65     private final Path keyCertPath;
66     private final String keyCertPasswordPath;
67     private final Path trustedCaPath;
68     private final String trustedCaPasswordPath;
69
70     /**
71      * Constructor.
72      *
73      * @param fileServerData info needed to connect to the PNF.
74      * @param keyCertPath path to DFC's key cert.
75      * @param keyCertPasswordPath path of file containing password for DFC's key
76      *        cert.
77      * @param trustedCaPath path to the PNF's trusted keystore.
78      * @param trustedCaPasswordPath path of file containing password for the PNF's
79      *        trusted keystore.
80      */
81     public FtpesClient(FileServerData fileServerData, Path keyCertPath, String keyCertPasswordPath, Path trustedCaPath,
82         String trustedCaPasswordPath) {
83         this.fileServerData = fileServerData;
84         this.keyCertPath = keyCertPath;
85         this.keyCertPasswordPath = keyCertPasswordPath;
86         this.trustedCaPath = trustedCaPath;
87         this.trustedCaPasswordPath = trustedCaPasswordPath;
88     }
89
90     @Override
91     public void open() throws DatafileTaskException {
92         try {
93             realFtpsClient.setNeedClientAuth(trustedCaPath != null);
94             realFtpsClient.setKeyManager(getKeyManager(keyCertPath, keyCertPasswordPath));
95             realFtpsClient.setTrustManager(getTrustManager(trustedCaPath, trustedCaPasswordPath));
96             setUpConnection();
97         } catch (DatafileTaskException e) {
98             throw e;
99         } catch (Exception e) {
100             throw new DatafileTaskException("Could not open connection: " + e, e);
101         }
102     }
103
104     @Override
105     public void close() {
106         logger.trace("starting to closeDownConnection");
107         if (realFtpsClient.isConnected()) {
108             try {
109                 boolean logOut = realFtpsClient.logout();
110                 logger.trace("logOut: {}", logOut);
111             } catch (Exception e) {
112                 logger.trace("Unable to logout connection.", e);
113             }
114             try {
115                 realFtpsClient.disconnect();
116                 logger.trace("disconnected!");
117             } catch (Exception e) {
118                 logger.trace("Unable to disconnect connection.", e);
119             }
120         }
121     }
122
123     @Override
124     public void collectFile(String remoteFileName, Path localFileName) throws DatafileTaskException {
125         logger.trace("collectFile called");
126
127         try (OutputStream output = createOutputStream(localFileName)) {
128             logger.trace("begin to retrieve from xNF.");
129             if (!realFtpsClient.retrieveFile(remoteFileName, output)) {
130                 throw new NonRetryableDatafileTaskException(
131                     "Could not retrieve file. No retry attempts will be done, file :" + remoteFileName);
132             }
133         } catch (IOException e) {
134             throw new DatafileTaskException("Could not fetch file: " + e, e);
135         }
136         logger.trace("collectFile fetched: {}", localFileName);
137     }
138
139     private static int getPort(Integer port) {
140         return port != null ? port : DEFAULT_PORT;
141     }
142
143     private void setUpConnection() throws DatafileTaskException, IOException {
144
145         realFtpsClient.connect(fileServerData.serverAddress, getPort(fileServerData.port));
146         logger.trace("after ftp connect");
147
148         if (!realFtpsClient.login(fileServerData.userId, fileServerData.password)) {
149             throw new DatafileTaskException("Unable to log in to xNF. " + fileServerData.serverAddress);
150         }
151
152         if (FTPReply.isPositiveCompletion(realFtpsClient.getReplyCode())) {
153             realFtpsClient.enterLocalPassiveMode();
154             realFtpsClient.setFileType(FTP.BINARY_FILE_TYPE);
155             // Set protection buffer size
156             realFtpsClient.execPBSZ(0);
157             // Set data channel protection to private
158             realFtpsClient.execPROT("P");
159             realFtpsClient.setBufferSize(1024 * 1024);
160         } else {
161             throw new DatafileTaskException("Unable to connect to xNF. " + fileServerData.serverAddress
162                 + " xNF reply code: " + realFtpsClient.getReplyCode());
163         }
164
165         logger.trace("setUpConnection successfully!");
166     }
167
168     private TrustManager createTrustManager(Path trustedCaPath, String trustedCaPassword)
169         throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
170         logger.trace("Creating trust manager from file: {}", trustedCaPath);
171         try (InputStream fis = createInputStream(trustedCaPath)) {
172             KeyStore keyStore = KeyStore.getInstance("JKS");
173             keyStore.load(fis, trustedCaPassword.toCharArray());
174             TrustManagerFactory factory = TrustManagerFactory.getInstance("SunX509");
175             factory.init(keyStore);
176             return factory.getTrustManagers()[0];
177         }
178     }
179
180     protected InputStream createInputStream(Path localFileName) throws IOException {
181         FileSystemResource realResource = new FileSystemResource(localFileName);
182         return realResource.getInputStream();
183     }
184
185     protected OutputStream createOutputStream(Path localFileName) throws IOException, DatafileTaskException {
186         File localFile = localFileName.toFile();
187         if (!localFile.createNewFile()) {
188             logger.debug("Local file {} already created", localFileName);
189             throw new NonRetryableDatafileTaskException("Local file already created: " + localFileName);
190         }
191         OutputStream output = new FileOutputStream(localFile);
192         logger.trace("File {} opened xNF", localFileName);
193         return output;
194     }
195
196     protected TrustManager getTrustManager(Path trustedCaPath, String trustedCaPasswordPath)
197         throws KeyStoreException, NoSuchAlgorithmException, IOException, CertificateException {
198         synchronized (FtpesClient.class) {
199             if (theTrustManager == null && trustedCaPath != null) {
200                 String trustedCaPassword = SecurityUtil.getTruststorePasswordFromFile(trustedCaPasswordPath);
201                 theTrustManager = createTrustManager(trustedCaPath, trustedCaPassword);
202             }
203             return theTrustManager;
204         }
205     }
206
207     protected KeyManager getKeyManager(Path keyCertPath, String keyCertPasswordPath)
208         throws IOException, GeneralSecurityException {
209
210         synchronized (FtpesClient.class) {
211             if (theKeyManager == null) {
212                 String keyCertPassword = SecurityUtil.getKeystorePasswordFromFile(keyCertPasswordPath);
213                 theKeyManager = createKeyManager(keyCertPath, keyCertPassword);
214             }
215             return theKeyManager;
216         }
217     }
218
219     private KeyManager createKeyManager(Path keyCertPath, String keyCertPassword) throws IOException, KeyStoreException,
220         NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
221         logger.trace("Creating key manager from file: {}", keyCertPath);
222         try (InputStream fis = createInputStream(keyCertPath)) {
223             KeyStore keyStore = KeyStore.getInstance("JKS");
224             keyStore.load(fis, keyCertPassword.toCharArray());
225             KeyManagerFactory factory = KeyManagerFactory.getInstance("SunX509");
226             factory.init(keyStore, keyCertPassword.toCharArray());
227             return factory.getKeyManagers()[0];
228         }
229     }
230 }