diff options
author | liamfallon <liam.fallon@est.tech> | 2022-11-07 13:53:29 +0000 |
---|---|---|
committer | liamfallon <liam.fallon@est.tech> | 2022-11-08 12:58:33 +0000 |
commit | 4d04e56e297cb9808a7e5378480526ba44f6a0bd (patch) | |
tree | 66784f5880b0319c47641fb3449a33bc30937b89 /gui-server | |
parent | 221006c687ec15b0811ec002ca806766fd18c91c (diff) |
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 <liam.fallon@est.tech>
Diffstat (limited to 'gui-server')
28 files changed, 765 insertions, 241 deletions
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 @@ <classifier>clamp-build</classifier> <type>tar.gz</type> <overWrite>true</overWrite> - <outputDirectory>${project.build.directory}/classes/static</outputDirectory> + <outputDirectory>${project.build.directory}/classes/static/runtime-ui</outputDirectory> </artifactItem> <!-- copy static resources from apex editor jar into static/apex-editor/ --> <artifactItem> @@ -121,7 +121,7 @@ <version>${project.version}</version> <type>jar</type> <overWrite>true</overWrite> - <outputDirectory>${project.build.directory}/classes/static/apex-editor</outputDirectory> + <outputDirectory>${project.build.directory}/classes/static/designtime-ui/apex-editor</outputDirectory> <includes>static/**</includes> <fileMappers> <org.codehaus.plexus.components.io.filemappers.RegExpFileMapper> 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/ClampRestTemplateConfig.java b/gui-server/src/main/java/org/onap/policy/gui/server/config/BaseRestTemplateConfig.java index 8d501d2..26d2296 100644 --- 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/BaseRestTemplateConfig.java @@ -25,6 +25,7 @@ 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; @@ -33,27 +34,24 @@ 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); +public class BaseRestTemplateConfig { + private static final Logger LOG = LoggerFactory.getLogger(BaseRestTemplateConfig.class); - @Value("${clamp.disable-ssl-validation:false}") + @Setter private boolean disableSslValidation; - @Value("${clamp.disable-ssl-hostname-check:false}") + @Setter private boolean disableSslHostnameCheck; @Value("${server.ssl.trust-store:#{null}}") - private Resource trustStore; + protected Resource trustStore; @Value("${server.ssl.trust-store-password:#{null}}") - private char[] trustStorePassword; + protected char[] trustStorePassword; @PostConstruct private void validateProperties() { @@ -69,8 +67,7 @@ public class ClampRestTemplateConfig { /** * Returns a RestTemplate, optionally disabling SSL hostname check or disabling SSL validation entirely. */ - @Bean - public RestTemplate clampRestTemplate() throws GeneralSecurityException, IOException { + protected RestTemplate getRestTemplate() throws GeneralSecurityException, IOException { SSLContext sslContext; if (disableSslValidation) { sslContext = new SSLContextBuilder().loadTrustMaterial(new TrustAllStrategy()).build(); 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> clientSslHeaderFilter() { FilterRegistrationBean<ClientSslHeaderFilter> 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<String> 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/ClampRestController.java b/gui-server/src/main/java/org/onap/policy/gui/server/rest/BaseRestController.java index b13003c..e4aa511 100644 --- 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/BaseRestController.java @@ -22,44 +22,37 @@ 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 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.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 { +public class BaseRestController { + @Setter + private String mappingPath; - @Value("${clamp.url}") - private URI clampUrl; + @Setter + private URI url; - @Autowired - @Qualifier("clampRestTemplate") + @Setter private RestTemplate restTemplate; /** - * Proxy rest calls to clamp backend. + * Proxy rest calls to a runtime. */ - @SuppressWarnings("java:S3752") // Suppress warning about RequestMapping without HTTP method. - @RequestMapping("/**") public ResponseEntity<String> 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) + // 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(); @@ -69,7 +62,7 @@ public class ClampRestController { return restTemplate.exchange(uri, method, httpEntity, String.class); } catch (HttpStatusCodeException e) { - // On error, return the backend error code instead of 500. + // 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/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<String> 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 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>ONAP Policy GUI</title> +</head> +<body> +<ul> + <li><a href="/designtime-ui/apex-editor/index.html">The Apex Policy Editor</a></li> +</ul> +</body> +</html> 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 @@ </head> <body> <ul> - <li><a href="/apex-editor/">Apex Policy Editor</a></li> - <li><a href="/clamp/">CLAMP Designer UI</a></li> + <li><a href="/designtime-ui/index.html">Design Time User Interface</a></li> + <li><a href="/runtime-ui/index.html">Run Time User Interface</a></li> </ul> </body> </html> 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 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>ONAP Policy GUI</title> +</head> +<body> +<ul> + <li><a href="/runtime-ui/clamp/index.html">The CLAMP GUI</a></li> +</ul> +</body> +</html> 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/RestTemplateConfig1Test.java index 44e4c46..e982db5 100644 --- 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/RestTemplateConfig1Test.java @@ -25,13 +25,10 @@ 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.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. @@ -40,30 +37,33 @@ import org.springframework.web.client.RestTemplate; * the SSL cert name does not match the server name 'localhost'. */ @SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, + 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", - "clamp.disable-ssl-validation=false", - "clamp.disable-ssl-hostname-check=false" + "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 ClampRestTemplateConfig1Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - +class RestTemplateConfig1Test { @Test void testRequestFailsWhenSslHostnameCheckIsEnabled() { - var helloUrl = "https://localhost:" + port + "/"; - Exception e = assertThrows(RestClientException.class, - () -> restTemplate.getForEntity(helloUrl, String.class)); - assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); + 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/ClampRestTemplateConfig2Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig2Test.java index b8e744c..f59eeaf 100644 --- 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/RestTemplateConfig2Test.java @@ -24,38 +24,37 @@ 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.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 }, + 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", - "clamp.disable-ssl-validation=true" + "runtime-ui.acm.disable-ssl-validation=true", + "runtime-ui.policy.disable-ssl-validation=true" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig2Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - +class RestTemplateConfig2Test { @Test void testRequestSucceedsWhenSslValidationIsDisabled() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); + 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/ClampRestTemplateConfig3Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig3Test.java index 4636982..60ae9ac 100644 --- 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/RestTemplateConfig3Test.java @@ -24,12 +24,9 @@ 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.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. @@ -38,33 +35,36 @@ import org.springframework.web.client.RestTemplate; * is disabled. */ @SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, + 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", - "clamp.disable-ssl-validation=false", - "clamp.disable-ssl-hostname-check=true" + "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 ClampRestTemplateConfig3Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - +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() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); + 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/ClampRestTemplateConfig4Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig4Test.java index f0f222f..e85cdd0 100644 --- 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/RestTemplateConfig4Test.java @@ -24,12 +24,9 @@ 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.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 @@ -39,29 +36,32 @@ import org.springframework.web.client.RestTemplate; * implicitly disabled. */ @SpringBootTest( - classes = { HelloWorldApplication.class, ClampRestTemplateConfig.class }, + 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", - "clamp.disable-ssl-validation=true", - "clamp.disable-ssl-hostname-check=false" + "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 ClampRestTemplateConfig4Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - +class RestTemplateConfig4Test { @Test void testHostnameCheckIsDisabledWhenSslValidationIsDisabled() { - var helloUrl = "https://localhost:" + port + "/"; - String response = restTemplate.getForObject(helloUrl, String.class); - assertEquals(HELLO_WORLD_STRING, response); + 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/ClampRestTemplateConfig5Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateConfig5Test.java index cc23de5..5905ebc 100644 --- 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/RestTemplateConfig5Test.java @@ -25,45 +25,43 @@ 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.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. + * 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, ClampRestTemplateConfig.class }, + 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", + "server.ssl.trust-store-password=changeit" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -class ClampRestTemplateConfig5Test { - - @LocalServerPort - private int port; - - @Autowired - @Qualifier("clampRestTemplate") - private RestTemplate restTemplate; - +class RestTemplateConfig5Test { @Test void testSslValidationIsEnabledByDefault() { - var helloUrl = "https://localhost:" + port + "/"; - Exception e = assertThrows(RestClientException.class, - () -> restTemplate.getForEntity(helloUrl, String.class)); - assertTrue(e.getCause() instanceof SSLPeerUnverifiedException); + 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/ClampRestTemplateConfig6Test.java b/gui-server/src/test/java/org/onap/policy/gui/server/config/RestTemplateTrustStoreUnsetTest.java index d1d3072..5edda12 100644 --- 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/RestTemplateTrustStoreUnsetTest.java @@ -22,6 +22,7 @@ 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; @@ -35,23 +36,30 @@ import org.springframework.test.util.ReflectionTestUtils; * An BeanCreationException should be thrown on application startup. */ @SpringBootTest( - classes = { HelloWorldApplication.class } + classes = { + HelloWorldApplication.class + } ) -class ClampRestTemplateConfig6Test { +class RestTemplateTrustStoreUnsetTest { + BaseRestTemplateConfig[] restTemplateConfigArray = { + new AcmRuntimeRestTemplateConfig(), + new PolicyApiRestTemplateConfig() + }; @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); + 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); + // 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"); + // 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/ClampRestControllerTest.java b/gui-server/src/test/java/org/onap/policy/gui/server/rest/AcmRuntimeRestControllerTest.java index fb3e843..56a805d 100644 --- 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/AcmRuntimeRestControllerTest.java @@ -51,17 +51,21 @@ import org.springframework.web.client.RestTemplate; @SpringBootTest( properties = { - "clamp.url=https://clamp-backend:8443/", - "clamp.disable-ssl-validation=true" + "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 ClampRestControllerTest { +class AcmRuntimeRestControllerTest { @Autowired private MockMvc mvc; @Autowired - @Qualifier("clampRestTemplate") + @Qualifier("acmRuntimeRestTemplate") private RestTemplate restTemplate; private MockRestServiceServer mockServer; @@ -73,32 +77,32 @@ class ClampRestControllerTest { @Test void testStaticContentUrls() throws Exception { - mvc.perform(get("/clamp/")) + mvc.perform(get("/runtime-ui/")) .andExpect(status().isOk()) - .andExpect(forwardedUrl("/clamp/index.html")); + .andExpect(forwardedUrl("/runtime-ui/index.html")); - mvc.perform(get("/clamp")) + mvc.perform(get("/runtime-ui")) .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/clamp/")); + .andExpect(redirectedUrl("/runtime-ui/")); } /* - * 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 + * This is a happy path test to verify that calls to <mapping-path>/** + * 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 testClampProxyWithClientCert() throws Exception { + void testServerProxyWithClientCert() throws Exception { X509Certificate cert = KeyStoreHelper.loadValidCert(); mockServer.expect( - requestTo("https://clamp-backend:8443/restservices/junit/test")) + requestTo("https://runtime-acm:8443/junit/test")) .andExpect(header(SSL_CERT_HEADER_NAME, urlEncodeCert(cert))) .andRespond(withStatus(HttpStatus.OK).body("admin")); mvc.perform( - get("/clamp/restservices/junit/test") + get("/runtime-ui/acm/restservices/junit/test") .with(x509(cert))) .andExpect(status().isOk()) .andExpect(content().string("admin")); @@ -108,20 +112,20 @@ class ClampRestControllerTest { /* * This test verifies that HTTP headers are preserved for requests to the - * clamp backend (including multi-value headers). + * server (including multi-value headers). */ @Test - void verifyClampProxyPassesHeaders() throws Exception { + void verifyServerProxyPassesHeaders() throws Exception { // Single value header final String userAgent = "User-Agent"; final String userAgentValue = "JUnit"; - // Multi value header + // 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")) + requestTo("https://runtime-acm:8443/junit/test")) .andExpect(method(HttpMethod.GET)) .andExpect(header(userAgent, userAgentValue)) .andExpect(header(acceptLanguage, enUs, enIe)) @@ -132,7 +136,7 @@ class ClampRestControllerTest { requestHeaders.add(acceptLanguage, enUs); requestHeaders.add(acceptLanguage, enIe); mvc.perform( - get("/clamp/restservices/junit/test") + get("/runtime-ui/acm/restservices/junit/test") .headers(requestHeaders)) .andExpect(status().isOk()); @@ -140,19 +144,19 @@ class ClampRestControllerTest { } /* - * This test verifies that error messages from the clamp backend are + * This test verifies that error messages from the server are * delivered to the client (as opposed to 500 "Internal Server Error"). */ @Test - void verifyClampProxyReturnsBackendErrorCode() throws Exception { + void verifyServerProxyReturnsBackendErrorCode() throws Exception { final String errorMessage = "This appliance cannot brew coffee"; mockServer.expect( - requestTo("https://clamp-backend:8443/restservices/coffee")) + requestTo("https://runtime-acm:8443/coffee")) .andRespond(withStatus(HttpStatus.I_AM_A_TEAPOT).body(errorMessage)); mvc.perform( - post("/clamp/restservices/coffee")) + post("/runtime-ui/acm/restservices/coffee").secure(true)) .andExpect(status().is(HttpStatus.I_AM_A_TEAPOT.value())) .andExpect(content().string(errorMessage)); 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/DesigntimeRestControllerTest.java index 4cfd994..92f75d5 100644 --- 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/DesigntimeRestControllerTest.java @@ -33,29 +33,27 @@ import org.springframework.test.web.servlet.MockMvc; @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/" }) @AutoConfigureMockMvc -class ApexEditorRestControllerTest { +class DesigntimeRestControllerTest { @Autowired private MockMvc mvc; @Test void testStaticContentUrls() throws Exception { - mvc.perform(get("/apex-editor/")) + mvc.perform(get("/designtime-ui/")) .andExpect(status().isOk()) - .andExpect(forwardedUrl("/apex-editor/index.html")); + .andExpect(forwardedUrl("/designtime-ui/index.html")); - mvc.perform(get("/apex-editor")) + mvc.perform(get("/designtime-ui")) .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")); + .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 <mapping-path>/** + * 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<RestTemplate> 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 |