From 69316aa635c8f28557a38aab90e3362295d0725f Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Wed, 31 May 2023 13:02:12 +0200 Subject: [PATCH] DFC shall provide a bearer authorization token in HTTP Change-Id: I7a697e100073656079b919f440b590a980eeb674 Issue-ID: CCSDK-3894 Signed-off-by: PatrikBuhr --- .../java/org/oran/datafile/http/DfcHttpClient.java | 30 +++---- .../org/oran/datafile/http/DfcHttpsClient.java | 50 ++++------- .../java/org/oran/datafile/http/HttpUtils.java | 100 +-------------------- .../oran/datafile/tasks/CollectAndReportFiles.java | 9 +- .../org/oran/datafile/tasks/FileCollector.java | 10 ++- .../test/java/org/oran/datafile/MockDatafile.java | 9 +- .../org/oran/datafile/http/DfcHttpClientTest.java | 48 +--------- .../org/oran/datafile/http/DfcHttpsClientTest.java | 29 ++---- .../java/org/oran/datafile/http/HttpUtilsTest.java | 90 ------------------- .../org/oran/datafile/tasks/FileCollectorTest.java | 17 ++-- 10 files changed, 70 insertions(+), 322 deletions(-) diff --git a/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpClient.java b/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpClient.java index 7c1ae92..f941155 100644 --- a/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpClient.java +++ b/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpClient.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START====================================================================== * Copyright (C) 2020-2021 Nokia. All rights reserved. + * Copyright (C) 2023 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 @@ -27,6 +28,7 @@ import org.oran.datafile.commons.FileCollectClient; import org.oran.datafile.exceptions.DatafileTaskException; import org.oran.datafile.exceptions.NonRetryableDatafileTaskException; import org.oran.datafile.model.FileServerData; +import org.oran.datafile.oauth2.SecurityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,31 +54,27 @@ public class DfcHttpClient implements FileCollectClient { private Disposable disposableClient; protected HttpClient client; + private final SecurityContext securityContext; - public DfcHttpClient(FileServerData fileServerData) { + public DfcHttpClient(SecurityContext securityContext, FileServerData fileServerData) { this.fileServerData = fileServerData; + this.securityContext = securityContext; } @Override public void open() throws DatafileTaskException { logger.trace("Setting httpClient for file download."); - String authorizationContent = getAuthorizationContent(); - this.client = - HttpClient.create(pool).keepAlive(true).headers(h -> h.add("Authorization", authorizationContent)); - - logger.trace("httpClient, auth header was set."); - } - - protected String getAuthorizationContent() throws DatafileTaskException { - String jwtToken = HttpUtils.getJWTToken(fileServerData); - if (!jwtToken.isEmpty()) { - return HttpUtils.jwtAuthContent(jwtToken); - } - if (!HttpUtils.isBasicAuthDataFilled(fileServerData)) { - throw new DatafileTaskException("Not sufficient basic auth data for file."); + final String authorizationContent = this.securityContext.getBearerAuthToken(); + this.client = HttpClient.create(pool).keepAlive(true); + if (!authorizationContent.isEmpty()) { + this.client = this.client.headers(h -> h.add("Authorization", "Bearer " + authorizationContent)); + logger.trace("httpClient, auth header was set."); + } else if (!this.fileServerData.password.isEmpty()) { + String basicAuthContent = + HttpUtils.basicAuthContent(this.fileServerData.userId, this.fileServerData.password); + this.client = this.client.headers(h -> h.add("Authorization", basicAuthContent)); } - return HttpUtils.basicAuthContent(this.fileServerData.userId, this.fileServerData.password); } @Override diff --git a/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpsClient.java b/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpsClient.java index 74a1398..5cd0a31 100644 --- a/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpsClient.java +++ b/datafilecollector/src/main/java/org/oran/datafile/http/DfcHttpsClient.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START====================================================================== * Copyright (C) 2021 Nokia. All rights reserved. + * Copyright (C) 2023 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 @@ -41,6 +42,7 @@ import org.oran.datafile.commons.FileCollectClient; import org.oran.datafile.exceptions.DatafileTaskException; import org.oran.datafile.exceptions.NonRetryableDatafileTaskException; import org.oran.datafile.model.FileServerData; +import org.oran.datafile.oauth2.SecurityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,10 +59,13 @@ public class DfcHttpsClient implements FileCollectClient { private final FileServerData fileServerData; private final PoolingHttpClientConnectionManager connectionManager; + private final SecurityContext securityContext; - public DfcHttpsClient(FileServerData fileServerData, PoolingHttpClientConnectionManager connectionManager) { + public DfcHttpsClient(SecurityContext securityContext, FileServerData fileServerData, + PoolingHttpClientConnectionManager connectionManager) { this.fileServerData = fileServerData; this.connectionManager = connectionManager; + this.securityContext = securityContext; } @Override @@ -81,8 +86,11 @@ public class DfcHttpsClient implements FileCollectClient { logger.trace("Prepare to collectFile {}", localFile); HttpGet httpGet = new HttpGet(HttpUtils.prepareHttpsUri(fileServerData, remoteFile)); - String authorizationContent = getAuthorizationContent(); + String authorizationContent = this.securityContext.getBearerAuthToken(); if (!authorizationContent.isEmpty()) { + httpGet.addHeader("Authorization", "Bearer " + authorizationContent); + } else if (!this.fileServerData.password.isEmpty()) { + authorizationContent = HttpUtils.basicAuthContent(this.fileServerData.userId, this.fileServerData.password); httpGet.addHeader("Authorization", authorizationContent); } try { @@ -95,33 +103,7 @@ public class DfcHttpsClient implements FileCollectClient { logger.trace("HTTPS collectFile OK"); } - private String getAuthorizationContent() throws DatafileTaskException { - String jwtToken = HttpUtils.getJWTToken(fileServerData); - if (shouldUseBasicAuth(jwtToken)) { - return HttpUtils.basicAuthContent(this.fileServerData.userId, this.fileServerData.password); - } - return HttpUtils.jwtAuthContent(jwtToken); - } - - private boolean shouldUseBasicAuth(String jwtToken) throws DatafileTaskException { - return basicAuthValidNotPresentOrThrow() && jwtToken.isEmpty(); - } - - protected boolean basicAuthValidNotPresentOrThrow() throws DatafileTaskException { - if (isAuthDataEmpty()) { - return false; - } - if (HttpUtils.isBasicAuthDataFilled(fileServerData)) { - return true; - } - throw new DatafileTaskException("Not sufficient basic auth data for file."); - } - - private boolean isAuthDataEmpty() { - return this.fileServerData.userId.isEmpty() && this.fileServerData.password.isEmpty(); - } - - protected HttpResponse makeCall(HttpGet httpGet) throws IOException, DatafileTaskException { + HttpResponse makeCall(HttpGet httpGet) throws IOException, DatafileTaskException { try { HttpResponse httpResponse = executeHttpClient(httpGet); if (isResponseOk(httpResponse)) { @@ -143,11 +125,11 @@ public class DfcHttpsClient implements FileCollectClient { } } - protected CloseableHttpResponse executeHttpClient(HttpGet httpGet) throws IOException { + CloseableHttpResponse executeHttpClient(HttpGet httpGet) throws IOException { return httpsClient.execute(httpGet); } - protected boolean isResponseOk(HttpResponse httpResponse) { + boolean isResponseOk(HttpResponse httpResponse) { return getResponseCode(httpResponse) == 200; } @@ -155,11 +137,11 @@ public class DfcHttpsClient implements FileCollectClient { return httpResponse.getStatusLine().getStatusCode(); } - protected boolean isErrorInConnection(HttpResponse httpResponse) { + boolean isErrorInConnection(HttpResponse httpResponse) { return getResponseCode(httpResponse) >= 400; } - protected void processResponse(HttpResponse response, Path localFile) throws IOException { + void processResponse(HttpResponse response, Path localFile) throws IOException { logger.trace("Starting to process response."); HttpEntity entity = response.getEntity(); InputStream stream = entity.getContent(); @@ -169,7 +151,7 @@ public class DfcHttpsClient implements FileCollectClient { logger.trace("Transmission was successful - {} bytes downloaded.", numBytes); } - protected long writeFile(Path localFile, InputStream stream) throws IOException { + long writeFile(Path localFile, InputStream stream) throws IOException { return Files.copy(stream, localFile, StandardCopyOption.REPLACE_EXISTING); } diff --git a/datafilecollector/src/main/java/org/oran/datafile/http/HttpUtils.java b/datafilecollector/src/main/java/org/oran/datafile/http/HttpUtils.java index 02155d3..308b47e 100644 --- a/datafilecollector/src/main/java/org/oran/datafile/http/HttpUtils.java +++ b/datafilecollector/src/main/java/org/oran/datafile/http/HttpUtils.java @@ -33,10 +33,6 @@ public final class HttpUtils implements HttpStatus { private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class); public static final int HTTP_DEFAULT_PORT = 80; public static final int HTTPS_DEFAULT_PORT = 443; - public static final String JWT_TOKEN_NAME = "access_token"; - public static final String AUTH_JWT_WARN = "Both JWT token and Basic auth data present. Omitting basic auth info."; - public static final String AUTH_JWT_ERROR = - "More than one JWT token present in the queryParameters. Omitting JWT token."; private HttpUtils() { } @@ -53,18 +49,10 @@ public final class HttpUtils implements HttpStatus { return statusCode >= 200 && statusCode < 300; } - public static boolean isBasicAuthDataFilled(final FileServerData fileServerData) { - return !fileServerData.userId.isEmpty() && !fileServerData.password.isEmpty(); - } - public static String basicAuthContent(String username, String password) { return "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); } - public static String jwtAuthContent(String token) { - return "Bearer " + token; - } - /** * Prepare uri to retrieve file from xNF using HTTP connection. If JWT token was * included @@ -107,7 +95,7 @@ public final class HttpUtils implements HttpStatus { */ public static String prepareUri(String scheme, FileServerData fileServerData, String remoteFile, int defaultPort) { int port = fileServerData.port != null ? fileServerData.port : defaultPort; - String query = rewriteQueryWithoutToken(fileServerData.queryParameters); + String query = queryParametersAsString(fileServerData.queryParameters); String fragment = fileServerData.uriRawFragment; if (!query.isEmpty()) { query = "?" + query; @@ -119,101 +107,19 @@ public final class HttpUtils implements HttpStatus { } /** - * Returns JWT token string (if single exist) from the queryParameters. - * - * @param fileServerData file server data which contain queryParameters where - * JWT token may exist - * @return JWT token value if single token entry exist or empty string - * elsewhere. - * If JWT token key has no value, empty string will be returned. - */ - public static String getJWTToken(FileServerData fileServerData) { - - if (fileServerData.queryParameters.isEmpty()) { - return ""; - } - boolean jwtTokenKeyPresent = HttpUtils.isQueryWithSingleJWT(fileServerData.queryParameters); - if (!jwtTokenKeyPresent) { - return ""; - } - String token = HttpUtils.getJWTToken(fileServerData.queryParameters); - if (HttpUtils.isBasicAuthDataFilled(fileServerData)) { - logger.warn(HttpUtils.AUTH_JWT_WARN); - } - return token; - } - - /** - * Checks if the queryParameters contains single JWT token entry. Valid - * queryParameters - * contains only one token entry. - * - * @param query queryParameters - * @return true if queryParameters contains single token - */ - public static boolean isQueryWithSingleJWT(List query) { - if (query == null) { - return false; - } - int i = getJWTTokenCount(query); - if (i == 0) { - return false; - } - if (i > 1) { - logger.error(AUTH_JWT_ERROR); - return false; - } - return true; - } - - /** - * Returns the number of JWT token entries. Valid queryParameters contains only - * one token entry. * - * @param queryElements elements of the queryParameters - * @return true if queryParameters contains single JWT token entry - */ - public static int getJWTTokenCount(List queryElements) { - int i = 0; - for (NameValuePair element : queryElements) { - if (element.getName().equals(JWT_TOKEN_NAME)) { - i++; - } - } - return i; - } - - private static String getJWTToken(List query) { - for (NameValuePair element : query) { - if (!element.getName().equals(JWT_TOKEN_NAME)) { - continue; - } - if (element.getValue() != null) { - return element.getValue(); - } - return ""; - } - return ""; - } - - /** - * Rewrites HTTP queryParameters without JWT token * * @param query list of NameValuePair of elements sent in the queryParameters * @return String representation of queryParameters elements which were provided * in the input - * Empty string is possible when queryParameters is empty or contains - * only access_token key. + * Empty string is possible when queryParameters is empty. */ - public static String rewriteQueryWithoutToken(List query) { + private static String queryParametersAsString(List query) { if (query.isEmpty()) { return ""; } StringBuilder sb = new StringBuilder(); for (NameValuePair nvp : query) { - if (nvp.getName().equals(JWT_TOKEN_NAME)) { - continue; - } sb.append(nvp.getName()); if (nvp.getValue() != null) { sb.append("="); diff --git a/datafilecollector/src/main/java/org/oran/datafile/tasks/CollectAndReportFiles.java b/datafilecollector/src/main/java/org/oran/datafile/tasks/CollectAndReportFiles.java index a78d969..93b9a71 100644 --- a/datafilecollector/src/main/java/org/oran/datafile/tasks/CollectAndReportFiles.java +++ b/datafilecollector/src/main/java/org/oran/datafile/tasks/CollectAndReportFiles.java @@ -42,6 +42,7 @@ import org.oran.datafile.model.Counters; import org.oran.datafile.model.FileData; import org.oran.datafile.model.FilePublishInformation; import org.oran.datafile.model.FileReadyMessage; +import org.oran.datafile.oauth2.SecurityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -82,14 +83,17 @@ public class CollectAndReportFiles { private final DataStore dataStore; + private final SecurityContext securityContext; + /** * Constructor for task registration in Datafile Workflow. * * @param applicationConfiguration - application configuration */ - public CollectAndReportFiles(AppConfig applicationConfiguration) { + public CollectAndReportFiles(SecurityContext securityContext, AppConfig applicationConfiguration) { this.appConfig = applicationConfiguration; this.kafkaSender = KafkaSender.create(kafkaSenderOptions()); + this.securityContext = securityContext; initCerts(); this.dataStore = DataStore.create(applicationConfiguration); @@ -217,7 +221,6 @@ public class CollectAndReportFiles { } private Flux> sendDataToKafkaStream(Flux> dataToSend) { - return kafkaSender.send(dataToSend) // .doOnError(e -> logger.error("Send to kafka failed", e)); } @@ -239,7 +242,7 @@ public class CollectAndReportFiles { } protected FileCollector createFileCollector() { - return new FileCollector(appConfig, counters); + return new FileCollector(securityContext, appConfig, counters); } private Mono fetchFile(FileData fileData) { diff --git a/datafilecollector/src/main/java/org/oran/datafile/tasks/FileCollector.java b/datafilecollector/src/main/java/org/oran/datafile/tasks/FileCollector.java index 26c3df6..c36bd49 100644 --- a/datafilecollector/src/main/java/org/oran/datafile/tasks/FileCollector.java +++ b/datafilecollector/src/main/java/org/oran/datafile/tasks/FileCollector.java @@ -38,6 +38,7 @@ import org.oran.datafile.model.Counters; import org.oran.datafile.model.FileData; import org.oran.datafile.model.FilePublishInformation; import org.oran.datafile.model.FileReadyMessage; +import org.oran.datafile.oauth2.SecurityContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,15 +53,17 @@ public class FileCollector { private static final Logger logger = LoggerFactory.getLogger(FileCollector.class); private final AppConfig appConfig; private final Counters counters; + private final SecurityContext securityContext; /** * Constructor. * * @param appConfig application configuration */ - public FileCollector(AppConfig appConfig, Counters counters) { + public FileCollector(SecurityContext securityContext, AppConfig appConfig, Counters counters) { this.appConfig = appConfig; this.counters = counters; + this.securityContext = securityContext; } /** @@ -175,10 +178,11 @@ public class FileCollector { } protected FileCollectClient createHttpClient(FileData fileData) { - return new DfcHttpClient(fileData.fileServerData()); + return new DfcHttpClient(securityContext, fileData.fileServerData()); } protected FileCollectClient createHttpsClient(FileData fileData) throws DatafileTaskException { - return new DfcHttpsClient(fileData.fileServerData(), HttpsClientConnectionManagerUtil.instance()); + return new DfcHttpsClient(securityContext, fileData.fileServerData(), + HttpsClientConnectionManagerUtil.instance()); } } diff --git a/datafilecollector/src/test/java/org/oran/datafile/MockDatafile.java b/datafilecollector/src/test/java/org/oran/datafile/MockDatafile.java index b565704..9e35320 100644 --- a/datafilecollector/src/test/java/org/oran/datafile/MockDatafile.java +++ b/datafilecollector/src/test/java/org/oran/datafile/MockDatafile.java @@ -48,6 +48,7 @@ import org.oran.datafile.model.FileData; import org.oran.datafile.model.FilePublishInformation; import org.oran.datafile.model.FileReadyMessage; import org.oran.datafile.model.FileReadyMessage.MessageMetaData; +import org.oran.datafile.oauth2.SecurityContext; import org.oran.datafile.tasks.CollectAndReportFiles; import org.oran.datafile.tasks.FileCollector; import org.oran.datafile.tasks.KafkaTopicListener; @@ -117,6 +118,8 @@ class MockDatafile { @Autowired CollectAndReportFiles scheduledTask; + static final SecurityContext securityContext = new SecurityContext(""); + private static KafkaReceiver kafkaReceiver; private static class KafkaReceiver { @@ -166,13 +169,13 @@ class MockDatafile { final AppConfig appConfig; public FileCollectorMock(AppConfig appConfig) { - super(appConfig, new Counters()); + super(securityContext, appConfig, new Counters()); this.appConfig = appConfig; } @Override // (override fetchFile to disable the actual file fetching) public Mono collectFile(FileData fileData, long numRetries, Duration firstBackoff) { - FileCollector fc = new FileCollector(this.appConfig, new Counters()); + FileCollector fc = new FileCollector(securityContext, this.appConfig, new Counters()); FilePublishInformation i = fc.createFilePublishInformation(fileData); try { @@ -191,7 +194,7 @@ class MockDatafile { final AppConfig appConfig; public CollectAndReportFilesMock(AppConfig appConfig) { - super(appConfig); + super(securityContext, appConfig); this.appConfig = appConfig; } diff --git a/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpClientTest.java b/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpClientTest.java index 0e9a8d0..4d605af 100644 --- a/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpClientTest.java +++ b/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpClientTest.java @@ -29,18 +29,16 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.net.URISyntaxException; import java.nio.file.Path; -import org.apache.hc.core5.net.URIBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.oran.datafile.exceptions.DatafileTaskException; import org.oran.datafile.model.FileServerData; +import org.oran.datafile.oauth2.SecurityContext; import reactor.core.publisher.Flux; import reactor.netty.http.client.HttpClientConfig; @@ -52,8 +50,6 @@ class DfcHttpClientTest { private static final String PASSWORD = "123"; private static final String XNF_ADDRESS = "127.0.0.1"; private static final int PORT = 80; - private static final String JWT_PASSWORD = "thisIsThePassword"; - private static String ACCESS_TOKEN = "access_token"; @Mock private Path pathMock; @@ -62,7 +58,8 @@ class DfcHttpClientTest { @BeforeEach public void setup() { - dfcHttpClientSpy = spy(new DfcHttpClient(createFileServerData())); + SecurityContext ctx = new SecurityContext(""); + dfcHttpClientSpy = spy(new DfcHttpClient(ctx, createFileServerData())); } @Test @@ -72,17 +69,6 @@ class DfcHttpClientTest { assertEquals(HttpUtils.basicAuthContent(USERNAME, PASSWORD), config.headers().get("Authorization")); } - @Test - void openConnection_failedBasicAuthSetupThrowException() { - FileServerData serverData = - FileServerData.builder().serverAddress(XNF_ADDRESS).userId(USERNAME).password("").port(PORT).build(); - - DfcHttpClient dfcHttpClientSpy = spy(new DfcHttpClient(serverData)); - - assertThatThrownBy(() -> dfcHttpClientSpy.open()) - .hasMessageContaining("Not sufficient basic auth data for file."); - } - @Test void collectFile_AllOk() throws Exception { String REMOTE_FILE = "any"; @@ -101,27 +87,6 @@ class DfcHttpClientTest { verify(dfcHttpClientSpy, times(1)).isDownloadFailed(any()); } - @Test - void collectFile_AllOkWithJWTToken() throws Exception { - dfcHttpClientSpy = spy(new DfcHttpClient(fileServerDataWithJWTToken())); - String REMOTE_FILE = "any"; - Flux fis = Flux.just(new ByteArrayInputStream("ReturnedString".getBytes())); - - dfcHttpClientSpy.open(); - HttpClientConfig config = dfcHttpClientSpy.client.configuration(); - assertEquals(HttpUtils.jwtAuthContent(JWT_PASSWORD), config.headers().get("Authorization")); - - when(dfcHttpClientSpy.getServerResponse(any())).thenReturn(fis); - doReturn(false).when(dfcHttpClientSpy).isDownloadFailed(any()); - - dfcHttpClientSpy.collectFile(REMOTE_FILE, pathMock); - dfcHttpClientSpy.close(); - - verify(dfcHttpClientSpy, times(1)).getServerResponse(ArgumentMatchers.eq(REMOTE_FILE)); - verify(dfcHttpClientSpy, times(1)).processDataFromServer(any(), any(), any()); - verify(dfcHttpClientSpy, times(1)).isDownloadFailed(any()); - } - @Test void collectFile_No200ResponseWriteToErrorMessage() throws DatafileTaskException { String ERROR_RESPONSE = "This is unexpected message"; @@ -149,11 +114,4 @@ class DfcHttpClientTest { return FileServerData.builder().serverAddress(XNF_ADDRESS).userId(USERNAME).password(PASSWORD).port(PORT) .build(); } - - private FileServerData fileServerDataWithJWTToken() throws URISyntaxException { - String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; - - return FileServerData.builder().serverAddress(XNF_ADDRESS).userId("").password("").port(PORT) - .queryParameters(new URIBuilder(query).getQueryParams()).build(); - } } diff --git a/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpsClientTest.java b/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpsClientTest.java index c74edbd..5936a09 100644 --- a/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpsClientTest.java +++ b/datafilecollector/src/test/java/org/oran/datafile/http/DfcHttpsClientTest.java @@ -16,7 +16,6 @@ */ package org.oran.datafile.http; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -45,6 +44,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.oran.datafile.exceptions.DatafileTaskException; import org.oran.datafile.exceptions.NonRetryableDatafileTaskException; import org.oran.datafile.model.FileServerData; +import org.oran.datafile.oauth2.SecurityContext; @ExtendWith(MockitoExtension.class) class DfcHttpsClientTest { @@ -66,28 +66,8 @@ class DfcHttpsClientTest { @BeforeEach public void setup() { - dfcHttpsClientSpy = spy(new DfcHttpsClient(createFileServerData(), connectionManager)); - } - - @Test - void fileServerData_properLocationBasicAuth() throws Exception { - boolean result = dfcHttpsClientSpy.basicAuthValidNotPresentOrThrow(); - assertEquals(true, result); - } - - @Test - void fileServerData_properLocationNoBasicAuth() throws Exception { - dfcHttpsClientSpy = spy(new DfcHttpsClient(emptyUserInFileServerData(), connectionManager)); - - boolean result = dfcHttpsClientSpy.basicAuthValidNotPresentOrThrow(); - assertEquals(false, result); - } - - @Test - void fileServerData_improperAuthDataExceptionOccurred() throws Exception { - dfcHttpsClientSpy = spy(new DfcHttpsClient(invalidUserInFileServerData(), connectionManager)); - - assertThrows(DatafileTaskException.class, () -> dfcHttpsClientSpy.basicAuthValidNotPresentOrThrow()); + SecurityContext ctx = new SecurityContext(""); + dfcHttpsClientSpy = spy(new DfcHttpsClient(ctx, createFileServerData(), connectionManager)); } @Test @@ -109,7 +89,8 @@ class DfcHttpsClientTest { @Test void dfcHttpsClient_flow_successfulCallWithJWTAndResponseProcessing() throws Exception { FileServerData serverData = jWTTokenInFileServerData(); - dfcHttpsClientSpy = spy(new DfcHttpsClient(serverData, connectionManager)); + SecurityContext ctx = new SecurityContext(""); + dfcHttpsClientSpy = spy(new DfcHttpsClient(ctx, serverData, connectionManager)); doReturn(HttpClientResponseHelper.APACHE_RESPONSE_OK).when(dfcHttpsClientSpy) .executeHttpClient(any(HttpGet.class)); diff --git a/datafilecollector/src/test/java/org/oran/datafile/http/HttpUtilsTest.java b/datafilecollector/src/test/java/org/oran/datafile/http/HttpUtilsTest.java index a72d698..05f4492 100644 --- a/datafilecollector/src/test/java/org/oran/datafile/http/HttpUtilsTest.java +++ b/datafilecollector/src/test/java/org/oran/datafile/http/HttpUtilsTest.java @@ -22,9 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.net.URISyntaxException; -import java.util.List; -import org.apache.hc.core5.http.NameValuePair; import org.apache.hc.core5.net.URIBuilder; import org.junit.jupiter.api.Test; import org.oran.datafile.model.FileServerData; @@ -33,10 +31,6 @@ class HttpUtilsTest { private static final String XNF_ADDRESS = "127.0.0.1"; private static final int PORT = 443; - private static final String JWT_PASSWORD = "thisIsThePassword"; - private static final String ACCESS_TOKEN = "access_token"; - private static final String ANOTHER_TOKEN = "another_token"; - private static final String ANOTHER_DATA = "another_data"; private static final String FRAGMENT = "thisIsTheFragment"; private static final String USERNAME = "bob"; private static final String PASSWORD = "123"; @@ -51,30 +45,6 @@ class HttpUtilsTest { assertFalse(HttpUtils.isSuccessfulResponseCodeWithDataRouter(404)); } - @Test - void isSingleQueryWithJWT_validToken() throws URISyntaxException { - assertTrue(HttpUtils.isQueryWithSingleJWT(validTokenSingleQueryData())); - assertTrue(HttpUtils.isQueryWithSingleJWT(validTokenDoubleQueryData())); - } - - @Test - void isSingleQueryWithJWT_invalidToken() throws URISyntaxException { - assertFalse(HttpUtils.isQueryWithSingleJWT(validQueryNoToken())); - assertFalse(HttpUtils.isQueryWithSingleJWT(queryDataDoubleToken())); - assertFalse(HttpUtils.isQueryWithSingleJWT(null)); - } - - @Test - void getJWTToken_jWTTokenPresent() throws URISyntaxException { - assertEquals(JWT_PASSWORD, HttpUtils.getJWTToken(fileServerDataWithJWTToken())); - assertEquals(JWT_PASSWORD, HttpUtils.getJWTToken(fileServerDataWithJWTTokenLongQueryAndFragment())); - } - - @Test - void getJWTToken_JWTTokenNotPresent() throws URISyntaxException { - assertEquals("", HttpUtils.getJWTToken(fileServerDataQueryWithoutToken())); - } - @Test void prepareUri_UriWithoutPort() { FileServerData serverData = @@ -85,15 +55,6 @@ class HttpUtilsTest { assertTrue(retrievedUri.startsWith("http://" + XNF_ADDRESS + ":80")); } - @Test - void prepareUri_verifyUriWithTokenAndFragment() throws URISyntaxException { - String file = "/file"; - String expected = "http://" + XNF_ADDRESS + ":" + PORT + file + "?" + ANOTHER_TOKEN + "=" + ANOTHER_DATA + "&" - + ANOTHER_TOKEN + "=" + ANOTHER_DATA + "&" + ANOTHER_TOKEN + "=" + ANOTHER_DATA + "#" + FRAGMENT; - assertEquals(expected, - HttpUtils.prepareUri("http", fileServerDataWithJWTTokenLongQueryAndFragment(), file, 443)); - } - @Test void prepareUri_verifyUriWithoutTokenAndWithoutFragment() throws URISyntaxException { String file = "/file"; @@ -101,57 +62,6 @@ class HttpUtilsTest { assertEquals(expected, HttpUtils.prepareUri("http", fileServerDataNoTokenNoFragment(), file, 443)); } - private List validTokenSingleQueryData() throws URISyntaxException { - String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; - return new URIBuilder(query).getQueryParams(); - } - - private List validTokenDoubleQueryData() throws URISyntaxException { - StringBuilder doubleQuery = new StringBuilder(); - doubleQuery.append("?" + ANOTHER_TOKEN + "=" + ANOTHER_DATA + "&"); - doubleQuery.append(ACCESS_TOKEN + "=" + JWT_PASSWORD); - return new URIBuilder(doubleQuery.toString()).getQueryParams(); - } - - private List validQueryNoToken() throws URISyntaxException { - String query = "?" + ANOTHER_TOKEN + "=" + JWT_PASSWORD; - return new URIBuilder(query).getQueryParams(); - } - - private List queryDataDoubleToken() throws URISyntaxException { - StringBuilder doubleToken = new StringBuilder(); - doubleToken.append("?" + ACCESS_TOKEN + "=" + JWT_PASSWORD + "&"); - doubleToken.append(ACCESS_TOKEN + "=" + JWT_PASSWORD + "&"); - doubleToken.append(ANOTHER_TOKEN + "=" + ANOTHER_DATA); - return new URIBuilder(doubleToken.toString()).getQueryParams(); - } - - private FileServerData fileServerDataWithJWTToken() throws URISyntaxException { - String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; - - return FileServerData.builder().serverAddress(XNF_ADDRESS).userId("").password("").port(PORT) - .queryParameters(new URIBuilder(query).getQueryParams()).build(); - } - - private FileServerData fileServerDataWithJWTTokenLongQueryAndFragment() throws URISyntaxException { - StringBuilder query = new StringBuilder(); - query.append("?" + ANOTHER_TOKEN + "=" + ANOTHER_DATA + "&"); - query.append(ANOTHER_TOKEN + "=" + ANOTHER_DATA + "&"); - query.append(ACCESS_TOKEN + "=" + JWT_PASSWORD + "&"); - query.append(ANOTHER_TOKEN + "=" + ANOTHER_DATA); - - return FileServerData.builder().serverAddress(XNF_ADDRESS).userId("").password("").port(PORT) - .queryParameters(new URIBuilder(query.toString()).getQueryParams()).uriRawFragment(FRAGMENT).build(); - } - - private FileServerData fileServerDataQueryWithoutToken() throws URISyntaxException { - StringBuilder query = new StringBuilder(); - query.append("?" + ANOTHER_TOKEN + "=" + ANOTHER_DATA); - - return FileServerData.builder().serverAddress(XNF_ADDRESS).userId("").password("").port(PORT) - .queryParameters(new URIBuilder(query.toString()).getQueryParams()).build(); - } - private FileServerData fileServerDataNoTokenNoFragment() throws URISyntaxException { return FileServerData.builder().serverAddress(XNF_ADDRESS).userId("").password("").port(PORT) .queryParameters(new URIBuilder("").getQueryParams()).uriRawFragment("").build(); diff --git a/datafilecollector/src/test/java/org/oran/datafile/tasks/FileCollectorTest.java b/datafilecollector/src/test/java/org/oran/datafile/tasks/FileCollectorTest.java index fa5d799..118e9c7 100644 --- a/datafilecollector/src/test/java/org/oran/datafile/tasks/FileCollectorTest.java +++ b/datafilecollector/src/test/java/org/oran/datafile/tasks/FileCollectorTest.java @@ -49,6 +49,7 @@ import org.oran.datafile.model.Counters; import org.oran.datafile.model.FileData; import org.oran.datafile.model.FilePublishInformation; import org.oran.datafile.model.FileReadyMessage; +import org.oran.datafile.oauth2.SecurityContext; import reactor.test.StepVerifier; public class FileCollectorTest { @@ -110,6 +111,8 @@ public class FileCollectorTest { private Counters counters; + static final SecurityContext securityContext = new SecurityContext(""); + FileReadyMessage.Event event(String location) { FileReadyMessage.MessageMetaData messageMetaData = FileReadyMessage.MessageMetaData.builder() // .lastEpochMicrosec(LAST_EPOCH_MICROSEC) // @@ -188,7 +191,7 @@ public class FileCollectorTest { @Test public void whenFtpesFile_returnCorrectResponse() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(ftpesClientMock).when(collectorUndetTest).createFtpesClient(any()); FileData fileData = createFileData(FTPES_LOCATION_NO_PORT); @@ -212,7 +215,7 @@ public class FileCollectorTest { @Test public void whenSftpFile_returnCorrectResponse() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(sftpClientMock).when(collectorUndetTest).createSftpClient(any()); FileData fileData = createFileData(SFTP_LOCATION_NO_PORT); @@ -241,7 +244,7 @@ public class FileCollectorTest { @Test public void whenHttpFile_returnCorrectResponse() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(dfcHttpClientMock).when(collectorUndetTest).createHttpClient(any()); FileData fileData = createFileData(HTTP_LOCATION_NO_PORT); @@ -273,7 +276,7 @@ public class FileCollectorTest { @Test public void whenHttpsFile_returnCorrectResponse() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(dfcHttpsClientMock).when(collectorUndetTest).createHttpsClient(any()); FileData fileData = createFileData(HTTPS_LOCATION_NO_PORT); @@ -305,7 +308,7 @@ public class FileCollectorTest { @Test public void whenFtpesFileAlwaysFail_retryAndFail() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(ftpesClientMock).when(collectorUndetTest).createFtpesClient(any()); FileData fileData = createFileData(FTPES_LOCATION); @@ -325,7 +328,7 @@ public class FileCollectorTest { @Test public void whenFtpesFileAlwaysFail_failWithoutRetry() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(ftpesClientMock).when(collectorUndetTest).createFtpesClient(any()); FileData fileData = createFileData(FTPES_LOCATION); @@ -345,7 +348,7 @@ public class FileCollectorTest { @Test public void whenFtpesFileFailOnce_retryAndReturnCorrectResponse() throws Exception { - FileCollector collectorUndetTest = spy(new FileCollector(appConfigMock, counters)); + FileCollector collectorUndetTest = spy(new FileCollector(securityContext, appConfigMock, counters)); doReturn(ftpesClientMock).when(collectorUndetTest).createFtpesClient(any()); doThrow(new DatafileTaskException("Unable to collect file.")).doNothing().when(ftpesClientMock) .collectFile(REMOTE_FILE_LOCATION, LOCAL_FILE_LOCATION); -- 2.16.6