2  * ============LICENSE_START==========================================
 
   4  * ===================================================================
 
   5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 
   6  * ===================================================================
 
   7  *  Modifications Copyright (c) 2019 Samsung
 
   8  * ===================================================================
 
  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
 
  15  *             http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  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
 
  28  *             https://creativecommons.org/licenses/by/4.0/
 
  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.
 
  36  * ============LICENSE_END============================================
 
  40 package org.onap.portalapp.portal.service;
 
  42 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
 
  44 import java.lang.reflect.Type;
 
  45 import java.net.MalformedURLException;
 
  47 import java.util.Base64;
 
  48 import java.util.Date;
 
  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;
 
  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;
 
  72 import org.springframework.beans.factory.annotation.Autowired;
 
  73 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 
  74 import org.springframework.stereotype.Service;
 
  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;
 
  84 @Service("applicationsRestClientService")
 
  85 @org.springframework.context.annotation.Configuration
 
  86 @EnableAspectJAutoProxy
 
  88 public class ApplicationsRestClientServiceImpl implements ApplicationsRestClientService {
 
  90         private static final String PASSWORD_HEADER = "password";
 
  92         private static final String APP_USERNAME_HEADER = "username";
 
  94         private static final String BASIC_AUTHENTICATION_HEADER = "Authorization";
 
  96         private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ApplicationsRestClientServiceImpl.class);
 
  99         private AppsCacheService appsCacheService;
 
 103         private final ObjectMapper mapper = new ObjectMapper();
 
 106         private void init() {
 
 107                 logger.debug(EELFLoggerDelegate.debugLogger, "initializing");
 
 108                 GsonBuilder builder = new GsonBuilder();
 
 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());
 
 118                 gson = builder.create();
 
 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);
 
 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()
 
 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);
 
 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);
 
 154         private static boolean isHttpSuccess(int status) {
 
 155                 return status / 100 == 2;
 
 159         private WebClient createClientForApp(long appId, String restPath) {
 
 160                 return createClientFor(appId, restPath, SystemType.APPLICATION);
 
 165         //TODO Need to implement the mylogins once the endpoint is confirmed
 
 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;
 
 171                 if(type == SystemType.APPLICATION){
 
 172                 externalApp = appsCacheService.getApp(appSystemId);
 
 177                 if (externalApp != null) {
 
 178                         String appBaseUri = (type == SystemType.APPLICATION) ? externalApp.getAppRestEndpoint() : "";
 
 179                         String username = (type == SystemType.APPLICATION) ? externalApp.getAppBasicAuthUsername(): "";
 
 180                         String encriptedPwd = (type == SystemType.APPLICATION) ? externalApp.getAppBasicAuthPassword(): "";
 
 182                         String appName = (type == SystemType.APPLICATION) ? externalApp.getName(): "";
 
 183                         String decreptedAppPwd = StringUtils.EMPTY;
 
 186                         MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTP);
 
 187                         if (appBaseUri != null && appBaseUri.contains("https")) {
 
 188                                 MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTPS);
 
 190                         MDC.put(EPCommonSystemProperties.FULL_URL, appBaseUri + restPath);
 
 191                         MDC.put(EPCommonSystemProperties.TARGET_ENTITY, appName);
 
 192                         MDC.put(EPCommonSystemProperties.TARGET_SERVICE_NAME, restPath);
 
 194                         if(!encriptedPwd.isEmpty() || encriptedPwd != null || StringUtils.isEmpty(encriptedPwd)){
 
 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);
 
 202                         WebClient client = createClientForPath(appBaseUri, restPath);
 
 205                         if(externalApp.getAppBasicAuthPassword().isEmpty() || externalApp.getAppBasicAuthPassword()==null){
 
 206                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password contains null : {}");
 
 208                                 externalApp = appsCacheService.getApp(1L);
 
 209                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App Information : {}",externalApp);
 
 211                                 String mechidUsername=externalApp.getAppBasicAuthUsername();
 
 212                                 logger.debug(EELFLoggerDelegate.debugLogger, "external App mechidUsername Information : {}",mechidUsername);
 
 214                                 String password=externalApp.getAppBasicAuthPassword();
 
 215                                 String decreptedexternalAppPwd = StringUtils.EMPTY;
 
 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);
 
 223                                 username =mechidUsername;
 
 224                                 decreptedAppPwd = decreptedexternalAppPwd;
 
 227                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering in the externalApp get app password  is not null : {}" );
 
 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);
 
 235                         // But still keep code downward compatible for non compliant apps
 
 236                         client.header(APP_USERNAME_HEADER, username);
 
 237                         client.header(PASSWORD_HEADER, decreptedAppPwd);
 
 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));
 
 253         public <T> T get(Class<T> clazz, long appId, String restPath) throws HTTPException {
 
 255                 Response response = getResponse(appId, restPath);
 
 257                 if (response != null) {
 
 258                         verifyResponse(response,restPath);
 
 259                         /* It is not recommendable to use the implementation class org.apache.cxf.jaxrs.impl.ResponseImpl in the code, 
 
 260                         but had to force this in-order to prevent conflict with the ResponseImpl class of Jersey Client which 
 
 261                         doesn't work as expected. Created Portal-253 for tracking */
 
 262                         String str = ((ResponseImpl)response).readEntity(String.class);
 
 264                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
 
 266                                 t = gson.fromJson(str, clazz);
 
 267                         } catch (Exception e) {
 
 268                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
 
 276         public String getIncomingJsonString(long appId, String restPath) throws HTTPException {
 
 277                 Response response = getResponse(appId, restPath);
 
 279                 if (response != null) {
 
 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                         return ((ResponseImpl)response).readEntity(String.class);
 
 295          * org.onap.portalapp.portal.service.ApplicationsRestClientService#get(
 
 296          * java.lang.Class, long, java.lang.String, boolean)
 
 299         public <T> T get(Class<T> clazz, long appId, String restPath, boolean useJacksonMapper) throws HTTPException {
 
 301                 if (!useJacksonMapper)
 
 302                         return get(clazz, appId, restPath);
 
 305                 Response response = getResponse(appId, restPath);
 
 307                 if (response != null) {
 
 308                         verifyResponse(response,restPath);
 
 309                         String str = ((ResponseImpl)response).readEntity(String.class);
 
 310                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
 
 313                                 t = mapper.readValue(str, clazz);
 
 314                         } catch (Exception e) {
 
 315                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
 
 322         protected Response getResponse(long appId, String restPath) {
 
 323                 WebClient webClient = null;
 
 324                 Response response = null;
 
 326                 webClient = createClientForApp(appId, restPath);
 
 327                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET request =", "no-payload");
 
 330                         if (webClient != null) {
 
 331                                 response = webClient.get();
 
 333                                 logger.error(EELFLoggerDelegate.errorLogger,
 
 334                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
 
 336                 } catch (Exception e) {
 
 337                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
 
 338                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
 
 339                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
 
 340                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the GET REST API call", e);
 
 346         @SuppressWarnings({ "unchecked", "null" })
 
 348         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath, SystemType type) throws HTTPException {
 
 349                 WebClient client = null;
 
 350                 Response response = null;
 
 353                 client = createClientFor(appId, restPath, type);
 
 354                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST request =", payload);
 
 357                         if (client != null) {
 
 358                                 response = client.post(payload);
 
 360                                 logger.error(EELFLoggerDelegate.errorLogger,
 
 361                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
 
 363                 } catch (Exception e) {
 
 364                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
 
 365                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
 
 366                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
 
 367                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the POST REST API call", e);
 
 370                 if (response != null) {
 
 371                         verifyResponse(response,restPath);
 
 373                                 String str = ((ResponseImpl)response).readEntity(String.class);
 
 374                                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
 
 376                                         t = (T) gson.fromJson(str, clazz);
 
 377                                 } catch (Exception e) {
 
 378                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
 
 386         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
 
 387                 return post( clazz, appId, payload, restPath, SystemType.APPLICATION);
 
 392         public <T> T put(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
 
 393                 WebClient client = null;
 
 394                 Response response = null;
 
 397                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
 
 399                 client = createClientForApp(appId, restPath);
 
 400                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT request =", payload);
 
 402                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished createClientForApp method for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
 
 405                         if (client != null) {
 
 406                                 logger.debug(EELFLoggerDelegate.debugLogger, "Entering to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
 
 408                                 response = client.put(payload);
 
 410                                 logger.debug(EELFLoggerDelegate.debugLogger, "Finished to PUT for payload: {} and restPath: {} and appId: {}", payload.toString(), restPath, appId);
 
 413                                 logger.error(EELFLoggerDelegate.errorLogger,
 
 414                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
 
 416                 } catch (Exception e) {
 
 417                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
 
 418                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
 
 419                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
 
 420                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the PUT REST API call", e);
 
 423                 if (response != null) {
 
 424                         verifyResponse(response,restPath);
 
 425                         String str = ((ResponseImpl)response).readEntity(String.class);
 
 426                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT result =", str);
 
 428                                 t = gson.fromJson(str, clazz);
 
 429                         } catch (Exception e) {
 
 430                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);