MicroserviceProxyController up 10/103010/1
authorDominik Mizyn <d.mizyn@samsung.com>
Wed, 4 Mar 2020 14:48:01 +0000 (15:48 +0100)
committerDominik Mizyn <d.mizyn@samsung.com>
Wed, 4 Mar 2020 14:48:03 +0000 (15:48 +0100)
MicroserviceProxyController up and all needed services

Issue-ID: PORTAL-710
Change-Id: I524a3083c22c7f52e4d8797c3e31c2de102be554
Signed-off-by: Dominik Mizyn <d.mizyn@samsung.com>
portal-BE/src/main/java/org/onap/portal/controller/MicroserviceProxyController.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/restTemplates/PortalWMSTemplate.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/service/MicroserviceProxyService.java [new file with mode: 0644]
portal-BE/src/main/java/org/onap/portal/service/microservice/EpMicroserviceService.java

diff --git a/portal-BE/src/main/java/org/onap/portal/controller/MicroserviceProxyController.java b/portal-BE/src/main/java/org/onap/portal/controller/MicroserviceProxyController.java
new file mode 100644 (file)
index 0000000..3a4fd96
--- /dev/null
@@ -0,0 +1,116 @@
+/*-
+ * ============LICENSE_START==========================================
+ * ONAP Portal
+ * ===================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ *
+ * Unless otherwise specified, all software contained herein is licensed
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this software except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Unless otherwise specified, all documentation contained herein is licensed
+ * under the Creative Commons License, Attribution 4.0 Intl. (the "License");
+ * you may not use this documentation except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *             https://creativecommons.org/licenses/by/4.0/
+ *
+ * Unless required by applicable law or agreed to in writing, documentation
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ============LICENSE_END============================================
+ *
+ *
+ */
+package org.onap.portal.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.security.Principal;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.onap.portal.domain.db.fn.FnUser;
+import org.onap.portal.service.MicroserviceProxyService;
+import org.onap.portal.service.user.FnUserService;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.HttpClientErrorException;
+
+@RestController
+@Configuration
+@EnableAspectJAutoProxy
+public class MicroserviceProxyController {
+
+    private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MicroserviceProxyController.class);
+
+    private final MicroserviceProxyService microserviceProxyService;
+    private final FnUserService fnUserService;
+
+    @Autowired
+    public MicroserviceProxyController(MicroserviceProxyService microserviceProxyService,
+        FnUserService fnUserService) {
+        this.microserviceProxyService = microserviceProxyService;
+        this.fnUserService = fnUserService;
+    }
+
+    @RequestMapping(value = {"/portalApi/microservice/proxy/{serviceId}"}, method = {
+        RequestMethod.GET}, produces = "application/json")
+    public String getMicroserviceProxy(Principal principal, HttpServletRequest request, HttpServletResponse response,
+        @PathVariable("serviceId") long serviceId) throws Exception {
+        FnUser user = fnUserService.loadUserByUsername(principal.getName());
+        String answer = "";
+        try {
+            answer = microserviceProxyService.proxyToDestination(serviceId, user, request);
+        } catch (HttpClientErrorException e) {
+            answer = e.getResponseBodyAsString();
+        }
+        return isValidJSON(answer) ? answer
+            : "{\"error\":\"" + answer.replace(System.getProperty("line.separator"), "") + "\"}";
+    }
+
+    @RequestMapping(value = {"/portalApi/microservice/proxy/parameter/{widgetId}"}, method = {
+        RequestMethod.GET}, produces = "application/json")
+    public String getMicroserviceProxyByWidgetId(Principal principal, HttpServletRequest request,
+        HttpServletResponse response,
+        @PathVariable("widgetId") long widgetId) throws Exception {
+        FnUser user = fnUserService.loadUserByUsername(principal.getName());
+        String answer = "";
+        try {
+            answer = microserviceProxyService.proxyToDestinationByWidgetId(widgetId, user, request);
+        } catch (HttpClientErrorException e) {
+            answer = e.getResponseBodyAsString();
+        }
+        return isValidJSON(answer) ? answer
+            : "{\"error\":\"" + answer.replace(System.getProperty("line.separator"), "") + "\"}";
+    }
+
+    private boolean isValidJSON(String response) {
+        try {
+            final ObjectMapper mapper = new ObjectMapper();
+            mapper.readTree(response);
+            return true;
+        } catch (IOException e) {
+            logger.debug(EELFLoggerDelegate.debugLogger, "isValidJSON failed", e);
+            return false;
+        }
+    }
+}
diff --git a/portal-BE/src/main/java/org/onap/portal/restTemplates/PortalWMSTemplate.java b/portal-BE/src/main/java/org/onap/portal/restTemplates/PortalWMSTemplate.java
new file mode 100644 (file)
index 0000000..7470744
--- /dev/null
@@ -0,0 +1,36 @@
+package org.onap.portal.restTemplates;
+
+import org.onap.portal.domain.dto.ecomp.WidgetServiceHeaders;
+import org.onap.portal.service.WidgetMService;
+import org.onap.portal.utils.EcompPortalUtils;
+import org.onap.portalsdk.core.util.SystemProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class PortalWMSTemplate {
+
+    private final RestTemplate template = new RestTemplate();
+
+    private final WidgetMService widgetMService;
+
+    @Autowired
+    public PortalWMSTemplate(WidgetMService widgetMService) {
+        this.widgetMService = widgetMService;
+    }
+
+
+    @SuppressWarnings("rawtypes")
+    public ResponseEntity<Long> proxyToDestinationByWidgetId(long widgetId) throws Exception {
+        return template.exchange(
+            EcompPortalUtils.widgetMsProtocol() + "://"
+                + widgetMService.getServiceLocation("widgets-service",
+                SystemProperties.getProperty("microservices.widget.local.port"))
+                + "/widget/microservices/widgetCatalog/parameters/" + widgetId,
+            HttpMethod.GET, new HttpEntity(WidgetServiceHeaders.getInstance()), Long.class);
+    }
+}
diff --git a/portal-BE/src/main/java/org/onap/portal/service/MicroserviceProxyService.java b/portal-BE/src/main/java/org/onap/portal/service/MicroserviceProxyService.java
new file mode 100644 (file)
index 0000000..9273b28
--- /dev/null
@@ -0,0 +1,210 @@
+package org.onap.portal.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.codec.binary.Base64;
+import org.onap.portal.domain.db.ep.EpMicroservice;
+import org.onap.portal.domain.db.ep.EpMicroserviceParameter;
+import org.onap.portal.domain.db.ep.EpWidgetCatalogParameter;
+import org.onap.portal.domain.db.fn.FnUser;
+import org.onap.portal.restTemplates.PortalWMSTemplate;
+import org.onap.portal.service.microservice.EpMicroserviceService;
+import org.onap.portal.service.widgetCatalogParameter.EpWidgetCatalogParameterService;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.onboarding.util.CipherUtil;
+import org.onap.portalsdk.core.util.SystemProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Service
+public class MicroserviceProxyService {
+
+    private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MicroserviceProxyService.class);
+
+    private static final String BASIC_AUTH = "Basic Authentication";
+    private static final String NO_AUTH = "No Authentication";
+    private static final String COOKIE_AUTH = "Cookie based Authentication";
+    private static final String QUESTION_MARK = "?";
+    private static final String ADD_MARK = "&";
+
+    private RestTemplate template = new RestTemplate();
+
+    private final EpMicroserviceService microserviceService;
+    private final EpWidgetCatalogParameterService widgetParameterService;
+
+    private final PortalWMSTemplate portalWMSTemplate;
+
+    @Autowired
+    public MicroserviceProxyService(EpMicroserviceService microserviceService,
+        EpWidgetCatalogParameterService widgetParameterService, WidgetMService widgetMService,
+        PortalWMSTemplate portalWMSTemplate) {
+        this.microserviceService = microserviceService;
+        this.widgetParameterService = widgetParameterService;
+        this.portalWMSTemplate = portalWMSTemplate;
+    }
+
+    public String proxyToDestination(long serviceId, FnUser user, HttpServletRequest request) throws Exception {
+        // get the microservice object by the id
+        Optional<EpMicroservice> data = microserviceService.getById(serviceId);
+        // No such microservice available
+        // can we return a better response than null?
+        return data
+            .map(epMicroservice -> authenticateAndRespond(epMicroservice, request, composeParams(epMicroservice, user)))
+            .orElse(null);
+    }
+
+    public String proxyToDestinationByWidgetId(long widgetId, FnUser user, HttpServletRequest request)
+        throws Exception {
+        ResponseEntity<Long> ans = portalWMSTemplate.proxyToDestinationByWidgetId(widgetId);
+        Long serviceId = ans.getBody();
+        // get the microservice object by the id
+        Optional<EpMicroservice> data = microserviceService.getById(serviceId);
+        // No such microservice available
+        if (!data.isPresent()) {
+            return null;
+        }
+        List<EpMicroserviceParameter> params = composeParams(data.get(), user);
+        for (EpMicroserviceParameter p : params) {
+            EpWidgetCatalogParameter userValue = widgetParameterService.getUserParamById(widgetId, user.getId(),
+                p.getId());
+            if (userValue != null) {
+                p.setParaValue(userValue.getUserValue());
+            }
+        }
+        return authenticateAndRespond(data.get(), request, params);
+    }
+
+    private String authenticateAndRespond(EpMicroservice data, HttpServletRequest request,
+        List<EpMicroserviceParameter> params) throws HttpClientErrorException, IllegalArgumentException {
+        String response = null;
+        switch (data.getSecurityType()) {
+            case NO_AUTH: {
+                HttpEntity<String> entity = new HttpEntity<>(headersForNoAuth());
+                String url = microserviceUrlConverter(data, params);
+                logger.debug(EELFLoggerDelegate.debugLogger,
+                    "authenticateAndRespond: Before making no authentication call: {}", url);
+                response = template.exchange(url, HttpMethod.GET, entity, String.class).getBody();
+                logger.debug(EELFLoggerDelegate.debugLogger,
+                    "authenticateAndRespond: No authentication call response: {}",
+                    response);
+                break;
+            }
+            case BASIC_AUTH: {
+                // encoding the username and password
+                String plainCreds;
+                try {
+                    plainCreds = data.getUsername() + ":" + decryptedPassword(data.getPassword());
+                } catch (Exception e) {
+                    logger.error("authenticateAndRespond failed to decrypt password", e);
+                    throw new IllegalArgumentException("Failed to decrypt password", e);
+                }
+                byte[] plainCredsBytes = plainCreds.getBytes();
+                byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
+                String base64Creds = new String(base64CredsBytes);
+
+                HttpEntity<String> entity = new HttpEntity<>(headersForBasicAuth(request, base64Creds));
+
+                String url = microserviceUrlConverter(data, params);
+                try {
+                    response = template.exchange(url, HttpMethod.GET, entity, String.class).getBody();
+                } catch (HttpClientErrorException e) {
+                    logger.error("authenticateAndRespond failed for basic security url " + url, e);
+                    throw e;
+                }
+                break;
+            }
+            case COOKIE_AUTH: {
+                HttpEntity<String> entity = new HttpEntity<>(headersForCookieAuth(request));
+                String url = microserviceUrlConverter(data, params);
+                try {
+                    response = template.exchange(url, HttpMethod.GET, entity, String.class).getBody();
+                } catch (HttpClientErrorException e) {
+                    logger.error("authenticateAndRespond failed for cookie auth url " + url, e);
+                    throw e;
+                }
+                break;
+            }
+        }
+
+        return response;
+    }
+
+    private String decryptedPassword(String encryptedPwd) throws Exception {
+        String result = "";
+        if (encryptedPwd != null && encryptedPwd.length() > 0) {
+            try {
+                result = CipherUtil.decryptPKC(encryptedPwd,
+                    SystemProperties.getProperty(SystemProperties.Decryption_Key));
+            } catch (Exception e) {
+                logger.error(EELFLoggerDelegate.errorLogger, "decryptedPassword failed", e);
+                throw e;
+            }
+        }
+
+        return result;
+    }
+
+    private String microserviceUrlConverter(EpMicroservice data, List<EpMicroserviceParameter> params) {
+        String url = data.getEndpointUrl();
+        for (int i = 0; i < params.size(); i++) {
+            if (i == 0) {
+                url += QUESTION_MARK;
+            }
+            url += params.get(i).getParaKey() + "=" + params.get(i).getParaValue();
+            if (i != (params.size() - 1)) {
+                url += ADD_MARK;
+            }
+        }
+
+        return url;
+    }
+
+    private HttpHeaders headersForNoAuth() {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+
+        return headers;
+    }
+
+    // TODO: why is this generically named cookie used?
+    private final static String Cookie = "Cookie";
+
+    private HttpHeaders headersForBasicAuth(HttpServletRequest request, String base64Creds) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Authorization", "Basic " + base64Creds);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        String rawCookie = request.getHeader(Cookie);
+        if (rawCookie != null) {
+            headers.add(Cookie, rawCookie);
+        }
+        return headers;
+    }
+
+    private HttpHeaders headersForCookieAuth(HttpServletRequest request) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        String rawCookie = request.getHeader(Cookie);
+        if (rawCookie != null) {
+            headers.add(Cookie, rawCookie);
+        }
+        return headers;
+    }
+
+    private List<EpMicroserviceParameter> composeParams(EpMicroservice data, FnUser user) {
+        List<EpMicroserviceParameter> params = new ArrayList<>(data.getEpMicroserviceParameters());
+        EpMicroserviceParameter userIdParam = new EpMicroserviceParameter();
+        userIdParam.setParaKey("userId");
+        userIdParam.setParaValue(user.getOrgUserId());
+        params.add(userIdParam);
+        return params;
+    }
+}
index 1b999f8..e93ca85 100644 (file)
@@ -1,5 +1,6 @@
 package org.onap.portal.service.microservice;
 
+import java.util.Optional;
 import org.onap.portal.domain.db.ep.EpMicroservice;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -19,4 +20,8 @@ public class EpMicroserviceService {
     public List<EpMicroservice> saveAll(List<EpMicroservice> epMicroservices) {
         return epMicroserviceDao.saveAll(epMicroservices);
     }
+
+    public Optional<EpMicroservice> getById(long serviceId) {
+        return epMicroserviceDao.findById(serviceId);
+    }
 }