From 71c1b158a19fbec07ff67fabda5012f7c6734494 Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Fri, 4 Mar 2022 10:37:00 +0100 Subject: [PATCH] ICS reading auth token from file Signed-off-by: PatrikBuhr Issue-ID: NONRTRIC-735 Change-Id: Ib7bf0f4f10f441f9a29366a4f32c953ecdea01a8 --- .../config/application.yaml | 5 +- .../src/main/java/org/oransc/ics/BeanFactory.java | 9 +-- .../main/java/org/oransc/ics/SwaggerConfig.java | 1 - .../org/oransc/ics/clients/AsyncRestClient.java | 78 +++++++++------------- .../oransc/ics/clients/AsyncRestClientFactory.java | 8 ++- .../org/oransc/ics/clients/SecurityContext.java | 76 +++++++++++++++++++++ .../oransc/ics/controllers/a1e/A1eCallbacks.java | 6 +- .../controllers/r1consumer/ConsumerCallbacks.java | 9 ++- .../controllers/r1producer/ProducerCallbacks.java | 6 +- .../test/java/org/oransc/ics/ApplicationTest.java | 35 +++++++++- .../oransc/ics/clients/AsyncRestClientTest.java | 4 +- .../controller/ProducerSimulatorController.java | 20 +++++- 12 files changed, 190 insertions(+), 67 deletions(-) create mode 100644 information-coordinator-service/src/main/java/org/oransc/ics/clients/SecurityContext.java diff --git a/information-coordinator-service/config/application.yaml b/information-coordinator-service/config/application.yaml index 72bb907a..372b61c0 100644 --- a/information-coordinator-service/config/application.yaml +++ b/information-coordinator-service/config/application.yaml @@ -6,7 +6,7 @@ spring: aop: auto: false springdoc: - show-actuator: true + show-actuator: true management: endpoints: web: @@ -48,4 +48,5 @@ app: http.proxy-host: http.proxy-port: 0 vardata-directory: /var/information-coordinator-service - + # If the file name is empty, no authorzation token is sent + auth-token-file: \ No newline at end of file diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/BeanFactory.java b/information-coordinator-service/src/main/java/org/oransc/ics/BeanFactory.java index 6adf8ad8..3847cc33 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/BeanFactory.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/BeanFactory.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.lang.invoke.MethodHandles; import org.apache.catalina.connector.Connector; +import org.oransc.ics.clients.SecurityContext; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.controllers.r1producer.ProducerCallbacks; import org.oransc.ics.repository.InfoJobs; @@ -65,9 +66,9 @@ class BeanFactory { } @Bean - public InfoJobs infoJobs() { + public InfoJobs infoJobs(SecurityContext securityContext) { if (infoJobs == null) { - infoJobs = new InfoJobs(getApplicationConfig(), producerCallbacks()); + infoJobs = new InfoJobs(getApplicationConfig(), producerCallbacks(securityContext)); try { infoJobs.restoreJobsFromDatabase(); } catch (Exception e) { @@ -91,9 +92,9 @@ class BeanFactory { } @Bean - public ProducerCallbacks producerCallbacks() { + public ProducerCallbacks producerCallbacks(SecurityContext securityContext) { if (this.producerCallbacks == null) { - producerCallbacks = new ProducerCallbacks(getApplicationConfig()); + producerCallbacks = new ProducerCallbacks(getApplicationConfig(), securityContext); } return this.producerCallbacks; } diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/SwaggerConfig.java b/information-coordinator-service/src/main/java/org/oransc/ics/SwaggerConfig.java index 4b225642..30c0d4a0 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/SwaggerConfig.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/SwaggerConfig.java @@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Info; import io.swagger.v3.oas.annotations.info.License; - /** * Swagger configuration class that uses swagger documentation type and scans * all the controllers. To access the swagger gui go to diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClient.java b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClient.java index 1de74377..2879092c 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClient.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClient.java @@ -35,10 +35,10 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.lang.Nullable; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec; -import org.springframework.web.reactive.function.client.WebClientResponseException; import reactor.core.publisher.Mono; import reactor.netty.http.client.HttpClient; @@ -55,17 +55,17 @@ public class AsyncRestClient { private static final AtomicInteger sequenceNumber = new AtomicInteger(); private final SslContext sslContext; private final HttpProxyConfig httpProxyConfig; + private final SecurityContext securityContext; - public AsyncRestClient(String baseUrl, @Nullable SslContext sslContext, @Nullable HttpProxyConfig httpProxyConfig) { + public AsyncRestClient(String baseUrl, @Nullable SslContext sslContext, @Nullable HttpProxyConfig httpProxyConfig, + SecurityContext securityContext) { this.baseUrl = baseUrl; this.sslContext = sslContext; this.httpProxyConfig = httpProxyConfig; + this.securityContext = securityContext; } public Mono> postForEntity(String uri, @Nullable String body) { - Object traceTag = createTraceTag(); - logger.debug("{} POST uri = '{}{}''", traceTag, baseUrl, uri); - logger.trace("{} POST body: {}", traceTag, body); Mono bodyProducer = body != null ? Mono.just(body) : Mono.empty(); RequestHeadersSpec request = getWebClient() // @@ -73,7 +73,7 @@ public class AsyncRestClient { .uri(uri) // .contentType(MediaType.APPLICATION_JSON) // .body(bodyProducer, String.class); - return retrieve(traceTag, request); + return retrieve(request); } public Mono post(String uri, @Nullable String body) { @@ -82,41 +82,30 @@ public class AsyncRestClient { } public Mono postWithAuthHeader(String uri, String body, String username, String password) { - Object traceTag = createTraceTag(); - logger.debug("{} POST (auth) uri = '{}{}''", traceTag, baseUrl, uri); - logger.trace("{} POST body: {}", traceTag, body); - RequestHeadersSpec request = getWebClient() // .post() // .uri(uri) // .headers(headers -> headers.setBasicAuth(username, password)) // .contentType(MediaType.APPLICATION_JSON) // .bodyValue(body); - return retrieve(traceTag, request) // + return retrieve(request) // .map(this::toBody); } public Mono> putForEntity(String uri, String body) { - Object traceTag = createTraceTag(); - logger.debug("{} PUT uri = '{}{}''", traceTag, baseUrl, uri); - logger.trace("{} PUT body: {}", traceTag, body); - RequestHeadersSpec request = getWebClient() // .put() // .uri(uri) // .contentType(MediaType.APPLICATION_JSON) // .bodyValue(body); - return retrieve(traceTag, request); + return retrieve(request); } public Mono> putForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} PUT uri = '{}{}''", traceTag, baseUrl, uri); - logger.trace("{} PUT body: ", traceTag); RequestHeadersSpec request = getWebClient() // .put() // .uri(uri); - return retrieve(traceTag, request); + return retrieve(request); } public Mono put(String uri, String body) { @@ -125,10 +114,8 @@ public class AsyncRestClient { } public Mono> getForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} GET uri = '{}{}''", traceTag, baseUrl, uri); RequestHeadersSpec request = getWebClient().get().uri(uri); - return retrieve(traceTag, request); + return retrieve(request); } public Mono get(String uri) { @@ -137,10 +124,8 @@ public class AsyncRestClient { } public Mono> deleteForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} DELETE uri = '{}{}''", traceTag, baseUrl, uri); RequestHeadersSpec request = getWebClient().delete().uri(uri); - return retrieve(traceTag, request); + return retrieve(request); } public Mono delete(String uri) { @@ -148,32 +133,18 @@ public class AsyncRestClient { .map(this::toBody); } - private Mono> retrieve(Object traceTag, RequestHeadersSpec request) { - final Class clazz = String.class; + private Mono> retrieve(RequestHeadersSpec request) { + if (securityContext.isConfigured()) { + request.headers(h -> h.setBearerAuth(securityContext.getBearerAuthToken())); + } return request.retrieve() // - .toEntity(clazz) // - .doOnNext(entity -> logReceivedData(traceTag, entity)) // - .doOnError(throwable -> onHttpError(traceTag, throwable)); - } - - private void logReceivedData(Object traceTag, ResponseEntity entity) { - logger.trace("{} Received: {} {}", traceTag, entity.getBody(), entity.getHeaders().getContentType()); + .toEntity(String.class); } private static Object createTraceTag() { return sequenceNumber.incrementAndGet(); } - private void onHttpError(Object traceTag, Throwable t) { - if (t instanceof WebClientResponseException) { - WebClientResponseException exception = (WebClientResponseException) t; - logger.debug("{} HTTP error status = '{}', body '{}'", traceTag, exception.getStatusCode(), - exception.getResponseBodyAsString()); - } else { - logger.debug("{} HTTP error {}", traceTag, t.getMessage()); - } - } - private String toBody(ResponseEntity entity) { if (entity.getBody() == null) { return ""; @@ -206,15 +177,30 @@ public class AsyncRestClient { return httpClient; } - private WebClient buildWebClient(String baseUrl) { + public WebClient buildWebClient(String baseUrl) { + Object traceTag = createTraceTag(); + final HttpClient httpClient = buildHttpClient(); ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder() // .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(-1)) // .build(); + + ExchangeFilterFunction reqLogger = ExchangeFilterFunction.ofRequestProcessor(req -> { + logger.debug("{} {} uri = '{}''", traceTag, req.method(), req.url()); + return Mono.just(req); + }); + + ExchangeFilterFunction respLogger = ExchangeFilterFunction.ofResponseProcessor(resp -> { + logger.debug("{} resp: {}", traceTag, resp.statusCode()); + return Mono.just(resp); + }); + return WebClient.builder() // .clientConnector(new ReactorClientHttpConnector(httpClient)) // .baseUrl(baseUrl) // .exchangeStrategies(exchangeStrategies) // + .filter(reqLogger) // + .filter(respLogger) // .build(); } diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java index 0b47733c..9a6c4f70 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/clients/AsyncRestClientFactory.java @@ -54,8 +54,9 @@ public class AsyncRestClientFactory { private final SslContextFactory sslContextFactory; private final HttpProxyConfig httpProxyConfig; + private final SecurityContext securityContext; - public AsyncRestClientFactory(WebClientConfig clientConfig) { + public AsyncRestClientFactory(WebClientConfig clientConfig, SecurityContext securityContext) { if (clientConfig != null) { this.sslContextFactory = new CachingSslContextFactory(clientConfig); this.httpProxyConfig = clientConfig.httpProxyConfig(); @@ -64,6 +65,7 @@ public class AsyncRestClientFactory { this.sslContextFactory = null; this.httpProxyConfig = null; } + this.securityContext = securityContext; } public AsyncRestClient createRestClientNoHttpProxy(String baseUrl) { @@ -78,13 +80,13 @@ public class AsyncRestClientFactory { if (this.sslContextFactory != null) { try { return new AsyncRestClient(baseUrl, this.sslContextFactory.createSslContext(), - useHttpProxy ? httpProxyConfig : null); + useHttpProxy ? httpProxyConfig : null, this.securityContext); } catch (Exception e) { String exceptionString = e.toString(); logger.error("Could not init SSL context, reason: {}", exceptionString); } } - return new AsyncRestClient(baseUrl, null, httpProxyConfig); + return new AsyncRestClient(baseUrl, null, httpProxyConfig, this.securityContext); } private class SslContextFactory { diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/clients/SecurityContext.java b/information-coordinator-service/src/main/java/org/oransc/ics/clients/SecurityContext.java new file mode 100644 index 00000000..aadc1bf5 --- /dev/null +++ b/information-coordinator-service/src/main/java/org/oransc/ics/clients/SecurityContext.java @@ -0,0 +1,76 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2022 Nordix Foundation + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================LICENSE_END=================================== + */ + +package org.oransc.ics.clients; + +import java.lang.invoke.MethodHandles; +import java.nio.file.Files; +import java.nio.file.Path; + +import lombok.Setter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.stereotype.Component; + +@EnableConfigurationProperties +@ConfigurationProperties() +@Component +public class SecurityContext { + + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private long tokenTimestamp = 0; + + private String authToken = ""; + + @Setter + private Path authTokenFilePath; + + public SecurityContext(@Value("${app.auth-token-file:\"\"}") String authTokenFilename) { + if (!authTokenFilename.isEmpty()) { + this.authTokenFilePath = Path.of(authTokenFilename); + } + } + + public boolean isConfigured() { + return authTokenFilePath != null; + } + + public synchronized String getBearerAuthToken() { + if (!isConfigured()) { + return ""; + } + try { + long lastModified = authTokenFilePath.toFile().lastModified(); + if (lastModified != this.tokenTimestamp) { + this.authToken = Files.readString(authTokenFilePath); + this.tokenTimestamp = lastModified; + } + } catch (Exception e) { + logger.warn("Could not read auth token file: {}, reason: {}", authTokenFilePath, e.getMessage()); + } + return this.authToken; + } + +} diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java index b3692613..15394ab6 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/a1e/A1eCallbacks.java @@ -28,6 +28,7 @@ import java.util.Collection; import org.oransc.ics.clients.AsyncRestClient; import org.oransc.ics.clients.AsyncRestClientFactory; +import org.oransc.ics.clients.SecurityContext; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.repository.InfoJob; import org.oransc.ics.repository.InfoJobs; @@ -55,8 +56,9 @@ public class A1eCallbacks { private final InfoJobs eiJobs; @Autowired - public A1eCallbacks(ApplicationConfig config, InfoJobs eiJobs) { - AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); + public A1eCallbacks(ApplicationConfig config, InfoJobs eiJobs, SecurityContext securityContext) { + AsyncRestClientFactory restClientFactory = + new AsyncRestClientFactory(config.getWebClientConfig(), securityContext); this.restClient = restClientFactory.createRestClientUseHttpProxy(""); this.eiJobs = eiJobs; } diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerCallbacks.java b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerCallbacks.java index b96c160a..3db904d6 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerCallbacks.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1consumer/ConsumerCallbacks.java @@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder; import org.oransc.ics.clients.AsyncRestClient; import org.oransc.ics.clients.AsyncRestClientFactory; +import org.oransc.ics.clients.SecurityContext; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.repository.InfoType; import org.oransc.ics.repository.InfoTypeSubscriptions; @@ -45,9 +46,11 @@ public class ConsumerCallbacks implements InfoTypeSubscriptions.ConsumerCallback public static final String API_VERSION = "version_1"; - public ConsumerCallbacks(@Autowired ApplicationConfig config, - @Autowired InfoTypeSubscriptions infoTypeSubscriptions) { - AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); + @Autowired + public ConsumerCallbacks(ApplicationConfig config, InfoTypeSubscriptions infoTypeSubscriptions, + SecurityContext securityContext) { + AsyncRestClientFactory restClientFactory = + new AsyncRestClientFactory(config.getWebClientConfig(), securityContext); this.restClient = restClientFactory.createRestClientNoHttpProxy(""); infoTypeSubscriptions.registerCallbackhandler(this, API_VERSION); } diff --git a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java index c861d203..0881cd7e 100644 --- a/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java +++ b/information-coordinator-service/src/main/java/org/oransc/ics/controllers/r1producer/ProducerCallbacks.java @@ -29,6 +29,7 @@ import java.util.Collection; import org.oransc.ics.clients.AsyncRestClient; import org.oransc.ics.clients.AsyncRestClientFactory; +import org.oransc.ics.clients.SecurityContext; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.repository.InfoJob; import org.oransc.ics.repository.InfoJobs; @@ -52,8 +53,9 @@ public class ProducerCallbacks { private final AsyncRestClient restClient; - public ProducerCallbacks(ApplicationConfig config) { - AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); + public ProducerCallbacks(ApplicationConfig config, SecurityContext securityContext) { + AsyncRestClientFactory restClientFactory = + new AsyncRestClientFactory(config.getWebClientConfig(), securityContext); this.restClient = restClientFactory.createRestClientNoHttpProxy(""); } diff --git a/information-coordinator-service/src/test/java/org/oransc/ics/ApplicationTest.java b/information-coordinator-service/src/test/java/org/oransc/ics/ApplicationTest.java index cc7e16ff..975bf81d 100644 --- a/information-coordinator-service/src/test/java/org/oransc/ics/ApplicationTest.java +++ b/information-coordinator-service/src/test/java/org/oransc/ics/ApplicationTest.java @@ -34,7 +34,10 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.lang.invoke.MethodHandles; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; +import java.util.Map; import org.json.JSONObject; import org.junit.jupiter.api.AfterEach; @@ -43,6 +46,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.oransc.ics.clients.AsyncRestClient; import org.oransc.ics.clients.AsyncRestClientFactory; +import org.oransc.ics.clients.SecurityContext; import org.oransc.ics.configuration.ApplicationConfig; import org.oransc.ics.configuration.ImmutableHttpProxyConfig; import org.oransc.ics.configuration.ImmutableWebClientConfig; @@ -145,6 +149,9 @@ class ApplicationTest { @Autowired InfoTypeSubscriptions infoTypeSubscriptions; + @Autowired + SecurityContext securityContext; + private static Gson gson = new GsonBuilder().create(); /** @@ -170,6 +177,7 @@ class ApplicationTest { this.producerSimulator.getTestResults().reset(); this.consumerSimulator.getTestResults().reset(); this.a1eCallbacksSimulator.getTestResults().reset(); + this.securityContext.setAuthTokenFilePath(null); } @AfterEach @@ -386,6 +394,7 @@ class ApplicationTest { ProducerSimulatorController.TestResults simulatorResults = this.producerSimulator.getTestResults(); await().untilAsserted(() -> assertThat(simulatorResults.jobsStopped).hasSize(1)); assertThat(simulatorResults.jobsStopped.get(0)).isEqualTo("jobId"); + } @Test @@ -1053,6 +1062,30 @@ class ApplicationTest { "Could not find Information subscription: junk"); } + @Test + void testAuthHeader() throws Exception { + final String AUTH_TOKEN = "testToken"; + Path authFile = Files.createTempFile("icsTestAuthToken", ".txt"); + Files.write(authFile, AUTH_TOKEN.getBytes()); + this.securityContext.setAuthTokenFilePath(authFile); + putInfoProducerWithOneType(PRODUCER_ID, TYPE_ID); + putInfoJob(TYPE_ID, "jobId"); + + // Test that authorization header is sent to the producer. + await().untilAsserted(() -> assertThat(this.producerSimulator.getTestResults().receivedHeaders).hasSize(1)); + Map headers = this.producerSimulator.getTestResults().receivedHeaders.get(0); + assertThat(headers).containsEntry("authorization", "Bearer " + AUTH_TOKEN); + + Files.delete(authFile); + + // Test that it works. The cached header is used + putInfoJob(TYPE_ID, "jobId2"); + await().untilAsserted(() -> assertThat(this.infoJobs.size()).isEqualByComparingTo(2)); + headers = this.producerSimulator.getTestResults().receivedHeaders.get(1); + assertThat(headers).containsEntry("authorization", "Bearer " + AUTH_TOKEN); + + } + private String typeSubscriptionUrl() { return ConsumerConsts.API_ROOT + "/info-type-subscription"; } @@ -1215,7 +1248,7 @@ class ApplicationTest { .trustStorePassword(config.trustStorePassword()) // .httpProxyConfig(httpProxyConfig).build(); - AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config); + AsyncRestClientFactory restClientFactory = new AsyncRestClientFactory(config, securityContext); return restClientFactory.createRestClientNoHttpProxy(baseUrl()); } diff --git a/information-coordinator-service/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java b/information-coordinator-service/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java index 67354478..3f5f78d4 100644 --- a/information-coordinator-service/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java +++ b/information-coordinator-service/src/test/java/org/oransc/ics/clients/AsyncRestClientTest.java @@ -52,13 +52,15 @@ class AsyncRestClientTest { private static AsyncRestClient clientUnderTest; + private static final SecurityContext securityContext = new SecurityContext(""); + @BeforeAll static void init() { // skip a lot of unnecessary logs from MockWebServer InternalLoggerFactory.setDefaultFactory(JdkLoggerFactory.INSTANCE); Loggers.useJdkLoggers(); mockWebServer = new MockWebServer(); - clientUnderTest = new AsyncRestClient(mockWebServer.url(BASE_URL).toString(), null, null); + clientUnderTest = new AsyncRestClient(mockWebServer.url(BASE_URL).toString(), null, null, securityContext); } @AfterAll diff --git a/information-coordinator-service/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java b/information-coordinator-service/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java index 9e383949..a5ddc490 100644 --- a/information-coordinator-service/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java +++ b/information-coordinator-service/src/test/java/org/oransc/ics/controller/ProducerSimulatorController.java @@ -31,6 +31,7 @@ import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import lombok.Getter; @@ -49,6 +50,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; @RestController("ProducerSimulatorController") @@ -67,6 +69,8 @@ public class ProducerSimulatorController { public List jobsStarted = Collections.synchronizedList(new ArrayList()); public List jobsStopped = Collections.synchronizedList(new ArrayList()); + public List> receivedHeaders = + Collections.synchronizedList(new ArrayList>()); public int noOfRejectedCreate = 0; public int noOfRejectedDelete = 0; public boolean errorFound = false; @@ -77,6 +81,7 @@ public class ProducerSimulatorController { public void reset() { jobsStarted.clear(); jobsStopped.clear(); + receivedHeaders.clear(); this.errorFound = false; this.noOfRejectedCreate = 0; this.noOfRejectedDelete = 0; @@ -98,9 +103,12 @@ public class ProducerSimulatorController { content = @Content(schema = @Schema(implementation = VoidResponse.class))) // }) public ResponseEntity jobCreatedCallback( // + @RequestHeader Map headers, // @RequestBody ProducerJobInfo request) { try { + logHeaders(headers); this.testResults.jobsStarted.add(request); + this.testResults.receivedHeaders.add(headers); logger.info("Job started callback {}", request.id); if (request.id == null) { throw new NullPointerException("Illegal argument"); @@ -124,10 +132,12 @@ public class ProducerSimulatorController { content = @Content(schema = @Schema(implementation = VoidResponse.class))) // }) public ResponseEntity jobDeletedCallback( // - @PathVariable(ConsumerConsts.INFO_JOB_ID_PATH) String infoJobId) { + @RequestHeader Map headers, @PathVariable(ConsumerConsts.INFO_JOB_ID_PATH) String infoJobId) { try { + logHeaders(headers); logger.info("Job deleted callback {}", infoJobId); this.testResults.jobsStopped.add(infoJobId); + this.testResults.receivedHeaders.add(headers); return new ResponseEntity<>(HttpStatus.OK); } catch (Exception e) { return ErrorResponse.create(e, HttpStatus.NOT_FOUND); @@ -179,7 +189,7 @@ public class ProducerSimulatorController { }) public ResponseEntity producerSupervision() { logger.info("Producer supervision"); - return new ResponseEntity<>(HttpStatus.OK); + return new ResponseEntity<>("Hunky dory", HttpStatus.OK); } @GetMapping(path = SUPERVISION_ERROR_URL, produces = MediaType.APPLICATION_JSON_VALUE) @@ -196,4 +206,10 @@ public class ProducerSimulatorController { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } + private void logHeaders(Map headers) { + logger.debug("Header begin"); + headers.forEach((key, value) -> logger.debug(" key: {}, value: {}", key, value)); + logger.debug("Header end"); + } + } -- 2.16.6