From a8cafe1c784ae68b2a7cca313b362d14b13fd631 Mon Sep 17 00:00:00 2001 From: Bartosz Gardziejewski Date: Fri, 29 Jan 2021 10:43:17 +0100 Subject: add basic auth using username and password Signed-off-by: Bartosz Gardziejewski Change-Id: I67bc2c25149c8e2d4943f23cfa8d726cdb95995f Issue-ID: INT-1805 --- pnfsimulator/README.md | 10 +- pnfsimulator/docker-compose.yml | 2 + .../integration/BasicAvailabilityTest.java | 10 +- .../integration/OptionalTemplatesTest.java | 108 +-------------- .../pnfsimulator/integration/SingleEventTest.java | 151 +++++++++++++++++++++ .../onap/pnfsimulator/integration/TestUtils.java | 57 ++++++++ .../integration/VariablesReplacement.java | 8 +- .../integration/suites/DockerBasedTestsSuite.java | 3 +- .../simulator/client/HttpClientAdapterImpl.java | 29 +++- .../src/main/resources/application.properties | 2 +- .../client/HttpClientAdapterImplTest.java | 37 ++++- 11 files changed, 287 insertions(+), 130 deletions(-) create mode 100644 pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SingleEventTest.java create mode 100644 pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestUtils.java diff --git a/pnfsimulator/README.md b/pnfsimulator/README.md index 1ab9c3d..844fdf5 100644 --- a/pnfsimulator/README.md +++ b/pnfsimulator/README.md @@ -375,8 +375,14 @@ CA certificates are incorporated into simulator docker image, thus no additional Certificates can be found in docker container under path: */usr/local/share/ca-certificates/* -Simulator works with VES that uses both self-signed certificate (already present in keystore) and VES integrated to AAF. - +Simulator works with VES that uses both self-signed certificate (already present in keystore) and VES integrated to AAF. + +Certification loading can be disabled by setting environment variable ```USE_CERTIFICATE_FOR_AUTHORIZATION``` to false. +Once certificate are not used for authorization, user can set up VES url using username and password. + + { + "vesServerUrl": "http://:@:/eventListener/v7" + } ## Developers Guide diff --git a/pnfsimulator/docker-compose.yml b/pnfsimulator/docker-compose.yml index 54e4699..c7a19eb 100644 --- a/pnfsimulator/docker-compose.yml +++ b/pnfsimulator/docker-compose.yml @@ -27,6 +27,8 @@ services: image: onap/org.onap.integration.simulators.pnfsimulator ports: - "5000:5000" + environment: + USE_CERTIFICATE_FOR_AUTHORIZATION: "true" volumes: - ./logs:/var/log - ./templates:/app/templates diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java index fffc447..323243c 100644 --- a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java @@ -24,6 +24,7 @@ import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.when; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.onap.pnfsimulator.integration.TestUtils.getCurrentIpAddress; import com.google.gson.JsonObject; @@ -230,13 +231,4 @@ public class BasicAvailabilityTest { return "http://0.0.0.0:5000/simulator/" + action; } - private String getCurrentIpAddress() throws SocketException { - return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() - .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) - .filter(ip -> ip instanceof Inet4Address) - .map(e -> (Inet4Address) e) - .findFirst() - .orElseThrow(RuntimeException::new) - .getHostAddress(); - } } diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java index 8c8767d..50ad1cd 100644 --- a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java @@ -23,24 +23,15 @@ package org.onap.pnfsimulator.integration; import static io.restassured.RestAssured.given; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.onap.pnfsimulator.integration.TestUtils.COMMON_EVENT_HEADER; +import static org.onap.pnfsimulator.integration.TestUtils.PATCHED; +import static org.onap.pnfsimulator.integration.TestUtils.SINGLE_EVENT_URL; +import static org.onap.pnfsimulator.integration.TestUtils.findSourceNameInMongoDB; +import static org.onap.pnfsimulator.integration.TestUtils.getCurrentIpAddress; import com.google.gson.JsonObject; -import com.mongodb.MongoClient; -import com.mongodb.MongoClientOptions; -import com.mongodb.MongoCredential; -import com.mongodb.ServerAddress; -import com.mongodb.client.FindIterable; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoCursor; -import com.mongodb.client.MongoDatabase; import java.time.Instant; -import java.net.Inet4Address; -import java.net.NetworkInterface; -import java.net.SocketException; import java.net.UnknownHostException; -import java.util.Collections; -import java.util.List; import org.assertj.core.api.Assertions; import org.bson.Document; @@ -60,16 +51,6 @@ import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest(classes = {Main.class, TestConfiguration.class}, webEnvironment = WebEnvironment.DEFINED_PORT) public class OptionalTemplatesTest { - private static final String PNF_SIMULATOR_DB = "pnf_simulator"; - private static final String COMMON_EVENT_HEADER = "commonEventHeader"; - private static final String PNF_SIMULATOR_DB_PSWD = "zXcVbN123!"; - private static final String PNF_SIMULATOR_DB_USER = "pnf_simulator_user"; - private static final String PATCHED = "patched"; - private static final String SINGLE_EVENT_URL = "http://0.0.0.0:5000/simulator/event"; - - @Autowired - VesSimulatorController vesSimulatorController; - @Autowired private VesSimulatorService vesSimulatorService; @@ -177,83 +158,4 @@ public class OptionalTemplatesTest { .isEqualTo("{\"commonEventHeader\":{\"sourceName\":\"HistoricalEvent\",\"version\":3}}"); } - @Test - public void whenTriggeredSimulatorWithWrongVesIpInformationShouldBeReturned() { - //given - String body = "{\n" - + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":8080/ves-simulator/eventListener/v5\",\n" - + "\"event\": { \n" - + "\"commonEventHeader\": {\n" - + "\"sourceName\": \"HistoricalEvent\",\n" - + "\"version\": 3" - + "}\n" - + "}\n" - + "}"; - - //when - given() - .contentType("application/json") - .body(body) - .when() - .post(SINGLE_EVENT_URL) - .then() - .statusCode(421) - .body("message", - equalTo( - "Fail to connect with ves: Connect to "+currentVesSimulatorIp+":8080 " + - "[/"+currentVesSimulatorIp+"] " + - "failed: Connection refused (Connection refused)")); - } - - @Test - public void whenTriggeredSimulatorWithWrongEventShouldReturnedError() { - //given - String body = "{\n" - + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" - + "\"event\": { \n" - + "this is not JSON {}" - + "}\n" - + "}"; - - //when - given() - .contentType("application/json") - .body(body) - .when() - .post(SINGLE_EVENT_URL) - .then() - .statusCode(HttpStatus.BAD_REQUEST.value()) - .body("message", - stringContainsInOrder(List.of("JSON parse error:","Unexpected character ('t' (code 116)):")) - ); - } - - private Document findSourceNameInMongoDB() throws UnknownHostException { - MongoCredential credential = MongoCredential - .createCredential(PNF_SIMULATOR_DB_USER, PNF_SIMULATOR_DB, PNF_SIMULATOR_DB_PSWD.toCharArray()); - MongoClient mongoClient = new MongoClient(new ServerAddress(Inet4Address.getLocalHost(), 27017), - credential, MongoClientOptions.builder().build()); - MongoDatabase pnfSimulatorDb = mongoClient.getDatabase(PNF_SIMULATOR_DB); - MongoCollection table = pnfSimulatorDb.getCollection("eventData"); - Document searchQuery = new Document(); - searchQuery.put(PATCHED, new Document("$regex", ".*" + "HistoricalEvent" + ".*")); - FindIterable findOfPatched = table.find(searchQuery); - Document dbObject = null; - MongoCursor cursor = findOfPatched.iterator(); - if (cursor.hasNext()) { - dbObject = cursor.next(); - } - return dbObject; - } - - private String getCurrentIpAddress() throws SocketException { - return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() - .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) - .filter(ip -> ip instanceof Inet4Address) - .map(e -> (Inet4Address) e) - .findFirst() - .orElseThrow(RuntimeException::new) - .getHostAddress(); - } - } diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SingleEventTest.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SingleEventTest.java new file mode 100644 index 0000000..3ad1385 --- /dev/null +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SingleEventTest.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2020 Nokia. 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========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import com.google.gson.JsonObject; +import org.assertj.core.api.Assertions; +import org.bson.Document; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.junit4.SpringRunner; + +import java.net.UnknownHostException; +import java.util.List; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.onap.pnfsimulator.integration.TestUtils.PATCHED; +import static org.onap.pnfsimulator.integration.TestUtils.SINGLE_EVENT_URL; +import static org.onap.pnfsimulator.integration.TestUtils.findSourceNameInMongoDB; +import static org.onap.pnfsimulator.integration.TestUtils.getCurrentIpAddress; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Main.class, TestConfiguration.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +public class SingleEventTest { + + @Autowired + private VesSimulatorService vesSimulatorService; + + private String currentVesSimulatorIp; + + @Before + public void setUp() throws Exception { + currentVesSimulatorIp = getCurrentIpAddress(); + } + + @After + public void tearDown() { + Mockito.reset(vesSimulatorService); + } + + @Test + public void whenTriggeredSimulatorWithWrongVesAddressInformationShouldBeReturned() { + //given + String body = "{\n" + + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":8080/ves-simulator/eventListener/v5\",\n" + + "\"event\": { \n" + + "\"commonEventHeader\": {\n" + + "\"sourceName\": \"HistoricalEvent\",\n" + + "\"version\": 3" + + "}\n" + + "}\n" + + "}"; + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(SINGLE_EVENT_URL) + .then() + .statusCode(421) + .body("message", + equalTo( + "Fail to connect with ves: Connect to "+currentVesSimulatorIp+":8080 " + + "[/"+currentVesSimulatorIp+"] " + + "failed: Connection refused (Connection refused)")); + } + + @Test + public void whenTriggeredSimulatorWithWrongEventShouldReturnedError() { + //given + String body = "{\n" + + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"event\": { \n" + + "this is not JSON {}" + + "}\n" + + "}"; + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(SINGLE_EVENT_URL) + .then() + .statusCode(HttpStatus.BAD_REQUEST.value()) + .body("message", + stringContainsInOrder(List.of("JSON parse error:","Unexpected character ('t' (code 116)):")) + ); + } + + @Test + public void whenTriggeredSimulatorWithUsernameAndPasswordInUrlVesShouldAcceptRequest() throws UnknownHostException { + //given + String body = "{\n" + + "\"vesServerUrl\": \"https://user1:pass1@" + currentVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"event\": { \n" + + "\"commonEventHeader\": {\n" + + "\"sourceName\": \"HistoricalEvent\",\n" + + "\"version\": 3" + + "}\n" + + "}\n" + + "}"; + ArgumentCaptor parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(SINGLE_EVENT_URL) + .then() + .statusCode(HttpStatus.ACCEPTED.value()) + .body("message", equalTo("Accepted")); + + //then + Mockito.verify(vesSimulatorService, + Mockito.timeout(3000)) + .sendEventToDmaapV5(parameterCaptor.capture()); + + Document sourceNameInMongoDB = findSourceNameInMongoDB(); + Assertions.assertThat(sourceNameInMongoDB.get(PATCHED)) + .isEqualTo("{\"commonEventHeader\":{\"sourceName\":\"HistoricalEvent\",\"version\":3}}"); + } +} diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestUtils.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestUtils.java new file mode 100644 index 0000000..f7df5e9 --- /dev/null +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestUtils.java @@ -0,0 +1,57 @@ +package org.onap.pnfsimulator.integration; + +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; + +import java.net.Inet4Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Collections; + +public class TestUtils { + + private TestUtils() {} + + public static final String PNF_SIMULATOR_DB = "pnf_simulator"; + public static final String COMMON_EVENT_HEADER = "commonEventHeader"; + public static final String PNF_SIMULATOR_DB_PSWD = "zXcVbN123!"; + public static final String PNF_SIMULATOR_DB_USER = "pnf_simulator_user"; + public static final String PATCHED = "patched"; + public static final String SINGLE_EVENT_URL = "http://0.0.0.0:5000/simulator/event"; + + public static Document findSourceNameInMongoDB() throws UnknownHostException { + MongoCredential credential = MongoCredential + .createCredential(PNF_SIMULATOR_DB_USER, PNF_SIMULATOR_DB, PNF_SIMULATOR_DB_PSWD.toCharArray()); + MongoClient mongoClient = new MongoClient(new ServerAddress(Inet4Address.getLocalHost(), 27017), + credential, MongoClientOptions.builder().build()); + MongoDatabase pnfSimulatorDb = mongoClient.getDatabase(PNF_SIMULATOR_DB); + MongoCollection table = pnfSimulatorDb.getCollection("eventData"); + Document searchQuery = new Document(); + searchQuery.put(PATCHED, new Document("$regex", ".*" + "HistoricalEvent" + ".*")); + FindIterable findOfPatched = table.find(searchQuery); + Document dbObject = null; + MongoCursor cursor = findOfPatched.iterator(); + if (cursor.hasNext()) { + dbObject = cursor.next(); + } + return dbObject; + } + + public static String getCurrentIpAddress() throws SocketException { + return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() + .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) + .filter(ip -> ip instanceof Inet4Address) + .map(e -> (Inet4Address) e) + .findFirst() + .orElseThrow(RuntimeException::new) + .getHostAddress(); + } +} diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java index c0bd989..ae7970c 100644 --- a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/VariablesReplacement.java @@ -3,6 +3,7 @@ package org.onap.pnfsimulator.integration; import static io.restassured.RestAssured.given; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.onap.pnfsimulator.integration.TestUtils.getCurrentIpAddress; import com.google.gson.JsonObject; import java.net.Inet4Address; @@ -76,11 +77,4 @@ public class VariablesReplacement { return "http://0.0.0.0:5000/simulator/start"; } - private String getCurrentIpAddress() throws SocketException { - return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() - .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) - .filter(ip -> ip instanceof Inet4Address).map(e -> (Inet4Address) e).findFirst() - .orElseThrow(RuntimeException::new).getHostAddress(); - } - } diff --git a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java index 3de06c3..f6a4c24 100644 --- a/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java +++ b/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java @@ -30,6 +30,7 @@ import org.junit.runners.Suite.SuiteClasses; import org.onap.pnfsimulator.integration.BasicAvailabilityTest; import org.onap.pnfsimulator.integration.OptionalTemplatesTest; import org.onap.pnfsimulator.integration.SearchInTemplatesTest; +import org.onap.pnfsimulator.integration.SingleEventTest; import org.onap.pnfsimulator.integration.TemplatesManagementTest; import org.onap.pnfsimulator.integration.VariablesReplacement; import org.slf4j.Logger; @@ -40,7 +41,7 @@ import static io.restassured.RestAssured.given; @RunWith(Suite.class) @SuiteClasses({BasicAvailabilityTest.class, TemplatesManagementTest.class, OptionalTemplatesTest.class, - SearchInTemplatesTest.class, VariablesReplacement.class}) + SearchInTemplatesTest.class, VariablesReplacement.class, SingleEventTest.class}) public class DockerBasedTestsSuite { private static final Logger LOGGER = LoggerFactory.getLogger(DockerBasedTestsSuite.class); diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java index 4f249b9..ba668fc 100644 --- a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -20,6 +20,8 @@ package org.onap.pnfsimulator.simulator.client; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; @@ -35,6 +37,9 @@ import org.slf4j.MarkerFactory; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.UUID; @@ -71,22 +76,27 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { LOGGER.info(INVOKE, "Message sent, ves response code: {}", response.getStatusLine()); vesResponse = responseFactory.create(response); EntityUtils.consumeQuietly(response.getEntity()); //response has to be fully consumed otherwise apache won't release connection - } catch (IOException e) { + } catch (IOException | URISyntaxException e) { LOGGER.warn("Error sending message to ves: {}", e.getMessage(), e.getCause()); vesResponse = new HttpResponseAdapter(421, String.format("Fail to connect with ves: %s", e.getMessage())); } return vesResponse; } - private HttpResponse sendAndRetrieve(String content) throws IOException { + private HttpResponse sendAndRetrieve(String content) throws IOException, URISyntaxException { HttpPost request = createRequest(content); HttpResponse httpResponse = client.execute(request); request.releaseConnection(); return httpResponse; } - private HttpPost createRequest(String content) throws UnsupportedEncodingException { - HttpPost request = new HttpPost(this.targetUrl); + private HttpPost createRequest(String content) throws UnsupportedEncodingException, URISyntaxException { + LOGGER.info("sending request using address: {}", this.targetUrl); + URI targetAddress = new URI(this.targetUrl); + HttpPost request = new HttpPost(targetAddress); + if(urlContainsUserInfo(targetAddress)) { + request.addHeader(HttpHeaders.AUTHORIZATION, getAuthenticationHeaderForUser(targetAddress.getUserInfo())); + } StringEntity stringEntity = new StringEntity(content); request.addHeader(CONTENT_TYPE, APPLICATION_JSON); request.addHeader(X_ONAP_REQUEST_ID, MDC.get(REQUEST_ID)); @@ -95,4 +105,15 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { return request; } + private boolean urlContainsUserInfo(URI targetAddress) { + return targetAddress.getUserInfo() != null && !targetAddress.getUserInfo().isEmpty(); + } + + private String getAuthenticationHeaderForUser(String userInfo) { + final byte[] encodedUserInfo = Base64.encodeBase64( + userInfo.getBytes(StandardCharsets.ISO_8859_1) + ); + return String.format("Basic %s", new String(encodedUserInfo)); + } + } diff --git a/pnfsimulator/src/main/resources/application.properties b/pnfsimulator/src/main/resources/application.properties index 1253e52..fddcec0 100644 --- a/pnfsimulator/src/main/resources/application.properties +++ b/pnfsimulator/src/main/resources/application.properties @@ -10,7 +10,7 @@ management.endpoint.configprops.enabled=true management.endpoints.web.base-path=/ management.endpoints.web.exposure.include=refresh,health -ssl.clientCertificateEnabled=true +ssl.clientCertificateEnabled=${USE_CERTIFICATE_FOR_AUTHORIZATION:true} ssl.strictHostnameVerification=${STRICT_HOSTNAME_VERIFICATION:false} ssl.clientCertificatePath=/app/store/cert.p12 ssl.clientCertificatePasswordPath=/app/store/p12.pass diff --git a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java index cfb03d0..cfbc8c1 100644 --- a/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java +++ b/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java @@ -20,18 +20,26 @@ package org.onap.pnfsimulator.simulator.client; +import org.apache.http.Header; +import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.message.BasicHeader; +import org.apache.tomcat.util.codec.binary.Base64; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.onap.pnfsimulator.simulator.client.utils.ssl.SslAuthenticationHelper; import java.io.IOException; import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -60,12 +68,23 @@ class HttpClientAdapterImplTest { @Test void sendShouldSuccessfullySendRequestGivenValidUrl() throws IOException { - assertAdapterSentRequest("http://valid-url:8080", HttpStatus.SC_FORBIDDEN, HttpTestUtils.HTTP_MESSAGE_FORBIDDEN); + assertAdapterSentRequest("http://valid-url:8080", + HttpStatus.SC_FORBIDDEN, HttpTestUtils.HTTP_MESSAGE_FORBIDDEN); } @Test void sendShouldSuccessfullySendRequestGivenValidUrlUsingHttps() throws IOException { - assertAdapterSentRequest("https://valid-url:8443", HttpStatus.SC_ACCEPTED, HttpTestUtils.HTTP_MESSAGE_ACCEPTER); + assertAdapterSentRequest("https://valid-url:8443", + HttpStatus.SC_ACCEPTED, HttpTestUtils.HTTP_MESSAGE_ACCEPTER); + } + + @Test + void sendShouldSuccessfullySendRequestUsingBasicAuth() throws IOException { + String testUserInfo = "user1:pass1"; + Header authorizationHeader = createAuthorizationHeader(testUserInfo); + assertAdapterSentRequest("https://" + testUserInfo + "@valid-url:8443", + HttpStatus.SC_ACCEPTED, HttpTestUtils.HTTP_MESSAGE_ACCEPTER, + List.of(authorizationHeader)); } @Test @@ -98,7 +117,16 @@ class HttpClientAdapterImplTest { } } + private Header createAuthorizationHeader(String testUserInfo) { + String encodedUserInfo = new String(Base64.encodeBase64(testUserInfo.getBytes(StandardCharsets.UTF_8))); + return new BasicHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodedUserInfo); + } + private void assertAdapterSentRequest(String targetUrl, int responseCode, String responseMessage) throws IOException { + assertAdapterSentRequest(targetUrl, responseCode, responseMessage, List.of()); + } + + private void assertAdapterSentRequest(String targetUrl, int responseCode, String responseMessage, List
expectedHeaders) throws IOException { HttpClientAdapter adapter = new HttpClientAdapterImpl(httpClient, targetUrl); doReturn(httpResponse).when(httpClient).execute(any()); doReturn(createStatusLine(responseCode)).when(httpResponse).getStatusLine(); @@ -106,9 +134,12 @@ class HttpClientAdapterImplTest { HttpResponseAdapter response = adapter.send("test-msg"); - verify(httpClient).execute(any()); + ArgumentCaptor httpPostCaptor = ArgumentCaptor.forClass(HttpPost.class); + verify(httpClient).execute(httpPostCaptor.capture()); + Header[] headers = httpPostCaptor.getValue().getAllHeaders(); assertEquals(responseCode, response.getCode()); assertEquals(responseMessage, response.getMessage()); + assertThat(headers).usingFieldByFieldElementComparator().containsAll(expectedHeaders); } private void assertAdapterInformsUserWhenServiceIsUnavailable(String targetUrl) throws IOException { -- cgit 1.2.3-korg