From 4d04e56e297cb9808a7e5378480526ba44f6a0bd Mon Sep 17 00:00:00 2001 From: liamfallon Date: Mon, 7 Nov 2022 13:53:29 +0000 Subject: Move GUI forwarding to gui-server from clamp-be This commit: - Adds redirect support for policy-api to the gui-server microservice. The gui-server can now proxy and forward calls to it across to policy-api, and can act as an autherntication/authorization gateway for policy-api for https - Adds redirect support for clamp-ACM, as for policy-gui - Restructured the static pages to add a designtime-ui and runtime-ui strucuture for current and future UIs - CLAMP UI moved into the runtime-ui part - Apex editor moved into the designtime-ui part - Unit tests added and coverage on code is > 95% This change moves the forwarding functionality from the clamp-backend microservice to the gui-server microservice, so once this review is merged, the clamp-backend microservice is no longer needed. Issue-ID: POLICY-4138 Change-Id: I4b45f7026d13b5e1046198cdba52074668b29956 Signed-off-by: liamfallon --- gui-server/pom.xml | 4 +- .../config/AcmRuntimeRestTemplateConfig.java | 54 +++++++ .../gui/server/config/BaseRestTemplateConfig.java | 91 ++++++++++++ .../gui/server/config/ClampRestTemplateConfig.java | 94 ------------ .../server/config/FilterRegistrationConfig.java | 14 +- .../server/config/PolicyApiRestTemplateConfig.java | 54 +++++++ .../gui/server/config/StaticContentConfig.java | 8 +- .../gui/server/filters/ClientSslHeaderFilter.java | 8 +- .../gui/server/rest/AcmRuntimeRestController.java | 76 ++++++++++ .../gui/server/rest/ApexEditorRestController.java | 41 ----- .../policy/gui/server/rest/BaseRestController.java | 72 +++++++++ .../gui/server/rest/ClampRestController.java | 79 ---------- .../gui/server/rest/PolicyApiRestController.java | 76 ++++++++++ .../main/resources/static/designtime-ui/index.html | 12 ++ gui-server/src/main/resources/static/index.html | 4 +- .../main/resources/static/runtime-ui/index.html | 12 ++ .../policy/gui/server/GuiServerAppMainTest.java | 11 +- .../onap/policy/gui/server/SpringContextTest.java | 9 +- .../config/ClampRestTemplateConfig1Test.java | 69 --------- .../config/ClampRestTemplateConfig2Test.java | 61 -------- .../config/ClampRestTemplateConfig3Test.java | 70 --------- .../config/ClampRestTemplateConfig4Test.java | 67 --------- .../config/ClampRestTemplateConfig5Test.java | 69 --------- .../config/ClampRestTemplateConfig6Test.java | 57 ------- .../gui/server/config/RestTemplateConfig1Test.java | 69 +++++++++ .../gui/server/config/RestTemplateConfig2Test.java | 60 ++++++++ .../gui/server/config/RestTemplateConfig3Test.java | 70 +++++++++ .../gui/server/config/RestTemplateConfig4Test.java | 67 +++++++++ .../gui/server/config/RestTemplateConfig5Test.java | 67 +++++++++ .../config/RestTemplateTrustStoreUnsetTest.java | 65 ++++++++ .../server/rest/AcmRuntimeRestControllerTest.java | 165 +++++++++++++++++++++ .../server/rest/ApexEditorRestControllerTest.java | 61 -------- .../gui/server/rest/ClampRestControllerTest.java | 161 -------------------- .../server/rest/DesigntimeRestControllerTest.java | 59 ++++++++ .../server/rest/PolicyApiRestControllerTest.java | 165 +++++++++++++++++++++ .../gui/server/test/util/RestTemplateConfig.java | 56 +++++++ .../src/test/resources/application_http.yaml | 23 ++- .../src/test/resources/application_https.yaml | 34 +++++ 38 files changed, 1379 insertions(+), 855 deletions(-) create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/config/AcmRuntimeRestTemplateConfig.java create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/config/BaseRestTemplateConfig.java delete mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig.java create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/config/PolicyApiRestTemplateConfig.java create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/rest/AcmRuntimeRestController.java delete mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/rest/ApexEditorRestController.java create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/rest/BaseRestController.java delete mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/rest/ClampRestController.java create mode 100644 gui-server/src/main/java/org/onap/policy/gui/server/rest/PolicyApiRestController.java create mode 100644 gui-server/src/main/resources/static/designtime-ui/index.html create mode 100644 gui-server/src/main/resources/static/runtime-ui/index.html delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig1Test.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig2Test.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig3Test.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig4Test.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig5Test.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig6Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig1Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig2Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig3Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig4Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig5Test.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateTrustStoreUnsetTest.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/rest/AcmRuntimeRestControllerTest.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/rest/ApexEditorRestControllerTest.java delete mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/rest/ClampRestControllerTest.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/rest/DesigntimeRestControllerTest.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/rest/PolicyApiRestControllerTest.java create mode 100644 gui-server/src/test/java/org/onap/policy/gui/server/test/util/RestTemplateConfig.java create mode 100644 gui-server/src/test/resources/application_https.yaml diff --git a/gui-server/pom.xml b/gui-server/pom.xml index ef1563b..b774f0d 100644 --- a/gui-server/pom.xml +++ b/gui-server/pom.xml @@ -112,7 +112,7 @@ clamp-build tar.gz true - ${project.build.directory}/classes/static + ${project.build.directory}/classes/static/runtime-ui @@ -121,7 +121,7 @@ ${project.version} jar true - ${project.build.directory}/classes/static/apex-editor + ${project.build.directory}/classes/static/designtime-ui/apex-editor static/** diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/AcmRuntimeRestTemplateConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/AcmRuntimeRestTemplateConfig.java new file mode 100644 index 0000000..e326a63 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/config/AcmRuntimeRestTemplateConfig.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class AcmRuntimeRestTemplateConfig extends BaseRestTemplateConfig { + + /** + * Set the SSL validation flags on the template. + * + * @param disableSslValidation Turn off SSL altogether on this REST interface + * @param disableSslHostnameCheck Turn off SSL host name checking + */ + @Value("{runtime-ui.acm}") + public void setSslFlags( + @Value("${runtime-ui.acm.disable-ssl-validation:false}") boolean disableSslValidation, + @Value("${runtime-ui.acm.disable-ssl-hostname-check:false}") boolean disableSslHostnameCheck) { + super.setDisableSslValidation(disableSslValidation); + super.setDisableSslHostnameCheck(disableSslHostnameCheck); + } + + /** + * Returns a RestTemplate, optionally disabling SSL host name check or disabling SSL validation entirely. + */ + @Bean + public RestTemplate acmRuntimeRestTemplate() throws GeneralSecurityException, IOException { + return super.getRestTemplate(); + } +} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/BaseRestTemplateConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/BaseRestTemplateConfig.java new file mode 100644 index 0000000..26d2296 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/config/BaseRestTemplateConfig.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import javax.annotation.PostConstruct; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import lombok.Setter; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +public class BaseRestTemplateConfig { + private static final Logger LOG = LoggerFactory.getLogger(BaseRestTemplateConfig.class); + + @Setter + private boolean disableSslValidation; + + @Setter + private boolean disableSslHostnameCheck; + + @Value("${server.ssl.trust-store:#{null}}") + protected Resource trustStore; + + @Value("${server.ssl.trust-store-password:#{null}}") + protected char[] trustStorePassword; + + @PostConstruct + private void validateProperties() { + if (trustStore == null && !disableSslValidation) { + throw new IllegalArgumentException("server.ssl.trust-store must be set if SSL validation is enabled"); + } + if (disableSslValidation && !disableSslHostnameCheck) { + LOG.info("Disabling SSL hostname check as SSL validation is disabled"); + disableSslHostnameCheck = true; + } + } + + /** + * Returns a RestTemplate, optionally disabling SSL hostname check or disabling SSL validation entirely. + */ + protected RestTemplate getRestTemplate() throws GeneralSecurityException, IOException { + SSLContext sslContext; + if (disableSslValidation) { + sslContext = new SSLContextBuilder().loadTrustMaterial(new TrustAllStrategy()).build(); + } else { + sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore.getURL(), trustStorePassword).build(); + } + + HostnameVerifier hostnameVerifier; + if (disableSslHostnameCheck) { + hostnameVerifier = new NoopHostnameVerifier(); + } else { + hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier(); + } + + var csf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + var httpClient = HttpClients.custom().setSSLSocketFactory(csf).build(); + var requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setHttpClient(httpClient); + return new RestTemplate(requestFactory); + } +} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig.java deleted file mode 100644 index 8d501d2..0000000 --- a/gui-server/src/main/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig.java +++ /dev/null @@ -1,94 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import javax.annotation.PostConstruct; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.TrustAllStrategy; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContextBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class ClampRestTemplateConfig { - private static final Logger LOG = LoggerFactory.getLogger(ClampRestTemplateConfig.class); - - @Value("${clamp.disable-ssl-validation:false}") - private boolean disableSslValidation; - - @Value("${clamp.disable-ssl-hostname-check:false}") - private boolean disableSslHostnameCheck; - - @Value("${server.ssl.trust-store:#{null}}") - private Resource trustStore; - - @Value("${server.ssl.trust-store-password:#{null}}") - private char[] trustStorePassword; - - @PostConstruct - private void validateProperties() { - if (trustStore == null && !disableSslValidation) { - throw new IllegalArgumentException("server.ssl.trust-store must be set if SSL validation is enabled"); - } - if (disableSslValidation && !disableSslHostnameCheck) { - LOG.info("Disabling SSL hostname check as SSL validation is disabled"); - disableSslHostnameCheck = true; - } - } - - /** - * Returns a RestTemplate, optionally disabling SSL hostname check or disabling SSL validation entirely. - */ - @Bean - public RestTemplate clampRestTemplate() throws GeneralSecurityException, IOException { - SSLContext sslContext; - if (disableSslValidation) { - sslContext = new SSLContextBuilder().loadTrustMaterial(new TrustAllStrategy()).build(); - } else { - sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore.getURL(), trustStorePassword).build(); - } - - HostnameVerifier hostnameVerifier; - if (disableSslHostnameCheck) { - hostnameVerifier = new NoopHostnameVerifier(); - } else { - hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier(); - } - - var csf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); - var httpClient = HttpClients.custom().setSSLSocketFactory(csf).build(); - var requestFactory = new HttpComponentsClientHttpRequestFactory(); - requestFactory.setHttpClient(httpClient); - return new RestTemplate(requestFactory); - } -} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/FilterRegistrationConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/FilterRegistrationConfig.java index 3e62237..179a3aa 100644 --- a/gui-server/src/main/java/org/onap/policy/gui/server/config/FilterRegistrationConfig.java +++ b/gui-server/src/main/java/org/onap/policy/gui/server/config/FilterRegistrationConfig.java @@ -20,22 +20,32 @@ package org.onap.policy.gui.server.config; +import org.apache.commons.lang3.StringUtils; import org.onap.policy.gui.server.filters.ClientSslHeaderFilter; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterRegistrationConfig { + @Value("${runtime-ui.policy.mapping-path}") + private String policyApiMappingPath; + + @Value("${runtime-ui.acm.mapping-path}") + private String acmRuntimeMappingPath; /** - * Registers ClientSslToHeaderFilter for /clamp/restservices/*. + * Registers ClientSslToHeaderFilter for the mapped URLs. */ @Bean public FilterRegistrationBean clientSslHeaderFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new ClientSslHeaderFilter()); - registrationBean.addUrlPatterns("/clamp/restservices/*"); + registrationBean.addUrlPatterns( + StringUtils.stripEnd(policyApiMappingPath, "/") + "/*", + StringUtils.stripEnd(acmRuntimeMappingPath, "/") + "/*" + ); return registrationBean; } diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/PolicyApiRestTemplateConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/PolicyApiRestTemplateConfig.java new file mode 100644 index 0000000..e88b0a5 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/config/PolicyApiRestTemplateConfig.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class PolicyApiRestTemplateConfig extends BaseRestTemplateConfig { + + /** + * Set the SSL validation flags on the template. + * + * @param disableSslValidation Turn off SSL altogether on this REST interface + * @param disableSslHostnameCheck Turn off SSL host name checking + */ + @Value("{runtime-ui.policy}") + public void setSslFlags( + @Value("${runtime-ui.policy.disable-ssl-validation:false}") boolean disableSslValidation, + @Value("${runtime-ui.policy.disable-ssl-hostname-check:false}") boolean disableSslHostnameCheck) { + super.setDisableSslValidation(disableSslValidation); + super.setDisableSslHostnameCheck(disableSslHostnameCheck); + } + + /** + * Returns a RestTemplate, optionally disabling SSL host name check or disabling SSL validation entirely. + */ + @Bean + public RestTemplate policyApiRestTemplate() throws GeneralSecurityException, IOException { + return super.getRestTemplate(); + } +} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/config/StaticContentConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/StaticContentConfig.java index 479202d..8338215 100644 --- a/gui-server/src/main/java/org/onap/policy/gui/server/config/StaticContentConfig.java +++ b/gui-server/src/main/java/org/onap/policy/gui/server/config/StaticContentConfig.java @@ -29,10 +29,10 @@ public class StaticContentConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/clamp").setViewName("redirect:/clamp/"); - registry.addViewController("/clamp/").setViewName("forward:/clamp/index.html"); - registry.addViewController("/apex-editor").setViewName("redirect:/apex-editor/"); - registry.addViewController("/apex-editor/").setViewName("forward:/apex-editor/index.html"); + registry.addViewController("/runtime-ui").setViewName("redirect:/runtime-ui/"); + registry.addViewController("/runtime-ui/").setViewName("forward:/runtime-ui/index.html"); + registry.addViewController("/designtime-ui").setViewName("redirect:/designtime-ui/"); + registry.addViewController("/designtime-ui/").setViewName("forward:/designtime-ui/index.html"); } } diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/filters/ClientSslHeaderFilter.java b/gui-server/src/main/java/org/onap/policy/gui/server/filters/ClientSslHeaderFilter.java index db8f593..06af720 100644 --- a/gui-server/src/main/java/org/onap/policy/gui/server/filters/ClientSslHeaderFilter.java +++ b/gui-server/src/main/java/org/onap/policy/gui/server/filters/ClientSslHeaderFilter.java @@ -43,9 +43,9 @@ import org.springframework.web.filter.OncePerRequestFilter; /** * Filter which encodes a client SSL certificate into X-SSL-Cert HTTP header. - * CLAMP has a corresponding filter called ClampCadiFilter which decodes the - * header. This is needed as CLAMP runtime uses AAF for auth, and AAF uses - * client cert authentication. Since REST requests from CLAMP GUI to CLAMP + * A target runtime may have a corresponding filter that decodes the + * header. This is needed as a target runtime may use a mechanism for + * client cert authentication. Since REST requests from the GUI to the * runtime are proxied in gui-server, the proxy needs to attach a copy of the * client SSL cert, as the proxy could not know the client's private key. */ @@ -56,7 +56,7 @@ public class ClientSslHeaderFilter extends OncePerRequestFilter { // Name of attribute containing request SSL cert. public static final String X509_ATTRIBUTE_NAME = "javax.servlet.request.X509Certificate"; - // Name of header containing encoded SSL cert - also used in clamp's ClampCadiFilter. + // Name of header containing encoded SSL cert - also used in the runtime filter. public static final String SSL_CERT_HEADER_NAME = "X-SSL-Cert"; @Override diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/rest/AcmRuntimeRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/AcmRuntimeRestController.java new file mode 100644 index 0000000..713ceb4 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/rest/AcmRuntimeRestController.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import java.net.URI; +import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("${runtime-ui.acm.mapping-path}") +public class AcmRuntimeRestController extends BaseRestController { + /** + * Set the mapping parameters for the REST controller. + * + * @param mappingPath The mapping path to map from + * @param url The URL path to map to + */ + @Value("{runtime-ui.acm}") + public void setSslFlags( + @Value("${runtime-ui.acm.mapping-path}") String mappingPath, + @Value("${runtime-ui.acm.url}") URI url) { + super.setMappingPath(mappingPath); + super.setUrl(url); + } + + /** + * Set the REST template for the REST controller. + * + * @param restTemplate The REST template + */ + @Autowired + public void setControllerRestTemplate( + @Qualifier("acmRuntimeRestTemplate") RestTemplate restTemplate) { + super.setRestTemplate(restTemplate); + } + + /** + * Proxy rest calls to ACM runtime. + */ + @Override + @RequestMapping("/**") + public ResponseEntity mirrorRest(@RequestBody(required = false) String body, + @RequestHeader HttpHeaders headers, + HttpMethod method, + HttpServletRequest request) { + return super.mirrorRest(body, headers, method, request); + } +} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/rest/ApexEditorRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/ApexEditorRestController.java deleted file mode 100644 index a4b92ef..0000000 --- a/gui-server/src/main/java/org/onap/policy/gui/server/rest/ApexEditorRestController.java +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.rest; - -import javax.servlet.http.HttpServletRequest; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.ModelAndView; - -@RestController -@RequestMapping("/apex-editor/policy/gui/v*/apex/editor") -public class ApexEditorRestController { - - /** - * Strip /apex-editor prefix from Apex Editor rest calls. - */ - @RequestMapping("/**") - public ModelAndView forwardApexEditorRest(ModelMap model, HttpServletRequest request) { - String targetUrl = request.getRequestURI().replaceFirst("^/apex-editor", ""); - return new ModelAndView("forward:" + targetUrl, model); - } -} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/rest/BaseRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/BaseRestController.java new file mode 100644 index 0000000..e4aa511 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/rest/BaseRestController.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import java.net.URI; +import javax.servlet.http.HttpServletRequest; +import lombok.Setter; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +public class BaseRestController { + @Setter + private String mappingPath; + + @Setter + private URI url; + + @Setter + private RestTemplate restTemplate; + + /** + * Proxy rest calls to a runtime. + */ + public ResponseEntity mirrorRest(@RequestBody(required = false) String body, + @RequestHeader HttpHeaders headers, + HttpMethod method, + HttpServletRequest request) { + // Strip the runtime prefix from request URI. + String requestUri = request.getRequestURI().replaceFirst(mappingPath, ""); + URI uri = UriComponentsBuilder.fromUri(url) + .path(requestUri) + .query(request.getQueryString()) + .build(true).toUri(); + + HttpEntity httpEntity = new HttpEntity<>(body, headers); + try { + return restTemplate.exchange(uri, method, httpEntity, String.class); + + } catch (HttpStatusCodeException e) { + // On error, return the server runtime error code instead of 500. + return ResponseEntity.status(e.getRawStatusCode()) + .headers(e.getResponseHeaders()) + .body(e.getResponseBodyAsString()); + } + } + +} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/rest/ClampRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/ClampRestController.java deleted file mode 100644 index b13003c..0000000 --- a/gui-server/src/main/java/org/onap/policy/gui/server/rest/ClampRestController.java +++ /dev/null @@ -1,79 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.rest; - -import java.net.URI; -import javax.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -@RestController -@RequestMapping("/clamp/restservices") -public class ClampRestController { - - @Value("${clamp.url}") - private URI clampUrl; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - /** - * Proxy rest calls to clamp backend. - */ - @SuppressWarnings("java:S3752") // Suppress warning about RequestMapping without HTTP method. - @RequestMapping("/**") - public ResponseEntity mirrorRest(@RequestBody(required = false) String body, - @RequestHeader HttpHeaders headers, - HttpMethod method, - HttpServletRequest request) { - // Strip /clamp/ prefix from request URI. - String requestUri = request.getRequestURI().replaceFirst("^/clamp/", ""); - URI uri = UriComponentsBuilder.fromUri(clampUrl) - .path(requestUri) - .query(request.getQueryString()) - .build(true).toUri(); - - HttpEntity httpEntity = new HttpEntity<>(body, headers); - try { - return restTemplate.exchange(uri, method, httpEntity, String.class); - - } catch (HttpStatusCodeException e) { - // On error, return the backend error code instead of 500. - return ResponseEntity.status(e.getRawStatusCode()) - .headers(e.getResponseHeaders()) - .body(e.getResponseBodyAsString()); - } - } - -} diff --git a/gui-server/src/main/java/org/onap/policy/gui/server/rest/PolicyApiRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/PolicyApiRestController.java new file mode 100644 index 0000000..2be3417 --- /dev/null +++ b/gui-server/src/main/java/org/onap/policy/gui/server/rest/PolicyApiRestController.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import java.net.URI; +import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("${runtime-ui.policy.mapping-path}") +public class PolicyApiRestController extends BaseRestController { + /** + * Set the mapping parameters for the REST controller. + * + * @param mappingPath The mapping path to map from + * @param url The URL path to map to + */ + @Value("{runtime-ui.policy}") + public void setSslFlags( + @Value("${runtime-ui.policy.mapping-path}") String mappingPath, + @Value("${runtime-ui.policy.url}") URI url) { + super.setMappingPath(mappingPath); + super.setUrl(url); + } + + /** + * Set the REST template for the REST controller. + * + * @param restTemplate The REST template + */ + @Autowired + public void setControllerRestTemplate( + @Qualifier("policyApiRestTemplate") RestTemplate restTemplate) { + super.setRestTemplate(restTemplate); + } + + /** + * Proxy rest calls to ACM runtime. + */ + @Override + @RequestMapping("/**") + public ResponseEntity mirrorRest(@RequestBody(required = false) String body, + @RequestHeader HttpHeaders headers, + HttpMethod method, + HttpServletRequest request) { + return super.mirrorRest(body, headers, method, request); + } +} diff --git a/gui-server/src/main/resources/static/designtime-ui/index.html b/gui-server/src/main/resources/static/designtime-ui/index.html new file mode 100644 index 0000000..8da1b06 --- /dev/null +++ b/gui-server/src/main/resources/static/designtime-ui/index.html @@ -0,0 +1,12 @@ + + + + + ONAP Policy GUI + + + + + diff --git a/gui-server/src/main/resources/static/index.html b/gui-server/src/main/resources/static/index.html index 3b079a8..b0bdb06 100644 --- a/gui-server/src/main/resources/static/index.html +++ b/gui-server/src/main/resources/static/index.html @@ -6,8 +6,8 @@ diff --git a/gui-server/src/main/resources/static/runtime-ui/index.html b/gui-server/src/main/resources/static/runtime-ui/index.html new file mode 100644 index 0000000..74fa41a --- /dev/null +++ b/gui-server/src/main/resources/static/runtime-ui/index.html @@ -0,0 +1,12 @@ + + + + + ONAP Policy GUI + + + + + diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/GuiServerAppMainTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/GuiServerAppMainTest.java index d0f6598..870eaaf 100644 --- a/gui-server/src/test/java/org/onap/policy/gui/server/GuiServerAppMainTest.java +++ b/gui-server/src/test/java/org/onap/policy/gui/server/GuiServerAppMainTest.java @@ -32,9 +32,14 @@ class GuiServerAppMainTest { @Test void whenMainIsCalled_thenNoExceptions() { String[] args = { - "--server.port=0", // use random available port - "--clamp.url=https://clamp-backend:8443/", - "--clamp.disable-ssl-validation=true" + "--server.port=0", + "--server.ssl.enabled=false", + "--runtime-ui.policy.disable-ssl-validation=true", + "--runtime-ui.policy.mapping-path=/policy-api", + "--runtime-ui.policy.url=http://policyapi:9876/", + "--runtime-ui.acm.disable-ssl-validation=true", + "--runtime-ui.acm.mapping-path=/acm-runtime", + "--runtime-ui.acm.url=http://acmruntime:9876/" }; assertDoesNotThrow(() -> GuiServerApplication.main(args)); } diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/SpringContextTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/SpringContextTest.java index 7be7694..1623ea7 100644 --- a/gui-server/src/test/java/org/onap/policy/gui/server/SpringContextTest.java +++ b/gui-server/src/test/java/org/onap/policy/gui/server/SpringContextTest.java @@ -25,9 +25,14 @@ import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest( properties = { - "clamp.url=https://clamp-backend:8443/", - "clamp.disable-ssl-validation=true" + "runtime-ui.policy.disable-ssl-validation=true", + "runtime-ui.policy.mapping-path=policy-api", + "runtime-ui.policy.url=http://policyapi:9876/", + "runtime-ui.acm.disable-ssl-validation=true", + "runtime-ui.acm.mapping-path=acm-runtime", + "runtime-ui.acm.url=http://acmruntime:9876/" }) + class SpringContextTest { @Test diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig1Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig1Test.java deleted file mode 100644 index 44e4c46..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig1Test.java +++ /dev/null @@ -1,69 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import javax.net.ssl.SSLPeerUnverifiedException; -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -/** - * In this test, SSL validation and hostname check are enabled. - * Since our keystore cert has a hostname 'helloworld' and our test request is - * to localhost, the request will fail with an SSLPeerUnverifiedException, as - * the SSL cert name does not match the server name 'localhost'. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, - properties = { - "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", - "server.ssl.key-store-password=changeit", - "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", - "server.ssl.trust-store-password=changeit", - "clamp.disable-ssl-validation=false", - "clamp.disable-ssl-hostname-check=false" - }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig1Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - @Test - void testRequestFailsWhenSslHostnameCheckIsEnabled() { - var helloUrl = "https://localhost:" + port + "/"; - Exception e = assertThrows(RestClientException.class, - () -> restTemplate.getForEntity(helloUrl, String.class)); - assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig2Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig2Test.java deleted file mode 100644 index b8e744c..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig2Test.java +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; - -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.web.client.RestTemplate; - -/** - * In this test, SSL validation is disabled. - * The test request should succeed. A trust store has not been supplied in this case. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, - properties = { - "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", - "server.ssl.key-store-password=changeit", - "clamp.disable-ssl-validation=true" - }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig2Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - @Test - void testRequestSucceedsWhenSslValidationIsDisabled() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig3Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig3Test.java deleted file mode 100644 index 4636982..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig3Test.java +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; - -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.web.client.RestTemplate; - -/** - * In this test, SSL validation is enabled but hostname check is disabled. - * Even though our keystore cert has a hostname 'helloworld' and our test - * request is to localhost, the request will succeed as the SSL hostname check - * is disabled. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, - properties = { - "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", - "server.ssl.key-store-password=changeit", - "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", - "server.ssl.trust-store-password=changeit", - "clamp.disable-ssl-validation=false", - "clamp.disable-ssl-hostname-check=true" - }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig3Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - /* - * In this test, the request will succeed even though the SSL cert name - * does not match 'localhost', as SSL hostname verification is disabled. - */ - @Test - void testRequestSucceedsWhenSslHostnameCheckIsDisabled() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig4Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig4Test.java deleted file mode 100644 index f0f222f..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig4Test.java +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; - -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.web.client.RestTemplate; - -/** - * In this test, SSL validation is disabled but hostname check is explicitly - * enabled. The expected behaviour is to disable the hostname check if SSL - * validation is disabled. We expect the request to succeed even though the - * SSL cert name does not match 'localhost', as SSL hostname verification is - * implicitly disabled. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, - properties = { - "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", - "server.ssl.key-store-password=changeit", - "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", - "server.ssl.trust-store-password=changeit", - "clamp.disable-ssl-validation=true", - "clamp.disable-ssl-hostname-check=false" - }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig4Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - @Test - void testHostnameCheckIsDisabledWhenSslValidationIsDisabled() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig5Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig5Test.java deleted file mode 100644 index cc23de5..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig5Test.java +++ /dev/null @@ -1,69 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import javax.net.ssl.SSLPeerUnverifiedException; -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; - -/** - * In this test, we verify that SSL validation and hostname check are enabled - * by default. Thus we do not explicitly set the Spring properties - * clamp.disable-ssl-validation and clamp.disable-ssl-hostname-check. - * Since our keystore cert has a hostname 'helloworld' and our test request is - * to localhost, the request will fail with an SSLPeerUnverifiedException, as - * the SSL cert name does not match the server name 'localhost'. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, - properties = { - "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", - "server.ssl.key-store-password=changeit", - "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", - "server.ssl.trust-store-password=changeit", - }, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig5Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - @Test - void testSslValidationIsEnabledByDefault() { - var helloUrl = "https://localhost:" + port + "/"; - Exception e = assertThrows(RestClientException.class, - () -> restTemplate.getForEntity(helloUrl, String.class)); - assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig6Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig6Test.java deleted file mode 100644 index d1d3072..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/config/ClampRestTemplateConfig6Test.java +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.config; - -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.test.util.ReflectionTestUtils; - -/** - * In this test, server.ssl.trust-store is unset while SSL validation is enabled. - * An BeanCreationException should be thrown on application startup. - */ -@SpringBootTest( - classes = { HelloWorldApplication.class } -) -class ClampRestTemplateConfig6Test { - - @Test - void expectExceptionWithNoTrustStore(ApplicationContext context) { - // Manually autowire the bean so we can test PostConstruct logic. - ClampRestTemplateConfig restTemplateConfig = new ClampRestTemplateConfig(); - AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); - factory.autowireBean(restTemplateConfig); - - // Enable SSL validation, but provide no trust store. - ReflectionTestUtils.setField(restTemplateConfig, "disableSslValidation", false); - - // Expect exception when creating bean. - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> factory.initializeBean(restTemplateConfig, "clampRestTemplate")) - .withMessageContaining("server.ssl.trust-store must be set"); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig1Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig1Test.java new file mode 100644 index 0000000..e982db5 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig1Test.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import javax.net.ssl.SSLPeerUnverifiedException; +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.RestTemplateConfig; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.web.client.RestClientException; + +/** + * In this test, SSL validation and hostname check are enabled. + * Since our keystore cert has a hostname 'helloworld' and our test request is + * to localhost, the request will fail with an SSLPeerUnverifiedException, as + * the SSL cert name does not match the server name 'localhost'. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class, + AcmRuntimeRestTemplateConfig.class, + PolicyApiRestTemplateConfig.class + }, + properties = { + "server.ssl.enabled=true", + "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", + "server.ssl.key-store-password=changeit", + "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", + "server.ssl.trust-store-password=changeit", + "runtime-ui.acm.disable-ssl-validation=false", + "runtime-ui.acm.disable-ssl-hostname-check=false", + "runtime-ui.policy.disable-ssl-validation=false", + "runtime-ui.policy.disable-ssl-hostname-check=false" + }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class RestTemplateConfig1Test { + @Test + void testRequestFailsWhenSslHostnameCheckIsEnabled() { + RestTemplateConfig rtConfig = new RestTemplateConfig(); + + rtConfig.getRestTemplateList().forEach(restTemplate -> { + var helloUrl = "https://localhost:" + rtConfig.getPort() + "/"; + Exception e = assertThrows(RestClientException.class, + () -> restTemplate.getForEntity(helloUrl, String.class)); + assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig2Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig2Test.java new file mode 100644 index 0000000..f59eeaf --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig2Test.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; + +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.RestTemplateConfig; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * In this test, SSL validation is disabled. + * The test request should succeed. A trust store has not been supplied in this case. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class, + AcmRuntimeRestTemplateConfig.class, + PolicyApiRestTemplateConfig.class, + }, + properties = { + "server.ssl.enabled=true", + "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", + "server.ssl.key-store-password=changeit", + "runtime-ui.acm.disable-ssl-validation=true", + "runtime-ui.policy.disable-ssl-validation=true" + }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class RestTemplateConfig2Test { + @Test + void testRequestSucceedsWhenSslValidationIsDisabled() { + RestTemplateConfig rtConfig = new RestTemplateConfig(); + + rtConfig.getRestTemplateList().forEach(restTemplate -> { + var helloUrl = "https://localhost:" + rtConfig.getPort() + "/"; + String response = restTemplate.getForObject(helloUrl, String.class); + assertEquals(HELLO_WORLD_STRING, response); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig3Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig3Test.java new file mode 100644 index 0000000..60ae9ac --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig3Test.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; + +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.RestTemplateConfig; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * In this test, SSL validation is enabled but hostname check is disabled. + * Even though our keystore cert has a hostname 'helloworld' and our test + * request is to localhost, the request will succeed as the SSL hostname check + * is disabled. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class, + AcmRuntimeRestTemplateConfig.class, + PolicyApiRestTemplateConfig.class + }, + properties = { + "server.ssl.enabled=true", + "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", + "server.ssl.key-store-password=changeit", + "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", + "server.ssl.trust-store-password=changeit", + "runtime-ui.acm.disable-ssl-validation=false", + "runtime-ui.acm.disable-ssl-hostname-check=true", + "runtime-ui.policy.disable-ssl-validation=false", + "runtime-ui.policy.disable-ssl-hostname-check=true" + }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class RestTemplateConfig3Test { + /* + * In this test, the request will succeed even though the SSL cert name + * does not match 'localhost', as SSL hostname verification is disabled. + */ + @Test + void testRequestSucceedsWhenSslHostnameCheckIsDisabled() { + RestTemplateConfig rtConfig = new RestTemplateConfig(); + + rtConfig.getRestTemplateList().forEach(restTemplate -> { + var helloUrl = "https://localhost:" + rtConfig.getPort() + "/"; + String response = restTemplate.getForObject(helloUrl, String.class); + assertEquals(HELLO_WORLD_STRING, response); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig4Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig4Test.java new file mode 100644 index 0000000..e85cdd0 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig4Test.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.onap.policy.gui.server.test.util.hello.HelloWorldRestController.HELLO_WORLD_STRING; + +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.RestTemplateConfig; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * In this test, SSL validation is disabled but hostname check is explicitly + * enabled. The expected behaviour is to disable the hostname check if SSL + * validation is disabled. We expect the request to succeed even though the + * SSL cert name does not match 'localhost', as SSL hostname verification is + * implicitly disabled. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class, + AcmRuntimeRestTemplateConfig.class, + PolicyApiRestTemplateConfig.class + }, + properties = { + "server.ssl.enabled=true", + "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", + "server.ssl.key-store-password=changeit", + "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", + "server.ssl.trust-store-password=changeit", + "runtime-ui.acm.disable-ssl-validation=true", + "runtime-ui.acm.disable-ssl-hostname-check=false", + "runtime-ui.policy.disable-ssl-validation=true", + "runtime-ui.policy.disable-ssl-hostname-check=false" + }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class RestTemplateConfig4Test { + @Test + void testHostnameCheckIsDisabledWhenSslValidationIsDisabled() { + RestTemplateConfig rtConfig = new RestTemplateConfig(); + + rtConfig.getRestTemplateList().forEach(restTemplate -> { + var helloUrl = "https://localhost:" + rtConfig.getPort() + "/"; + String response = restTemplate.getForObject(helloUrl, String.class); + assertEquals(HELLO_WORLD_STRING, response); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig5Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig5Test.java new file mode 100644 index 0000000..5905ebc --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig5Test.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import javax.net.ssl.SSLPeerUnverifiedException; +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.RestTemplateConfig; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.web.client.RestClientException; + +/** + * In this test, we verify that SSL validation and hostname check are enabled + * by default. Thus we explicitly set the Spring properties + * runtime-ui.acm.disable-ssl-validation and runtime-ui.acm.disable-ssl-hostname-check as false. + * Since our keystore cert has a hostname 'helloworld' and our test request is + * to localhost, the request will fail with an SSLPeerUnverifiedException, as + * the SSL cert name does not match the server name 'localhost'. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class, + AcmRuntimeRestTemplateConfig.class, + PolicyApiRestTemplateConfig.class + }, + properties = { + "server.ssl.enabled=true", + "server.ssl.key-store=file:src/test/resources/helloworld-keystore.jks", + "server.ssl.key-store-password=changeit", + "server.ssl.trust-store=file:src/test/resources/helloworld-truststore.jks", + "server.ssl.trust-store-password=changeit" + }, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class RestTemplateConfig5Test { + @Test + void testSslValidationIsEnabledByDefault() { + RestTemplateConfig rtConfig = new RestTemplateConfig(); + + rtConfig.getRestTemplateList().forEach(restTemplate -> { + var helloUrl = "https://localhost:" + rtConfig.getPort() + "/"; + Exception e = assertThrows(RestClientException.class, + () -> restTemplate.getForEntity(helloUrl, String.class)); + assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateTrustStoreUnsetTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateTrustStoreUnsetTest.java new file mode 100644 index 0000000..5edda12 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateTrustStoreUnsetTest.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.config; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import org.assertj.core.util.Arrays; +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.hello.HelloWorldApplication; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * In this test, server.ssl.trust-store is unset while SSL validation is enabled. + * An BeanCreationException should be thrown on application startup. + */ +@SpringBootTest( + classes = { + HelloWorldApplication.class + } +) +class RestTemplateTrustStoreUnsetTest { + BaseRestTemplateConfig[] restTemplateConfigArray = { + new AcmRuntimeRestTemplateConfig(), + new PolicyApiRestTemplateConfig() + }; + + @Test + void expectExceptionWithNoTrustStore(ApplicationContext context) { + Arrays.asList(restTemplateConfigArray).forEach(restTemplateConfig -> { + // Manually autowire the bean so we can test PostConstruct logic. + AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); + factory.autowireBean(restTemplateConfig); + + // Enable SSL validation, but provide no trust store. + ReflectionTestUtils.setField(restTemplateConfig, "disableSslValidation", false); + + // Expect exception when creating bean. + assertThatExceptionOfType(BeanCreationException.class) + .isThrownBy(() -> factory.initializeBean(restTemplateConfig, "dummyRestTemplate")) + .withMessageContaining("server.ssl.trust-store must be set"); + }); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/rest/AcmRuntimeRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/AcmRuntimeRestControllerTest.java new file mode 100644 index 0000000..56a805d --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/rest/AcmRuntimeRestControllerTest.java @@ -0,0 +1,165 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import static org.onap.policy.gui.server.filters.ClientSslHeaderFilter.SSL_CERT_HEADER_NAME; +import static org.onap.policy.gui.server.test.util.X509RequestPostProcessor.x509; +import static org.onap.policy.gui.server.util.X509CertificateEncoder.urlEncodeCert; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.security.cert.X509Certificate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.KeyStoreHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.RestTemplate; + +@SpringBootTest( + properties = { + "runtime-ui.policy.mapping-path=/runtime-ui/policy/restservices/", + "runtime-ui.policy.url=http://policy-api:9876/", + "runtime-ui.policy.disable-ssl-validation=true", + "runtime-ui.acm.mapping-path=/runtime-ui/acm/restservices/", + "runtime-ui.acm.url=https://runtime-acm:8443/", + "runtime-ui.acm.disable-ssl-validation=true" + }) +@AutoConfigureMockMvc +class AcmRuntimeRestControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + @Qualifier("acmRuntimeRestTemplate") + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + @BeforeEach + public void init() { + mockServer = MockRestServiceServer.createServer(restTemplate); + } + + @Test + void testStaticContentUrls() throws Exception { + mvc.perform(get("/runtime-ui/")) + .andExpect(status().isOk()) + .andExpect(forwardedUrl("/runtime-ui/index.html")); + + mvc.perform(get("/runtime-ui")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/runtime-ui/")); + } + + /* + * This is a happy path test to verify that calls to /** + * are relayed to the server, and that the server receives the + * client certificate encoded in a header. More extensive tests of the + * certificate cert filter are in ClientSslHeaderFilterTest. + */ + @Test + void testServerProxyWithClientCert() throws Exception { + X509Certificate cert = KeyStoreHelper.loadValidCert(); + + mockServer.expect( + requestTo("https://runtime-acm:8443/junit/test")) + .andExpect(header(SSL_CERT_HEADER_NAME, urlEncodeCert(cert))) + .andRespond(withStatus(HttpStatus.OK).body("admin")); + + mvc.perform( + get("/runtime-ui/acm/restservices/junit/test") + .with(x509(cert))) + .andExpect(status().isOk()) + .andExpect(content().string("admin")); + + mockServer.verify(); + } + + /* + * This test verifies that HTTP headers are preserved for requests to the + * server (including multi-value headers). + */ + @Test + void verifyServerProxyPassesHeaders() throws Exception { + // Single value header + final String userAgent = "User-Agent"; + final String userAgentValue = "JUnit"; + // Multi-value header + final String acceptLanguage = "Accept-Language"; + final String enUs = "en-US"; + final String enIe = "en-IE"; + + mockServer.expect( + requestTo("https://runtime-acm:8443/junit/test")) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(userAgent, userAgentValue)) + .andExpect(header(acceptLanguage, enUs, enIe)) + .andRespond(withStatus(HttpStatus.OK)); + + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.set(userAgent, userAgentValue); + requestHeaders.add(acceptLanguage, enUs); + requestHeaders.add(acceptLanguage, enIe); + mvc.perform( + get("/runtime-ui/acm/restservices/junit/test") + .headers(requestHeaders)) + .andExpect(status().isOk()); + + mockServer.verify(); + } + + /* + * This test verifies that error messages from the server are + * delivered to the client (as opposed to 500 "Internal Server Error"). + */ + @Test + void verifyServerProxyReturnsBackendErrorCode() throws Exception { + final String errorMessage = "This appliance cannot brew coffee"; + + mockServer.expect( + requestTo("https://runtime-acm:8443/coffee")) + .andRespond(withStatus(HttpStatus.I_AM_A_TEAPOT).body(errorMessage)); + + mvc.perform( + post("/runtime-ui/acm/restservices/coffee").secure(true)) + .andExpect(status().is(HttpStatus.I_AM_A_TEAPOT.value())) + .andExpect(content().string(errorMessage)); + + mockServer.verify(); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/rest/ApexEditorRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/ApexEditorRestControllerTest.java deleted file mode 100644 index 4cfd994..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/rest/ApexEditorRestControllerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.rest; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.servlet.MockMvc; - -@SpringBootTest( - properties = { - "clamp.url=https://clamp-backend:8443/", - "clamp.disable-ssl-validation=true" - }) -@AutoConfigureMockMvc -class ApexEditorRestControllerTest { - - @Autowired - private MockMvc mvc; - - @Test - void testStaticContentUrls() throws Exception { - mvc.perform(get("/apex-editor/")) - .andExpect(status().isOk()) - .andExpect(forwardedUrl("/apex-editor/index.html")); - - mvc.perform(get("/apex-editor")) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/apex-editor/")); - } - - @Test - void testApexEditorRestForwarding() throws Exception { - mvc.perform(get("/apex-editor/policy/gui/v1/apex/editor/-1/Session/Create")) - .andExpect(forwardedUrl("/policy/gui/v1/apex/editor/-1/Session/Create")); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/rest/ClampRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/ClampRestControllerTest.java deleted file mode 100644 index fb3e843..0000000 --- a/gui-server/src/test/java/org/onap/policy/gui/server/rest/ClampRestControllerTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.gui.server.rest; - -import static org.onap.policy.gui.server.filters.ClientSslHeaderFilter.SSL_CERT_HEADER_NAME; -import static org.onap.policy.gui.server.test.util.X509RequestPostProcessor.x509; -import static org.onap.policy.gui.server.util.X509CertificateEncoder.urlEncodeCert; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; -import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; -import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.security.cert.X509Certificate; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.onap.policy.gui.server.test.util.KeyStoreHelper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.web.client.RestTemplate; - -@SpringBootTest( - properties = { - "clamp.url=https://clamp-backend:8443/", - "clamp.disable-ssl-validation=true" - }) -@AutoConfigureMockMvc -class ClampRestControllerTest { - - @Autowired - private MockMvc mvc; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - - private MockRestServiceServer mockServer; - - @BeforeEach - public void init() { - mockServer = MockRestServiceServer.createServer(restTemplate); - } - - @Test - void testStaticContentUrls() throws Exception { - mvc.perform(get("/clamp/")) - .andExpect(status().isOk()) - .andExpect(forwardedUrl("/clamp/index.html")); - - mvc.perform(get("/clamp")) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/clamp/")); - } - - /* - * This is a happy path test to verify that calls to /clamp/restservices/** - * are relayed to the clamp backend, and that the backend receives the - * client certificate encoded in a header. More extensive tests of the - * certificate cert filter are in ClientSslHeaderFilterTest. - */ - @Test - void testClampProxyWithClientCert() throws Exception { - X509Certificate cert = KeyStoreHelper.loadValidCert(); - - mockServer.expect( - requestTo("https://clamp-backend:8443/restservices/junit/test")) - .andExpect(header(SSL_CERT_HEADER_NAME, urlEncodeCert(cert))) - .andRespond(withStatus(HttpStatus.OK).body("admin")); - - mvc.perform( - get("/clamp/restservices/junit/test") - .with(x509(cert))) - .andExpect(status().isOk()) - .andExpect(content().string("admin")); - - mockServer.verify(); - } - - /* - * This test verifies that HTTP headers are preserved for requests to the - * clamp backend (including multi-value headers). - */ - @Test - void verifyClampProxyPassesHeaders() throws Exception { - // Single value header - final String userAgent = "User-Agent"; - final String userAgentValue = "JUnit"; - // Multi value header - final String acceptLanguage = "Accept-Language"; - final String enUs = "en-US"; - final String enIe = "en-IE"; - - mockServer.expect( - requestTo("https://clamp-backend:8443/restservices/junit/test")) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(userAgent, userAgentValue)) - .andExpect(header(acceptLanguage, enUs, enIe)) - .andRespond(withStatus(HttpStatus.OK)); - - HttpHeaders requestHeaders = new HttpHeaders(); - requestHeaders.set(userAgent, userAgentValue); - requestHeaders.add(acceptLanguage, enUs); - requestHeaders.add(acceptLanguage, enIe); - mvc.perform( - get("/clamp/restservices/junit/test") - .headers(requestHeaders)) - .andExpect(status().isOk()); - - mockServer.verify(); - } - - /* - * This test verifies that error messages from the clamp backend are - * delivered to the client (as opposed to 500 "Internal Server Error"). - */ - @Test - void verifyClampProxyReturnsBackendErrorCode() throws Exception { - final String errorMessage = "This appliance cannot brew coffee"; - - mockServer.expect( - requestTo("https://clamp-backend:8443/restservices/coffee")) - .andRespond(withStatus(HttpStatus.I_AM_A_TEAPOT).body(errorMessage)); - - mvc.perform( - post("/clamp/restservices/coffee")) - .andExpect(status().is(HttpStatus.I_AM_A_TEAPOT.value())) - .andExpect(content().string(errorMessage)); - - mockServer.verify(); - } -} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/rest/DesigntimeRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/DesigntimeRestControllerTest.java new file mode 100644 index 0000000..92f75d5 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/rest/DesigntimeRestControllerTest.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; + +@SpringBootTest( + properties = { + "runtime-ui.policy.disable-ssl-validation=true", + "runtime-ui.policy.mapping-path=policy-api", + "runtime-ui.policy.url=http://policyapi:9876/", + "runtime-ui.acm.disable-ssl-validation=true", + "runtime-ui.acm.mapping-path=acm-runtime", + "runtime-ui.acm.url=http://acmruntime:9876/" + }) +@AutoConfigureMockMvc +class DesigntimeRestControllerTest { + + @Autowired + private MockMvc mvc; + + @Test + void testStaticContentUrls() throws Exception { + mvc.perform(get("/designtime-ui/")) + .andExpect(status().isOk()) + .andExpect(forwardedUrl("/designtime-ui/index.html")); + + mvc.perform(get("/designtime-ui")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/designtime-ui/")); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/rest/PolicyApiRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/PolicyApiRestControllerTest.java new file mode 100644 index 0000000..e7c8db6 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/rest/PolicyApiRestControllerTest.java @@ -0,0 +1,165 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.rest; + +import static org.onap.policy.gui.server.filters.ClientSslHeaderFilter.SSL_CERT_HEADER_NAME; +import static org.onap.policy.gui.server.test.util.X509RequestPostProcessor.x509; +import static org.onap.policy.gui.server.util.X509CertificateEncoder.urlEncodeCert; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.header; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.security.cert.X509Certificate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.onap.policy.gui.server.test.util.KeyStoreHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.RestTemplate; + +@SpringBootTest( + properties = { + "runtime-ui.policy.mapping-path=/runtime-ui/policy/restservices/", + "runtime-ui.policy.url=https://policy-api:9876/", + "runtime-ui.policy.disable-ssl-validation=true", + "runtime-ui.acm.mapping-path=/runtime-ui/acm/restservices/", + "runtime-ui.acm.url=https://runtime-acm:8443/", + "runtime-ui.acm.disable-ssl-validation=true" + }) +@AutoConfigureMockMvc +class PolicyApiRestControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + @Qualifier("policyApiRestTemplate") + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + @BeforeEach + public void init() { + mockServer = MockRestServiceServer.createServer(restTemplate); + } + + @Test + void testStaticContentUrls() throws Exception { + mvc.perform(get("/runtime-ui/")) + .andExpect(status().isOk()) + .andExpect(forwardedUrl("/runtime-ui/index.html")); + + mvc.perform(get("/runtime-ui")) + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/runtime-ui/")); + } + + /* + * This is a happy path test to verify that calls to /** + * are relayed to the server, and that the server receives the + * client certificate encoded in a header. More extensive tests of the + * certificate cert filter are in ClientSslHeaderFilterTest. + */ + @Test + void testServerProxyWithClientCert() throws Exception { + X509Certificate cert = KeyStoreHelper.loadValidCert(); + + mockServer.expect( + requestTo("https://policy-api:9876/junit/test")) + .andExpect(header(SSL_CERT_HEADER_NAME, urlEncodeCert(cert))) + .andRespond(withStatus(HttpStatus.OK).body("admin")); + + mvc.perform( + get("/runtime-ui/policy/restservices/junit/test") + .with(x509(cert))) + .andExpect(status().isOk()) + .andExpect(content().string("admin")); + + mockServer.verify(); + } + + /* + * This test verifies that HTTP headers are preserved for requests to the + * server (including multi-value headers). + */ + @Test + void verifyServerProxyPassesHeaders() throws Exception { + // Single value header + final String userAgent = "User-Agent"; + final String userAgentValue = "JUnit"; + // Multi-value header + final String acceptLanguage = "Accept-Language"; + final String enUs = "en-US"; + final String enIe = "en-IE"; + + mockServer.expect( + requestTo("https://policy-api:9876/junit/test")) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(userAgent, userAgentValue)) + .andExpect(header(acceptLanguage, enUs, enIe)) + .andRespond(withStatus(HttpStatus.OK)); + + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.set(userAgent, userAgentValue); + requestHeaders.add(acceptLanguage, enUs); + requestHeaders.add(acceptLanguage, enIe); + mvc.perform( + get("/runtime-ui/policy/restservices/junit/test") + .headers(requestHeaders)) + .andExpect(status().isOk()); + + mockServer.verify(); + } + + /* + * This test verifies that error messages from the server are + * delivered to the client (as opposed to 500 "Internal Server Error"). + */ + @Test + void verifyServerProxyReturnsBackendErrorCode() throws Exception { + final String errorMessage = "This appliance cannot brew coffee"; + + mockServer.expect( + requestTo("https://policy-api:9876/coffee")) + .andRespond(withStatus(HttpStatus.I_AM_A_TEAPOT).body(errorMessage)); + + mvc.perform( + post("/runtime-ui/policy/restservices/coffee").secure(true)) + .andExpect(status().is(HttpStatus.I_AM_A_TEAPOT.value())) + .andExpect(content().string(errorMessage)); + + mockServer.verify(); + } +} diff --git a/gui-server/src/test/java/org/onap/policy/gui/server/test/util/RestTemplateConfig.java b/gui-server/src/test/java/org/onap/policy/gui/server/test/util/RestTemplateConfig.java new file mode 100644 index 0000000..0d11eb7 --- /dev/null +++ b/gui-server/src/test/java/org/onap/policy/gui/server/test/util/RestTemplateConfig.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.gui.server.test.util; + +import java.util.ArrayList; +import java.util.List; +import javax.annotation.PostConstruct; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.web.client.RestTemplate; + +/** + * This class setups up the REST templates for testing. + */ +public class RestTemplateConfig { + @Getter + @LocalServerPort + private int port; + + @Autowired + @Qualifier("acmRuntimeRestTemplate") + private RestTemplate acmRuntimeRestTemplate; + + @Autowired + @Qualifier("policyApiRestTemplate") + private RestTemplate policyApiRestTemplate; + + @Getter + List restTemplateList = new ArrayList<>(); + + @PostConstruct + public void setupRestTemplateList() { + restTemplateList.add(acmRuntimeRestTemplate); + restTemplateList.add(policyApiRestTemplate); + } +} diff --git a/gui-server/src/test/resources/application_http.yaml b/gui-server/src/test/resources/application_http.yaml index 24f3e8e..cebdc09 100644 --- a/gui-server/src/test/resources/application_http.yaml +++ b/gui-server/src/test/resources/application_http.yaml @@ -3,14 +3,23 @@ server: ssl: enabled: false -clamp: - url: http://localhost:30258 - disable-ssl-validation: true - disable-ssl-hostname-check: true +runtime-ui: + policy: + mapping-path: "/runtime-ui/policy/restservices" + url: http://localhost:30440 + disable-ssl-validation: true + disable-ssl-hostname-check: true -apex-editor: - upload-url: - upload-userid: + acm: + mapping-path: "/runtime-ui/acm/restservices" + url: http://localhost:30258 + disable-ssl-validation: true + disable-ssl-hostname-check: true + +designtime-ui: + apex-editor: + upload-url: + upload-userid: management: endpoints: diff --git a/gui-server/src/test/resources/application_https.yaml b/gui-server/src/test/resources/application_https.yaml new file mode 100644 index 0000000..8882c29 --- /dev/null +++ b/gui-server/src/test/resources/application_https.yaml @@ -0,0 +1,34 @@ +server: + port: 2443 + ssl: + enabled: true + enabled-protocols: TLSv1.2 + client-auth: want + key-store: file:./src/test/resources/helloworld-keystore.jks + key-store-password: changeit + trust-store: file:./src/test/resources/helloworld-truststore.jks + trust-store-password: changeit + +runtime-ui: + policy: + mapping-path: "/runtime-ui/policy/restservices" + url: http://localhost:30440 + disable-ssl-validation: true + disable-ssl-hostname-check: true + + acm: + mapping-path: "/runtime-ui/acm/restservices" + url: http://localhost:30258 + disable-ssl-validation: true + disable-ssl-hostname-check: true + +designtime-ui: + apex-editor: + upload-url: + upload-userid: + +management: + endpoints: + web: + exposure: + include: health, metrics, prometheus -- cgit 1.2.3-korg