diff options
author | PatrikBuhr <patrik.buhr@est.tech> | 2022-03-31 12:08:56 +0200 |
---|---|---|
committer | PatrikBuhr <patrik.buhr@est.tech> | 2022-03-31 12:14:30 +0200 |
commit | de7a573e413e5b32bd4c4d2b20d2488d6eca87a8 (patch) | |
tree | baab7adaeb8cb0c5a90017c82adaa50fa79af78f /a1-policy-management/src/main/java | |
parent | 4b6205245fd4839e4449e26aa4e3000ddb30ecc1 (diff) |
NONRTRIC PMS using authorization token
Added support for PMS sending an authorization token in each REST call(in the HTTP header).
The token is read from a file.
Issue-ID: CCSDK-3560
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Change-Id: I92229f67d2c1486530f3c6ebb22f60bd3b359676
Diffstat (limited to 'a1-policy-management/src/main/java')
8 files changed, 137 insertions, 72 deletions
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java index 93fd2f77..bf161954 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/BeanFactory.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.catalina.connector.Connector; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services; @@ -56,8 +57,9 @@ public class BeanFactory { } @Bean - public A1ClientFactory getA1ClientFactory(@Autowired ApplicationConfig applicationConfig) { - return new A1ClientFactory(applicationConfig); + public A1ClientFactory getA1ClientFactory(@Autowired ApplicationConfig applicationConfig, + @Autowired SecurityContext securityContext) { + return new A1ClientFactory(applicationConfig, securityContext); } @Bean diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java index 642385aa..1d465c3a 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactory.java @@ -43,9 +43,9 @@ public class A1ClientFactory { private final AsyncRestClientFactory restClientFactory; @Autowired - public A1ClientFactory(ApplicationConfig appConfig) { + public A1ClientFactory(ApplicationConfig appConfig, SecurityContext securityContext) { this.appConfig = appConfig; - this.restClientFactory = new AsyncRestClientFactory(appConfig.getWebClientConfig()); + this.restClientFactory = new AsyncRestClientFactory(appConfig.getWebClientConfig(), securityContext); } /** diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java index 3461876d..959d85e2 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClient.java @@ -2,7 +2,7 @@ * ========================LICENSE_START================================= * ONAP : ccsdk oran * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. + * Copyright (C) 2019-2022 Nordix Foundation. 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. @@ -35,13 +35,14 @@ 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; +import reactor.netty.transport.ProxyProvider; /** * Generic reactive REST client. @@ -54,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<ResponseEntity<String>> postForEntity(String uri, @Nullable String body) { - Object traceTag = createTraceTag(); - logger.debug("{} POST uri = '{}{}'", traceTag, baseUrl, uri); - logger.trace("{} POST body: {}", traceTag, body); Mono<String> bodyProducer = body != null ? Mono.just(body) : Mono.empty(); RequestHeadersSpec<?> request = getWebClient() // @@ -72,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<String> post(String uri, @Nullable String body) { @@ -81,41 +82,30 @@ public class AsyncRestClient { } public Mono<String> 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<ResponseEntity<String>> 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<ResponseEntity<String>> putForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} PUT uri = '{}{}'", traceTag, baseUrl, uri); - logger.trace("{} PUT body: <empty>", traceTag); RequestHeadersSpec<?> request = getWebClient() // .put() // .uri(uri); - return retrieve(traceTag, request); + return retrieve(request); } public Mono<String> put(String uri, String body) { @@ -124,12 +114,8 @@ public class AsyncRestClient { } public Mono<ResponseEntity<String>> getForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} GET uri = '{}{}'", traceTag, baseUrl, uri); - RequestHeadersSpec<?> request = getWebClient() // - .get() // - .uri(uri); - return retrieve(traceTag, request); + RequestHeadersSpec<?> request = getWebClient().get().uri(uri); + return retrieve(request); } public Mono<String> get(String uri) { @@ -138,12 +124,8 @@ public class AsyncRestClient { } public Mono<ResponseEntity<String>> deleteForEntity(String uri) { - Object traceTag = createTraceTag(); - logger.debug("{} DELETE uri = '{}{}'", traceTag, baseUrl, uri); - RequestHeadersSpec<?> request = getWebClient() // - .delete() // - .uri(uri); - return retrieve(traceTag, request); + RequestHeadersSpec<?> request = getWebClient().delete().uri(uri); + return retrieve(request); } public Mono<String> delete(String uri) { @@ -151,32 +133,18 @@ public class AsyncRestClient { .map(this::toBody); } - private Mono<ResponseEntity<String>> retrieve(Object traceTag, RequestHeadersSpec<?> request) { - final Class<String> clazz = String.class; + private Mono<ResponseEntity<String>> 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<String> 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<String> entity) { if (entity.getBody() == null) { return ""; @@ -203,22 +171,36 @@ public class AsyncRestClient { } if (isHttpProxyConfigured()) { - httpClient = httpClient.proxy(proxy -> proxy.type(httpProxyConfig.httpProxyType()) // - .host(httpProxyConfig.httpProxyHost()) // - .port(httpProxyConfig.httpProxyPort())); + httpClient = httpClient.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP) + .host(httpProxyConfig.httpProxyHost()).port(httpProxyConfig.httpProxyPort())); } 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/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java index cde6647a..844db540 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientFactory.java @@ -2,7 +2,7 @@ * ========================LICENSE_START================================= * ONAP : ccsdk oran * ====================================================================== - * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved. + * Copyright (C) 2019-2022 Nordix Foundation. 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. @@ -50,14 +50,14 @@ import org.springframework.util.ResourceUtils; /** * Factory for a generic reactive REST client. */ -@SuppressWarnings("squid:S2629") // Invoke method(s) only conditionally public class AsyncRestClientFactory { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 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(); @@ -66,6 +66,7 @@ public class AsyncRestClientFactory { this.sslContextFactory = null; this.httpProxyConfig = null; } + this.securityContext = securityContext; } public AsyncRestClient createRestClientNoHttpProxy(String baseUrl) { @@ -80,13 +81,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/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SecurityContext.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SecurityContext.java new file mode 100644 index 00000000..3566aada --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SecurityContext.java @@ -0,0 +1,76 @@ +/*- + * ========================LICENSE_START================================= + * ONAP : ccsdk oran + * ====================================================================== + * Copyright (C) 2019-2022 Nordix Foundation. 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.ccsdk.oran.a1policymanagementservice.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/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java index bc67e663..1224d00b 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumer.java @@ -32,6 +32,7 @@ import java.util.List; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -109,11 +110,11 @@ public class DmaapMessageConsumer { } @Autowired - public DmaapMessageConsumer(ApplicationConfig applicationConfig) { + public DmaapMessageConsumer(ApplicationConfig applicationConfig, SecurityContext securityContext) { this.applicationConfig = applicationConfig; GsonBuilder gsonBuilder = new GsonBuilder(); this.gson = gsonBuilder.create(); - this.restClientFactory = new AsyncRestClientFactory(applicationConfig.getWebClientConfig()); + this.restClientFactory = new AsyncRestClientFactory(applicationConfig.getWebClientConfig(), securityContext); } /** diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java index 651ba5ed..e3d489b5 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTask.java @@ -31,6 +31,7 @@ import lombok.Getter; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser; @@ -88,7 +89,8 @@ public class RefreshConfigTask { @Autowired public RefreshConfigTask(ConfigurationFile configurationFile, ApplicationConfig appConfig, Rics rics, - Policies policies, Services services, PolicyTypes policyTypes, A1ClientFactory a1ClientFactory) { + Policies policies, Services services, PolicyTypes policyTypes, A1ClientFactory a1ClientFactory, + SecurityContext securityContext) { this.configurationFile = configurationFile; this.appConfig = appConfig; this.rics = rics; @@ -96,7 +98,7 @@ public class RefreshConfigTask { this.services = services; this.policyTypes = policyTypes; this.a1ClientFactory = a1ClientFactory; - this.restClientFactory = new AsyncRestClientFactory(appConfig.getWebClientConfig()); + this.restClientFactory = new AsyncRestClientFactory(appConfig.getWebClientConfig(), securityContext); } public void start() { @@ -171,7 +173,7 @@ public class RefreshConfigTask { /** * for an added RIC after a restart it is nesessary to get the suypported policy * types from the RIC unless a full synchronization is wanted. - * + * * @param ric the ric to get supprted types from * @return the same ric */ diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java index 2c037838..8926ec16 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervision.java @@ -25,6 +25,7 @@ import java.util.Collection; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client; import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory; import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory; +import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig; import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType; @@ -87,13 +88,13 @@ public class RicSupervision { @Autowired public RicSupervision(Rics rics, Policies policies, A1ClientFactory a1ClientFactory, PolicyTypes policyTypes, - Services services, ApplicationConfig config) { + Services services, ApplicationConfig config, SecurityContext securityContext) { this.rics = rics; this.policies = policies; this.a1ClientFactory = a1ClientFactory; this.policyTypes = policyTypes; this.services = services; - this.restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig()); + this.restClientFactory = new AsyncRestClientFactory(config.getWebClientConfig(), securityContext); } /** |