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 --------------------- 24 files changed, 917 insertions(+), 941 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 (limited to 'sidecar/fproxy') 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))); - } -} -- cgit 1.2.3-korg