Merge "Fix sql injection vulnerability"
[portal.git] / ecomp-portal-BE-common / src / main / java / org / onap / portalapp / portal / service / ApplicationsRestClientServiceImpl.java
1 /*-
2  * ============LICENSE_START==========================================
3  * ONAP Portal
4  * ===================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ===================================================================
7  *  Modifications Copyright (c) 2019 Samsung
8  * ===================================================================
9  *
10  * Unless otherwise specified, all software contained herein is licensed
11  * under the Apache License, Version 2.0 (the "License");
12  * you may not use this software except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *             http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  * Unless otherwise specified, all documentation contained herein is licensed
24  * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
25  * you may not use this documentation except in compliance with the License.
26  * You may obtain a copy of the License at
27  *
28  *             https://creativecommons.org/licenses/by/4.0/
29  *
30  * Unless required by applicable law or agreed to in writing, documentation
31  * distributed under the License is distributed on an "AS IS" BASIS,
32  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33  * See the License for the specific language governing permissions and
34  * limitations under the License.
35  *
36  * ============LICENSE_END============================================
37  *
38  * 
39  */
40 package org.onap.portalapp.portal.service;
41
42 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
43
44 import java.lang.reflect.Type;
45 import java.net.MalformedURLException;
46 import java.net.URL;
47 import java.util.Base64;
48 import java.util.Date;
49
50 import javax.annotation.PostConstruct;
51 import javax.servlet.http.HttpServletResponse;
52 import javax.ws.rs.core.MediaType;
53 import javax.ws.rs.core.Response;
54
55 import org.apache.commons.lang.StringUtils;
56 import org.apache.cxf.jaxrs.client.WebClient;
57 import org.apache.cxf.jaxrs.impl.ResponseImpl;
58 import org.apache.cxf.transport.http.HTTPException;
59 import org.onap.portalapp.portal.domain.EPApp;
60 import org.onap.portalapp.portal.logging.aop.EPAuditLog;
61 import org.onap.portalapp.portal.logging.aop.EPMetricsLog;
62 import org.onap.portalapp.portal.logging.format.EPAppMessagesEnum;
63 import org.onap.portalapp.portal.logging.logic.EPLogUtil;
64 import org.onap.portalapp.portal.utils.EPCommonSystemProperties;
65 import org.onap.portalapp.portal.utils.EcompPortalUtils;
66 import org.onap.portalapp.util.SystemType;
67 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
68 import org.onap.portalsdk.core.onboarding.exception.CipherUtilException;
69 import org.onap.portalsdk.core.onboarding.util.CipherUtil;
70 import org.onap.portalsdk.core.util.SystemProperties;
71 import org.slf4j.MDC;
72 import org.springframework.beans.factory.annotation.Autowired;
73 import org.springframework.context.annotation.EnableAspectJAutoProxy;
74 import org.springframework.stereotype.Service;
75
76 import com.fasterxml.jackson.databind.ObjectMapper;
77 import com.google.gson.Gson;
78 import com.google.gson.GsonBuilder;
79 import com.google.gson.JsonDeserializationContext;
80 import com.google.gson.JsonDeserializer;
81 import com.google.gson.JsonElement;
82 import com.google.gson.JsonParseException;
83
84 @Service("applicationsRestClientService")
85 @org.springframework.context.annotation.Configuration
86 @EnableAspectJAutoProxy
87 @EPAuditLog
88 public class ApplicationsRestClientServiceImpl implements ApplicationsRestClientService {
89
90         private static final String PASSWORD_HEADER = "password";
91
92         private static final String APP_USERNAME_HEADER = "username";
93
94         private static final String BASIC_AUTHENTICATION_HEADER = "Authorization";
95
96         private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ApplicationsRestClientServiceImpl.class);
97
98         @Autowired
99         private AppsCacheService appsCacheService;
100
101         Gson gson = null;
102
103         private final ObjectMapper mapper = new ObjectMapper();
104
105         @PostConstruct
106         private void init() {
107                 logger.debug(EELFLoggerDelegate.debugLogger, "initializing");
108                 GsonBuilder builder = new GsonBuilder();
109
110                 // Register an adapter to manage the date types as long values
111                 builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
112                         public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
113                                         throws JsonParseException {
114                                 return new Date(json.getAsJsonPrimitive().getAsLong());
115                         }
116                 });
117
118                 gson = builder.create();
119         }
120
121         // TODO: do we need to do additional logging for remote API calls?
122         private static WebClient createClientForPath(String baseUri, String path) {
123                 logger.info(EELFLoggerDelegate.debugLogger, "Creating web client for " + baseUri + "   +   " + path);
124                 WebClient client = WebClient.create(baseUri);
125                 client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
126                 client.path(path);
127                 return client;
128         }
129
130         @EPMetricsLog
131         private void verifyResponse(Response response,String restPath) throws HTTPException {
132                 int status = response.getStatus();
133                 logger.debug(EELFLoggerDelegate.debugLogger, "http response status=" + status);
134                 MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE, Integer.toString(status));
135                 if (!isHttpSuccess(status)) {
136                         String errMsg = "Failed. Status=" + status + restPath +"; [" + ((ResponseImpl)response).getStatusInfo().getReasonPhrase().toString()
137                                         + "]";
138                         URL url = null;
139                         try {
140                                 // must not be null to avoid NPE in HTTPException constructor
141                                 url = new URL("http://null");
142                                 if (((ResponseImpl)response).getLocation() != null)
143                                         url = ((ResponseImpl)response).getLocation().toURL();
144                         } catch (MalformedURLException e) {
145                                 // never mind. it is only for the debug message.
146                                 logger.warn(EELFLoggerDelegate.errorLogger, "Failed to build URL", e);
147                         }
148                         logger.error(EELFLoggerDelegate.errorLogger, "http response failed. " + restPath + errMsg + "; url=" + url);
149                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeIncorrectHttpStatusError);
150                         throw new HTTPException(status, errMsg, url);
151                 }
152         }
153
154         private static boolean isHttpSuccess(int status) {
155                 return status / 100 == 2;
156         }
157         
158         
159         private WebClient createClientForApp(long appId, String restPath) {
160                 return createClientFor(appId, restPath, SystemType.APPLICATION);
161         }
162
163         
164         
165         //TODO Need to implement the mylogins once the endpoint is confirmed
166         @EPMetricsLog
167         private WebClient createClientFor(long appSystemId, String restPath, SystemType type) {
168                 logger.debug(EELFLoggerDelegate.debugLogger, "creating client for appId=" + appSystemId + "; restPath=" + restPath);
169                 EPApp externalApp = null;
170                 
171                 if(type == SystemType.APPLICATION){
172                 externalApp = appsCacheService.getApp(appSystemId);
173                 }else{
174                         // TO DO 
175                 }
176                 
177                 if (externalApp != null) {
178                         String appBaseUri = (type == SystemType.APPLICATION) ? externalApp.getAppRestEndpoint() : "";
179                         String username = (type == SystemType.APPLICATION) ? externalApp.getUsername(): "";
180                         String encriptedPwd = (type == SystemType.APPLICATION) ? externalApp.getAppPassword(): "";
181
182                         String appName = (type == SystemType.APPLICATION) ? externalApp.getName(): "";
183                         String decreptedAppPwd = StringUtils.EMPTY;
184
185                         // Set local context
186                         MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTP);
187                         if (appBaseUri != null && appBaseUri.contains("https")) {
188                                 MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTPS);
189                         }
190                         MDC.put(EPCommonSystemProperties.FULL_URL, appBaseUri + restPath);
191                         MDC.put(EPCommonSystemProperties.TARGET_ENTITY, appName);
192                         MDC.put(EPCommonSystemProperties.TARGET_SERVICE_NAME, restPath);
193
194                         if(!encriptedPwd.isEmpty() || encriptedPwd != null || StringUtils.isEmpty(encriptedPwd)){
195                         try {
196                                 decreptedAppPwd = CipherUtil.decryptPKC(encriptedPwd,
197                                                 SystemProperties.getProperty(SystemProperties.Decryption_Key));
198                         } catch (Exception e) {
199                                 logger.error(EELFLoggerDelegate.errorLogger, "createClientFor failed to decrypt", e);
200                         }
201                         }
202                         WebClient client = createClientForPath(appBaseUri, restPath);
203                         
204                         
205                         if(externalApp.getAppPassword().isEmpty() || externalApp.getAppPassword()==null){
206                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password contains null : {}");
207
208                                 externalApp = appsCacheService.getApp(1L);
209                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App Information : {}",externalApp);
210
211                                 String mechidUsername=externalApp.getUsername();
212                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App mechidUsername Information : {}",mechidUsername);
213
214                                 String password=externalApp.getAppPassword();
215                                 String decreptedexternalAppPwd = StringUtils.EMPTY;
216                                 try {
217                                         decreptedexternalAppPwd = CipherUtil.decryptPKC(password,
218                                                         SystemProperties.getProperty(SystemProperties.Decryption_Key));
219                                 } catch (CipherUtilException e) {
220                                         logger.error(EELFLoggerDelegate.errorLogger, "failed to decreptedexternalAppPwd when external app pwd is null", e);
221                                 }
222                                 
223                                 username =mechidUsername;
224                                 decreptedAppPwd = decreptedexternalAppPwd;
225                         
226                         }else{
227                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password  is not null : {}" );
228
229                         // support basic authentication for some partners
230                         String encoding = Base64.getEncoder().encodeToString((username + ":" + decreptedAppPwd).getBytes());
231                         String encodingStr = "Basic " + encoding;
232                         client.header(BASIC_AUTHENTICATION_HEADER, encodingStr);
233                         }
234                         
235                         // But still keep code downward compatible for non compliant apps
236                         client.header(APP_USERNAME_HEADER, username);
237                         client.header(PASSWORD_HEADER, decreptedAppPwd);
238
239                         String encoding = Base64.getEncoder().encodeToString((username + ":" + decreptedAppPwd).getBytes());
240                         String encodingStr = "Basic " + encoding;
241                         client.header(BASIC_AUTHENTICATION_HEADER, encodingStr);
242                         client.header(SystemProperties.ECOMP_REQUEST_ID, MDC.get(MDC_KEY_REQUEST_ID));
243                         client.header(SystemProperties.USERAGENT_NAME, EPCommonSystemProperties.ECOMP_PORTAL_BE);
244                         logger.debug(EELFLoggerDelegate.debugLogger,
245                                         String.format("check the partner application URL App %d found, baseUri=[%s], Headers: [%s=%s]", appSystemId, appBaseUri,
246                                                         APP_USERNAME_HEADER, username));
247                         return client;
248                 }
249                 return null;
250         }
251
252         @Override
253         public <T> T get(Class<T> clazz, long appId, String restPath) throws HTTPException {
254                 T t = null;
255                 Response response = getResponse(appId, restPath);
256
257                 if (response != null) {
258                         //verifyResponse(response);
259                         verifyResponse(response,restPath);
260                         /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
261                         but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
262                         doesn't work as expected. Created Portal-253 for tracking */
263                         String str = ((ResponseImpl)response).readEntity(String.class);
264                         
265                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
266                         try {
267                                 t = gson.fromJson(str, clazz);
268                         } catch (Exception e) {
269                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
270                         }
271                 }
272
273                 return t;
274         }
275         
276         @Override
277         public String getIncomingJsonString(long appId, String restPath) throws HTTPException {
278                 Response response = getResponse(appId, restPath);
279
280                 if (response != null) {
281                         //verifyResponse(response);
282                         verifyResponse(response,restPath);
283                         /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
284                         but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
285                         doesn't work as expected. Created Portal-253 for tracking  */
286                         String incomingJson = ((ResponseImpl)response).readEntity(String.class);
287                         return incomingJson;
288                 }
289                 
290                 return "";
291         }
292
293
294         /*
295          * (non-Javadoc)
296          * 
297          * @see
298          * org.onap.portalapp.portal.service.ApplicationsRestClientService#get(
299          * java.lang.Class, long, java.lang.String, boolean)
300          */
301         @Override
302         public <T> T get(Class<T> clazz, long appId, String restPath, boolean useJacksonMapper) throws HTTPException {
303
304                 if (!useJacksonMapper)
305                         return get(clazz, appId, restPath);
306
307                 T t = null;
308                 Response response = getResponse(appId, restPath);
309
310                 if (response != null) {
311                         //verifyResponse(response);
312                         verifyResponse(response,restPath);
313                         String str = ((ResponseImpl)response).readEntity(String.class);
314                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
315
316                         try {
317                                 t = mapper.readValue(str, clazz);
318                         } catch (Exception e) {
319                                 e.printStackTrace();
320                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
321                         }
322                 }
323
324                 return t;
325         }
326
327         protected Response getResponse(long appId, String restPath) {
328                 WebClient webClient = null;
329                 Response response = null;
330
331                 webClient = createClientForApp(appId, restPath);
332                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET request =", "no-payload");
333
334                 try {
335                         if (webClient != null) {
336                                 response = webClient.get();
337                         } else {
338                                 logger.error(EELFLoggerDelegate.errorLogger,
339                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
340                         }
341                 } catch (Exception e) {
342                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
343                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
344                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
345                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the GET REST API call", e);
346                 }
347                 return response;
348         }
349         
350         
351         @SuppressWarnings({ "unchecked", "null" })
352         @Override
353         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath, SystemType type) throws HTTPException {
354                 WebClient client = null;
355                 Response response = null;
356                 T t = null;
357
358                 client = createClientFor(appId, restPath, type);
359                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST request =", payload);
360
361                 try {
362                         if (client != null) {
363                                 response = client.post(payload);
364                         } else {
365                                 logger.error(EELFLoggerDelegate.errorLogger,
366                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
367                         }
368                 } catch (Exception e) {
369                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
370                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
371                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
372                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the POST REST API call", e);
373                 }
374
375                 if (response != null) {
376                         //verifyResponse(response);
377                         verifyResponse(response,restPath);
378                         // String contentType = response.getHeaderString("Content-Type");
379                         if (clazz != null) {
380                                 String str = ((ResponseImpl)response).readEntity(String.class);
381                                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
382                                 try {
383                                         t = (T) gson.fromJson(str, clazz);
384
385                                         //t = gson.fromJson(str, clazz);
386                                 } catch (Exception e) {
387                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
388                                 }
389                         }
390                 }
391                 return t;
392         }
393
394         @Override
395         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
396                 return post( clazz, appId, payload, restPath, SystemType.APPLICATION);
397         }
398
399         
400         @Override
401         public <T> T put(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
402                 WebClient client = null;
403                 Response response = null;
404                 T t = null;
405
406                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
407
408                 client = createClientForApp(appId, restPath);
409                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT request =", payload);
410                 
411                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
412
413                 try {
414                         if (client != null) {
415                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
416
417                                 response = client.put(payload);
418                                 
419                                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
420
421                         } else {
422                                 logger.error(EELFLoggerDelegate.errorLogger,
423                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
424                         }
425                 } catch (Exception e) {
426                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
427                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
428                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
429                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the PUT REST API call", e);
430                 }
431
432                 if (response != null) {
433                         //verifyResponse(response);
434                         verifyResponse(response,restPath);
435                         String str = ((ResponseImpl)response).readEntity(String.class);
436                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT result =", str);
437                         try {
438                                 t = gson.fromJson(str, clazz);
439                         } catch (Exception e) {
440                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
441                         }
442                 }
443                 return t;
444         }
445 }