From 6055339221e6e81d76c33c2b95ecc8798d378996 Mon Sep 17 00:00:00 2001 From: Krzysztof Gajewski Date: Mon, 15 Feb 2021 14:07:44 +0100 Subject: Add JWT support in HTTP/HTTPS based locations Issue-ID: DCAEGEN2-2536 Signed-off-by: Krzysztof Gajewski Change-Id: I47a928159853333014b0fd413a085b7c50eeb7a0 --- .../datafile/http/DfcHttpClientTest.java | 49 +++++-- .../datafile/http/DfcHttpsClientTest.java | 44 +++++- .../collectors/datafile/service/HttpUtilsTest.java | 160 ++++++++++++++++++++- 3 files changed, 233 insertions(+), 20 deletions(-) (limited to 'datafile-app-server/src/test/java') diff --git a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpClientTest.java b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpClientTest.java index 2013950a..98804a0c 100644 --- a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpClientTest.java +++ b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpClientTest.java @@ -15,6 +15,7 @@ */ package org.onap.dcaegen2.collectors.datafile.http; +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; @@ -29,6 +30,7 @@ import reactor.netty.http.client.HttpClientConfig; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.file.Path; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -49,6 +51,8 @@ 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; @@ -61,10 +65,10 @@ class DfcHttpClientTest { } @Test - void openConnection_successAuthSetup() throws DatafileTaskException { + void openConnection_successBasicAuthSetup() throws DatafileTaskException { dfcHttpClientSpy.open(); HttpClientConfig config = dfcHttpClientSpy.client.configuration(); - assertEquals(HttpUtils.basicAuth(USERNAME, PASSWORD), config.headers().get("Authorization")); + assertEquals(HttpUtils.basicAuthContent(USERNAME, PASSWORD), config.headers().get("Authorization")); } @Test @@ -81,25 +85,34 @@ class DfcHttpClientTest { .hasMessageContaining("Not sufficient basic auth data for file."); } + @Test - void prepareUri_UriWithoutPort() { - ImmutableFileServerData serverData = ImmutableFileServerData.builder() - .serverAddress(XNF_ADDRESS) - .userId(USERNAME).password(PASSWORD) - .build(); - DfcHttpClient clientNoPortSpy = spy(new DfcHttpClient(serverData)); + void collectFile_AllOk() throws Exception { String REMOTE_FILE = "any"; + Flux fis = Flux.just(new ByteArrayInputStream("ReturnedString".getBytes())); + + dfcHttpClientSpy.open(); + + when(dfcHttpClientSpy.getServerResponse(any())).thenReturn(fis); + doReturn(false).when(dfcHttpClientSpy).isDownloadFailed(any()); + + dfcHttpClientSpy.collectFile(REMOTE_FILE, pathMock); + dfcHttpClientSpy.close(); - String retrievedUri = clientNoPortSpy.prepareUri(REMOTE_FILE); - assertTrue(retrievedUri.startsWith("http://" + XNF_ADDRESS + ":80")); + 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_AllOk() throws Exception { + 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()); @@ -123,7 +136,7 @@ class DfcHttpClientTest { doReturn(fis).when(dfcHttpClientSpy).getServerResponse(any()); assertThatThrownBy(() -> dfcHttpClientSpy.collectFile(REMOTE_FILE, pathMock)) - .hasMessageContaining("Error occured during datafile download: "); + .hasMessageContaining(ERROR_RESPONSE); verify(dfcHttpClientSpy, times(1)).getServerResponse(REMOTE_FILE); verify(dfcHttpClientSpy, times(1)).processFailedConnectionWithServer(any(), any()); dfcHttpClientSpy.close(); @@ -142,4 +155,16 @@ class DfcHttpClientTest { .port(PORT) .build(); } + + private ImmutableFileServerData fileServerDataWithJWTToken() throws URISyntaxException { + String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; + + return ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("") + .password("") + .port(PORT) + .queryParameters(new URIBuilder(query).getQueryParams()) + .build(); + } } diff --git a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpsClientTest.java b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpsClientTest.java index 8df91d3a..168bb08c 100644 --- a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpsClientTest.java +++ b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/http/DfcHttpsClientTest.java @@ -16,6 +16,7 @@ package org.onap.dcaegen2.collectors.datafile.http; +import org.apache.hc.core5.net.URIBuilder; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ConnectTimeoutException; @@ -25,15 +26,18 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.dcaegen2.collectors.datafile.commons.FileServerData; import org.onap.dcaegen2.collectors.datafile.commons.ImmutableFileServerData; import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException; import org.onap.dcaegen2.collectors.datafile.exceptions.NonRetryableDatafileTaskException; import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.file.Path; 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; import static org.mockito.ArgumentMatchers.eq; @@ -50,6 +54,8 @@ class DfcHttpsClientTest { private static final String PASSWORD = "123"; 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 String ACCESS_TOKEN = "access_token"; private static String remoteFile = "remoteFile"; @Mock @@ -104,6 +110,29 @@ class DfcHttpsClientTest { .writeFile(eq(localFile), any(InputStream.class)); } + @Test + void dfcHttpsClient_flow_successfulCallWithJWTAndResponseProcessing() throws Exception { + FileServerData serverData = jWTTokenInFileServerData(); + dfcHttpsClientSpy = spy(new DfcHttpsClient(serverData, connectionManager)); + + doReturn(HttpClientResponseHelper.APACHE_RESPONSE_OK).when(dfcHttpsClientSpy) + .executeHttpClient(any(HttpGet.class)); + doReturn((long)3).when(dfcHttpsClientSpy).writeFile(eq(localFile), any(InputStream.class)); + + dfcHttpsClientSpy.open(); + dfcHttpsClientSpy.collectFile(remoteFile, localFile); + dfcHttpsClientSpy.close(); + + verify(dfcHttpsClientSpy, times(1)).makeCall(any(HttpGet.class)); + verify(dfcHttpsClientSpy, times(1)) + .executeHttpClient(any(HttpGet.class)); + verify(dfcHttpsClientSpy, times(1)) + .processResponse(HttpClientResponseHelper.APACHE_RESPONSE_OK, localFile); + verify(dfcHttpsClientSpy, times(1)) + .writeFile(eq(localFile), any(InputStream.class)); + assertFalse(serverData.toString().contains(JWT_PASSWORD)); + } + @Test void dfcHttpsClient_flow_failedCallUnexpectedResponseCode() throws Exception { doReturn(HttpClientResponseHelper.APACHE_RESPONSE_OK).when(dfcHttpsClientSpy) @@ -112,7 +141,7 @@ class DfcHttpsClientTest { dfcHttpsClientSpy.open(); - assertThrows(NonRetryableDatafileTaskException.class, + assertThrows(DatafileTaskException.class, () -> dfcHttpsClientSpy.collectFile(remoteFile, localFile)); } @@ -157,8 +186,19 @@ class DfcHttpsClientTest { private ImmutableFileServerData invalidUserInFileServerData() { return ImmutableFileServerData.builder() .serverAddress(XNF_ADDRESS) - .userId("demo").password("") + .userId(USERNAME).password("") + .port(PORT) + .build(); + } + + private ImmutableFileServerData jWTTokenInFileServerData() throws URISyntaxException { + String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; + + return ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("").password("") .port(PORT) + .queryParameters(new URIBuilder(query).getQueryParams()) .build(); } } diff --git a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/service/HttpUtilsTest.java b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/service/HttpUtilsTest.java index a95bfe2b..953f3226 100644 --- a/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/service/HttpUtilsTest.java +++ b/datafile-app-server/src/test/java/org/onap/dcaegen2/collectors/datafile/service/HttpUtilsTest.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START====================================================================== * Copyright (C) 2018-2019 Nordix Foundation. All rights reserved. + * Modifications Copyright (C) 2021 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 @@ -16,20 +17,167 @@ package org.onap.dcaegen2.collectors.datafile.service; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.net.URIBuilder; +import org.junit.jupiter.api.Test; +import org.onap.dcaegen2.collectors.datafile.commons.ImmutableFileServerData; + +import java.net.URISyntaxException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; - 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"; + + @Test + void shouldReturnSuccessfulResponse() { + assertTrue(HttpUtils.isSuccessfulResponseCodeWithDataRouter(200)); + } + + @Test + void shouldReturnBadResponse() { + assertFalse(HttpUtils.isSuccessfulResponseCodeWithDataRouter(404)); + } + @Test - public void shouldReturnSuccessfulResponse() { - assertTrue(HttpUtils.isSuccessfulResponseCode(200)); + void isSingleQueryWithJWT_validToken() throws URISyntaxException { + assertTrue(HttpUtils.isQueryWithSingleJWT(validTokenSingleQueryData())); + assertTrue(HttpUtils.isQueryWithSingleJWT(validTokenDoubleQueryData())); } @Test - public void shouldReturnBadResponse() { - assertFalse(HttpUtils.isSuccessfulResponseCode(404)); + 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() { + ImmutableFileServerData serverData = ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId(USERNAME).password(PASSWORD) + .build(); + String REMOTE_FILE = "any"; + + String retrievedUri = HttpUtils.prepareUri("http", serverData, REMOTE_FILE, 80); + 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"; + String expected = "http://" + XNF_ADDRESS + ":" + PORT + file; + 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 ImmutableFileServerData fileServerDataWithJWTToken() throws URISyntaxException { + String query = "?" + ACCESS_TOKEN + "=" + JWT_PASSWORD; + + return ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("") + .password("") + .port(PORT) + .queryParameters(new URIBuilder(query).getQueryParams()) + .build(); + } + + private ImmutableFileServerData 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 ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("") + .password("") + .port(PORT) + .queryParameters(new URIBuilder(query.toString()).getQueryParams()) + .uriRawFragment(FRAGMENT) + .build(); + } + + private ImmutableFileServerData fileServerDataQueryWithoutToken() throws URISyntaxException { + StringBuilder query = new StringBuilder(); + query.append("?" + ANOTHER_TOKEN + "=" + ANOTHER_DATA); + + return ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("") + .password("") + .port(PORT) + .queryParameters(new URIBuilder(query.toString()).getQueryParams()) + .build(); + } + + private ImmutableFileServerData fileServerDataNoTokenNoFragment() throws URISyntaxException { + return ImmutableFileServerData.builder() + .serverAddress(XNF_ADDRESS) + .userId("") + .password("") + .port(PORT) + .queryParameters(new URIBuilder("").getQueryParams()) + .uriRawFragment("") + .build(); } } -- cgit 1.2.3-korg