From 5aa8aec689a399e7803e84e531532d0c61631ec1 Mon Sep 17 00:00:00 2001 From: Instrumental Date: Wed, 7 Nov 2018 20:52:15 -0600 Subject: Fix/Renable sidecar builds Issue-ID: AAF-613 Change-Id: Ic13411eebbf3c1c9b6d8492aff1b37db37a965e4 Signed-off-by: Instrumental --- sidecar/fproxy/.gitignore | 1 + sidecar/fproxy/pom.xml | 58 ++--- .../cadi/sidecar/fproxy/CredentialCacheConfig.java | 37 +++ .../aaf/cadi/sidecar/fproxy/FProxyApplication.java | 74 ++++++ .../cadi/sidecar/fproxy/RestTemplateConfig.java | 77 ++++++ .../cadi/sidecar/fproxy/cache/CredentialCache.java | 37 +++ .../fproxy/cache/InMemoryCredentialCache.java | 117 +++++++++ .../sidecar/fproxy/cache/utils/CacheUtils.java | 90 +++++++ .../sidecar/fproxy/data/CredentialCacheData.java | 72 ++++++ .../fproxy/service/ForwardingProxyService.java | 101 ++++++++ .../fproxy/util/RequestValidationException.java | 35 +++ .../org/onap/aaf/fproxy/CredentialCacheConfig.java | 37 --- .../org/onap/aaf/fproxy/FProxyApplication.java | 74 ------ .../org/onap/aaf/fproxy/RestTemplateConfig.java | 77 ------ .../org/onap/aaf/fproxy/cache/CredentialCache.java | 37 --- .../aaf/fproxy/cache/InMemoryCredentialCache.java | 116 --------- .../onap/aaf/fproxy/cache/utils/CacheUtils.java | 89 ------- .../onap/aaf/fproxy/data/CredentialCacheData.java | 72 ------ .../aaf/fproxy/service/ForwardingProxyService.java | 100 -------- .../fproxy/util/RequestValidationException.java | 35 --- .../aaf/cadi/sidecar/fproxy/test/FProxyIT.java | 49 ++++ .../sidecar/fproxy/test/FProxyServiceTest.java | 212 +++++++++++++++++ .../test/java/org/onap/aaf/fproxy/FProxyIT.java | 49 ---- .../org/onap/aaf/fproxy/FProxyServiceTest.java | 212 ----------------- sidecar/pom.xml | 156 +++++++----- sidecar/rproxy/.gitignore | 1 + sidecar/rproxy/pom.xml | 24 +- .../ReverseProxyEntryExitLoggingAspect.java | 45 ++++ .../rpoxy/logging/ReverseProxyMethodLogTime.java | 51 ++++ .../ReverseProxyMethodLogTimeAnnotation.java | 30 +++ .../sidecar/rproxy/ReverseProxyApplication.java | 182 ++++++++++++++ .../rproxy/ReverseProxyAuthorizationFilter.java | 216 +++++++++++++++++ .../cadi/sidecar/rproxy/ReverseProxyService.java | 167 +++++++++++++ .../cadi/sidecar/rproxy/config/CadiProperties.java | 41 ++++ .../rproxy/config/ForwardProxyProperties.java | 67 ++++++ .../rproxy/config/PrimaryServiceProperties.java | 58 +++++ .../rproxy/config/ReverseProxySSLProperties.java | 56 +++++ .../ReverseProxyURIAuthorizationProperties.java | 38 +++ .../rproxy/mocks/ReverseProxyMockCadiFilter.java | 143 +++++++++++ .../rproxy/utils/ReverseProxyAuthorization.java | 34 +++ .../sidecar/rproxy/utils/ReverseProxyUtils.java | 29 +++ .../onap/aaf/rproxy/ReverseProxyApplication.java | 182 -------------- .../rproxy/ReverseProxyAuthorizationFilter.java | 216 ----------------- .../org/onap/aaf/rproxy/ReverseProxyService.java | 166 ------------- .../org/onap/aaf/rproxy/config/CadiProperties.java | 41 ---- .../aaf/rproxy/config/ForwardProxyProperties.java | 67 ------ .../rproxy/config/PrimaryServiceProperties.java | 58 ----- .../rproxy/config/ReverseProxySSLProperties.java | 56 ----- .../ReverseProxyURIAuthorizationProperties.java | 38 --- .../ReverseProxyEntryExitLoggingAspect.java | 45 ---- .../rproxy/logging/ReverseProxyMethodLogTime.java | 51 ---- .../ReverseProxyMethodLogTimeAnnotation.java | 30 --- .../rproxy/mocks/ReverseProxyMockCadiFilter.java | 143 ----------- .../rproxy/utils/ReverseProxyAuthorization.java | 34 --- .../onap/aaf/rproxy/utils/ReverseProxyUtils.java | 29 --- .../rproxy/test/PermissionMatchingTest.java | 262 +++++++++++++++++++++ .../rproxy/test/ReverseProxyApplicationTest.java | 158 +++++++++++++ .../cadi/sidecar/rproxy/test/ReverseProxyIT.java | 49 ++++ .../rproxy/test/ReverseProxyTestConfig.java | 42 ++++ .../onap/aaf/rproxy/PermissionMatchingTest.java | 262 --------------------- .../aaf/rproxy/ReverseProxyApplicationTest.java | 158 ------------- .../java/org/onap/aaf/rproxy/ReverseProxyIT.java | 48 ---- .../onap/aaf/rproxy/ReverseProxyTestConfig.java | 42 ---- sidecar/tproxy-config/pom.xml | 1 - 64 files changed, 2700 insertions(+), 2674 deletions(-) create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/CredentialCacheConfig.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/FProxyApplication.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/RestTemplateConfig.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/CredentialCache.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/InMemoryCredentialCache.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/utils/CacheUtils.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/data/CredentialCacheData.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/service/ForwardingProxyService.java create mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/util/RequestValidationException.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/CredentialCacheConfig.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/FProxyApplication.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/RestTemplateConfig.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/CredentialCache.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/InMemoryCredentialCache.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/utils/CacheUtils.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/data/CredentialCacheData.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/service/ForwardingProxyService.java delete mode 100644 sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/util/RequestValidationException.java create mode 100644 sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyIT.java create mode 100644 sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyServiceTest.java delete mode 100644 sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyIT.java delete mode 100644 sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyServiceTest.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyEntryExitLoggingAspect.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTime.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTimeAnnotation.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyApplication.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyAuthorizationFilter.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/CadiProperties.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ForwardProxyProperties.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/PrimaryServiceProperties.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxySSLProperties.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxyURIAuthorizationProperties.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/mocks/ReverseProxyMockCadiFilter.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyAuthorization.java create mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyUtils.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyApplication.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyAuthorizationFilter.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyService.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/CadiProperties.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ForwardProxyProperties.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/PrimaryServiceProperties.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxySSLProperties.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxyURIAuthorizationProperties.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyEntryExitLoggingAspect.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTime.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTimeAnnotation.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/mocks/ReverseProxyMockCadiFilter.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyAuthorization.java delete mode 100644 sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyUtils.java create mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/PermissionMatchingTest.java create mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyApplicationTest.java create mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyIT.java create mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyTestConfig.java delete mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/PermissionMatchingTest.java delete mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyApplicationTest.java delete mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyIT.java delete mode 100644 sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyTestConfig.java (limited to 'sidecar') diff --git a/sidecar/fproxy/.gitignore b/sidecar/fproxy/.gitignore index 6028f0a..f3bad09 100644 --- a/sidecar/fproxy/.gitignore +++ b/sidecar/fproxy/.gitignore @@ -2,3 +2,4 @@ /.settings/ /target/ /.project +/logs/ diff --git a/sidecar/fproxy/pom.xml b/sidecar/fproxy/pom.xml index 0246eb2..e79bd3e 100644 --- a/sidecar/fproxy/pom.xml +++ b/sidecar/fproxy/pom.xml @@ -33,68 +33,40 @@ Sidecar fproxy ONAP AAF Forward Proxy Microservice For Pluggable Security - - - 2.0.3.RELEASE - ${basedir}/target - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - + org.springframework.boot - spring-boot-starter-jetty + spring-boot-dependencies + ${spring.boot.version} + pom + import - + - org.springframework.boot - spring-boot-starter-web - - - spring-boot-starter-tomcat - org.springframework.boot - - - org.springframework.boot - spring-boot-starter-json - - + org.apache.httpcomponents + httpclient - + - org.apache.commons - commons-lang3 + org.springframework.boot + spring-boot-starter-jetty - org.apache.httpcomponents - httpclient + org.springframework.boot + spring-boot-starter-aop - com.google.code.gson - gson + org.springframework.boot + spring-boot-starter-web - org.springframework.boot spring-boot-starter-test - test - diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/CredentialCacheConfig.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/CredentialCacheConfig.java new file mode 100644 index 0000000..53132d2 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/CredentialCacheConfig.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy; + +import org.onap.aaf.cadi.sidecar.fproxy.cache.CredentialCache; +import org.onap.aaf.cadi.sidecar.fproxy.cache.InMemoryCredentialCache; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +public class CredentialCacheConfig { + + @Bean + @Scope("singleton") + public CredentialCache inMemoryCredentialCacheSingleton() { + return new InMemoryCredentialCache(); + } + +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/FProxyApplication.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/FProxyApplication.java new file mode 100644 index 0000000..7e3ffe4 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/FProxyApplication.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy; + +import java.util.HashMap; +import javax.annotation.PostConstruct; +import org.eclipse.jetty.util.security.Password; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; + +@SpringBootApplication +@PropertySource("file:${CONFIG_HOME}/fproxy.properties") +public class FProxyApplication extends SpringBootServletInitializer { + + @Autowired + private Environment env; + + /** + * Spring Boot Initialization. + * + * @param args main args + */ + public static void main(String[] args) { + String keyStorePassword = System.getProperty("KEY_STORE_PASSWORD"); + if (keyStorePassword == null || keyStorePassword.isEmpty()) { + throw new IllegalArgumentException("Env property KEY_STORE_PASSWORD not set"); + } + HashMap props = new HashMap<>(); + props.put("server.ssl.key-store-password", Password.deobfuscate(keyStorePassword)); + new FProxyApplication().configure(new SpringApplicationBuilder(FProxyApplication.class).properties(props)) + .run(args); + } + + /** + * Set required trust store system properties using values from application.properties + */ + @PostConstruct + public void setSystemProperties() { + String keyStorePath = env.getProperty("server.ssl.key-store"); + if (keyStorePath != null) { + String keyStorePassword = env.getProperty("server.ssl.key-store-password"); + + if (keyStorePassword != null) { + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); + System.setProperty("javax.net.ssl.trustStore", keyStorePath); + System.setProperty("javax.net.ssl.trustStorePassword", keyStorePassword); + } else { + throw new IllegalArgumentException("Env property server.ssl.key-store-password not set"); + } + } + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/RestTemplateConfig.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/RestTemplateConfig.java new file mode 100644 index 0000000..23f3471 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/RestTemplateConfig.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import javax.net.ssl.SSLContext; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.eclipse.jetty.util.security.Password; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.ResourceUtils; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Value("${server.ssl.client-cert}") + private String clientCertPath; + + @Value("${server.ssl.client-cert-password}") + private String clientCertPassword; + + @Value("${server.ssl.key-store}") + private String keystorePath; + + @Value("${server.ssl.key-store-password}") + private String keystorePassword; + + @Profile("secure") + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) throws GeneralSecurityException, IOException { + return new RestTemplate(new HttpComponentsClientHttpRequestFactory(getClientBuilder().build())); + } + + @Profile("noHostVerification") + @Bean + public RestTemplate restTemplateNoHostVerification(RestTemplateBuilder builder) + throws GeneralSecurityException, IOException { + return new RestTemplate(new HttpComponentsClientHttpRequestFactory( + getClientBuilder().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build())); + } + + private HttpClientBuilder getClientBuilder() throws GeneralSecurityException, IOException { + + SSLContext sslContext = SSLContextBuilder.create() + .loadKeyMaterial(ResourceUtils.getFile(clientCertPath), Password.deobfuscate(clientCertPassword).toCharArray(), + keystorePassword.toCharArray()) + .loadTrustMaterial(ResourceUtils.getFile(keystorePath), keystorePassword.toCharArray()).build(); + + return HttpClients.custom().setSSLContext(sslContext); + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/CredentialCache.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/CredentialCache.java new file mode 100644 index 0000000..bd05313 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/CredentialCache.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.cache; + +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; +import org.springframework.lang.Nullable; + +public interface CredentialCache { + + void add(String key, CredentialCacheData value, long periodInMillis); + + void remove(String key); + + @Nullable + CredentialCacheData get(String key); + + void clear(); + + long size(); +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/InMemoryCredentialCache.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/InMemoryCredentialCache.java new file mode 100644 index 0000000..5ba9bdb --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/InMemoryCredentialCache.java @@ -0,0 +1,117 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.cache; + +import java.lang.ref.SoftReference; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; + +public class InMemoryCredentialCache implements CredentialCache { + + private final ConcurrentHashMap> cache = new ConcurrentHashMap<>(); + private final DelayQueue cleaningUpQueue = new DelayQueue<>(); + + public InMemoryCredentialCache() { + Thread cleanerThread = new Thread(() -> { + while (!Thread.currentThread().isInterrupted()) { + try { + DelayedCacheObject delayedCacheObject = cleaningUpQueue.take(); + cache.remove(delayedCacheObject.getKey(), delayedCacheObject.getReference()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }); + cleanerThread.setDaemon(true); + cleanerThread.start(); + } + + @Override + public void add(String key, CredentialCacheData value, long periodInMillis) { + if (key == null) { + return; + } + if (value == null) { + cache.remove(key); + } else { + long expiryTime = System.currentTimeMillis() + periodInMillis; + SoftReference reference = new SoftReference<>(value); + cache.put(key, reference); + cleaningUpQueue.put(new DelayedCacheObject(key, reference, expiryTime)); + } + } + + @Override + public void remove(String key) { + cache.remove(key); + } + + @Override + public CredentialCacheData get(String key) { + return Optional.ofNullable(cache.get(key)).map(SoftReference::get).orElse(null); + } + + @Override + public void clear() { + cache.clear(); + } + + @Override + public long size() { + return cache.size(); + } + + private static class DelayedCacheObject implements Delayed { + + private final String key; + private final SoftReference reference; + private final long expiryTime; + + public DelayedCacheObject(String key, SoftReference reference, long expiryTime) { + super(); + this.key = key; + this.reference = reference; + this.expiryTime = expiryTime; + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(expiryTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + return Long.compare(expiryTime, ((DelayedCacheObject) o).expiryTime); + } + + public String getKey() { + return key; + } + + public SoftReference getReference() { + return reference; + } + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/utils/CacheUtils.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/utils/CacheUtils.java new file mode 100644 index 0000000..1825293 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/cache/utils/CacheUtils.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.cache.utils; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.cadi.sidecar.fproxy.cache.CredentialCache; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData.CredentialType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.util.WebUtils; + +@Component +public class CacheUtils { + + Logger logger = LoggerFactory.getLogger(CacheUtils.class); + + @Autowired + private CredentialCache credentialCache; + + @Value("${transactionid.header.name}") + private String transactionIdHeaderName; + + public void populateCredentialsFromCache(HttpHeaders headers, HttpServletRequest request) { + String transactionId = headers.getFirst(transactionIdHeaderName); + if (transactionId != null) { + CredentialCacheData cacheData = credentialCache.get(transactionId); + if (cacheData == null) { + logger.info("Transaction ID {} not found in cache, skipping credential population...", transactionId); + } else if (cacheData.getCredentialType().equals(CredentialType.HEADER)) { + logger.info("Populating header credentials from cache for transaction ID: {}", transactionId); + applyHeaderCacheData(cacheData, headers); + } else if (cacheData.getCredentialType().equals(CredentialType.COOKIE)) { + logger.info("Populating cookie credentials from cache for transaction ID: {}", transactionId); + applyCookieCacheData(cacheData, headers, request); + } + } else { + logger.info("No transaction ID found in request, skipping credential population..."); + } + } + + private void applyHeaderCacheData(CredentialCacheData cacheData, HttpHeaders headers) { + String credentialName = cacheData.getCredentialName(); + if (!headers.containsKey(credentialName)) { + headers.add(credentialName, cacheData.getCredentialValue()); + logger.info("Header credentials successfully populated."); + } else { + logger.info("Request already contains header with name: {}, skipping credential population...", + credentialName); + } + } + + private void applyCookieCacheData(CredentialCacheData cacheData, HttpHeaders headers, HttpServletRequest request) { + String credentialName = cacheData.getCredentialName(); + // Check if Cookie with same name is already set then skip + if (WebUtils.getCookie(request, credentialName) == null) { + headers.add(HttpHeaders.COOKIE, cacheData.getCredentialValue()); + logger.info("Cookie credentials successfully populated."); + } else { + logger.info("Request already contains cookie with name: {}, skipping credential population...", + credentialName); + } + } + + public void addCredentialsToCache(String transactionId, CredentialCacheData credentialdata, long cacheExpiryMs) { + credentialCache.add(transactionId, credentialdata, cacheExpiryMs); + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/data/CredentialCacheData.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/data/CredentialCacheData.java new file mode 100644 index 0000000..6918ded --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/data/CredentialCacheData.java @@ -0,0 +1,72 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.data; + +public class CredentialCacheData { + + public enum CredentialType { + HEADER, COOKIE; + } + + private String credentialName; + private String credentialValue; + private CredentialType credentialType; + + public CredentialCacheData() { + super(); + } + + public CredentialCacheData(String credentialName, String credentialValue, CredentialType credentialType) { + super(); + this.credentialName = credentialName; + this.credentialValue = credentialValue; + this.credentialType = credentialType; + } + + public String getCredentialName() { + return credentialName; + } + + public void setCredentialName(String credentialName) { + this.credentialName = credentialName; + } + + public String getCredentialValue() { + return credentialValue; + } + + public void setCredentialValue(String credentialValue) { + this.credentialValue = credentialValue; + } + + public Enum getCredentialType() { + return credentialType; + } + + public void setCredentialType(CredentialType credentialType) { + this.credentialType = credentialType; + } + + @Override + public String toString() { + return "CredentialCacheData [credentialName=" + credentialName + ", credentialType=" + credentialType + "]"; + } + +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/service/ForwardingProxyService.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/service/ForwardingProxyService.java new file mode 100644 index 0000000..6a09bb9 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/service/ForwardingProxyService.java @@ -0,0 +1,101 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.service; + +import java.net.URI; +import java.util.Enumeration; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.aaf.cadi.sidecar.fproxy.cache.utils.CacheUtils; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@RestController +public class ForwardingProxyService { + + Logger logger = LoggerFactory.getLogger(ForwardingProxyService.class); + + private static final long DEFAULT_CACHE_EXPIRY_MS = 180000; // 3 mins + + @Autowired + RestTemplate restTemplate; + + @Autowired + CacheUtils cacheUtils; + + @Value("${credential.cache.timeout.ms:" + DEFAULT_CACHE_EXPIRY_MS + "}") + long cacheExpiryMs; + + @RequestMapping(value = "/credential-cache/{transactionId}", method = RequestMethod.POST) + public ResponseEntity addCredentialToCache(@PathVariable("transactionId") String transactionId, + @RequestBody CredentialCacheData credentialdata) { + logger.info("Updating credential cache with transaction ID: {}", transactionId); + + // Update credential cache + logger.debug("Credential data: {}", credentialdata); + cacheUtils.addCredentialsToCache(transactionId, credentialdata, cacheExpiryMs); + + logger.info("Credential cache successfully updated with transaction ID: {}", transactionId); + return new ResponseEntity<>(transactionId, HttpStatus.OK); + } + + @RequestMapping("/**") + public ResponseEntity forwardRest(@RequestBody(required = false) String body, HttpMethod method, + HttpServletRequest request, HttpServletResponse response) { + + String requestUrl = request.getRequestURI(); + + logger.info("Request received: {}", requestUrl); + + URI uri = UriComponentsBuilder.fromHttpUrl(request.getRequestURL().toString()).query(request.getQueryString()) + .build(true).toUri(); + + HttpHeaders headers = new HttpHeaders(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + headers.set(headerName, request.getHeader(headerName)); + } + + cacheUtils.populateCredentialsFromCache(headers, request); + + HttpEntity httpEntity = new HttpEntity<>(body, headers); + + logger.info("Forwarding request..."); + + return restTemplate.exchange(uri, method, httpEntity, String.class); + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/util/RequestValidationException.java b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/util/RequestValidationException.java new file mode 100644 index 0000000..236d093 --- /dev/null +++ b/sidecar/fproxy/src/main/java/org/onap/aaf/cadi/sidecar/fproxy/util/RequestValidationException.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.util; + +/** This exception is thrown when the request fails validation. */ +public class RequestValidationException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor for an instance of this exception with just a message. + * + * @param message information about the exception + */ + public RequestValidationException(String message) { + super(message); + } +} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/CredentialCacheConfig.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/CredentialCacheConfig.java deleted file mode 100644 index f433c65..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/CredentialCacheConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy; - -import org.onap.aaf.fproxy.cache.CredentialCache; -import org.onap.aaf.fproxy.cache.InMemoryCredentialCache; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -@Configuration -public class CredentialCacheConfig { - - @Bean - @Scope("singleton") - public CredentialCache inMemoryCredentialCacheSingleton() { - return new InMemoryCredentialCache(); - } - -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/FProxyApplication.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/FProxyApplication.java deleted file mode 100644 index d226dc8..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/FProxyApplication.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy; - -import java.util.HashMap; -import javax.annotation.PostConstruct; -import org.eclipse.jetty.util.security.Password; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.Environment; - -@SpringBootApplication -@PropertySource("file:${CONFIG_HOME}/fproxy.properties") -public class FProxyApplication extends SpringBootServletInitializer { - - @Autowired - private Environment env; - - /** - * Spring Boot Initialization. - * - * @param args main args - */ - public static void main(String[] args) { - String keyStorePassword = System.getProperty("KEY_STORE_PASSWORD"); - if (keyStorePassword == null || keyStorePassword.isEmpty()) { - throw new IllegalArgumentException("Env property KEY_STORE_PASSWORD not set"); - } - HashMap props = new HashMap<>(); - props.put("server.ssl.key-store-password", Password.deobfuscate(keyStorePassword)); - new FProxyApplication().configure(new SpringApplicationBuilder(FProxyApplication.class).properties(props)) - .run(args); - } - - /** - * Set required trust store system properties using values from application.properties - */ - @PostConstruct - public void setSystemProperties() { - String keyStorePath = env.getProperty("server.ssl.key-store"); - if (keyStorePath != null) { - String keyStorePassword = env.getProperty("server.ssl.key-store-password"); - - if (keyStorePassword != null) { - System.setProperty("javax.net.ssl.keyStore", keyStorePath); - System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); - System.setProperty("javax.net.ssl.trustStore", keyStorePath); - System.setProperty("javax.net.ssl.trustStorePassword", keyStorePassword); - } else { - throw new IllegalArgumentException("Env property server.ssl.key-store-password not set"); - } - } - } -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/RestTemplateConfig.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/RestTemplateConfig.java deleted file mode 100644 index 8acfd86..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/RestTemplateConfig.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import javax.net.ssl.SSLContext; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContextBuilder; -import org.eclipse.jetty.util.security.Password; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.util.ResourceUtils; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Value("${server.ssl.client-cert}") - private String clientCertPath; - - @Value("${server.ssl.client-cert-password}") - private String clientCertPassword; - - @Value("${server.ssl.key-store}") - private String keystorePath; - - @Value("${server.ssl.key-store-password}") - private String keystorePassword; - - @Profile("secure") - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) throws GeneralSecurityException, IOException { - return new RestTemplate(new HttpComponentsClientHttpRequestFactory(getClientBuilder().build())); - } - - @Profile("noHostVerification") - @Bean - public RestTemplate restTemplateNoHostVerification(RestTemplateBuilder builder) - throws GeneralSecurityException, IOException { - return new RestTemplate(new HttpComponentsClientHttpRequestFactory( - getClientBuilder().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build())); - } - - private HttpClientBuilder getClientBuilder() throws GeneralSecurityException, IOException { - - SSLContext sslContext = SSLContextBuilder.create() - .loadKeyMaterial(ResourceUtils.getFile(clientCertPath), Password.deobfuscate(clientCertPassword).toCharArray(), - keystorePassword.toCharArray()) - .loadTrustMaterial(ResourceUtils.getFile(keystorePath), keystorePassword.toCharArray()).build(); - - return HttpClients.custom().setSSLContext(sslContext); - } -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/CredentialCache.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/CredentialCache.java deleted file mode 100644 index 00fe9d4..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/CredentialCache.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.cache; - -import org.onap.aaf.fproxy.data.CredentialCacheData; -import org.springframework.lang.Nullable; - -public interface CredentialCache { - - void add(String key, CredentialCacheData value, long periodInMillis); - - void remove(String key); - - @Nullable - CredentialCacheData get(String key); - - void clear(); - - long size(); -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/InMemoryCredentialCache.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/InMemoryCredentialCache.java deleted file mode 100644 index 44ce0cd..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/InMemoryCredentialCache.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.cache; - -import java.lang.ref.SoftReference; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.Delayed; -import java.util.concurrent.TimeUnit; -import org.onap.aaf.fproxy.data.CredentialCacheData; - -public class InMemoryCredentialCache implements CredentialCache { - - private final ConcurrentHashMap> cache = new ConcurrentHashMap<>(); - private final DelayQueue cleaningUpQueue = new DelayQueue<>(); - - public InMemoryCredentialCache() { - Thread cleanerThread = new Thread(() -> { - while (!Thread.currentThread().isInterrupted()) { - try { - DelayedCacheObject delayedCacheObject = cleaningUpQueue.take(); - cache.remove(delayedCacheObject.getKey(), delayedCacheObject.getReference()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - }); - cleanerThread.setDaemon(true); - cleanerThread.start(); - } - - @Override - public void add(String key, CredentialCacheData value, long periodInMillis) { - if (key == null) { - return; - } - if (value == null) { - cache.remove(key); - } else { - long expiryTime = System.currentTimeMillis() + periodInMillis; - SoftReference reference = new SoftReference<>(value); - cache.put(key, reference); - cleaningUpQueue.put(new DelayedCacheObject(key, reference, expiryTime)); - } - } - - @Override - public void remove(String key) { - cache.remove(key); - } - - @Override - public CredentialCacheData get(String key) { - return Optional.ofNullable(cache.get(key)).map(SoftReference::get).orElse(null); - } - - @Override - public void clear() { - cache.clear(); - } - - @Override - public long size() { - return cache.size(); - } - - private static class DelayedCacheObject implements Delayed { - - private final String key; - private final SoftReference reference; - private final long expiryTime; - - public DelayedCacheObject(String key, SoftReference reference, long expiryTime) { - super(); - this.key = key; - this.reference = reference; - this.expiryTime = expiryTime; - } - - @Override - public long getDelay(TimeUnit unit) { - return unit.convert(expiryTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); - } - - @Override - public int compareTo(Delayed o) { - return Long.compare(expiryTime, ((DelayedCacheObject) o).expiryTime); - } - - public String getKey() { - return key; - } - - public SoftReference getReference() { - return reference; - } - } -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/utils/CacheUtils.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/utils/CacheUtils.java deleted file mode 100644 index b80fc32..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/cache/utils/CacheUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.cache.utils; - -import javax.servlet.http.HttpServletRequest; -import org.onap.aaf.fproxy.cache.CredentialCache; -import org.onap.aaf.fproxy.data.CredentialCacheData; -import org.onap.aaf.fproxy.data.CredentialCacheData.CredentialType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Component; -import org.springframework.web.util.WebUtils; - -@Component -public class CacheUtils { - - Logger logger = LoggerFactory.getLogger(CacheUtils.class); - - @Autowired - private CredentialCache credentialCache; - - @Value("${transactionid.header.name}") - private String transactionIdHeaderName; - - public void populateCredentialsFromCache(HttpHeaders headers, HttpServletRequest request) { - String transactionId = headers.getFirst(transactionIdHeaderName); - if (transactionId != null) { - CredentialCacheData cacheData = credentialCache.get(transactionId); - if (cacheData == null) { - logger.info("Transaction ID {} not found in cache, skipping credential population...", transactionId); - } else if (cacheData.getCredentialType().equals(CredentialType.HEADER)) { - logger.info("Populating header credentials from cache for transaction ID: {}", transactionId); - applyHeaderCacheData(cacheData, headers); - } else if (cacheData.getCredentialType().equals(CredentialType.COOKIE)) { - logger.info("Populating cookie credentials from cache for transaction ID: {}", transactionId); - applyCookieCacheData(cacheData, headers, request); - } - } else { - logger.info("No transaction ID found in request, skipping credential population..."); - } - } - - private void applyHeaderCacheData(CredentialCacheData cacheData, HttpHeaders headers) { - String credentialName = cacheData.getCredentialName(); - if (!headers.containsKey(credentialName)) { - headers.add(credentialName, cacheData.getCredentialValue()); - logger.info("Header credentials successfully populated."); - } else { - logger.info("Request already contains header with name: {}, skipping credential population...", - credentialName); - } - } - - private void applyCookieCacheData(CredentialCacheData cacheData, HttpHeaders headers, HttpServletRequest request) { - String credentialName = cacheData.getCredentialName(); - // Check if Cookie with same name is already set then skip - if (WebUtils.getCookie(request, credentialName) == null) { - headers.add(HttpHeaders.COOKIE, cacheData.getCredentialValue()); - logger.info("Cookie credentials successfully populated."); - } else { - logger.info("Request already contains cookie with name: {}, skipping credential population...", - credentialName); - } - } - - public void addCredentialsToCache(String transactionId, CredentialCacheData credentialdata, long cacheExpiryMs) { - credentialCache.add(transactionId, credentialdata, cacheExpiryMs); - } -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/data/CredentialCacheData.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/data/CredentialCacheData.java deleted file mode 100644 index b72ea08..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/data/CredentialCacheData.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.data; - -public class CredentialCacheData { - - public enum CredentialType { - HEADER, COOKIE; - } - - private String credentialName; - private String credentialValue; - private CredentialType credentialType; - - public CredentialCacheData() { - super(); - } - - public CredentialCacheData(String credentialName, String credentialValue, CredentialType credentialType) { - super(); - this.credentialName = credentialName; - this.credentialValue = credentialValue; - this.credentialType = credentialType; - } - - public String getCredentialName() { - return credentialName; - } - - public void setCredentialName(String credentialName) { - this.credentialName = credentialName; - } - - public String getCredentialValue() { - return credentialValue; - } - - public void setCredentialValue(String credentialValue) { - this.credentialValue = credentialValue; - } - - public Enum getCredentialType() { - return credentialType; - } - - public void setCredentialType(CredentialType credentialType) { - this.credentialType = credentialType; - } - - @Override - public String toString() { - return "CredentialCacheData [credentialName=" + credentialName + ", credentialType=" + credentialType + "]"; - } - -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/service/ForwardingProxyService.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/service/ForwardingProxyService.java deleted file mode 100644 index 0d150ba..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/service/ForwardingProxyService.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.service; - -import java.net.URI; -import java.util.Enumeration; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.onap.aaf.fproxy.cache.utils.CacheUtils; -import org.onap.aaf.fproxy.data.CredentialCacheData; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -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.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -@RestController -public class ForwardingProxyService { - - Logger logger = LoggerFactory.getLogger(ForwardingProxyService.class); - - private static final long DEFAULT_CACHE_EXPIRY_MS = 180000; // 3 mins - - @Autowired - RestTemplate restTemplate; - - @Autowired - CacheUtils cacheUtils; - - @Value("${credential.cache.timeout.ms:" + DEFAULT_CACHE_EXPIRY_MS + "}") - long cacheExpiryMs; - - @RequestMapping(value = "/credential-cache/{transactionId}", method = RequestMethod.POST) - public ResponseEntity addCredentialToCache(@PathVariable("transactionId") String transactionId, - @RequestBody CredentialCacheData credentialdata) { - logger.info("Updating credential cache with transaction ID: {}", transactionId); - - // Update credential cache - logger.debug("Credential data: {}", credentialdata); - cacheUtils.addCredentialsToCache(transactionId, credentialdata, cacheExpiryMs); - - logger.info("Credential cache successfully updated with transaction ID: {}", transactionId); - return new ResponseEntity<>(transactionId, HttpStatus.OK); - } - - @RequestMapping("/**") - public ResponseEntity forwardRest(@RequestBody(required = false) String body, HttpMethod method, - HttpServletRequest request, HttpServletResponse response) { - - String requestUrl = request.getRequestURI(); - - logger.info("Request received: {}", requestUrl); - - URI uri = UriComponentsBuilder.fromHttpUrl(request.getRequestURL().toString()).query(request.getQueryString()) - .build(true).toUri(); - - HttpHeaders headers = new HttpHeaders(); - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - headers.set(headerName, request.getHeader(headerName)); - } - - cacheUtils.populateCredentialsFromCache(headers, request); - - HttpEntity httpEntity = new HttpEntity<>(body, headers); - - logger.info("Forwarding request..."); - - return restTemplate.exchange(uri, method, httpEntity, String.class); - } -} diff --git a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/util/RequestValidationException.java b/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/util/RequestValidationException.java deleted file mode 100644 index ce6e162..0000000 --- a/sidecar/fproxy/src/main/java/org/onap/aaf/fproxy/util/RequestValidationException.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy.util; - -/** This exception is thrown when the request fails validation. */ -public class RequestValidationException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructor for an instance of this exception with just a message. - * - * @param message information about the exception - */ - public RequestValidationException(String message) { - super(message); - } -} diff --git a/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyIT.java b/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyIT.java new file mode 100644 index 0000000..308eb26 --- /dev/null +++ b/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyIT.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.eclipse.jetty.util.security.Password; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.cadi.sidecar.fproxy.service.ForwardingProxyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class FProxyIT { + + static { + System.setProperty("server.ssl.key-store-password", + Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); + } + + @Autowired + private ForwardingProxyService fProxyService; + + @Test + public void contexLoads() throws Exception { + assertThat(fProxyService).isNotNull(); + } +} diff --git a/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyServiceTest.java b/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyServiceTest.java new file mode 100644 index 0000000..8943a09 --- /dev/null +++ b/sidecar/fproxy/src/test/java/org/onap/aaf/cadi/sidecar/fproxy/test/FProxyServiceTest.java @@ -0,0 +1,212 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.fproxy.test; + +import static org.hamcrest.Matchers.equalTo; +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.withSuccess; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import javax.servlet.http.Cookie; +import org.eclipse.jetty.util.security.Password; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData.CredentialType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +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.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.client.RestTemplate; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class FProxyServiceTest { + + static { + System.setProperty("server.ssl.key-store-password", + Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); + } + + @Value("${transactionid.header.name}") + private String transactionIdHeaderName; + + @Autowired + private MockMvc mvc; + + @Autowired + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + @Before + public void setUp() { + mockServer = MockRestServiceServer.createServer(restTemplate); + } + + @Test + public void testRequestFrowarding() throws Exception { + String testUrl = "https://localhost:80/testurl"; + String testResponse = "Response from MockRestService"; + String testTransactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + + mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, testTransactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void testCredentialCacheEndpoint() throws Exception { + populateCredentialCache("tx1", "headername", "headervalue", CredentialType.HEADER.toString()); + } + + @Test + public void testPopulateHeaderFromCache() throws Exception { + String testTransactionId = "tx1"; + String testUrl = "https://localhost:80/testurl"; + String headerName = "headername"; + String headerValue = "headervalue"; + + String testResponse = "Response from MockRestService"; + + // Populate the cache with header credentials + populateCredentialCache(testTransactionId, headerName, headerValue, CredentialType.HEADER.toString()); + + // Expect mock server to be called with request containing cached header + mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, testTransactionId)) + .andExpect(header(headerName, headerValue)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void testHeaderAlreadyExists() throws Exception { + String testTransactionId = "tx1"; + String testUrl = "https://localhost:80/testurl"; + String headerName = "headername"; + String headerValue = "headervalue"; + String newHeaderValue = "newheadervalue"; + + String testResponse = "Response from MockRestService"; + + // Populate the cache with header credentials using a new value + populateCredentialCache(testTransactionId, headerName, newHeaderValue, CredentialType.HEADER.toString()); + + // Expect mock server to be called with request containing the original header credential value, not the cached + // new header value + mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(headerName, headerValue)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server that already contains a header with same name as the one that has been cached + mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, testTransactionId).header(headerName, headerValue)) + .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void testPopulateCookieFromCache() throws Exception { + String testTransactionId = "tx1"; + String testUrl = "https://localhost:80/testurl"; + String cookieName = "testcookie"; + String cookieValue = "testcookie=testvalue"; + String testResponse = "Response from MockRestService"; + + // Populate the cache with cookie credentials + populateCredentialCache(testTransactionId, cookieName, cookieValue, CredentialType.COOKIE.toString()); + + // Expect mock server to be called with request containing cached header + mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(HttpHeaders.COOKIE, cookieValue)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void testCookieAlreadyExists() throws Exception { + String testTransactionId = "tx1"; + String testUrl = "https://localhost:80/testurl"; + String cookieName = "testcookie"; + String cookieValue = "testvalue"; + String newCookieValue = "newtestvalue"; + + String testResponse = "Response from MockRestService"; + + // Populate the cache with cookie credentials using a new value + populateCredentialCache(testTransactionId, cookieName, newCookieValue, CredentialType.COOKIE.toString()); + + // Expect mock server to be called with request containing the original cookie credential value, not the cached + // new cookie value + mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(HttpHeaders.COOKIE, cookieName + "=" + cookieValue)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server that already contains a cookie with same name as the one that has been cached + mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, testTransactionId).cookie(new Cookie(cookieName, cookieValue))) + .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + private void populateCredentialCache(String transactionId, String credentialName, String credentialValue, + String credentialType) throws Exception { + String cacheUrl = "https://localhost:80/credential-cache/" + transactionId; + String requestBody = "{ \"credentialName\":\"" + credentialName + "\", \"credentialValue\":\"" + credentialValue + + "\", \"credentialType\":\"" + credentialType + "\" }"; + + // Populate the cache with credentials + mvc.perform(MockMvcRequestBuilders.post(cacheUrl).content(requestBody).contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(transactionId))); + } +} diff --git a/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyIT.java b/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyIT.java deleted file mode 100644 index ba876e0..0000000 --- a/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyIT.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.eclipse.jetty.util.security.Password; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.onap.aaf.fproxy.service.ForwardingProxyService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class FProxyIT { - - static { - System.setProperty("server.ssl.key-store-password", - Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); - } - - @Autowired - private ForwardingProxyService fProxyService; - - @Test - public void contexLoads() throws Exception { - assertThat(fProxyService).isNotNull(); - } -} diff --git a/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyServiceTest.java b/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyServiceTest.java deleted file mode 100644 index e78d48b..0000000 --- a/sidecar/fproxy/src/test/java/org/onap/aaf/fproxy/FProxyServiceTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.fproxy; - -import static org.hamcrest.Matchers.equalTo; -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.withSuccess; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import javax.servlet.http.Cookie; -import org.eclipse.jetty.util.security.Password; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.onap.aaf.fproxy.data.CredentialCacheData.CredentialType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -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.MediaType; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.client.RestTemplate; - -@RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureMockMvc -public class FProxyServiceTest { - - static { - System.setProperty("server.ssl.key-store-password", - Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); - } - - @Value("${transactionid.header.name}") - private String transactionIdHeaderName; - - @Autowired - private MockMvc mvc; - - @Autowired - private RestTemplate restTemplate; - - private MockRestServiceServer mockServer; - - @Before - public void setUp() { - mockServer = MockRestServiceServer.createServer(restTemplate); - } - - @Test - public void testRequestFrowarding() throws Exception { - String testUrl = "https://localhost:80/testurl"; - String testResponse = "Response from MockRestService"; - String testTransactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - - mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, testTransactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void testCredentialCacheEndpoint() throws Exception { - populateCredentialCache("tx1", "headername", "headervalue", CredentialType.HEADER.toString()); - } - - @Test - public void testPopulateHeaderFromCache() throws Exception { - String testTransactionId = "tx1"; - String testUrl = "https://localhost:80/testurl"; - String headerName = "headername"; - String headerValue = "headervalue"; - - String testResponse = "Response from MockRestService"; - - // Populate the cache with header credentials - populateCredentialCache(testTransactionId, headerName, headerValue, CredentialType.HEADER.toString()); - - // Expect mock server to be called with request containing cached header - mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, testTransactionId)) - .andExpect(header(headerName, headerValue)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void testHeaderAlreadyExists() throws Exception { - String testTransactionId = "tx1"; - String testUrl = "https://localhost:80/testurl"; - String headerName = "headername"; - String headerValue = "headervalue"; - String newHeaderValue = "newheadervalue"; - - String testResponse = "Response from MockRestService"; - - // Populate the cache with header credentials using a new value - populateCredentialCache(testTransactionId, headerName, newHeaderValue, CredentialType.HEADER.toString()); - - // Expect mock server to be called with request containing the original header credential value, not the cached - // new header value - mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(headerName, headerValue)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server that already contains a header with same name as the one that has been cached - mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, testTransactionId).header(headerName, headerValue)) - .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void testPopulateCookieFromCache() throws Exception { - String testTransactionId = "tx1"; - String testUrl = "https://localhost:80/testurl"; - String cookieName = "testcookie"; - String cookieValue = "testcookie=testvalue"; - String testResponse = "Response from MockRestService"; - - // Populate the cache with cookie credentials - populateCredentialCache(testTransactionId, cookieName, cookieValue, CredentialType.COOKIE.toString()); - - // Expect mock server to be called with request containing cached header - mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(HttpHeaders.COOKIE, cookieValue)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, testTransactionId)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void testCookieAlreadyExists() throws Exception { - String testTransactionId = "tx1"; - String testUrl = "https://localhost:80/testurl"; - String cookieName = "testcookie"; - String cookieValue = "testvalue"; - String newCookieValue = "newtestvalue"; - - String testResponse = "Response from MockRestService"; - - // Populate the cache with cookie credentials using a new value - populateCredentialCache(testTransactionId, cookieName, newCookieValue, CredentialType.COOKIE.toString()); - - // Expect mock server to be called with request containing the original cookie credential value, not the cached - // new cookie value - mockServer.expect(requestTo(testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(HttpHeaders.COOKIE, cookieName + "=" + cookieValue)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server that already contains a cookie with same name as the one that has been cached - mvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, testTransactionId).cookie(new Cookie(cookieName, cookieValue))) - .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - private void populateCredentialCache(String transactionId, String credentialName, String credentialValue, - String credentialType) throws Exception { - String cacheUrl = "https://localhost:80/credential-cache/" + transactionId; - String requestBody = "{ \"credentialName\":\"" + credentialName + "\", \"credentialValue\":\"" + credentialValue - + "\", \"credentialType\":\"" + credentialType + "\" }"; - - // Populate the cache with credentials - mvc.perform(MockMvcRequestBuilders.post(cacheUrl).content(requestBody).contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(transactionId))); - } -} diff --git a/sidecar/pom.xml b/sidecar/pom.xml index def9f20..c926d99 100644 --- a/sidecar/pom.xml +++ b/sidecar/pom.xml @@ -1,29 +1,29 @@ - - - org.onap.aaf.cadi - parent - 2.1.7-SNAPSHOT - .. - + * =========================================================================== + * org.onap.aaf + * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * 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. + * ============LICENSE_END==================================================== + * --> + + + org.onap.aaf.cadi + parent + 2.1.7-SNAPSHOT + .. + 4.0.0 org.onap.aaf.cadi.sidecar sidecar @@ -33,38 +33,97 @@ UTF-8 UTF-8 + true + 0.7.7.201606060606 + 3.2 + jacoco + + target/code-coverage/jacoco-ut.exec + target/code-coverage/jacoco-it.exec + + **/gen/**,**/generated-sources/**,**/yang-gen**,**/pax/** + https://nexus.onap.org + /content/repositories/snapshots/ + /content/repositories/releases/ + /content/repositories/staging/ + /content/sites/site/org/onap/aaf/authz/${project.artifactId}/${project.version} + 1.8 - 2.0.3.RELEASE + + 2.0.3.RELEASE + 3.0.4.RELEASE ${basedir}/target + - - - org.onap.aaf.cadi.sidecar - fproxy - ${project.version} - - - org.onap.aaf.cadi.sidecar - rproxy - ${project.version} - + + org.onap.aaf.cadi.sidecar + fproxy + ${project.version} + + + org.onap.aaf.cadi.sidecar + rproxy + ${project.version} + + + javax.servlet + javax.servlet-api + 3.1.0 + + + + org.aspectj + aspectjrt + 1.9.2 + + + + com.google.code.gson + gson + 2.8.5 + + + + org.apache.commons + commons-lang3 + 3.8.1 + + + + org.springframework.boot + spring-boot-starter-jetty + ${spring.boot.version} + + + + org.springframework.boot + spring-boot-starter-aop + ${spring.boot.version} + - org.springframework.boot - spring-boot-dependencies + spring-boot-starter-web + ${spring.boot.version} + + + + org.springframework.boot + spring-boot-starter-test ${spring.boot.version} - pom - import + - + @@ -74,19 +133,6 @@ - - - - true - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - ${java.version} - ${java.version} - - - @@ -112,7 +158,7 @@ - + diff --git a/sidecar/rproxy/.gitignore b/sidecar/rproxy/.gitignore index 6028f0a..f3bad09 100644 --- a/sidecar/rproxy/.gitignore +++ b/sidecar/rproxy/.gitignore @@ -2,3 +2,4 @@ /.settings/ /target/ /.project +/logs/ diff --git a/sidecar/rproxy/pom.xml b/sidecar/rproxy/pom.xml index 6c32238..57f5f0d 100644 --- a/sidecar/rproxy/pom.xml +++ b/sidecar/rproxy/pom.xml @@ -40,6 +40,7 @@ org.springframework.boot spring-boot-starter-web + @@ -57,11 +60,6 @@ spring-boot-starter-jetty - - org.apache.httpcomponents - httpclient - - org.springframework.boot spring-boot-starter-aop @@ -70,7 +68,16 @@ org.springframework.boot spring-boot-starter-test - test + + + + org.apache.httpcomponents + httpclient + + + + org.aspectj + aspectjrt @@ -85,11 +92,6 @@ gson - - org.mockito - mockito-core - - diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyEntryExitLoggingAspect.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyEntryExitLoggingAspect.java new file mode 100644 index 0000000..b6e2f85 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyEntryExitLoggingAspect.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rpoxy.logging; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class ReverseProxyEntryExitLoggingAspect { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyEntryExitLoggingAspect.class); + + @Before("execution(* org.onap.platform.security.*.*(..))") + public void before(JoinPoint joinPoint) { + LOGGER.info("Entry of {}#{}", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName()); + } + + @After("execution(* org.onap.platform.security.*.*(..))") + public void after(JoinPoint joinPoint) { + LOGGER.info("Exit of {}#{}", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName()); + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTime.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTime.java new file mode 100644 index 0000000..bc3a489 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTime.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rpoxy.logging; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; + +@Aspect +@Configuration +public class ReverseProxyMethodLogTime { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyMethodLogTime.class); + + @Around("@annotation(org.onap.aaf.rproxy.logging.ReverseProxyMethodLogTimeAnnotation)") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + + long startTime = System.currentTimeMillis(); + + Object object = joinPoint.proceed(); + + long duration = System.currentTimeMillis() - startTime; + + LOGGER.info("Time taken by {} is {} ms", joinPoint, duration); + + return object; + } + + + +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTimeAnnotation.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTimeAnnotation.java new file mode 100644 index 0000000..ddd6fe9 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rpoxy/logging/ReverseProxyMethodLogTimeAnnotation.java @@ -0,0 +1,30 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rpoxy.logging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ReverseProxyMethodLogTimeAnnotation { +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyApplication.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyApplication.java new file mode 100644 index 0000000..3e36935 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyApplication.java @@ -0,0 +1,182 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.HashMap; +import java.util.Properties; +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import javax.net.ssl.SSLContext; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.eclipse.jetty.util.security.Password; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.aaf.cadi.sidecar.rproxy.config.ForwardProxyProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.PrimaryServiceProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.ReverseProxySSLProperties; +import org.onap.aaf.cadi.sidecar.rproxy.mocks.ReverseProxyMockCadiFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.RegistrationBean; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.ResourceUtils; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@ServletComponentScan +@EnableConfigurationProperties(ReverseProxySSLProperties.class) +@PropertySource("file:${CONFIG_HOME}/reverse-proxy.properties") +public class ReverseProxyApplication extends SpringBootServletInitializer { + + private static final String CADI_TRUSTSTORE_PASS = "cadi_truststore_password"; + + @Autowired + private Environment env; + + /** + * Spring Boot Initialisation. + * + * @param args main args + */ + public static void main(String[] args) { + String keyStorePassword = System.getProperty("KEY_STORE_PASSWORD"); + if (keyStorePassword == null || keyStorePassword.isEmpty()) { + throw new IllegalArgumentException("Env property KEY_STORE_PASSWORD not set"); + } + HashMap props = new HashMap<>(); + props.put("server.ssl.key-store-password", Password.deobfuscate(keyStorePassword)); + new ReverseProxyApplication() + .configure(new SpringApplicationBuilder(ReverseProxyApplication.class).properties(props)).run(args); + } + + /** + * Set required trust store system properties using values from application.properties + */ + @PostConstruct + public void setSystemProperties() { + String keyStorePath = env.getProperty("server.ssl.key-store"); + if (keyStorePath != null) { + String keyStorePassword = env.getProperty("server.ssl.key-store-password"); + + if (keyStorePassword != null) { + System.setProperty("javax.net.ssl.keyStore", keyStorePath); + System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); + System.setProperty("javax.net.ssl.trustStore", keyStorePath); + System.setProperty("javax.net.ssl.trustStorePassword", keyStorePassword); + } else { + throw new IllegalArgumentException("Env property server.ssl.key-store-password not set"); + } + } + } + + @Resource + private ReverseProxySSLProperties reverseProxySSLProperties; + + @Resource + Properties cadiProps; + + @Bean(name = "ForwardProxyProperties") + public ForwardProxyProperties forwardProxyProperties() { + return new ForwardProxyProperties(); + } + + @Bean(name = "PrimaryServiceProperties") + public PrimaryServiceProperties primaryServiceProperties() { + return new PrimaryServiceProperties(); + } + + @Profile("secure") + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) throws GeneralSecurityException, IOException { + return new RestTemplate(new HttpComponentsClientHttpRequestFactory(getClientBuilder().build())); + } + + @Profile("noHostVerification") + @Bean + public RestTemplate restTemplateNoHostVerification(RestTemplateBuilder builder) + throws GeneralSecurityException, IOException { + return new RestTemplate(new HttpComponentsClientHttpRequestFactory( + getClientBuilder().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build())); + } + + private HttpClientBuilder getClientBuilder() throws GeneralSecurityException, IOException { + + SSLContext sslContext = SSLContextBuilder.create() + .loadKeyMaterial(ResourceUtils.getFile(reverseProxySSLProperties.getClientcert()), + reverseProxySSLProperties.getKeystorePassword().toCharArray(), + reverseProxySSLProperties.getKeystorePassword().toCharArray()) + .loadTrustMaterial(ResourceUtils.getFile(reverseProxySSLProperties.getKeystore()), + reverseProxySSLProperties.getKeystorePassword().toCharArray()) + .build(); + + return HttpClients.custom().setSSLContext(sslContext); + } + + @Profile("cadi") + @Bean + public FilterRegistrationBean registerCADIFilter() { + + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + + filterRegistrationBean.setFilter(new CadiFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.setName("CADIFilter"); + filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); + + // Deobfuscate truststore password + String trustStorePassword = cadiProps.getProperty(CADI_TRUSTSTORE_PASS); + if (trustStorePassword != null) { + cadiProps.setProperty(CADI_TRUSTSTORE_PASS, Password.deobfuscate(trustStorePassword)); + } + + // Add filter init params + cadiProps.forEach((k, v) -> filterRegistrationBean.addInitParameter((String) k, (String) v)); + + return filterRegistrationBean; + } + + @Profile("mockCadi") + @Bean + public FilterRegistrationBean registerMockCADIFilter() { + + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + + filterRegistrationBean.setFilter(new ReverseProxyMockCadiFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.setName("CADIFilter"); + filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); + + return filterRegistrationBean; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyAuthorizationFilter.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyAuthorizationFilter.java new file mode 100644 index 0000000..2ef4cc0 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyAuthorizationFilter.java @@ -0,0 +1,216 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Resource; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.HttpStatus; +import org.onap.aaf.cadi.CadiWrap; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.sidecar.rproxy.config.ReverseProxyURIAuthorizationProperties; +import org.onap.aaf.cadi.sidecar.rproxy.utils.ReverseProxyAuthorization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +@Component +@Order(1) +@EnableConfigurationProperties(ReverseProxyURIAuthorizationProperties.class) +public class ReverseProxyAuthorizationFilter implements Filter { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyAuthorizationFilter.class); + + private List reverseProxyAuthorizations = new ArrayList<>(); + + @Resource + private ReverseProxyURIAuthorizationProperties reverseProxyURIAuthorizationProperties; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + // Read in the URI Authorisation configuration file + String authFilePath = reverseProxyURIAuthorizationProperties.getConfigurationFile(); + if (authFilePath != null) { + try (InputStream inputStream = + new FileInputStream(new File(reverseProxyURIAuthorizationProperties.getConfigurationFile())); + JsonReader jsonReader = new JsonReader(new InputStreamReader(inputStream))) { + List untrimmedList = new Gson().fromJson(jsonReader, + new TypeToken>() {}.getType()); + untrimmedList.removeAll(Collections.singleton(null)); + reverseProxyAuthorizations = untrimmedList; + } catch (IOException e) { + throw new ServletException("Authorizations config file not found.", e); + } + } + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + + CadiWrap cadiWrap = (CadiWrap) servletRequest; + Principal principal = cadiWrap.getUserPrincipal(); + List grantedPermissions = new ArrayList<>(); + cadiWrap.getLur().fishAll(principal, grantedPermissions); + + if (LOGGER.isDebugEnabled()) { + logNeededPermissions(); + } + + String requestPath; + try { + requestPath = new URI(((HttpServletRequest) servletRequest).getRequestURI()).getPath(); + } catch (URISyntaxException e) { + throw new ServletException("Request URI not valid", e); + } + + if (authorizeRequest(grantedPermissions, requestPath)) { + LOGGER.info("Authorized"); + filterChain.doFilter(servletRequest, servletResponse); + } else { + LOGGER.info("Unauthorized"); + ((HttpServletResponse) servletResponse).setStatus(HttpStatus.FORBIDDEN_403); + ((HttpServletResponse) servletResponse).setContentType("application/json"); + ((HttpServletResponse) servletResponse).sendError(HttpStatus.FORBIDDEN_403, + "Sorry, the request is not allowed"); + } + } + + /** + * Check if the granted permissions for the request path matches the configured needed permissions. + * + * @param grantedPermissions The granted permissions for the request path + * @param requestPath The request path + * @return true if permissions match + */ + private boolean authorizeRequest(List grantedPermissions, String requestPath) { + boolean authorized = false; + for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) { + if (requestPath.matches(reverseProxyAuthorization.getUri())) { + LOGGER.debug("The URI:{} matches:{}", requestPath, reverseProxyAuthorization.getUri()); + if (checkPermissionsMatch(grantedPermissions, reverseProxyAuthorization)) { + authorized = true; + break; + } + } else { + LOGGER.debug("The URI:{} doesn't match any in the configuration:{}", requestPath, + reverseProxyAuthorization.getUri()); + } + } + return authorized; + } + + /** + * Check all needed permissions match the granted permissions. + * + * @param grantedPermissions the granted permissions + * @param reverseProxyAuthorization the bean that contains the needed permissions + * @return true if all needed permissions match + */ + private boolean checkPermissionsMatch(List grantedPermissions, + ReverseProxyAuthorization reverseProxyAuthorization) { + + boolean matchedAllPermissions = true; + for (String neededPermission : reverseProxyAuthorization.getPermissions()) { + + // Check needed permission is granted + boolean matchedNeededPermission = false; + for (Permission grantedPermission : grantedPermissions) { + if (checkGrantedPermission(neededPermission, grantedPermission.getKey())) { + LOGGER.debug("Permission match found - needed permission:{}, granted permission:{}", + neededPermission, grantedPermission.getKey()); + matchedNeededPermission = true; + break; + } + } + if (!matchedNeededPermission) { + matchedAllPermissions = false; + break; + } + } + return matchedAllPermissions; + } + + /** + * Check whether an AAF style permission matches a needed permission. Wildcards (*) are supported. + * + * @param neededPermission, the needed permission + * @param grantedPermission, the granted permission + * + * @return true if the needed permission matches a granted permission + */ + private boolean checkGrantedPermission(String neededPermission, String grantedPermission) { + boolean permissionMatch = false; + if (grantedPermission.matches(neededPermission)) { + permissionMatch = true; + } else if (grantedPermission.contains("*")) { + String[] splitNeededPermission = neededPermission.split("\\\\\\|"); + String[] splitGrantedPermission = grantedPermission.split("\\|"); + if ((splitGrantedPermission[0].matches(splitNeededPermission[0])) + && (splitGrantedPermission[1].equals("*") + || splitGrantedPermission[1].matches(splitNeededPermission[1])) + && (splitGrantedPermission[2].equals("*") + || splitGrantedPermission[2].matches(splitNeededPermission[2]))) { + permissionMatch = true; + } + } + return permissionMatch; + } + + /** + * Log the needed permissions for each URL configured. + */ + private void logNeededPermissions() { + for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) { + LOGGER.debug("URI For authorization: {}", reverseProxyAuthorization.getUri()); + for (String permission : reverseProxyAuthorization.getPermissions()) { + LOGGER.debug("\t Needed permission:{}", permission); + } + } + } + + @Override + public void destroy() { + // No op + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java new file mode 100644 index 0000000..e15fb2a --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/ReverseProxyService.java @@ -0,0 +1,167 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Enumeration; +import java.util.UUID; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData; +import org.onap.aaf.cadi.sidecar.fproxy.data.CredentialCacheData.CredentialType; +import org.onap.aaf.cadi.sidecar.rpoxy.logging.ReverseProxyMethodLogTimeAnnotation; +import org.onap.aaf.cadi.sidecar.rproxy.config.ForwardProxyProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.PrimaryServiceProperties; +import org.onap.aaf.cadi.sidecar.rproxy.utils.ReverseProxyUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +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.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +@RestController +@EnableConfigurationProperties({ForwardProxyProperties.class, PrimaryServiceProperties.class}) +public class ReverseProxyService { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyService.class); + + private String validatedTransactionId; + + @Resource(name = "ForwardProxyProperties") + private ForwardProxyProperties forwardProxyProperties; + + @Resource(name = "PrimaryServiceProperties") + private PrimaryServiceProperties primaryServiceProperties; + + @Autowired + private RestTemplate restTemplate; + + @Value("${transactionid.header.name}") + private String transactionIdHeader; + + @RequestMapping("/**") + @ReverseProxyMethodLogTimeAnnotation + public ResponseEntity handleRequest(HttpServletRequest request, + @RequestHeader(value = "${transactionid.header.name}", defaultValue = "") String transactionId, + @RequestBody(required = false) String requestBody, HttpMethod requestMethod) throws URISyntaxException { + validatedTransactionId = getValidTransactionId(transactionId); + + // Extract Request Permissions and store in Forward Proxy cache + CredentialCacheData credentialCacheData = getCredentialDataFromRequest(request); + if (credentialCacheData != null) { + postCredentialsToCache(credentialCacheData); + } + + // Call out to Primary Service & Return Response + URI requestURI = new URI(request.getRequestURI()); + + LOGGER.debug("Request URI: {}", request.getRequestURI()); + + // Get Request Endpoint & substitute in local values + URI primaryServiceURI = new URI(primaryServiceProperties.getProtocol(), requestURI.getUserInfo(), + primaryServiceProperties.getHost(), Integer.parseInt(primaryServiceProperties.getPort()), + requestURI.getPath(), requestURI.getQuery(), requestURI.getFragment()); + + LOGGER.debug("Primary Service URI:{}, HTTP Method: {}", primaryServiceURI, requestMethod); + + HttpHeaders requestHeaders = setForwardedRequestHeaders(request); + HttpEntity httpEntity = new HttpEntity<>(requestBody, requestHeaders); + + return restTemplate.exchange(primaryServiceURI, requestMethod, httpEntity, String.class); + } + + private String getValidTransactionId(String transactionId) { + LOGGER.debug("Request transaction ID: {}", transactionId); + if (transactionId == null || !ReverseProxyUtils.validTransactionId(transactionId)) { + transactionId = UUID.randomUUID().toString(); + } + LOGGER.debug("Validated transaction ID: {}", transactionId); + return transactionId; + } + + private HttpHeaders setForwardedRequestHeaders(HttpServletRequest httpServletRequest) { + HttpHeaders httpHeaders = new HttpHeaders(); + Enumeration headerNames = httpServletRequest.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + if (!headerName.equals(transactionIdHeader)) { + httpHeaders.set(headerName, httpServletRequest.getHeader(headerName)); + } + } + // Always set transaction ID + httpHeaders.set(transactionIdHeader, validatedTransactionId); + + return httpHeaders; + } + + /** + * Retrieves credential data from request. + * + * @param request The request to retrieve credentials from + * @return The retrieved credential data, or null if no credentials are found in request + */ + private CredentialCacheData getCredentialDataFromRequest(HttpServletRequest request) { + CredentialCacheData credentialCacheData = null; + String authValue = request.getHeader(HttpHeaders.AUTHORIZATION); + if (authValue != null) { + credentialCacheData = new CredentialCacheData(HttpHeaders.AUTHORIZATION, authValue, CredentialType.HEADER); + } + return credentialCacheData; + } + + /** + * Posts credential data to credential cache endpoint + * + * @param credentialCacheData The credential data to post + * @throws URISyntaxException + */ + private void postCredentialsToCache(CredentialCacheData credentialCacheData) throws URISyntaxException { + URI forwardProxyURI = new URI(forwardProxyProperties.getProtocol(), null, forwardProxyProperties.getHost(), + forwardProxyProperties.getPort(), forwardProxyProperties.getCacheurl() + "/" + validatedTransactionId, + null, null); + + ResponseEntity response = + restTemplate.postForEntity(forwardProxyURI, credentialCacheData, String.class); + + if (!response.getStatusCode().is2xxSuccessful()) { + throw new HttpClientErrorException(response.getStatusCode(), + "Error posting to credential cache. Message: " + response.getBody()); + } + } + + @Override + public String toString() { + return this.getClass().getName() + ": Forward proxy host:" + forwardProxyProperties.getHost() + + ": Primary service host:" + primaryServiceProperties.getHost(); + + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/CadiProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/CadiProperties.java new file mode 100644 index 0000000..841d8d8 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/CadiProperties.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.config; + +import java.net.MalformedURLException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.UrlResource; + +@Configuration +public class CadiProperties { + + @Value("${CONFIG_HOME}") + private String configHome; + + @Bean(name = "cadiProps") + public PropertiesFactoryBean mapper() throws MalformedURLException { + PropertiesFactoryBean bean = new PropertiesFactoryBean(); + bean.setLocation(new UrlResource("file:" + configHome + "/cadi.properties")); + return bean; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ForwardProxyProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ForwardProxyProperties.java new file mode 100644 index 0000000..5c0d2c8 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ForwardProxyProperties.java @@ -0,0 +1,67 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource("file:${CONFIG_HOME}/forward-proxy.properties") +@ConfigurationProperties(prefix = "forward-proxy") +public class ForwardProxyProperties { + + private String protocol; + private String host; + private int port; + private String cacheurl; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getCacheurl() { + return cacheurl; + } + + public void setCacheurl(String cacheurl) { + this.cacheurl = cacheurl; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/PrimaryServiceProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/PrimaryServiceProperties.java new file mode 100644 index 0000000..e201ae6 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/PrimaryServiceProperties.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource("file:${CONFIG_HOME}/primary-service.properties") +@ConfigurationProperties(prefix = "primary-service") +public class PrimaryServiceProperties { + + private String protocol; + private String host; + private String port; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxySSLProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxySSLProperties.java new file mode 100644 index 0000000..ee7a240 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxySSLProperties.java @@ -0,0 +1,56 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "server.ssl") +public class ReverseProxySSLProperties { + + private String keystore; + private String keystorePassword; + private String clientcert; + + public String getKeystore() { + return keystore; + } + + public void setKeystore(String keystore) { + this.keystore = keystore; + } + + public String getClientcert() { + return clientcert; + } + + public void setClientcert(String clientcert) { + this.clientcert = clientcert; + } + + public String getKeystorePassword() { + return keystorePassword; + } + + public void setKeystorePassword(String keystorePassword) { + this.keystorePassword = keystorePassword; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxyURIAuthorizationProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxyURIAuthorizationProperties.java new file mode 100644 index 0000000..193d753 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/config/ReverseProxyURIAuthorizationProperties.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "uri.authorization") +public class ReverseProxyURIAuthorizationProperties { + + private String configurationFile; + + public String getConfigurationFile() { + return configurationFile; + } + + public void setConfigurationFile(String configurationFile) { + this.configurationFile = configurationFile; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/mocks/ReverseProxyMockCadiFilter.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/mocks/ReverseProxyMockCadiFilter.java new file mode 100644 index 0000000..1c4de92 --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/mocks/ReverseProxyMockCadiFilter.java @@ -0,0 +1,143 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.mocks; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.security.Principal; +import java.util.List; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import org.onap.aaf.cadi.CadiWrap; +import org.onap.aaf.cadi.Lur; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.aaf.cadi.principal.TaggedPrincipal; +import org.onap.aaf.cadi.taf.TafResp; + +public class ReverseProxyMockCadiFilter implements Filter { + + private FakeLur fakeLur = new FakeLur(); + + static class FakeLur implements Lur { + + @Override + public void fishAll(Principal bait, List permissions) { + + final String WildcardPermissionType = "test.wildcard.access"; + final String MultiplePermissionType = "test.multiple.access"; + final String TestAuthAccessPermissionType = "test.auth.access"; + final String PermissionAction = "permission"; + + String principalName = bait.getName(); + + if (principalName != null && principalName.equals("UserWithInstanceActionWildcardPermissionGranted")) { + permissions.add(new AAFPermission(null, WildcardPermissionType, "*", "*")); + } + else + if (principalName != null && principalName.equals("UserWithInstanceWildcardPermissionGranted")) { + permissions.add(new AAFPermission(null, WildcardPermissionType, "*", PermissionAction)); + } + else + if (principalName != null && principalName.equals("UserWithActionWildcardPermissionGranted")) { + permissions.add(new AAFPermission(null, WildcardPermissionType, "first", "*")); + } + else { + + // For single permission test + permissions.add(new AAFPermission(null, "test.single.access", "single", PermissionAction)); + + // For multiple permission test + permissions.add(new AAFPermission(null, MultiplePermissionType, "first", PermissionAction)); + permissions.add(new AAFPermission(null, MultiplePermissionType, "second", PermissionAction)); + permissions.add(new AAFPermission(null, MultiplePermissionType, "third", PermissionAction)); + + // For transaction id test + permissions.add(new AAFPermission(null, TestAuthAccessPermissionType, "rest", "write")); + permissions.add(new AAFPermission(null, TestAuthAccessPermissionType, "rpc", "write")); + } + } + + @Override + public Permission createPerm(String p) { + return null; + } + + @Override + public boolean fish(Principal bait, Permission... pond) { + return false; + } + + @Override + public void destroy() { + // Mock implementation + } + + @Override + public boolean handlesExclusively(Permission... pond) { + return false; + } + + @Override + public boolean handles(Principal principal) { + return false; + } + + @Override + public void clear(Principal p, StringBuilder report) { + // Mock implementation + } + + } + + @Override + public void destroy() { + // Mock implementation + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + + String userName = ((HttpServletRequest)servletRequest).getHeader("PermissionsUser"); + + TaggedPrincipal mockTaggedPrincipal = mock(TaggedPrincipal.class); + when(mockTaggedPrincipal.getName()).thenReturn(userName); + + TafResp tafResponseMock = mock(TafResp.class); + when(tafResponseMock.getPrincipal()).thenReturn(mockTaggedPrincipal); + + CadiWrap cadiWrap = new CadiWrap((HttpServletRequest) servletRequest, tafResponseMock, fakeLur); + filterChain.doFilter(cadiWrap, servletResponse); + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + // Mock implementation + } + +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyAuthorization.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyAuthorization.java new file mode 100644 index 0000000..fd9db8e --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyAuthorization.java @@ -0,0 +1,34 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.utils; + +public class ReverseProxyAuthorization { + + private String uri; + private String[] permissions; + + public String getUri() { + return uri; + } + + public String[] getPermissions() { + return permissions; + } +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyUtils.java b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyUtils.java new file mode 100644 index 0000000..495a78c --- /dev/null +++ b/sidecar/rproxy/src/main/java/org/onap/aaf/cadi/sidecar/rproxy/utils/ReverseProxyUtils.java @@ -0,0 +1,29 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.utils; + +public class ReverseProxyUtils { + + public static boolean validTransactionId(String transactionId) { + return transactionId.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + } + + private ReverseProxyUtils() {} +} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyApplication.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyApplication.java deleted file mode 100644 index ebceceb..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyApplication.java +++ /dev/null @@ -1,182 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.HashMap; -import java.util.Properties; -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import javax.net.ssl.SSLContext; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContextBuilder; -import org.eclipse.jetty.util.security.Password; -import org.onap.aaf.cadi.filter.CadiFilter; -import org.onap.aaf.rproxy.config.ForwardProxyProperties; -import org.onap.aaf.rproxy.config.PrimaryServiceProperties; -import org.onap.aaf.rproxy.config.ReverseProxySSLProperties; -import org.onap.aaf.rproxy.mocks.ReverseProxyMockCadiFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.boot.web.servlet.RegistrationBean; -import org.springframework.boot.web.servlet.ServletComponentScan; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.Environment; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.util.ResourceUtils; -import org.springframework.web.client.RestTemplate; - -@SpringBootApplication -@ServletComponentScan -@EnableConfigurationProperties(ReverseProxySSLProperties.class) -@PropertySource("file:${CONFIG_HOME}/reverse-proxy.properties") -public class ReverseProxyApplication extends SpringBootServletInitializer { - - private static final String CADI_TRUSTSTORE_PASS = "cadi_truststore_password"; - - @Autowired - private Environment env; - - /** - * Spring Boot Initialisation. - * - * @param args main args - */ - public static void main(String[] args) { - String keyStorePassword = System.getProperty("KEY_STORE_PASSWORD"); - if (keyStorePassword == null || keyStorePassword.isEmpty()) { - throw new IllegalArgumentException("Env property KEY_STORE_PASSWORD not set"); - } - HashMap props = new HashMap<>(); - props.put("server.ssl.key-store-password", Password.deobfuscate(keyStorePassword)); - new ReverseProxyApplication() - .configure(new SpringApplicationBuilder(ReverseProxyApplication.class).properties(props)).run(args); - } - - /** - * Set required trust store system properties using values from application.properties - */ - @PostConstruct - public void setSystemProperties() { - String keyStorePath = env.getProperty("server.ssl.key-store"); - if (keyStorePath != null) { - String keyStorePassword = env.getProperty("server.ssl.key-store-password"); - - if (keyStorePassword != null) { - System.setProperty("javax.net.ssl.keyStore", keyStorePath); - System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword); - System.setProperty("javax.net.ssl.trustStore", keyStorePath); - System.setProperty("javax.net.ssl.trustStorePassword", keyStorePassword); - } else { - throw new IllegalArgumentException("Env property server.ssl.key-store-password not set"); - } - } - } - - @Resource - private ReverseProxySSLProperties reverseProxySSLProperties; - - @Resource - Properties cadiProps; - - @Bean(name = "ForwardProxyProperties") - public ForwardProxyProperties forwardProxyProperties() { - return new ForwardProxyProperties(); - } - - @Bean(name = "PrimaryServiceProperties") - public PrimaryServiceProperties primaryServiceProperties() { - return new PrimaryServiceProperties(); - } - - @Profile("secure") - @Bean - public RestTemplate restTemplate(RestTemplateBuilder builder) throws GeneralSecurityException, IOException { - return new RestTemplate(new HttpComponentsClientHttpRequestFactory(getClientBuilder().build())); - } - - @Profile("noHostVerification") - @Bean - public RestTemplate restTemplateNoHostVerification(RestTemplateBuilder builder) - throws GeneralSecurityException, IOException { - return new RestTemplate(new HttpComponentsClientHttpRequestFactory( - getClientBuilder().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build())); - } - - private HttpClientBuilder getClientBuilder() throws GeneralSecurityException, IOException { - - SSLContext sslContext = SSLContextBuilder.create() - .loadKeyMaterial(ResourceUtils.getFile(reverseProxySSLProperties.getClientcert()), - reverseProxySSLProperties.getKeystorePassword().toCharArray(), - reverseProxySSLProperties.getKeystorePassword().toCharArray()) - .loadTrustMaterial(ResourceUtils.getFile(reverseProxySSLProperties.getKeystore()), - reverseProxySSLProperties.getKeystorePassword().toCharArray()) - .build(); - - return HttpClients.custom().setSSLContext(sslContext); - } - - @Profile("cadi") - @Bean - public FilterRegistrationBean registerCADIFilter() { - - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); - - filterRegistrationBean.setFilter(new CadiFilter()); - filterRegistrationBean.addUrlPatterns("/*"); - filterRegistrationBean.setName("CADIFilter"); - filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); - - // Deobfuscate truststore password - String trustStorePassword = cadiProps.getProperty(CADI_TRUSTSTORE_PASS); - if (trustStorePassword != null) { - cadiProps.setProperty(CADI_TRUSTSTORE_PASS, Password.deobfuscate(trustStorePassword)); - } - - // Add filter init params - cadiProps.forEach((k, v) -> filterRegistrationBean.addInitParameter((String) k, (String) v)); - - return filterRegistrationBean; - } - - @Profile("mockCadi") - @Bean - public FilterRegistrationBean registerMockCADIFilter() { - - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); - - filterRegistrationBean.setFilter(new ReverseProxyMockCadiFilter()); - filterRegistrationBean.addUrlPatterns("/*"); - filterRegistrationBean.setName("CADIFilter"); - filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); - - return filterRegistrationBean; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyAuthorizationFilter.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyAuthorizationFilter.java deleted file mode 100644 index f939249..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyAuthorizationFilter.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.annotation.Resource; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.HttpStatus; -import org.onap.aaf.cadi.CadiWrap; -import org.onap.aaf.cadi.Permission; -import org.onap.aaf.rproxy.config.ReverseProxyURIAuthorizationProperties; -import org.onap.aaf.rproxy.utils.ReverseProxyAuthorization; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -@Component -@Order(1) -@EnableConfigurationProperties(ReverseProxyURIAuthorizationProperties.class) -public class ReverseProxyAuthorizationFilter implements Filter { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyAuthorizationFilter.class); - - private List reverseProxyAuthorizations = new ArrayList<>(); - - @Resource - private ReverseProxyURIAuthorizationProperties reverseProxyURIAuthorizationProperties; - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - - // Read in the URI Authorisation configuration file - String authFilePath = reverseProxyURIAuthorizationProperties.getConfigurationFile(); - if (authFilePath != null) { - try (InputStream inputStream = - new FileInputStream(new File(reverseProxyURIAuthorizationProperties.getConfigurationFile())); - JsonReader jsonReader = new JsonReader(new InputStreamReader(inputStream))) { - List untrimmedList = new Gson().fromJson(jsonReader, - new TypeToken>() {}.getType()); - untrimmedList.removeAll(Collections.singleton(null)); - reverseProxyAuthorizations = untrimmedList; - } catch (IOException e) { - throw new ServletException("Authorizations config file not found.", e); - } - } - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - - CadiWrap cadiWrap = (CadiWrap) servletRequest; - Principal principal = cadiWrap.getUserPrincipal(); - List grantedPermissions = new ArrayList<>(); - cadiWrap.getLur().fishAll(principal, grantedPermissions); - - if (LOGGER.isDebugEnabled()) { - logNeededPermissions(); - } - - String requestPath; - try { - requestPath = new URI(((HttpServletRequest) servletRequest).getRequestURI()).getPath(); - } catch (URISyntaxException e) { - throw new ServletException("Request URI not valid", e); - } - - if (authorizeRequest(grantedPermissions, requestPath)) { - LOGGER.info("Authorized"); - filterChain.doFilter(servletRequest, servletResponse); - } else { - LOGGER.info("Unauthorized"); - ((HttpServletResponse) servletResponse).setStatus(HttpStatus.FORBIDDEN_403); - ((HttpServletResponse) servletResponse).setContentType("application/json"); - ((HttpServletResponse) servletResponse).sendError(HttpStatus.FORBIDDEN_403, - "Sorry, the request is not allowed"); - } - } - - /** - * Check if the granted permissions for the request path matches the configured needed permissions. - * - * @param grantedPermissions The granted permissions for the request path - * @param requestPath The request path - * @return true if permissions match - */ - private boolean authorizeRequest(List grantedPermissions, String requestPath) { - boolean authorized = false; - for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) { - if (requestPath.matches(reverseProxyAuthorization.getUri())) { - LOGGER.debug("The URI:{} matches:{}", requestPath, reverseProxyAuthorization.getUri()); - if (checkPermissionsMatch(grantedPermissions, reverseProxyAuthorization)) { - authorized = true; - break; - } - } else { - LOGGER.debug("The URI:{} doesn't match any in the configuration:{}", requestPath, - reverseProxyAuthorization.getUri()); - } - } - return authorized; - } - - /** - * Check all needed permissions match the granted permissions. - * - * @param grantedPermissions the granted permissions - * @param reverseProxyAuthorization the bean that contains the needed permissions - * @return true if all needed permissions match - */ - private boolean checkPermissionsMatch(List grantedPermissions, - ReverseProxyAuthorization reverseProxyAuthorization) { - - boolean matchedAllPermissions = true; - for (String neededPermission : reverseProxyAuthorization.getPermissions()) { - - // Check needed permission is granted - boolean matchedNeededPermission = false; - for (Permission grantedPermission : grantedPermissions) { - if (checkGrantedPermission(neededPermission, grantedPermission.getKey())) { - LOGGER.debug("Permission match found - needed permission:{}, granted permission:{}", - neededPermission, grantedPermission.getKey()); - matchedNeededPermission = true; - break; - } - } - if (!matchedNeededPermission) { - matchedAllPermissions = false; - break; - } - } - return matchedAllPermissions; - } - - /** - * Check whether an AAF style permission matches a needed permission. Wildcards (*) are supported. - * - * @param neededPermission, the needed permission - * @param grantedPermission, the granted permission - * - * @return true if the needed permission matches a granted permission - */ - private boolean checkGrantedPermission(String neededPermission, String grantedPermission) { - boolean permissionMatch = false; - if (grantedPermission.matches(neededPermission)) { - permissionMatch = true; - } else if (grantedPermission.contains("*")) { - String[] splitNeededPermission = neededPermission.split("\\\\\\|"); - String[] splitGrantedPermission = grantedPermission.split("\\|"); - if ((splitGrantedPermission[0].matches(splitNeededPermission[0])) - && (splitGrantedPermission[1].equals("*") - || splitGrantedPermission[1].matches(splitNeededPermission[1])) - && (splitGrantedPermission[2].equals("*") - || splitGrantedPermission[2].matches(splitNeededPermission[2]))) { - permissionMatch = true; - } - } - return permissionMatch; - } - - /** - * Log the needed permissions for each URL configured. - */ - private void logNeededPermissions() { - for (ReverseProxyAuthorization reverseProxyAuthorization : reverseProxyAuthorizations) { - LOGGER.debug("URI For authorization: {}", reverseProxyAuthorization.getUri()); - for (String permission : reverseProxyAuthorization.getPermissions()) { - LOGGER.debug("\t Needed permission:{}", permission); - } - } - } - - @Override - public void destroy() { - // No op - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyService.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyService.java deleted file mode 100644 index 55fcdd1..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/ReverseProxyService.java +++ /dev/null @@ -1,166 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Enumeration; -import java.util.UUID; -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import org.onap.aaf.fproxy.data.CredentialCacheData; -import org.onap.aaf.fproxy.data.CredentialCacheData.CredentialType; -import org.onap.aaf.rproxy.config.ForwardProxyProperties; -import org.onap.aaf.rproxy.config.PrimaryServiceProperties; -import org.onap.aaf.rproxy.logging.ReverseProxyMethodLogTimeAnnotation; -import org.onap.aaf.rproxy.utils.ReverseProxyUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -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.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; - -@RestController -@EnableConfigurationProperties({ForwardProxyProperties.class, PrimaryServiceProperties.class}) -public class ReverseProxyService { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyService.class); - - private String validatedTransactionId; - - @Resource(name = "ForwardProxyProperties") - private ForwardProxyProperties forwardProxyProperties; - - @Resource(name = "PrimaryServiceProperties") - private PrimaryServiceProperties primaryServiceProperties; - - @Autowired - private RestTemplate restTemplate; - - @Value("${transactionid.header.name}") - private String transactionIdHeader; - - @RequestMapping("/**") - @ReverseProxyMethodLogTimeAnnotation - public ResponseEntity handleRequest(HttpServletRequest request, - @RequestHeader(value = "${transactionid.header.name}", defaultValue = "") String transactionId, - @RequestBody(required = false) String requestBody, HttpMethod requestMethod) throws URISyntaxException { - validatedTransactionId = getValidTransactionId(transactionId); - - // Extract Request Permissions and store in Forward Proxy cache - CredentialCacheData credentialCacheData = getCredentialDataFromRequest(request); - if (credentialCacheData != null) { - postCredentialsToCache(credentialCacheData); - } - - // Call out to Primary Service & Return Response - URI requestURI = new URI(request.getRequestURI()); - - LOGGER.debug("Request URI: {}", request.getRequestURI()); - - // Get Request Endpoint & substitute in local values - URI primaryServiceURI = new URI(primaryServiceProperties.getProtocol(), requestURI.getUserInfo(), - primaryServiceProperties.getHost(), Integer.parseInt(primaryServiceProperties.getPort()), - requestURI.getPath(), requestURI.getQuery(), requestURI.getFragment()); - - LOGGER.debug("Primary Service URI:{}, HTTP Method: {}", primaryServiceURI, requestMethod); - - HttpHeaders requestHeaders = setForwardedRequestHeaders(request); - HttpEntity httpEntity = new HttpEntity<>(requestBody, requestHeaders); - - return restTemplate.exchange(primaryServiceURI, requestMethod, httpEntity, String.class); - } - - private String getValidTransactionId(String transactionId) { - LOGGER.debug("Request transaction ID: {}", transactionId); - if (transactionId == null || !ReverseProxyUtils.validTransactionId(transactionId)) { - transactionId = UUID.randomUUID().toString(); - } - LOGGER.debug("Validated transaction ID: {}", transactionId); - return transactionId; - } - - private HttpHeaders setForwardedRequestHeaders(HttpServletRequest httpServletRequest) { - HttpHeaders httpHeaders = new HttpHeaders(); - Enumeration headerNames = httpServletRequest.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - if (!headerName.equals(transactionIdHeader)) { - httpHeaders.set(headerName, httpServletRequest.getHeader(headerName)); - } - } - // Always set transaction ID - httpHeaders.set(transactionIdHeader, validatedTransactionId); - - return httpHeaders; - } - - /** - * Retrieves credential data from request. - * - * @param request The request to retrieve credentials from - * @return The retrieved credential data, or null if no credentials are found in request - */ - private CredentialCacheData getCredentialDataFromRequest(HttpServletRequest request) { - CredentialCacheData credentialCacheData = null; - String authValue = request.getHeader(HttpHeaders.AUTHORIZATION); - if (authValue != null) { - credentialCacheData = new CredentialCacheData(HttpHeaders.AUTHORIZATION, authValue, CredentialType.HEADER); - } - return credentialCacheData; - } - - /** - * Posts credential data to credential cache endpoint - * - * @param credentialCacheData The credential data to post - * @throws URISyntaxException - */ - private void postCredentialsToCache(CredentialCacheData credentialCacheData) throws URISyntaxException { - URI forwardProxyURI = new URI(forwardProxyProperties.getProtocol(), null, forwardProxyProperties.getHost(), - forwardProxyProperties.getPort(), forwardProxyProperties.getCacheurl() + "/" + validatedTransactionId, - null, null); - - ResponseEntity response = - restTemplate.postForEntity(forwardProxyURI, credentialCacheData, String.class); - - if (!response.getStatusCode().is2xxSuccessful()) { - throw new HttpClientErrorException(response.getStatusCode(), - "Error posting to credential cache. Message: " + response.getBody()); - } - } - - @Override - public String toString() { - return this.getClass().getName() + ": Forward proxy host:" + forwardProxyProperties.getHost() - + ": Primary service host:" + primaryServiceProperties.getHost(); - - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/CadiProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/CadiProperties.java deleted file mode 100644 index 0afb506..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/CadiProperties.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.config; - -import java.net.MalformedURLException; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.PropertiesFactoryBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.UrlResource; - -@Configuration -public class CadiProperties { - - @Value("${CONFIG_HOME}") - private String configHome; - - @Bean(name = "cadiProps") - public PropertiesFactoryBean mapper() throws MalformedURLException { - PropertiesFactoryBean bean = new PropertiesFactoryBean(); - bean.setLocation(new UrlResource("file:" + configHome + "/cadi.properties")); - return bean; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ForwardProxyProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ForwardProxyProperties.java deleted file mode 100644 index 3607797..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ForwardProxyProperties.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -@Configuration -@PropertySource("file:${CONFIG_HOME}/forward-proxy.properties") -@ConfigurationProperties(prefix = "forward-proxy") -public class ForwardProxyProperties { - - private String protocol; - private String host; - private int port; - private String cacheurl; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getCacheurl() { - return cacheurl; - } - - public void setCacheurl(String cacheurl) { - this.cacheurl = cacheurl; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/PrimaryServiceProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/PrimaryServiceProperties.java deleted file mode 100644 index 994dc55..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/PrimaryServiceProperties.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -@Configuration -@PropertySource("file:${CONFIG_HOME}/primary-service.properties") -@ConfigurationProperties(prefix = "primary-service") -public class PrimaryServiceProperties { - - private String protocol; - private String host; - private String port; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public String getPort() { - return port; - } - - public void setPort(String port) { - this.port = port; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxySSLProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxySSLProperties.java deleted file mode 100644 index 31e8a0d..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxySSLProperties.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties(prefix = "server.ssl") -public class ReverseProxySSLProperties { - - private String keystore; - private String keystorePassword; - private String clientcert; - - public String getKeystore() { - return keystore; - } - - public void setKeystore(String keystore) { - this.keystore = keystore; - } - - public String getClientcert() { - return clientcert; - } - - public void setClientcert(String clientcert) { - this.clientcert = clientcert; - } - - public String getKeystorePassword() { - return keystorePassword; - } - - public void setKeystorePassword(String keystorePassword) { - this.keystorePassword = keystorePassword; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxyURIAuthorizationProperties.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxyURIAuthorizationProperties.java deleted file mode 100644 index da25d9c..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/config/ReverseProxyURIAuthorizationProperties.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Configuration -@ConfigurationProperties(prefix = "uri.authorization") -public class ReverseProxyURIAuthorizationProperties { - - private String configurationFile; - - public String getConfigurationFile() { - return configurationFile; - } - - public void setConfigurationFile(String configurationFile) { - this.configurationFile = configurationFile; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyEntryExitLoggingAspect.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyEntryExitLoggingAspect.java deleted file mode 100644 index 174420c..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyEntryExitLoggingAspect.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.logging; - -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.After; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -@Aspect -@Component -public class ReverseProxyEntryExitLoggingAspect { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyEntryExitLoggingAspect.class); - - @Before("execution(* org.onap.platform.security.*.*(..))") - public void before(JoinPoint joinPoint) { - LOGGER.info("Entry of {}#{}", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName()); - } - - @After("execution(* org.onap.platform.security.*.*(..))") - public void after(JoinPoint joinPoint) { - LOGGER.info("Exit of {}#{}", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName()); - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTime.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTime.java deleted file mode 100644 index 00cfba6..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTime.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.logging; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Configuration; - -@Aspect -@Configuration -public class ReverseProxyMethodLogTime { - - private static final Logger LOGGER = LoggerFactory.getLogger(ReverseProxyMethodLogTime.class); - - @Around("@annotation(org.onap.aaf.rproxy.logging.ReverseProxyMethodLogTimeAnnotation)") - public Object around(ProceedingJoinPoint joinPoint) throws Throwable { - - long startTime = System.currentTimeMillis(); - - Object object = joinPoint.proceed(); - - long duration = System.currentTimeMillis() - startTime; - - LOGGER.info("Time taken by {} is {} ms", joinPoint, duration); - - return object; - } - - - -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTimeAnnotation.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTimeAnnotation.java deleted file mode 100644 index 55f00f4..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/logging/ReverseProxyMethodLogTimeAnnotation.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.logging; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface ReverseProxyMethodLogTimeAnnotation { -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/mocks/ReverseProxyMockCadiFilter.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/mocks/ReverseProxyMockCadiFilter.java deleted file mode 100644 index 10bfc3e..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/mocks/ReverseProxyMockCadiFilter.java +++ /dev/null @@ -1,143 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.mocks; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.security.Principal; -import java.util.List; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import org.onap.aaf.cadi.CadiWrap; -import org.onap.aaf.cadi.Lur; -import org.onap.aaf.cadi.Permission; -import org.onap.aaf.cadi.aaf.AAFPermission; -import org.onap.aaf.cadi.principal.TaggedPrincipal; -import org.onap.aaf.cadi.taf.TafResp; - -public class ReverseProxyMockCadiFilter implements Filter { - - private FakeLur fakeLur = new FakeLur(); - - static class FakeLur implements Lur { - - @Override - public void fishAll(Principal bait, List permissions) { - - final String WildcardPermissionType = "test.wildcard.access"; - final String MultiplePermissionType = "test.multiple.access"; - final String TestAuthAccessPermissionType = "test.auth.access"; - final String PermissionAction = "permission"; - - String principalName = bait.getName(); - - if (principalName != null && principalName.equals("UserWithInstanceActionWildcardPermissionGranted")) { - permissions.add(new AAFPermission(null, WildcardPermissionType, "*", "*")); - } - else - if (principalName != null && principalName.equals("UserWithInstanceWildcardPermissionGranted")) { - permissions.add(new AAFPermission(null, WildcardPermissionType, "*", PermissionAction)); - } - else - if (principalName != null && principalName.equals("UserWithActionWildcardPermissionGranted")) { - permissions.add(new AAFPermission(null, WildcardPermissionType, "first", "*")); - } - else { - - // For single permission test - permissions.add(new AAFPermission(null, "test.single.access", "single", PermissionAction)); - - // For multiple permission test - permissions.add(new AAFPermission(null, MultiplePermissionType, "first", PermissionAction)); - permissions.add(new AAFPermission(null, MultiplePermissionType, "second", PermissionAction)); - permissions.add(new AAFPermission(null, MultiplePermissionType, "third", PermissionAction)); - - // For transaction id test - permissions.add(new AAFPermission(null, TestAuthAccessPermissionType, "rest", "write")); - permissions.add(new AAFPermission(null, TestAuthAccessPermissionType, "rpc", "write")); - } - } - - @Override - public Permission createPerm(String p) { - return null; - } - - @Override - public boolean fish(Principal bait, Permission... pond) { - return false; - } - - @Override - public void destroy() { - // Mock implementation - } - - @Override - public boolean handlesExclusively(Permission... pond) { - return false; - } - - @Override - public boolean handles(Principal principal) { - return false; - } - - @Override - public void clear(Principal p, StringBuilder report) { - // Mock implementation - } - - } - - @Override - public void destroy() { - // Mock implementation - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - - String userName = ((HttpServletRequest)servletRequest).getHeader("PermissionsUser"); - - TaggedPrincipal mockTaggedPrincipal = mock(TaggedPrincipal.class); - when(mockTaggedPrincipal.getName()).thenReturn(userName); - - TafResp tafResponseMock = mock(TafResp.class); - when(tafResponseMock.getPrincipal()).thenReturn(mockTaggedPrincipal); - - CadiWrap cadiWrap = new CadiWrap((HttpServletRequest) servletRequest, tafResponseMock, fakeLur); - filterChain.doFilter(cadiWrap, servletResponse); - } - - @Override - public void init(FilterConfig arg0) throws ServletException { - // Mock implementation - } - -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyAuthorization.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyAuthorization.java deleted file mode 100644 index 6c5baa2..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyAuthorization.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.utils; - -public class ReverseProxyAuthorization { - - private String uri; - private String[] permissions; - - public String getUri() { - return uri; - } - - public String[] getPermissions() { - return permissions; - } -} diff --git a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyUtils.java b/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyUtils.java deleted file mode 100644 index d2d1ba4..0000000 --- a/sidecar/rproxy/src/main/java/org/onap/aaf/rproxy/utils/ReverseProxyUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy.utils; - -public class ReverseProxyUtils { - - public static boolean validTransactionId(String transactionId) { - return transactionId.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); - } - - private ReverseProxyUtils() {} -} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/PermissionMatchingTest.java b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/PermissionMatchingTest.java new file mode 100644 index 0000000..e9dd95b --- /dev/null +++ b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/PermissionMatchingTest.java @@ -0,0 +1,262 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.test; + +import static org.hamcrest.Matchers.equalTo; +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.withSuccess; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import javax.annotation.Resource; +import org.eclipse.jetty.util.security.Password; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.cadi.sidecar.rproxy.config.ForwardProxyProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.PrimaryServiceProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.client.RestTemplate; + + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc + +@TestPropertySource(locations = {"classpath:primary-service.properties", "classpath:forward-proxy.properties"}) + +@ContextConfiguration(classes = ReverseProxyTestConfig.class) +public class PermissionMatchingTest { + + static { + System.setProperty("server.ssl.key-store-password", + Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); + } + + @Value("${transactionid.header.name}") + private String transactionIdHeaderName; + + @Resource(name = "PrimaryServiceProperties") + private PrimaryServiceProperties primaryServiceProps; + + @Resource(name = "ForwardProxyProperties") + private ForwardProxyProperties forwardProxyProps; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + private String primaryServiceBaseUrl; + + @Before + public void setUp() throws Exception { + mockServer = MockRestServiceServer.createServer(restTemplate); + primaryServiceBaseUrl = primaryServiceProps.getProtocol() + "://" + primaryServiceProps.getHost() + ":" + + primaryServiceProps.getPort(); + } + + @Test + public void testURIMismatch() throws Exception { + + String testUrl = "/uri/does/not/exist"; + String testResponse = "Sorry, the request is not allowed"; + + mockMvc + .perform(get(testUrl)) + .andExpect(status().isForbidden()) + .andExpect(status().reason(testResponse)); + + } + + @Test + public void testURINoPermission() throws Exception { + + String testUrl = "/not/allowed/at/all"; + String testResponse = "Sorry, the request is not allowed"; + + mockMvc + .perform(get(testUrl)) + .andExpect(status().isForbidden()) + .andExpect(status().reason(testResponse)); + + } + + @Test + public void testURIMatchSinglePermissionMatch() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/single/permission/required"; + String testResponse = "Response from MockRestService"; + + mockServer + .expect(requestTo(primaryServiceBaseUrl + testUrl)) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc + .perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON).header(transactionIdHeaderName, transactionId)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + + } + + @Test + public void testURIMatchMultiplePermissionMatch() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/multiple/permissions/required"; + String testResponse = "Response from MockRestService"; + + mockServer + .expect(requestTo(primaryServiceBaseUrl + testUrl)) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc + .perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON).header(transactionIdHeaderName, transactionId)) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + + } + + @Test + public void testURIMatchMultipleMissingOnePermissionMatch() throws Exception { + + String testUrl = "/multiple/permissions/required/one/missing"; + String testResponse = "Sorry, the request is not allowed"; + + mockMvc + .perform(get(testUrl)) + .andExpect(status().isForbidden()) + .andExpect(status().reason(testResponse)); + } + + @Test + public void testURIInstanceActionWildCardPermissionMatch() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/wildcard/permission/granted"; + String testResponse = "Response from MockRestService"; + + mockServer + .expect(requestTo(primaryServiceBaseUrl + testUrl)) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc + .perform(MockMvcRequestBuilders + .get(testUrl) + .accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, transactionId) + .header("PermissionsUser", "UserWithInstanceActionWildcardPermissionGranted") + ) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + + } + + @Test + public void testURIInstanceWildCardPermissionMatch() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/instance/wildcard/permission/granted"; + String testResponse = "Response from MockRestService"; + + mockServer + .expect(requestTo(primaryServiceBaseUrl + testUrl)) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc + .perform(MockMvcRequestBuilders + .get(testUrl) + .accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, transactionId) + .header("PermissionsUser", "UserWithInstanceWildcardPermissionGranted") + ) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + + } + + @Test + public void testURIActionWildCardPermissionMatch() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/action/wildcard/permission/granted"; + String testResponse = "Response from MockRestService"; + + mockServer + .expect(requestTo(primaryServiceBaseUrl + testUrl)) + .andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc + .perform(MockMvcRequestBuilders + .get(testUrl) + .accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, transactionId) + .header("PermissionsUser", "UserWithActionWildcardPermissionGranted") + ) + .andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + + } + +} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyApplicationTest.java b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyApplicationTest.java new file mode 100644 index 0000000..cff8f9b --- /dev/null +++ b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyApplicationTest.java @@ -0,0 +1,158 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.test; + +import static org.hamcrest.Matchers.equalTo; +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.withSuccess; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import javax.annotation.Resource; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.util.security.Password; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.cadi.sidecar.rproxy.config.ForwardProxyProperties; +import org.onap.aaf.cadi.sidecar.rproxy.config.PrimaryServiceProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.client.match.MockRestRequestMatchers; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.client.RestTemplate; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@TestPropertySource(locations = {"classpath:primary-service.properties", "classpath:forward-proxy.properties"}) +@ContextConfiguration(classes = ReverseProxyTestConfig.class) +public class ReverseProxyApplicationTest { + + static { + System.setProperty("server.ssl.key-store-password", + Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); + } + + @Value("${transactionid.header.name}") + private String transactionIdHeaderName; + + @Resource(name = "PrimaryServiceProperties") + private PrimaryServiceProperties primaryServiceProps; + + @Resource(name = "ForwardProxyProperties") + private ForwardProxyProperties forwardProxyProps; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private RestTemplate restTemplate; + + private MockRestServiceServer mockServer; + + private String primaryServiceBaseUrl; + private String forwardProxyBaseUrl; + + @Before + public void setUp() throws Exception { + mockServer = MockRestServiceServer.createServer(restTemplate); + primaryServiceBaseUrl = primaryServiceProps.getProtocol() + "://" + primaryServiceProps.getHost() + ":" + + primaryServiceProps.getPort(); + forwardProxyBaseUrl = forwardProxyProps.getProtocol() + "://" + forwardProxyProps.getHost() + ":" + + forwardProxyProps.getPort() + forwardProxyProps.getCacheurl() + "/"; + } + + @Test + public void checkForwardRequest() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; + String testResponse = "Response from MockRestService"; + + mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, transactionId)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void checkTransactionIdIsSetIfEmptyInRequest() throws Exception { + + String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; + String testResponse = "Response from MockRestService"; + + mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, Matchers.any(String.class))) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server without transaction Id + mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } + + @Test + public void checkBasicAuthCaching() throws Exception { + + String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; + String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; + String testResponse = "Response from MockRestService"; + String testAuthValue = "testAuthValue"; + String testCachePayload = "{ \"credentialName\":" + HttpHeader.AUTHORIZATION + ", \"credentialValue\":" + + testAuthValue + ", \"credentialType\":\"HEADER\" }"; + + mockServer.expect(requestTo(forwardProxyBaseUrl + transactionId)).andExpect(method(HttpMethod.POST)) + .andExpect(MockRestRequestMatchers.content().json(testCachePayload)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) + .andExpect(header(transactionIdHeaderName, transactionId)) + .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); + + // Send request to mock server with transaction Id + mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) + .header(transactionIdHeaderName, transactionId) + .header(HttpHeader.AUTHORIZATION.asString(), testAuthValue)).andExpect(status().isOk()) + .andExpect(content().string(equalTo(testResponse))); + + mockServer.verify(); + } +} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyIT.java b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyIT.java new file mode 100644 index 0000000..17f55f6 --- /dev/null +++ b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyIT.java @@ -0,0 +1,49 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.eclipse.jetty.util.security.Password; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aaf.cadi.sidecar.rproxy.ReverseProxyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class ReverseProxyIT { + + static { + System.setProperty("server.ssl.key-store-password", + Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); + } + + @Autowired + private ReverseProxyService rProxyService; + + @Test + public void contexLoads() throws Exception { + assertThat(rProxyService).isNotNull(); + } +} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyTestConfig.java b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyTestConfig.java new file mode 100644 index 0000000..eada157 --- /dev/null +++ b/sidecar/rproxy/src/test/java/org/onap/aaf/cadi/sidecar/rproxy/test/ReverseProxyTestConfig.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aaf + * ================================================================================ + * Copyright © 2018 European Software Marketing Ltd. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aaf.cadi.sidecar.rproxy.test; + +import org.onap.aaf.cadi.sidecar.rproxy.mocks.ReverseProxyMockCadiFilter; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.RegistrationBean; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class ReverseProxyTestConfig extends SpringBootServletInitializer { + + @Bean + public FilterRegistrationBean registerCADIFilter() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + filterRegistrationBean.setFilter(new ReverseProxyMockCadiFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.setName("CADIFilter"); + filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); + + return filterRegistrationBean; + } +} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/PermissionMatchingTest.java b/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/PermissionMatchingTest.java deleted file mode 100644 index 43e20fe..0000000 --- a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/PermissionMatchingTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import static org.hamcrest.Matchers.equalTo; -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.withSuccess; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import javax.annotation.Resource; -import org.eclipse.jetty.util.security.Password; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.onap.aaf.rproxy.config.ForwardProxyProperties; -import org.onap.aaf.rproxy.config.PrimaryServiceProperties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.client.RestTemplate; - - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@AutoConfigureMockMvc - -@TestPropertySource(locations = {"classpath:primary-service.properties", "classpath:forward-proxy.properties"}) - -@ContextConfiguration(classes = ReverseProxyTestConfig.class) -public class PermissionMatchingTest { - - static { - System.setProperty("server.ssl.key-store-password", - Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); - } - - @Value("${transactionid.header.name}") - private String transactionIdHeaderName; - - @Resource(name = "PrimaryServiceProperties") - private PrimaryServiceProperties primaryServiceProps; - - @Resource(name = "ForwardProxyProperties") - private ForwardProxyProperties forwardProxyProps; - - @Autowired - private MockMvc mockMvc; - - @Autowired - private RestTemplate restTemplate; - - private MockRestServiceServer mockServer; - - private String primaryServiceBaseUrl; - - @Before - public void setUp() throws Exception { - mockServer = MockRestServiceServer.createServer(restTemplate); - primaryServiceBaseUrl = primaryServiceProps.getProtocol() + "://" + primaryServiceProps.getHost() + ":" - + primaryServiceProps.getPort(); - } - - @Test - public void testURIMismatch() throws Exception { - - String testUrl = "/uri/does/not/exist"; - String testResponse = "Sorry, the request is not allowed"; - - mockMvc - .perform(get(testUrl)) - .andExpect(status().isForbidden()) - .andExpect(status().reason(testResponse)); - - } - - @Test - public void testURINoPermission() throws Exception { - - String testUrl = "/not/allowed/at/all"; - String testResponse = "Sorry, the request is not allowed"; - - mockMvc - .perform(get(testUrl)) - .andExpect(status().isForbidden()) - .andExpect(status().reason(testResponse)); - - } - - @Test - public void testURIMatchSinglePermissionMatch() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/single/permission/required"; - String testResponse = "Response from MockRestService"; - - mockServer - .expect(requestTo(primaryServiceBaseUrl + testUrl)) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc - .perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON).header(transactionIdHeaderName, transactionId)) - .andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - - } - - @Test - public void testURIMatchMultiplePermissionMatch() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/multiple/permissions/required"; - String testResponse = "Response from MockRestService"; - - mockServer - .expect(requestTo(primaryServiceBaseUrl + testUrl)) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc - .perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON).header(transactionIdHeaderName, transactionId)) - .andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - - } - - @Test - public void testURIMatchMultipleMissingOnePermissionMatch() throws Exception { - - String testUrl = "/multiple/permissions/required/one/missing"; - String testResponse = "Sorry, the request is not allowed"; - - mockMvc - .perform(get(testUrl)) - .andExpect(status().isForbidden()) - .andExpect(status().reason(testResponse)); - } - - @Test - public void testURIInstanceActionWildCardPermissionMatch() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/wildcard/permission/granted"; - String testResponse = "Response from MockRestService"; - - mockServer - .expect(requestTo(primaryServiceBaseUrl + testUrl)) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc - .perform(MockMvcRequestBuilders - .get(testUrl) - .accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, transactionId) - .header("PermissionsUser", "UserWithInstanceActionWildcardPermissionGranted") - ) - .andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - - } - - @Test - public void testURIInstanceWildCardPermissionMatch() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/instance/wildcard/permission/granted"; - String testResponse = "Response from MockRestService"; - - mockServer - .expect(requestTo(primaryServiceBaseUrl + testUrl)) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc - .perform(MockMvcRequestBuilders - .get(testUrl) - .accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, transactionId) - .header("PermissionsUser", "UserWithInstanceWildcardPermissionGranted") - ) - .andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - - } - - @Test - public void testURIActionWildCardPermissionMatch() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/action/wildcard/permission/granted"; - String testResponse = "Response from MockRestService"; - - mockServer - .expect(requestTo(primaryServiceBaseUrl + testUrl)) - .andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc - .perform(MockMvcRequestBuilders - .get(testUrl) - .accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, transactionId) - .header("PermissionsUser", "UserWithActionWildcardPermissionGranted") - ) - .andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - - } - -} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyApplicationTest.java b/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyApplicationTest.java deleted file mode 100644 index 61a0923..0000000 --- a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyApplicationTest.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import static org.hamcrest.Matchers.equalTo; -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.withSuccess; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import javax.annotation.Resource; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.util.security.Password; -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.onap.aaf.rproxy.config.ForwardProxyProperties; -import org.onap.aaf.rproxy.config.PrimaryServiceProperties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.client.MockRestServiceServer; -import org.springframework.test.web.client.match.MockRestRequestMatchers; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.client.RestTemplate; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@AutoConfigureMockMvc -@TestPropertySource(locations = {"classpath:primary-service.properties", "classpath:forward-proxy.properties"}) -@ContextConfiguration(classes = ReverseProxyTestConfig.class) -public class ReverseProxyApplicationTest { - - static { - System.setProperty("server.ssl.key-store-password", - Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); - } - - @Value("${transactionid.header.name}") - private String transactionIdHeaderName; - - @Resource(name = "PrimaryServiceProperties") - private PrimaryServiceProperties primaryServiceProps; - - @Resource(name = "ForwardProxyProperties") - private ForwardProxyProperties forwardProxyProps; - - @Autowired - private MockMvc mockMvc; - - @Autowired - private RestTemplate restTemplate; - - private MockRestServiceServer mockServer; - - private String primaryServiceBaseUrl; - private String forwardProxyBaseUrl; - - @Before - public void setUp() throws Exception { - mockServer = MockRestServiceServer.createServer(restTemplate); - primaryServiceBaseUrl = primaryServiceProps.getProtocol() + "://" + primaryServiceProps.getHost() + ":" - + primaryServiceProps.getPort(); - forwardProxyBaseUrl = forwardProxyProps.getProtocol() + "://" + forwardProxyProps.getHost() + ":" - + forwardProxyProps.getPort() + forwardProxyProps.getCacheurl() + "/"; - } - - @Test - public void checkForwardRequest() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; - String testResponse = "Response from MockRestService"; - - mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, transactionId)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void checkTransactionIdIsSetIfEmptyInRequest() throws Exception { - - String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; - String testResponse = "Response from MockRestService"; - - mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, Matchers.any(String.class))) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server without transaction Id - mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()).andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } - - @Test - public void checkBasicAuthCaching() throws Exception { - - String transactionId = "63f88b50-6345-4a61-bc59-3a48cabb60a4"; - String testUrl = "/aai/v13/cloud-infrastructure/cloud-regions"; - String testResponse = "Response from MockRestService"; - String testAuthValue = "testAuthValue"; - String testCachePayload = "{ \"credentialName\":" + HttpHeader.AUTHORIZATION + ", \"credentialValue\":" - + testAuthValue + ", \"credentialType\":\"HEADER\" }"; - - mockServer.expect(requestTo(forwardProxyBaseUrl + transactionId)).andExpect(method(HttpMethod.POST)) - .andExpect(MockRestRequestMatchers.content().json(testCachePayload)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - mockServer.expect(requestTo(primaryServiceBaseUrl + testUrl)).andExpect(method(HttpMethod.GET)) - .andExpect(header(transactionIdHeaderName, transactionId)) - .andRespond(withSuccess(testResponse, MediaType.APPLICATION_JSON)); - - // Send request to mock server with transaction Id - mockMvc.perform(MockMvcRequestBuilders.get(testUrl).accept(MediaType.APPLICATION_JSON) - .header(transactionIdHeaderName, transactionId) - .header(HttpHeader.AUTHORIZATION.asString(), testAuthValue)).andExpect(status().isOk()) - .andExpect(content().string(equalTo(testResponse))); - - mockServer.verify(); - } -} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyIT.java b/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyIT.java deleted file mode 100644 index 615afd4..0000000 --- a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyIT.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.eclipse.jetty.util.security.Password; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -public class ReverseProxyIT { - - static { - System.setProperty("server.ssl.key-store-password", - Password.deobfuscate("OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10")); - } - - @Autowired - private ReverseProxyService rProxyService; - - @Test - public void contexLoads() throws Exception { - assertThat(rProxyService).isNotNull(); - } -} diff --git a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyTestConfig.java b/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyTestConfig.java deleted file mode 100644 index c512e6a..0000000 --- a/sidecar/rproxy/src/test/java/org/onap/aaf/rproxy/ReverseProxyTestConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aaf - * ================================================================================ - * Copyright © 2018 European Software Marketing Ltd. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aaf.rproxy; - -import org.onap.aaf.rproxy.mocks.ReverseProxyMockCadiFilter; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.boot.web.servlet.RegistrationBean; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.annotation.Bean; - -@TestConfiguration -public class ReverseProxyTestConfig extends SpringBootServletInitializer { - - @Bean - public FilterRegistrationBean registerCADIFilter() { - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); - filterRegistrationBean.setFilter(new ReverseProxyMockCadiFilter()); - filterRegistrationBean.addUrlPatterns("/*"); - filterRegistrationBean.setName("CADIFilter"); - filterRegistrationBean.setOrder(RegistrationBean.HIGHEST_PRECEDENCE); - - return filterRegistrationBean; - } -} diff --git a/sidecar/tproxy-config/pom.xml b/sidecar/tproxy-config/pom.xml index b9a7104..a0b6982 100644 --- a/sidecar/tproxy-config/pom.xml +++ b/sidecar/tproxy-config/pom.xml @@ -46,7 +46,6 @@ com.mycila license-maven-plugin - 3.0
License.txt
-- cgit 1.2.3-korg