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