dme2 & ueb support
[ccsdk/sli/plugins.git] / restapi-call-node / provider / src / main / java / org / onap / ccsdk / sli / plugins / restapicall / RestapiCallNode.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                      reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.plugins.restapicall;
23
24 import com.sun.jersey.api.client.ClientHandlerException;
25 import com.sun.jersey.api.client.UniformInterfaceException;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.net.SocketException;
29 import java.net.URI;
30 import java.nio.file.Files;
31 import java.nio.file.Paths;
32 import java.security.KeyStore;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Properties;
41 import java.util.Set;
42
43 import javax.net.ssl.HostnameVerifier;
44 import javax.net.ssl.HttpsURLConnection;
45 import javax.net.ssl.KeyManagerFactory;
46 import javax.net.ssl.SSLContext;
47 import javax.net.ssl.SSLSession;
48 import javax.ws.rs.core.EntityTag;
49 import javax.ws.rs.core.MultivaluedMap;
50 import javax.ws.rs.core.UriBuilder;
51
52 import org.apache.commons.lang3.StringUtils;
53 import org.codehaus.jettison.json.JSONException;
54 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
55 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
56 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import com.sun.jersey.api.client.Client;
61 import com.sun.jersey.api.client.ClientResponse;
62 import com.sun.jersey.api.client.WebResource;
63 import com.sun.jersey.api.client.config.ClientConfig;
64 import com.sun.jersey.api.client.config.DefaultClientConfig;
65 import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
66 import com.sun.jersey.api.client.filter.HTTPDigestAuthFilter;
67 import com.sun.jersey.oauth.client.OAuthClientFilter;
68 import com.sun.jersey.oauth.signature.OAuthParameters;
69 import com.sun.jersey.oauth.signature.OAuthSecrets;
70 import com.sun.jersey.client.urlconnection.HTTPSProperties;
71
72 public class RestapiCallNode implements SvcLogicJavaPlugin {
73
74     private static final Logger log = LoggerFactory.getLogger(RestapiCallNode.class);
75
76     private String uebServers;
77     private String defaultUebTemplateFileName = "/opt/bvc/restapi/templates/default-ueb-message.json";
78     protected RetryPolicyStore retryPolicyStore;
79     protected static final String DME2_PROPERTIES_FILE_NAME = "dme2.properties";
80     protected static final String UEB_PROPERTIES_FILE_NAME = "ueb.properties";
81     protected static final String DEFAULT_PROPERTIES_DIR = "/opt/onap/ccsdk/data/properties";
82     protected static final String PROPERTIES_DIR_KEY = "SDNC_CONFIG_DIR";
83
84     protected RetryPolicyStore getRetryPolicyStore() {
85         return retryPolicyStore;
86     }
87
88     public void setRetryPolicyStore(RetryPolicyStore retryPolicyStore) {
89         this.retryPolicyStore = retryPolicyStore;
90     }
91
92     public RestapiCallNode() {
93         String configDir = System.getProperty(PROPERTIES_DIR_KEY, DEFAULT_PROPERTIES_DIR);
94
95         try (FileInputStream in = new FileInputStream(configDir + "/" + DME2_PROPERTIES_FILE_NAME)) {
96             Properties props = new Properties();
97             props.load(in);
98             this.retryPolicyStore = new RetryPolicyStore();
99             this.retryPolicyStore.setProxyServers(props.getProperty("proxyUrl"));
100             log.info("DME2 support enabled");
101         } catch (Exception e) {
102             log.warn("DME2 properties could not be read, DME2 support will not be enabled.", e);
103         }
104
105         try (FileInputStream in = new FileInputStream(configDir + "/" + UEB_PROPERTIES_FILE_NAME)) {
106             Properties props = new Properties();
107             props.load(in);
108             this.uebServers = props.getProperty("servers");
109             log.info("UEB support enabled");
110         } catch (Exception e) {
111             log.warn("UEB properties could not be read, UEB support will not be enabled.", e);
112         }
113     }
114
115      /**
116      * Allows Directed Graphs  the ability to interact with REST APIs.
117      * @param paramMap HashMap<String,String> of parameters passed by the DG to this function
118      * <table border="1">
119      *  <thead><th>parameter</th><th>Mandatory/Optional</th><th>description</th><th>example values</th></thead>
120      *  <tbody>
121      *      <tr><td>templateFileName</td><td>Optional</td><td>full path to template file that can be used to build a request</td><td>/sdncopt/bvc/restapi/templates/vnf_service-configuration-operation_minimal.json</td></tr>
122      *      <tr><td>restapiUrl</td><td>Mandatory</td><td>url to send the request to</td><td>https://sdncodl:8543/restconf/operations/L3VNF-API:create-update-vnf-request</td></tr>
123      *      <tr><td>restapiUser</td><td>Optional</td><td>user name to use for http basic authentication</td><td>sdnc_ws</td></tr>
124      *      <tr><td>restapiPassword</td><td>Optional</td><td>unencrypted password to use for http basic authentication</td><td>plain_password</td></tr>
125      *      <tr><td>oAuthConsumerKey</td><td>Optional</td><td>Consumer key to use for http oAuth authentication</td><td>plain_key</td></tr>
126      *      <tr><td>oAuthConsumerSecret</td><td>Optional</td><td>Consumer secret to use for http oAuth authentication</td><td>plain_secret</td></tr>
127      *      <tr><td>oAuthSignatureMethod</td><td>Optional</td><td>Consumer method to use for http oAuth authentication</td><td>method</td></tr>
128      *      <tr><td>oAuthVersion</td><td>Optional</td><td>Version http oAuth authentication</td><td>version</td></tr>
129      *      <tr><td>contentType</td><td>Optional</td><td>http content type to set in the http header</td><td>usually application/json or application/xml</td></tr>
130      *      <tr><td>format</td><td>Optional</td><td>should match request body format</td><td>json or xml</td></tr>
131      *      <tr><td>httpMethod</td><td>Optional</td><td>http method to use when sending the request</td><td>get post put delete patch</td></tr>
132      *      <tr><td>responsePrefix</td><td>Optional</td><td>location the response will be written to in context memory</td><td>tmp.restapi.result</td></tr>
133      *      <tr><td>listName[i]</td><td>Optional</td><td>Used for processing XML responses with repeating elements.</td>vpn-information.vrf-details<td></td></tr>
134      *      <tr><td>skipSending</td><td>Optional</td><td></td><td>true or false</td></tr>
135      *      <tr><td>convertResponse </td><td>Optional</td><td>whether the response should be converted</td><td>true or false</td></tr>
136      *      <tr><td>customHttpHeaders</td><td>Optional</td><td>a list additional http headers to be passed in, follow the format in the example</td><td>X-CSI-MessageId=messageId,headerFieldName=headerFieldValue</td></tr>
137      *      <tr><td>dumpHeaders</td><td>Optional</td><td>when true writes http header content to context memory</td><td>true or false</td></tr>
138      *      <tr><td>partner</td><td>Optional</td><td>needed for DME2 calls</td><td>dme2proxy</td></tr>
139      *      <tr><td>returnRequestPayload</td><td>Optional</td><td>used to return payload built in the request</td><td>true or false</td></tr>
140      *  </tbody>
141      * </table>
142      * @param ctx Reference to context memory
143      * @throws SvcLogicException
144      * @since 11.0.2
145      * @see String#split(String, int)
146      */
147     public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
148         sendRequest(paramMap, ctx, null);
149     }
150
151     public void sendRequest(Map<String, String> paramMap, SvcLogicContext ctx, Integer retryCount)
152             throws SvcLogicException {
153
154         RetryPolicy retryPolicy = null;
155         HttpResponse r = new HttpResponse();
156         try {
157             Parameters p = getParameters(paramMap);
158             if (p.partner != null) {
159                 retryPolicy = retryPolicyStore.getRetryPolicy(p.partner);
160             }
161             String pp = p.responsePrefix != null ? p.responsePrefix + '.' : "";
162
163             String req = null;
164             if (p.templateFileName != null) {
165                 String reqTemplate = readFile(p.templateFileName);
166                 req = buildXmlJsonRequest(ctx, reqTemplate, p.format);
167             } else if (p.requestBody != null) {
168                 req = p.requestBody;
169             }
170             r = sendHttpRequest(req, p);
171             setResponseStatus(ctx, p.responsePrefix, r);
172
173             if (p.dumpHeaders && r.headers != null) {
174                 for (Entry<String, List<String>> a : r.headers.entrySet()) {
175                     ctx.setAttribute(pp + "header." + a.getKey(), StringUtils.join(a.getValue(), ","));
176                 }
177             }
178             
179             if (p.returnRequestPayload && req != null) {
180                 ctx.setAttribute(pp + "httpRequest", req);
181             }
182
183             if (r.body != null && r.body.trim().length() > 0) {
184                 ctx.setAttribute(pp + "httpResponse", r.body);
185
186                 if (p.convertResponse) {
187                     Map<String, String> mm = null;
188                     if (p.format == Format.XML)
189                         mm = XmlParser.convertToProperties(r.body, p.listNameList);
190                     else if (p.format == Format.JSON)
191                         mm = JsonParser.convertToProperties(r.body);
192
193                     if (mm != null)
194                         for (Map.Entry<String,String> entry : mm.entrySet())
195                             ctx.setAttribute(pp + entry.getKey(), entry.getValue());
196                 }
197             }
198         } catch (SvcLogicException e) {
199             boolean shouldRetry = false;
200             if (e.getCause().getCause() instanceof SocketException) {
201                 shouldRetry = true;
202             }
203
204             log.error("Error sending the request: " + e.getMessage(), e);
205             String prefix = parseParam(paramMap, "responsePrefix", false, null);
206             if (retryPolicy == null || shouldRetry == false) {
207                 setFailureResponseStatus(ctx, prefix, e.getMessage(), r);
208             } else {
209                 if (retryCount == null) {
210                     retryCount = 0;
211                 }
212                 String retryMessage = retryCount + " attempts were made out of " + retryPolicy.getMaximumRetries() +
213                         " maximum retries.";
214                 log.debug(retryMessage);
215                 try {
216                     retryCount = retryCount + 1;
217                     if (retryCount < retryPolicy.getMaximumRetries() + 1) {
218                         URI uri = new URI(paramMap.get("restapiUrl"));
219                         String hostname = uri.getHost();
220                         String retryString = retryPolicy.getNextHostName(uri.toString());
221                         URI uriTwo = new URI(retryString);
222                         URI retryUri = UriBuilder.fromUri(uri).host(uriTwo.getHost()).port(uriTwo.getPort()).scheme(
223                                 uriTwo.getScheme()).build();
224                         paramMap.put("restapiUrl", retryUri.toString());
225                         log.debug("URL was set to {}", retryUri.toString());
226                         log.debug("Failed to communicate with host {}. Request will be re-attempted using the host {}.",
227                             hostname, retryString);
228                         log.debug("This is retry attempt {} out of {}", retryCount, retryPolicy.getMaximumRetries());
229                         sendRequest(paramMap, ctx, retryCount);
230                     } else {
231                         log.debug("Maximum retries reached, calling setFailureResponseStatus.");
232                         setFailureResponseStatus(ctx, prefix, e.getMessage(), r);
233                     }
234                 } catch (Exception ex) {
235                     log.error("Could not attempt retry.", ex);
236                     String retryErrorMessage =
237                             "Retry attempt has failed. No further retry shall be attempted, calling " +
238                                 "setFailureResponseStatus.";
239                     setFailureResponseStatus(ctx, prefix, retryErrorMessage, r);
240                 }
241             }
242         }
243
244         if (r != null && r.code >= 300)
245             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
246     }
247
248     protected Parameters getParameters(Map<String, String> paramMap) throws SvcLogicException {
249         Parameters p = new Parameters();
250         p.templateFileName = parseParam(paramMap, "templateFileName", false, null);
251         p.requestBody = parseParam(paramMap, "requestBody", false, null);
252         p.restapiUrl = parseParam(paramMap, "restapiUrl", true, null);
253         validateUrl(p.restapiUrl);
254         p.restapiUser = parseParam(paramMap, "restapiUser", false, null);
255         p.restapiPassword = parseParam(paramMap, "restapiPassword", false, null);
256         p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null);
257         p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
258         p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
259         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
260         p.contentType = parseParam(paramMap, "contentType", false, null);
261         p.format = Format.fromString(parseParam(paramMap, "format", false, "json"));
262         p.authtype = AuthType.fromString(parseParam(paramMap, "authType", false, "unspecified"));
263         p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod", false, "post"));
264         p.responsePrefix = parseParam(paramMap, "responsePrefix", false, null);
265         p.listNameList = getListNameList(paramMap);
266         String skipSendingStr = paramMap.get("skipSending");
267         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
268         p.convertResponse = Boolean.valueOf(parseParam(paramMap, "convertResponse", false, "true"));
269         p.trustStoreFileName = parseParam(paramMap, "trustStoreFileName", false, null);
270         p.trustStorePassword = parseParam(paramMap, "trustStorePassword", false, null);
271         p.keyStoreFileName = parseParam(paramMap, "keyStoreFileName", false, null);
272         p.keyStorePassword = parseParam(paramMap, "keyStorePassword", false, null);
273         p.ssl = p.trustStoreFileName != null && p.trustStorePassword != null && p.keyStoreFileName != null &&
274                 p.keyStorePassword != null;
275         p.customHttpHeaders = parseParam(paramMap, "customHttpHeaders", false, null);
276         p.partner = parseParam(paramMap, "partner", false, null);
277         p.dumpHeaders = Boolean.valueOf(parseParam(paramMap, "dumpHeaders", false, null));
278         p.returnRequestPayload = Boolean.valueOf(parseParam(paramMap, "returnRequestPayload", false, null));
279         return p;
280     }
281
282     private void validateUrl(String restapiUrl) throws SvcLogicException {
283         try {
284             URI.create(restapiUrl);
285         } catch (IllegalArgumentException e) {
286             throw new SvcLogicException("Invalid input of url " + e.getLocalizedMessage(), e);
287         }
288     }
289
290     protected Set<String> getListNameList(Map<String, String> paramMap) {
291         Set<String> ll = new HashSet<>();
292         for (Map.Entry<String,String> entry : paramMap.entrySet())
293             if (entry.getKey().startsWith("listName"))
294                 ll.add(entry.getValue());
295         return ll;
296     }
297
298     protected String parseParam(Map<String, String> paramMap, String name, boolean required, String def)
299             throws SvcLogicException {
300         String s = paramMap.get(name);
301
302         if (s == null || s.trim().length() == 0) {
303             if (!required)
304                 return def;
305             throw new SvcLogicException("Parameter " + name + " is required in RestapiCallNode");
306         }
307
308         s = s.trim();
309         StringBuilder value = new StringBuilder();
310         int i = 0;
311         int i1 = s.indexOf('%');
312         while (i1 >= 0) {
313             int i2 = s.indexOf('%', i1 + 1);
314             if (i2 < 0)
315                 break;
316
317             String varName = s.substring(i1 + 1, i2);
318             String varValue = System.getenv(varName);
319             if (varValue == null)
320                 varValue = "%" + varName + "%";
321
322             value.append(s.substring(i, i1));
323             value.append(varValue);
324
325             i = i2 + 1;
326             i1 = s.indexOf('%', i);
327         }
328         value.append(s.substring(i));
329
330         log.info("Parameter {}: [{}]", name, value);
331         return value.toString();
332     }
333
334     protected String buildXmlJsonRequest(SvcLogicContext ctx, String template, Format format)
335         throws SvcLogicException {
336         log.info("Building {} started", format);
337         long t1 = System.currentTimeMillis();
338
339         template = expandRepeats(ctx, template, 1);
340
341         Map<String, String> mm = new HashMap<>();
342         for (String s : ctx.getAttributeKeySet())
343             mm.put(s, ctx.getAttribute(s));
344
345         StringBuilder ss = new StringBuilder();
346         int i = 0;
347         while (i < template.length()) {
348             int i1 = template.indexOf("${", i);
349             if (i1 < 0) {
350                 ss.append(template.substring(i));
351                 break;
352             }
353
354             int i2 = template.indexOf('}', i1 + 2);
355             if (i2 < 0)
356                 throw new SvcLogicException("Template error: Matching } not found");
357
358             String var1 = template.substring(i1 + 2, i2);
359             String value1 = format == Format.XML ? XmlJsonUtil.getXml(mm, var1) : XmlJsonUtil.getJson(mm, var1);
360             // log.info(" " + var1 + ": " + value1);
361             if (value1 == null || value1.trim().length() == 0) {
362                 // delete the whole element (line)
363                 int i3 = template.lastIndexOf('\n', i1);
364                 if (i3 < 0)
365                     i3 = 0;
366                 int i4 = template.indexOf('\n', i1);
367                 if (i4 < 0)
368                     i4 = template.length();
369
370                 if (i < i3)
371                     ss.append(template.substring(i, i3));
372                 i = i4;
373             } else {
374                 ss.append(template.substring(i, i1)).append(value1);
375                 i = i2 + 1;
376             }
377         }
378
379         String req = format == Format.XML
380                 ? XmlJsonUtil.removeEmptyStructXml(ss.toString()) : XmlJsonUtil.removeEmptyStructJson(ss.toString());
381
382         if (format == Format.JSON)
383             req = XmlJsonUtil.removeLastCommaJson(req);
384
385         long t2 = System.currentTimeMillis();
386         log.info("Building {} completed. Time: {}", format, (t2 - t1));
387
388         return req;
389     }
390
391     protected String expandRepeats(SvcLogicContext ctx, String template, int level) throws SvcLogicException {
392         StringBuilder newTemplate = new StringBuilder();
393         int k = 0;
394         while (k < template.length()) {
395             int i1 = template.indexOf("${repeat:", k);
396             if (i1 < 0) {
397                 newTemplate.append(template.substring(k));
398                 break;
399             }
400
401             int i2 = template.indexOf(':', i1 + 9);
402             if (i2 < 0)
403                 throw new SvcLogicException(
404                         "Template error: Context variable name followed by : is required after repeat");
405
406             // Find the closing }, store in i3
407             int nn = 1;
408             int i3 = -1;
409             int i = i2;
410             while (nn > 0 && i < template.length()) {
411                 i3 = template.indexOf('}', i);
412                 if (i3 < 0)
413                     throw new SvcLogicException("Template error: Matching } not found");
414                 int i32 = template.indexOf('{', i);
415                 if (i32 >= 0 && i32 < i3) {
416                     nn++;
417                     i = i32 + 1;
418                 } else {
419                     nn--;
420                     i = i3 + 1;
421                 }
422             }
423
424             String var1 = template.substring(i1 + 9, i2);
425             String value1 = ctx.getAttribute(var1);
426             log.info("     {}:{}", var1, value1);
427             int n = 0;
428             try {
429                 n = Integer.parseInt(value1);
430             } catch (NumberFormatException e) {
431                 log.info("value1 not set or not a number, n will remain set at zero");
432             }
433
434             newTemplate.append(template.substring(k, i1));
435
436             String rpt = template.substring(i2 + 1, i3);
437
438             for (int ii = 0; ii < n; ii++) {
439                 String ss = rpt.replaceAll("\\[\\$\\{" + level + "\\}\\]", "[" + ii + "]");
440                 if (ii == n - 1 && ss.trim().endsWith(",")) {
441                     int i4 = ss.lastIndexOf(',');
442                     if (i4 > 0)
443                         ss = ss.substring(0, i4) + ss.substring(i4 + 1);
444                 }
445                 newTemplate.append(ss);
446             }
447
448             k = i3 + 1;
449         }
450
451         if (k == 0)
452             return newTemplate.toString();
453
454         return expandRepeats(ctx, newTemplate.toString(), level + 1);
455     }
456
457     protected String readFile(String fileName) throws SvcLogicException {
458         try {
459             byte[] encoded = Files.readAllBytes(Paths.get(fileName));
460             return new String(encoded, "UTF-8");
461         } catch (IOException | SecurityException e) {
462             throw new SvcLogicException("Unable to read file " + fileName + e.getLocalizedMessage(), e);
463         }
464     }
465
466     protected Client addAuthType(Client c, FileParam fp) throws SvcLogicException {
467         Parameters p = new Parameters();
468         p.restapiUser = fp.user;
469         p.restapiPassword = fp.password;
470         p.oAuthConsumerKey = fp.oAuthConsumerKey;
471         p.oAuthVersion = fp.oAuthVersion;
472         p.oAuthConsumerSecret = fp.oAuthConsumerSecret;
473         p.oAuthSignatureMethod = fp.oAuthSignatureMethod;
474         p.authtype = fp.authtype;
475         return addAuthType(c,p);
476     }
477
478     protected Client addAuthType(Client client, Parameters p) throws SvcLogicException {
479         if (p.authtype == AuthType.Unspecified){
480             if (p.restapiUser != null && p.restapiPassword != null)
481                 client.addFilter(new HTTPBasicAuthFilter(p.restapiUser, p.restapiPassword));
482             else if(p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null
483                     && p.oAuthSignatureMethod != null) {
484                 OAuthParameters params = new OAuthParameters()
485                         .signatureMethod(p.oAuthSignatureMethod)
486                         .consumerKey(p.oAuthConsumerKey)
487                         .version(p.oAuthVersion);
488
489                 OAuthSecrets secrets = new OAuthSecrets()
490                         .consumerSecret(p.oAuthConsumerSecret);
491                 client.addFilter(new OAuthClientFilter(client.getProviders(), params, secrets));
492             }
493         } else {
494             if (p.authtype == AuthType.DIGEST) {
495                 if (p.restapiUser != null && p.restapiPassword != null) {
496                     client.addFilter(new HTTPDigestAuthFilter(p.restapiUser, p.restapiPassword));
497                 } else {
498                     throw new SvcLogicException("oAUTH authentication type selected but all restapiUser and restapiPassword " +
499                                                         "parameters doesn't exist", new Throwable());
500                 }
501             } else if (p.authtype == AuthType.BASIC){
502                 if (p.restapiUser != null && p.restapiPassword != null) {
503                     client.addFilter(new HTTPBasicAuthFilter(p.restapiUser, p.restapiPassword));
504                 } else {
505                     throw new SvcLogicException("oAUTH authentication type selected but all restapiUser and restapiPassword " +
506                                                         "parameters doesn't exist", new Throwable());
507                 }
508             } else if(p.authtype == AuthType.OAUTH ) {
509                 if(p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) {
510                     OAuthParameters params = new OAuthParameters()
511                             .signatureMethod(p.oAuthSignatureMethod)
512                             .consumerKey(p.oAuthConsumerKey)
513                             .version(p.oAuthVersion);
514
515                     OAuthSecrets secrets = new OAuthSecrets()
516                             .consumerSecret(p.oAuthConsumerSecret);
517                     client.addFilter(new OAuthClientFilter(client.getProviders(), params, secrets));
518                 } else {
519                     throw new SvcLogicException("oAUTH authentication type selected but all oAuthConsumerKey, oAuthConsumerSecret " +
520                                                         "and oAuthSignatureMethod parameters doesn't exist", new Throwable());
521                 }
522             }
523         }
524         return client;
525     }
526
527     protected HttpResponse sendHttpRequest(String request, Parameters p) throws SvcLogicException {
528
529         ClientConfig config = new DefaultClientConfig();
530         SSLContext ssl = null;
531         if (p.ssl && p.restapiUrl.startsWith("https"))
532             ssl = createSSLContext(p);
533         if (ssl != null) {
534             HostnameVerifier hostnameVerifier = (hostname, session) -> true;
535
536             config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
537                     new HTTPSProperties(hostnameVerifier, ssl));
538         }
539
540         logProperties(config.getProperties());
541
542         Client client = Client.create(config);
543         client.setConnectTimeout(5000);
544         WebResource webResource = addAuthType(client,p).resource(p.restapiUrl);
545
546         log.info("Sending request:");
547         log.info(request);
548         long t1 = System.currentTimeMillis();
549
550         HttpResponse r = new HttpResponse();
551         r.code = 200;
552
553         if (!p.skipSending) {
554             String tt = p.format == Format.XML ? "application/xml" : "application/json";
555             String tt1 = tt + ";charset=UTF-8";
556             if (p.contentType != null) {
557                 tt = p.contentType;
558                 tt1 = p.contentType;
559             }
560
561             WebResource.Builder webResourceBuilder = webResource.accept(tt).type(tt1);
562             if(p.format == Format.NONE){
563                 webResourceBuilder = webResource.header("","");
564             }
565
566             if (p.customHttpHeaders != null && p.customHttpHeaders.length() > 0) {
567                 String[] keyValuePairs = p.customHttpHeaders.split(",");
568                 for (String singlePair : keyValuePairs) {
569                     int equalPosition = singlePair.indexOf('=');
570                     webResourceBuilder.header(singlePair.substring(0, equalPosition),
571                             singlePair.substring(equalPosition + 1, singlePair.length()));
572                 }
573             }
574
575             webResourceBuilder.header("X-ECOMP-RequestID",org.slf4j.MDC.get("X-ECOMP-RequestID"));
576
577             ClientResponse response;
578
579             try {
580                 response = webResourceBuilder.method(p.httpMethod.toString(), ClientResponse.class, request);
581             } catch (UniformInterfaceException | ClientHandlerException e) {
582                 throw new SvcLogicException("Exception while sending http request to client "
583                     + e.getLocalizedMessage(), e);
584             }
585
586             r.code = response.getStatus();
587             r.headers = response.getHeaders();
588             EntityTag etag = response.getEntityTag();
589             if (etag != null)
590                 r.message = etag.getValue();
591             if (response.hasEntity() && r.code != 204)
592                 r.body = response.getEntity(String.class);
593         }
594
595         long t2 = System.currentTimeMillis();
596         log.info("Response received. Time: {}", (t2 - t1));
597         log.info("HTTP response code: {}", r.code);
598         log.info("HTTP response message: {}", r.message);
599         logHeaders(r.headers);
600         log.info("HTTP response: {}", r.body);
601
602         return r;
603     }
604
605     protected SSLContext createSSLContext(Parameters p) {
606         try (FileInputStream in = new FileInputStream(p.keyStoreFileName)) {
607             System.setProperty("jsse.enableSNIExtension", "false");
608             System.setProperty("javax.net.ssl.trustStore", p.trustStoreFileName);
609             System.setProperty("javax.net.ssl.trustStorePassword", p.trustStorePassword);
610
611             HttpsURLConnection.setDefaultHostnameVerifier((string, ssls) -> true);
612
613             KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
614             KeyStore ks = KeyStore.getInstance("PKCS12");
615             char[] pwd = p.keyStorePassword.toCharArray();
616             ks.load(in, pwd);
617             kmf.init(ks, pwd);
618
619             SSLContext ctx = SSLContext.getInstance("TLS");
620             ctx.init(kmf.getKeyManagers(), null, null);
621             return ctx;
622         } catch (Exception e) {
623             log.error("Error creating SSLContext: {}", e.getMessage(), e);
624         }
625         return null;
626     }
627
628     protected void setFailureResponseStatus(SvcLogicContext ctx, String prefix, String errorMessage,
629         HttpResponse resp) {
630         resp.code = 500;
631         resp.message = errorMessage;
632         String pp = prefix != null ? prefix + '.' : "";
633         ctx.setAttribute(pp + "response-code", String.valueOf(resp.code));
634         ctx.setAttribute(pp + "response-message", resp.message);
635     }
636
637     protected void setResponseStatus(SvcLogicContext ctx, String prefix, HttpResponse r) {
638         String pp = prefix != null ? prefix + '.' : "";
639         ctx.setAttribute(pp + "response-code", String.valueOf(r.code));
640         ctx.setAttribute(pp + "response-message", r.message);
641     }
642
643     public void sendFile(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
644         HttpResponse r = null;
645         try {
646             FileParam p = getFileParameters(paramMap);
647             byte[] data = Files.readAllBytes(Paths.get(p.fileName));
648
649             r = sendHttpData(data, p);
650             setResponseStatus(ctx, p.responsePrefix, r);
651
652         } catch (SvcLogicException | IOException e) {
653             log.error("Error sending the request: {}", e.getMessage(), e);
654
655             r = new HttpResponse();
656             r.code = 500;
657             r.message = e.getMessage();
658             String prefix = parseParam(paramMap, "responsePrefix", false, null);
659             setResponseStatus(ctx, prefix, r);
660         }
661
662         if (r != null && r.code >= 300)
663             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
664     }
665
666     private static class FileParam {
667
668         public String fileName;
669         public String url;
670         public String user;
671         public String password;
672         public HttpMethod httpMethod;
673         public String responsePrefix;
674         public boolean skipSending;
675         public String oAuthConsumerKey;
676         public String oAuthConsumerSecret;
677         public String oAuthSignatureMethod;
678         public String oAuthVersion;
679         public AuthType authtype;
680     }
681
682     private FileParam getFileParameters(Map<String, String> paramMap) throws SvcLogicException {
683         FileParam p = new FileParam();
684         p.fileName = parseParam(paramMap, "fileName", true, null);
685         p.url = parseParam(paramMap, "url", true, null);
686         p.user = parseParam(paramMap, "user", false, null);
687         p.password = parseParam(paramMap, "password", false, null);
688         p.httpMethod = HttpMethod.fromString(parseParam(paramMap, "httpMethod", false, "post"));
689         p.responsePrefix = parseParam(paramMap, "responsePrefix", false, null);
690         String skipSendingStr = paramMap.get("skipSending");
691         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
692         p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null);
693         p.oAuthVersion = parseParam(paramMap, "oAuthVersion", false, null);
694         p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null);
695         p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null);
696         p.authtype = AuthType.fromString(parseParam(paramMap, "authType", false, "unspecified"));
697         return p;
698     }
699
700     protected HttpResponse sendHttpData(byte[] data, FileParam p) throws SvcLogicException {
701         Client client = Client.create();
702         client.setConnectTimeout(5000);
703         client.setFollowRedirects(true);
704         WebResource webResource = addAuthType(client,p).resource(p.url);
705
706         log.info("Sending file");
707         long t1 = System.currentTimeMillis();
708
709         HttpResponse r = new HttpResponse();
710         r.code = 200;
711
712         if (!p.skipSending) {
713             String tt = "application/octet-stream";
714
715             ClientResponse response;
716             try {
717                 if (p.httpMethod == HttpMethod.POST)
718                     response = webResource.accept(tt).type(tt).post(ClientResponse.class, data);
719                 else if (p.httpMethod == HttpMethod.PUT)
720                     response = webResource.accept(tt).type(tt).put(ClientResponse.class, data);
721                 else
722                     throw new SvcLogicException("Http operation" + p.httpMethod + "not supported");
723             } catch (UniformInterfaceException | ClientHandlerException e) {
724                 throw new SvcLogicException("Exception while sending http request to client " +
725                     e.getLocalizedMessage(), e);
726             }
727
728             r.code = response.getStatus();
729             r.headers = response.getHeaders();
730             EntityTag etag = response.getEntityTag();
731             if (etag != null)
732                 r.message = etag.getValue();
733             if (response.hasEntity() && r.code != 204)
734                 r.body = response.getEntity(String.class);
735
736             if (r.code == 301) {
737                 String newUrl = response.getHeaders().getFirst("Location");
738
739                 log.info("Got response code 301. Sending same request to URL: {}", newUrl);
740
741                 webResource = client.resource(newUrl);
742
743                 try {
744                     if (p.httpMethod == HttpMethod.POST)
745                         response = webResource.accept(tt).type(tt).post(ClientResponse.class, data);
746                     else if (p.httpMethod == HttpMethod.PUT)
747                         response = webResource.accept(tt).type(tt).put(ClientResponse.class, data);
748                     else
749                         throw new SvcLogicException("Http operation" + p.httpMethod + "not supported");
750                 } catch (UniformInterfaceException | ClientHandlerException e) {
751                     throw new SvcLogicException("Exception while sending http request to client " +
752                         e.getLocalizedMessage(), e);
753                 }
754
755                 r.code = response.getStatus();
756                 etag = response.getEntityTag();
757                 if (etag != null)
758                     r.message = etag.getValue();
759                 if (response.hasEntity() && r.code != 204)
760                     r.body = response.getEntity(String.class);
761             }
762         }
763
764         long t2 = System.currentTimeMillis();
765         log.info("Response received. Time: {}", (t2 - t1));
766         log.info("HTTP response code: {}", r.code);
767         log.info("HTTP response message: {}", r.message);
768         logHeaders(r.headers);
769         log.info("HTTP response: {}", r.body);
770
771         return r;
772     }
773
774     public void postMessageOnUeb(Map<String, String> paramMap, SvcLogicContext ctx) throws SvcLogicException {
775         HttpResponse r;
776         try {
777             UebParam p = getUebParameters(paramMap);
778
779             String pp = p.responsePrefix != null ? p.responsePrefix + '.' : "";
780
781             String req;
782
783             if (p.templateFileName == null) {
784                 log.info("No template file name specified. Using default UEB template: {}", defaultUebTemplateFileName);
785                 p.templateFileName = defaultUebTemplateFileName;
786             }
787
788             String reqTemplate = readFile(p.templateFileName);
789             reqTemplate = reqTemplate.replaceAll("rootVarName", p.rootVarName);
790             req = buildXmlJsonRequest(ctx, reqTemplate, Format.JSON);
791
792             r = postOnUeb(req, p);
793             setResponseStatus(ctx, p.responsePrefix, r);
794             if (r.body != null)
795                 ctx.setAttribute(pp + "httpResponse", r.body);
796
797         } catch (SvcLogicException e) {
798             log.error("Error sending the request: {}", e.getMessage(), e);
799
800             r = new HttpResponse();
801             r.code = 500;
802             r.message = e.getMessage();
803             String prefix = parseParam(paramMap, "responsePrefix", false, null);
804             setResponseStatus(ctx, prefix, r);
805         }
806
807         if (r.code >= 300)
808             throw new SvcLogicException(String.valueOf(r.code) + ": " + r.message);
809     }
810
811     private static class UebParam {
812
813         public String topic;
814         public String templateFileName;
815         public String rootVarName;
816         public String responsePrefix;
817         public boolean skipSending;
818     }
819
820     private UebParam getUebParameters(Map<String, String> paramMap) throws SvcLogicException {
821         UebParam p = new UebParam();
822         p.topic = parseParam(paramMap, "topic", true, null);
823         p.templateFileName = parseParam(paramMap, "templateFileName", false, null);
824         p.rootVarName = parseParam(paramMap, "rootVarName", false, null);
825         p.responsePrefix = parseParam(paramMap, "responsePrefix", false, null);
826         String skipSendingStr = paramMap.get("skipSending");
827         p.skipSending = "true".equalsIgnoreCase(skipSendingStr);
828         return p;
829     }
830
831     protected HttpResponse postOnUeb(String request, UebParam p) throws SvcLogicException {
832         String[] urls = uebServers.split(" ");
833         for (int i = 0; i < urls.length; i++) {
834             if (!urls[i].endsWith("/"))
835                 urls[i] += "/";
836             urls[i] += "events/" + p.topic;
837         }
838
839         Client client = Client.create();
840         client.setConnectTimeout(5000);
841         WebResource webResource = client.resource(urls[0]);
842
843         log.info("UEB URL: {}", urls[0]);
844         log.info("Sending request:");
845         log.info(request);
846         long t1 = System.currentTimeMillis();
847
848         HttpResponse r = new HttpResponse();
849         r.code = 200;
850
851         if (!p.skipSending) {
852             String tt = "application/json";
853             String tt1 = tt + ";charset=UTF-8";
854
855             ClientResponse response;
856
857             try {
858                 response = webResource.accept(tt).type(tt1).post(ClientResponse.class, request);
859             } catch (UniformInterfaceException | ClientHandlerException e) {
860                 throw new SvcLogicException("Exception while posting http request to client " +
861                     e.getLocalizedMessage(), e);
862             }
863
864             r.code = response.getStatus();
865             r.headers = response.getHeaders();
866             if (response.hasEntity())
867                 r.body = response.getEntity(String.class);
868         }
869
870         long t2 = System.currentTimeMillis();
871         log.info("Response received. Time: {}", (t2 - t1));
872         log.info("HTTP response code: {}", r.code);
873         logHeaders(r.headers);
874         log.info("HTTP response:\n {}", r.body);
875
876         return r;
877     }
878
879     protected void logProperties(Map<String, Object> mm) {
880         List<String> ll = new ArrayList<>();
881         for (Object o : mm.keySet())
882             ll.add((String) o);
883         Collections.sort(ll);
884
885         log.info("Properties:");
886         for (String name : ll)
887             log.info("--- {}:{}", name, String.valueOf(mm.get(name)));
888     }
889
890     protected void logHeaders(MultivaluedMap<String, String> mm) {
891         log.info("HTTP response headers:");
892
893         if (mm == null)
894             return;
895
896         List<String> ll = new ArrayList<>();
897         for (Object o : mm.keySet())
898             ll.add((String) o);
899         Collections.sort(ll);
900
901         for (String name : ll)
902             log.info("--- {}:{}", name, String.valueOf(mm.get(name)));
903     }
904
905     public void setUebServers(String uebServers) {
906         this.uebServers = uebServers;
907     }
908
909     public void setDefaultUebTemplateFileName(String defaultUebTemplateFileName) {
910         this.defaultUebTemplateFileName = defaultUebTemplateFileName;
911     }
912 }