Resubmitting KeyProperty code change since tests failed
[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.onboarding.util.KeyConstants;
71 import org.onap.portalsdk.core.onboarding.util.KeyProperties;
72 import org.onap.portalsdk.core.util.SystemProperties;
73 import org.slf4j.MDC;
74 import org.springframework.beans.factory.annotation.Autowired;
75 import org.springframework.context.annotation.EnableAspectJAutoProxy;
76 import org.springframework.stereotype.Service;
77
78 import com.fasterxml.jackson.databind.ObjectMapper;
79 import com.google.gson.Gson;
80 import com.google.gson.GsonBuilder;
81 import com.google.gson.JsonDeserializationContext;
82 import com.google.gson.JsonDeserializer;
83 import com.google.gson.JsonElement;
84 import com.google.gson.JsonParseException;
85
86 @Service("applicationsRestClientService")
87 @org.springframework.context.annotation.Configuration
88 @EnableAspectJAutoProxy
89 @EPAuditLog
90 public class ApplicationsRestClientServiceImpl implements ApplicationsRestClientService {
91
92         private static final String PASSWORD_HEADER = "password";
93
94         private static final String APP_USERNAME_HEADER = "username";
95
96         private static final String BASIC_AUTHENTICATION_HEADER = "Authorization";
97
98         private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ApplicationsRestClientServiceImpl.class);
99
100         @Autowired
101         private AppsCacheService appsCacheService;
102
103         Gson gson = null;
104
105         private final ObjectMapper mapper = new ObjectMapper();
106
107         @PostConstruct
108         private void init() {
109                 logger.debug(EELFLoggerDelegate.debugLogger, "initializing");
110                 GsonBuilder builder = new GsonBuilder();
111
112                 // Register an adapter to manage the date types as long values
113                 builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
114                         public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
115                                         throws JsonParseException {
116                                 return new Date(json.getAsJsonPrimitive().getAsLong());
117                         }
118                 });
119
120                 gson = builder.create();
121         }
122
123         // TODO: do we need to do additional logging for remote API calls?
124         private static WebClient createClientForPath(String baseUri, String path) {
125                 logger.info(EELFLoggerDelegate.debugLogger, "Creating web client for " + baseUri + "   +   " + path);
126                 WebClient client = WebClient.create(baseUri);
127                 client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
128                 client.path(path);
129                 return client;
130         }
131
132         @EPMetricsLog
133         private void verifyResponse(Response response,String restPath) throws HTTPException {
134                 int status = response.getStatus();
135                 logger.debug(EELFLoggerDelegate.debugLogger, "http response status=" + status);
136                 MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE, Integer.toString(status));
137                 if (!isHttpSuccess(status)) {
138                         String errMsg = "Failed. Status=" + status + restPath +"; [" + ((ResponseImpl)response).getStatusInfo().getReasonPhrase()
139                                         + "]";
140                         URL url = null;
141                         try {
142                                 // must not be null to avoid NPE in HTTPException constructor
143                                 url = new URL("http://null");
144                                 if (((ResponseImpl)response).getLocation() != null)
145                                         url = ((ResponseImpl)response).getLocation().toURL();
146                         } catch (MalformedURLException e) {
147                                 // never mind. it is only for the debug message.
148                                 logger.warn(EELFLoggerDelegate.errorLogger, "Failed to build URL", e);
149                         }
150                         logger.error(EELFLoggerDelegate.errorLogger, "http response failed. " + restPath + errMsg + "; url=" + url);
151                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeIncorrectHttpStatusError);
152                         throw new HTTPException(status, errMsg, url);
153                 }
154         }
155
156         private static boolean isHttpSuccess(int status) {
157                 return status / 100 == 2;
158         }
159         
160         
161         private WebClient createClientForApp(long appId, String restPath) {
162                 return createClientFor(appId, restPath, SystemType.APPLICATION);
163         }
164
165         
166         
167         //TODO Need to implement the mylogins once the endpoint is confirmed
168         @EPMetricsLog
169         private WebClient createClientFor(long appSystemId, String restPath, SystemType type) {
170                 logger.debug(EELFLoggerDelegate.debugLogger, "creating client for appId=" + appSystemId + "; restPath=" + restPath);
171                 EPApp externalApp = null;
172                 
173                 if(type == SystemType.APPLICATION){
174                 externalApp = appsCacheService.getApp(appSystemId);
175                 }else{
176                         // TO DO 
177                 }
178                 
179                 if (externalApp != null) {
180                         String appBaseUri = (type == SystemType.APPLICATION) ? externalApp.getAppRestEndpoint() : "";
181                         String username = (type == SystemType.APPLICATION) ? externalApp.getAppBasicAuthUsername(): "";
182                         String encriptedPwd = (type == SystemType.APPLICATION) ? externalApp.getAppBasicAuthPassword(): "";
183
184                         String appName = (type == SystemType.APPLICATION) ? externalApp.getName(): "";
185                         String decreptedAppPwd = StringUtils.EMPTY;
186
187                         // Set local context
188                         MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTP);
189                         if (appBaseUri != null && appBaseUri.contains("https")) {
190                                 MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTPS);
191                         }
192                         MDC.put(EPCommonSystemProperties.FULL_URL, appBaseUri + restPath);
193                         MDC.put(EPCommonSystemProperties.TARGET_ENTITY, appName);
194                         MDC.put(EPCommonSystemProperties.TARGET_SERVICE_NAME, restPath);
195
196                         if(!encriptedPwd.isEmpty() || encriptedPwd != null || StringUtils.isEmpty(encriptedPwd)){
197                         try {
198                                 decreptedAppPwd = CipherUtil.decryptPKC(encriptedPwd,
199                                                 KeyProperties.getProperty(KeyConstants.CIPHER_ENCRYPTION_KEY));
200                         } catch (Exception e) {
201                                 logger.error(EELFLoggerDelegate.errorLogger, "createClientFor failed to decrypt", e);
202                         }
203                         }
204                         WebClient client = createClientForPath(appBaseUri, restPath);
205                         
206                         
207                         if(externalApp.getAppBasicAuthPassword().isEmpty() || externalApp.getAppBasicAuthPassword()==null){
208                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password contains null : {}");
209
210                                 externalApp = appsCacheService.getApp(1L);
211                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App Information : {}",externalApp);
212
213                                 String mechidUsername=externalApp.getAppBasicAuthUsername();
214                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App mechidUsername Information : {}",mechidUsername);
215
216                                 String password=externalApp.getAppBasicAuthPassword();
217                                 String decreptedexternalAppPwd = StringUtils.EMPTY;
218                                 try {
219                                         decreptedexternalAppPwd = CipherUtil.decryptPKC(password,
220                                                         KeyProperties.getProperty(KeyConstants.CIPHER_ENCRYPTION_KEY));
221                                 } catch (CipherUtilException e) {
222                                         logger.error(EELFLoggerDelegate.errorLogger, "failed to decreptedexternalAppPwd when external app pwd is null", e);
223                                 }
224                                 
225                                 username =mechidUsername;
226                                 decreptedAppPwd = decreptedexternalAppPwd;
227                         
228                         }else{
229                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password  is not null : {}" );
230
231                         // support basic authentication for some partners
232                         String encoding = Base64.getEncoder().encodeToString((username + ":" + decreptedAppPwd).getBytes());
233                         String encodingStr = "Basic " + encoding;
234                         client.header(BASIC_AUTHENTICATION_HEADER, encodingStr);
235                         }
236                         
237                         // But still keep code downward compatible for non compliant apps
238                         client.header(APP_USERNAME_HEADER, username);
239                         client.header(PASSWORD_HEADER, decreptedAppPwd);
240
241                         String encoding = Base64.getEncoder().encodeToString((username + ":" + decreptedAppPwd).getBytes());
242                         String encodingStr = "Basic " + encoding;
243                         client.header(BASIC_AUTHENTICATION_HEADER, encodingStr);
244                         client.header(SystemProperties.ECOMP_REQUEST_ID, MDC.get(MDC_KEY_REQUEST_ID));
245                         client.header(SystemProperties.USERAGENT_NAME, EPCommonSystemProperties.ECOMP_PORTAL_BE);
246                         logger.debug(EELFLoggerDelegate.debugLogger,
247                                         String.format("check the partner application URL App %d found, baseUri=[%s], Headers: [%s=%s]", appSystemId, appBaseUri,
248                                                         APP_USERNAME_HEADER, username));
249                         return client;
250                 }
251                 return null;
252         }
253
254         @Override
255         public <T> T get(Class<T> clazz, long appId, String restPath) throws HTTPException {
256                 T t = null;
257                 Response response = getResponse(appId, restPath);
258
259                 if (response != null) {
260                         verifyResponse(response,restPath);
261                         /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
262                         but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
263                         doesn't work as expected. Created Portal-253 for tracking */
264                         String str = ((ResponseImpl)response).readEntity(String.class);
265                         
266                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
267                         try {
268                                 t = gson.fromJson(str, clazz);
269                         } catch (Exception e) {
270                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
271                         }
272                 }
273
274                 return t;
275         }
276         
277         @Override
278         public String getIncomingJsonString(long appId, String restPath) throws HTTPException {
279                 Response response = getResponse(appId, restPath);
280
281                 if (response != null) {
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                         return ((ResponseImpl)response).readEntity(String.class);
287                 }
288                 
289                 return "";
290         }
291
292
293         /*
294          * (non-Javadoc)
295          * 
296          * @see
297          * org.onap.portalapp.portal.service.ApplicationsRestClientService#get(
298          * java.lang.Class, long, java.lang.String, boolean)
299          */
300         @Override
301         public <T> T get(Class<T> clazz, long appId, String restPath, boolean useJacksonMapper) throws HTTPException {
302
303                 if (!useJacksonMapper)
304                         return get(clazz, appId, restPath);
305
306                 T t = null;
307                 Response response = getResponse(appId, restPath);
308
309                 if (response != null) {
310                         verifyResponse(response,restPath);
311                         String str = ((ResponseImpl)response).readEntity(String.class);
312                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
313
314                         try {
315                                 t = mapper.readValue(str, clazz);
316                         } catch (Exception e) {
317                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
318                         }
319                 }
320
321                 return t;
322         }
323
324         protected Response getResponse(long appId, String restPath) {
325                 WebClient webClient = null;
326                 Response response = null;
327
328                 webClient = createClientForApp(appId, restPath);
329                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET request =", "no-payload");
330
331                 try {
332                         if (webClient != null) {
333                                 response = webClient.get();
334                         } else {
335                                 logger.error(EELFLoggerDelegate.errorLogger,
336                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
337                         }
338                 } catch (Exception e) {
339                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
340                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
341                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
342                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the GET REST API call", e);
343                 }
344                 return response;
345         }
346         
347         
348         @SuppressWarnings({ "unchecked", "null" })
349         @Override
350         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath, SystemType type) throws HTTPException {
351                 WebClient client = null;
352                 Response response = null;
353                 T t = null;
354
355                 client = createClientFor(appId, restPath, type);
356                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST request =", payload);
357
358                 try {
359                         if (client != null) {
360                                 response = client.post(payload);
361                         } else {
362                                 logger.error(EELFLoggerDelegate.errorLogger,
363                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
364                         }
365                 } catch (Exception e) {
366                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
367                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
368                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
369                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the POST REST API call", e);
370                 }
371
372                 if (response != null) {
373                         verifyResponse(response,restPath);
374                         if (clazz != null) {
375                                 String str = ((ResponseImpl)response).readEntity(String.class);
376                                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
377                                 try {
378                                         t = (T) gson.fromJson(str, clazz);
379                                 } catch (Exception e) {
380                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
381                                 }
382                         }
383                 }
384                 return t;
385         }
386
387         @Override
388         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
389                 return post( clazz, appId, payload, restPath, SystemType.APPLICATION);
390         }
391
392         
393         @Override
394         public <T> T put(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
395                 WebClient client = null;
396                 Response response = null;
397                 T t = null;
398
399                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
400
401                 client = createClientForApp(appId, restPath);
402                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT request =", payload);
403                 
404                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
405
406                 try {
407                         if (client != null) {
408                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
409
410                                 response = client.put(payload);
411                                 
412                                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
413
414                         } else {
415                                 logger.error(EELFLoggerDelegate.errorLogger,
416                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
417                         }
418                 } catch (Exception e) {
419                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
420                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
421                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
422                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the PUT REST API call", e);
423                 }
424
425                 if (response != null) {
426                         verifyResponse(response,restPath);
427                         String str = ((ResponseImpl)response).readEntity(String.class);
428                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT result =", str);
429                         try {
430                                 t = gson.fromJson(str, clazz);
431                         } catch (Exception e) {
432                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
433                         }
434                 }
435                 return t;
436         }
437 }