b0404eed64bdd1664d0124f90b80c2cc0793dd3c
[ccsdk/features.git] /
1 /*******************************************************************************
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  ******************************************************************************/
18 package org.onap.ccsdk.features.sdnr.wt.devicemanager.base.http;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.net.HttpURLConnection;
28 import java.net.URL;
29 import java.net.URLConnection;
30 import java.nio.charset.Charset;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.Files;
33 import java.security.KeyFactory;
34 import java.security.KeyManagementException;
35 import java.security.KeyStore;
36 import java.security.KeyStoreException;
37 import java.security.NoSuchAlgorithmException;
38 import java.security.UnrecoverableKeyException;
39 import java.security.cert.Certificate;
40 import java.security.cert.CertificateException;
41 import java.security.cert.CertificateFactory;
42 import java.security.cert.X509Certificate;
43 import java.security.interfaces.RSAPrivateKey;
44 import java.security.spec.InvalidKeySpecException;
45 import java.security.spec.PKCS8EncodedKeySpec;
46 import java.util.Base64;
47 import java.util.Map;
48 import javax.annotation.Nonnull;
49 import javax.net.ssl.HostnameVerifier;
50 import javax.net.ssl.HttpsURLConnection;
51 import javax.net.ssl.KeyManager;
52 import javax.net.ssl.KeyManagerFactory;
53 import javax.net.ssl.SSLContext;
54 import javax.net.ssl.TrustManager;
55 import javax.xml.bind.DatatypeConverter;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public class BaseHTTPClient {
60
61     private static Logger LOG = LoggerFactory.getLogger(BaseHTTPClient.class);
62     private static final int SSLCERT_NONE = -1;
63     private static final int SSLCERT_PCKS = 0;
64     private static final int SSLCERT_PEM = 1;
65     private static final int BUFSIZE = 1024;
66     private static final Charset CHARSET = StandardCharsets.UTF_8;
67     private static final String SSLCONTEXT = "TLSv1.2";
68     private static final int DEFAULT_HTTP_TIMEOUT_MS = 30000; // in ms
69
70     private final boolean trustAll;
71     private final String baseUrl;
72
73     private int timeout = DEFAULT_HTTP_TIMEOUT_MS;
74     private SSLContext sc = null;
75
76     public BaseHTTPClient(String base) {
77         this(base, false);
78     }
79
80     public BaseHTTPClient(String base, boolean trustAllCerts) {
81         this(base, trustAllCerts, null, null, SSLCERT_NONE);
82     }
83
84     public BaseHTTPClient(String base, boolean trustAllCerts, String certFilename, String passphrase, int sslCertType) {
85         this.baseUrl = base;
86         this.trustAll = trustAllCerts;
87         try {
88             sc = setupSsl(trustAll, certFilename, passphrase, sslCertType);
89         } catch (KeyManagementException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException
90                 | KeyStoreException | IOException | InvalidKeySpecException e) {
91             LOG.warn("problem ssl setup: " + e.getMessage());
92         }
93     }
94
95     protected @Nonnull BaseHTTPResponse sendRequest(String uri, String method, String body, Map<String, String> headers)
96             throws IOException {
97         return this.sendRequest(uri, method, body != null ? body.getBytes(CHARSET) : null, headers);
98     }
99
100     protected @Nonnull BaseHTTPResponse sendRequest(String uri, String method, byte[] body, Map<String, String> headers)
101             throws IOException {
102         if (uri == null) {
103             uri = "";
104         }
105         String surl = this.baseUrl;
106         if (!surl.endsWith("/") && uri.length() > 0) {
107             surl += "/";
108         }
109         if (uri.startsWith("/")) {
110             uri = uri.substring(1);
111         }
112         surl += uri;
113         LOG.debug("try to send request with url=" + this.baseUrl + uri + " as method=" + method);
114         LOG.trace("body:" + (body == null ? "null" : new String(body, CHARSET)));
115         URL url = new URL(surl);
116         URLConnection http = url.openConnection();
117         http.setConnectTimeout(this.timeout);
118         if (surl.toString().startsWith("https")) {
119             if (sc != null) {
120                 ((HttpsURLConnection) http).setSSLSocketFactory(sc.getSocketFactory());
121                 if (trustAll) {
122                     LOG.debug("trusting all certs");
123                     HostnameVerifier allHostsValid = (hostname, session) -> true;
124                     ((HttpsURLConnection) http).setHostnameVerifier(allHostsValid);
125                 }
126             } else // Should never happen
127             {
128                 LOG.warn("No SSL context available");
129                 return new BaseHTTPResponse(-1, "");
130             }
131         }
132         ((HttpURLConnection) http).setRequestMethod(method);
133         http.setDoOutput(true);
134         if (headers != null && headers.size() > 0) {
135             for (String key : headers.keySet()) {
136                 http.setRequestProperty(key, headers.get(key));
137                 LOG.trace("set http header " + key + ": " + headers.get(key));
138             }
139         }
140         byte[] buffer = new byte[BUFSIZE];
141         int len = 0, lensum = 0;
142         // send request
143         // Send the message to destination
144         if (!method.equals("GET") && body != null && body.length > 0) {
145             try (OutputStream output = http.getOutputStream()) {
146                 output.write(body);
147             }
148         }
149         // Receive answer
150         int responseCode = ((HttpURLConnection) http).getResponseCode();
151         String sresponse = "";
152         InputStream response = null;
153         try {
154             if (responseCode >= 200 && responseCode < 300) {
155                 response = http.getInputStream();
156             } else {
157                 response = ((HttpURLConnection) http).getErrorStream();
158                 if (response == null) {
159                     response = http.getInputStream();
160                 }
161             }
162             if (response != null) {
163                 while (true) {
164                     len = response.read(buffer, 0, BUFSIZE);
165                     if (len <= 0) {
166                         break;
167                     }
168                     lensum += len;
169                     sresponse += new String(buffer, 0, len, CHARSET);
170                 }
171             } else {
172                 LOG.debug("response is null");
173             }
174         } catch (Exception e) {
175             LOG.debug("No response. ", e);
176         } finally {
177             if (response != null) {
178                 response.close();
179             }
180         }
181         LOG.debug("ResponseCode: " + responseCode);
182         LOG.trace("Response (len:{}): {}", String.valueOf(lensum), sresponse);
183         return new BaseHTTPResponse(responseCode, sresponse);
184     }
185
186     public static SSLContext setupSsl(boolean trustall)
187             throws NoSuchAlgorithmException, KeyManagementException, CertificateException, FileNotFoundException,
188             IOException, UnrecoverableKeyException, KeyStoreException, InvalidKeySpecException {
189
190         return setupSsl(trustall, null, null, SSLCERT_NONE);
191     }
192
193     /**
194      * @param keyFilename filename for key file
195      * @param certFilename filename for cert file
196      * @throws NoSuchAlgorithmException
197      * @throws KeyManagementException
198      * @throws IOException
199      * @throws FileNotFoundException
200      * @throws CertificateException
201      * @throws KeyStoreException
202      * @throws UnrecoverableKeyException
203      * @throws InvalidKeySpecException
204      */
205     /**
206      * Setup of SSLContext
207      *
208      * @param trustall true to switch of certificate verification
209      * @param certFilename filename for certificate file
210      * @param passPhrase for certificate
211      * @param certType of certificate
212      * @return SSL Context according to parameters
213      * @throws NoSuchAlgorithmException according name
214      * @throws KeyManagementException according name
215      * @throws CertificateException according name
216      * @throws FileNotFoundException according name
217      * @throws IOException according name
218      * @throws UnrecoverableKeyException according name
219      * @throws KeyStoreException according name
220      * @throws InvalidKeySpecException according name
221      */
222     public static SSLContext setupSsl(boolean trustall, String certFilename, String passPhrase, int certType)
223             throws NoSuchAlgorithmException, KeyManagementException, CertificateException, FileNotFoundException,
224             IOException, UnrecoverableKeyException, KeyStoreException, InvalidKeySpecException {
225
226         SSLContext sc = SSLContext.getInstance(SSLCONTEXT);
227         TrustManager[] trustCerts = null;
228         if (trustall) {
229             trustCerts = new TrustManager[] {new javax.net.ssl.X509TrustManager() {
230                 @Override
231                 public java.security.cert.X509Certificate[] getAcceptedIssuers() {
232                     return null;
233                 }
234
235                 @Override
236                 public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
237
238                 @Override
239                 public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
240             }};
241
242         }
243         KeyManager[] kms = null;
244         if (certFilename != null && passPhrase != null && !certFilename.isEmpty() && !passPhrase.isEmpty()) {
245             if (certType == SSLCERT_PCKS) {
246                 LOG.debug("try to load pcks file " + certFilename + " with passphrase=" + passPhrase);
247                 KeyStore keyStore = KeyStore.getInstance("PKCS12");
248                 FileInputStream fileInputStream = new FileInputStream(certFilename);
249                 keyStore.load(fileInputStream, passPhrase.toCharArray());
250                 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
251                 kmf.init(keyStore, passPhrase.toCharArray());
252                 kms = kmf.getKeyManagers();
253                 fileInputStream.close();
254                 LOG.debug("successful");
255
256             } else if (certType == SSLCERT_PEM) {
257                 LOG.debug("try to load pem files cert=" + certFilename + " key=" + passPhrase);
258                 File fCert = new File(certFilename);
259                 File fKey = new File(passPhrase);
260                 KeyStore keyStore = KeyStore.getInstance("JKS");
261                 keyStore.load(null);
262                 byte[] certBytes = parseDERFromPEM(Files.readAllBytes(fCert.toPath()), "-----BEGIN CERTIFICATE-----",
263                         "-----END CERTIFICATE-----");
264                 byte[] keyBytes = parseDERFromPEM(Files.readAllBytes(fKey.toPath()), "-----BEGIN PRIVATE KEY-----",
265                         "-----END PRIVATE KEY-----");
266
267                 X509Certificate cert = generateCertificateFromDER(certBytes);
268                 RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
269                 keyStore.setCertificateEntry("cert-alias", cert);
270                 keyStore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] {cert});
271
272                 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
273                 kmf.init(keyStore, "changeit".toCharArray());
274                 kms = kmf.getKeyManagers();
275                 LOG.debug("successful");
276             }
277         }
278         // Init the SSLContext with a TrustManager[] and SecureRandom()
279         sc.init(kms, trustCerts, new java.security.SecureRandom());
280         return sc;
281     }
282
283     protected static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
284         String data = new String(pem);
285         String[] tokens = data.split(beginDelimiter);
286         tokens = tokens[1].split(endDelimiter);
287         return DatatypeConverter.parseBase64Binary(tokens[0]);
288     }
289
290     protected static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes)
291             throws InvalidKeySpecException, NoSuchAlgorithmException {
292         PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
293
294         KeyFactory factory = KeyFactory.getInstance("RSA");
295
296         return (RSAPrivateKey) factory.generatePrivate(spec);
297     }
298
299     protected static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
300         CertificateFactory factory = CertificateFactory.getInstance("X.509");
301
302         return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
303     }
304
305     public static String getAuthorizationHeaderValue(String username, String password) {
306         return "Basic " + new String(Base64.getEncoder().encode((username + ":" + password).getBytes()));
307     }
308
309     public void setTimeout(int timeout) {
310         this.timeout = timeout;
311     }
312
313     public static int getSslCertPcks() {
314         return SSLCERT_PCKS;
315     }
316
317     public static int getSslCertNone() {
318         return SSLCERT_NONE;
319     }
320
321     public static int getSslCertPEM() {
322         return SSLCERT_PEM;
323     }
324
325 }