- Make cert paths field optional in configuration.
- Allow to skip ssl context load.
- Make PublisherConfig and SubscriberConfig fields optional.
- Remove Auth Header when AAF credentials are empty
Issue-ID: DCAEGEN2-3032
Issue-ID: DCAEGEN2-3038
Signed-off-by: Tomasz Wrobel <tomasz.wrobel@nokia.com>
Change-Id: I27d44cf8c2887b3a75c5ad16f833439b7b5757ee
### Changed
- [DCAEGEN2-2964] Switch configuration provider to CBS Client - DCAE SDK
- [DCAEGEN2-3049] Remove vulnerability
+- - [DCAEGEN2-3032] [DCAEGEN2-3038] Allow supports unauthenticated topic and connection without TLS
## [1.7.2] - 2021/08/26
### Changed
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
- * Copyright (C) 2021-2022 Nokia.
+ * Copyright (C) 2021-2022 Nokia. All rights reserved.
* Copyright (C) 2021 Samsung Electronics.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
this.serverResources = Arrays.asList(healthCheckHandler, deliveryHandler, dynamicConfiguration);
try {
this.applicationServer = server(this.mapperConfig, this.serverResources);
- } catch (IOException e) {
+ } catch (IOException | MapperConfigException e ) {
logger.unwrap().error("Failed to create server instance.", e);
throw new IllegalStateException("Server instantiation failed");
}
private Undertow server(MapperConfig config, List<ServerResource> serverResources) throws IOException {
SSLContextFactory sslContextFactory = new SSLContextFactory(config);
SSLContext sslContext = sslContextFactory.createSSLContext(config);
- SSLContext.setDefault(sslContext);
+ if (sslContext != null) {
+ SSLContext.setDefault(sslContext);
+ logger.unwrap().info("SSL Context loaded");
+ }
Undertow.Builder builder = Undertow.builder();
if (config.getEnableHttp()) {
builder.addHttpListener(this.httpPort, "0.0.0.0");
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
- * Copyright (C) 2022 Nokia.
+ * Copyright (C) 2022 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.
.create()
.fromJson(jsonObject, MapperConfig.class);
} catch (Exception exception) {
- String exceptionMessage = "Error parsing configuration, mapper config:\n" + mapperConfig;
- logger.unwrap().error(exceptionMessage);
+ String exceptionMessage = "Error parsing configuration, mapper config: " + mapperConfig;
+ logger.unwrap().error("Error parsing configuration", exception);
throw new MapperConfigException(exceptionMessage, exception);
}
logger.unwrap().info("PM-mapper configuration processed successful");
/*-\r
* ============LICENSE_START=======================================================\r
* Copyright (C) 2019 Nordix Foundation.\r
+ * Copyright (C) 2022 Nokia. All rights reserved.\r
* ================================================================================\r
* Licensed under the Apache License, Version 2.0 (the "License");\r
* you may not use this file except in compliance with the License.\r
public MapperConfigException(String message, Throwable cause) {\r
super(message, cause);\r
}\r
+\r
+ public MapperConfigException(String message) {\r
+ super(message);\r
+ }\r
}\r
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
+ * Copyright (C) 2022 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.
@SerializedName("enable_http")
private Boolean enableHttp;
- @GSONRequired
@SerializedName("key_store_path")
private String keyStorePath;
- @GSONRequired
@SerializedName("key_store_pass_path")
private String keyStorePassPath;
- @GSONRequired
@SerializedName("trust_store_path")
private String trustStorePath;
- @GSONRequired
@SerializedName("trust_store_pass_path")
private String trustStorePassPath;
@JsonAdapter(MeasFilterConfigAdapter.class)
private MeasFilterConfig filterConfig;
- @GSONRequired
@SerializedName("aaf_identity")
private String aafUsername;
- @GSONRequired
@SerializedName("aaf_password")
private String aafPassword;
", publisherConfig=" + publisherConfig +
'}';
}
-}
\ No newline at end of file
+}
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
+ * Copyright (C) 2022 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.
@SerializedName("topic_url")
private String topicUrl;
- @GSONRequired
@SerializedName("client_role")
private String clientRole;
- @GSONRequired
@SerializedName("client_id")
private String clientId;
- @GSONRequired
@SerializedName("location")
private String clusterLocation;
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
+ * Copyright (C) 2022 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.
@Data
public class SubscriberConfig {
- @GSONRequired
+
@SerializedName("username")
private String username;
- @GSONRequired
@SerializedName("password")
private String password;
- @GSONRequired
@SerializedName("location")
private String drLocation;
* ============LICENSE_START=======================================================
* Copyright (C) 2019-2020 Nordix Foundation.
* Copyright (C) 2021 Samsung Electronics.
+ * Copyright (C) 2022 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.
import org.onap.dcaegen2.services.pmmapper.exceptions.CreateContextException;
import org.onap.dcaegen2.services.pmmapper.exceptions.KeyManagerException;
import org.onap.dcaegen2.services.pmmapper.exceptions.LoadKeyStoreException;
+import org.onap.dcaegen2.services.pmmapper.exceptions.MapperConfigException;
import org.onap.dcaegen2.services.pmmapper.exceptions.TrustManagerException;
import org.onap.dcaegen2.services.pmmapper.model.MapperConfig;
import org.onap.logging.ref.slf4j.ONAPLogAdapter;
public class SSLContextFactory {
private static final ONAPLogAdapter logger = new ONAPLogAdapter(LoggerFactory.getLogger(SSLContextFactory.class));
- private MapperConfig mapperConfig;
+ private final MapperConfig mapperConfig;
public SSLContextFactory(MapperConfig config) {
mapperConfig = config;
}
public SSLContext createSSLContext(MapperConfig mapperConfig) throws IOException {
- SSLContext sslContext = null;
+ logger.unwrap().info("Attempt to Create SSL Context");
+ if (isSslDisabled(mapperConfig)) {
+ logger.unwrap().warn("SSL is disabled. Skip creating SSL Context");
+ return null;
+ }
try {
KeyStore keyStore = loadKeyStore(mapperConfig.getKeyStorePath(), mapperConfig.getKeyStorePassPath());
KeyStore trustStore = loadKeyStore(mapperConfig.getTrustStorePath(), mapperConfig.getTrustStorePassPath());
TrustManager[] trustManagers = createTrustManager(trustStore);
- sslContext = SSLContext.getInstance("TLSv1.2");
+ SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(keyManagers, trustManagers, null);
+ return sslContext;
} catch(KeyManagementException | NoSuchAlgorithmException e) {
logger.unwrap().error("Failed to create SSL Context.", e);
throw new CreateContextException("Failed to create SSL Context", e);
}
- return sslContext;
}
+ private boolean isSslDisabled(MapperConfig mapperConfig) {
+ boolean isCertPathMissing = !areCertPathsConfigured(mapperConfig);
+ if (isCertPathMissing && !mapperConfig.getEnableHttp()) {
+ throw new MapperConfigException("Certificate paths are missing, HTTP is disabled. Not allowed configuration");
+ }
+
+ return isCertPathMissing;
+ }
+
+ private boolean areCertPathsConfigured(MapperConfig mapperConfig) {
+ return isNotBlank(mapperConfig.getKeyStorePath()) &&
+ isNotBlank(mapperConfig.getKeyStorePassPath()) &&
+ isNotBlank(mapperConfig.getTrustStorePath()) &&
+ isNotBlank(mapperConfig.getTrustStorePassPath());
+ }
+
+ private boolean isNotBlank(String str) {
+ return str != null && !str.isEmpty();
+ }
+
+
private KeyManager[] createKeyManager(KeyStore keyStore) throws NoSuchAlgorithmException, IOException {
KeyManager[] keyManager;
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nokia.
+ * Copyright (C) 2021-2022 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.
import io.vavr.control.Try;
import org.onap.dcaegen2.services.sdk.model.streams.AafCredentials;
import org.onap.dcaegen2.services.sdk.model.streams.dmaap.ImmutableMessageRouterSink;
+import org.onap.dcaegen2.services.sdk.model.streams.dmaap.ImmutableMessageRouterSink.Builder;
import org.onap.dcaegen2.services.sdk.model.streams.dmaap.MessageRouterSink;
import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.ContentType;
import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.api.DmaapClientFactory;
}
private static MessageRouterSink sink(String topicUrl, AafCredentials credentials) {
- return ImmutableMessageRouterSink.builder()
- .aafCredentials(credentials)
- .topicUrl(topicUrl)
- .build();
+ Builder builder = ImmutableMessageRouterSink.builder();
+ if (credentialsExists(credentials)) {
+ builder.aafCredentials(credentials);
+ }
+ return builder.topicUrl(topicUrl).build();
+ }
+
+ private static boolean credentialsExists(AafCredentials credentials) {
+ return isNotBlank(credentials.username()) && isNotBlank(credentials.password());
+ }
+
+ private static boolean isNotBlank(String str) {
+ return str != null && !str.isEmpty();
}
private static RequestDiagnosticContext diagnosticContext() {
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
- * Copyright (C) 2022 Nokia.
+ * Copyright (C) 2022 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.
*/
package org.onap.dcaegen2.services.pmmapper.config;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
private static String validMapperConfigChanged;
private static final Path INVALID_CONFIGS_DIRECTORY = Paths.get("src/test/resources/invalid_configs/");
+ private static final Path MISSING_OPTIONAL_FIELDS_CONFIGS_DIRECTORY =
+ Paths.get("src/test/resources/missing_optional_fields/");
private static final String EXPECTED_ERROR_MESSAGE_IN_LOG = "Error parsing configuration";
private static final String EXPECTED_CHANGED_VALUE = "https://dmaap-dr-node:8443/delete_changed";
logAppender.stop();
}
+ @ParameterizedTest
+ @MethodSource("getConfigsWithMissingOptionalFields")
+ void should_parse_json_with_missing_optional_fields(String mapperConfig) {
+ Mono<JsonObject> just = createMonoJsonObject(mapperConfig);
+
+ when(cbsClient.get(any())).thenReturn(just);
+ ConfigHandler configHandler = new ConfigHandler(cbsClient, cbsRequest);
+
+ assertDoesNotThrow(configHandler::getInitialConfiguration);
+ }
+
@ParameterizedTest
@MethodSource("getInvalidConfigs")
void parse_valid_json_bad_values_mapper_config(String mapperConfig) throws Exception {
private static List<String> getInvalidConfigs() throws IOException {
return FileUtils.getFilesFromDirectory(INVALID_CONFIGS_DIRECTORY);
}
+
+ private static List<String> getConfigsWithMissingOptionalFields() throws IOException {
+ return FileUtils.getFilesFromDirectory(MISSING_OPTIONAL_FIELDS_CONFIGS_DIRECTORY);
+ }
}
/*-
* ============LICENSE_START=======================================================
* Copyright (C) 2019 Nordix Foundation.
+ * Copyright (C) 2022 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.
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
+import java.util.ArrayList;
+import java.util.List;
+import javax.net.ssl.SSLContext;
import org.junit.Rule;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
import org.junit.rules.ExpectedException;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.dcaegen2.services.pmmapper.exceptions.MapperConfigException;
import org.onap.dcaegen2.services.pmmapper.model.MapperConfig;
-import javax.net.ssl.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class SSLContextFactoryTest {
+ private static final String TEST_PATH = "";
+
@Rule
public ExpectedException exception = ExpectedException.none();
private static MapperConfig validConfig;
private static MapperConfig inValidConfig;
-
private static final Path validConfigPath = Paths.get("src/test/resources/valid_mapper_config.json");
private SSLContextFactory objUnderTest;
assertThrows(IOException.class, () -> objUnderTest.createSSLContext(inValidConfig));
}
-}
\ No newline at end of file
+
+ @Test
+ void shouldThrowExceptionWhenCertPathAreMissingButHttpIsDisabled() {
+ MapperConfig mapperConfig = mock(MapperConfig.class);
+ when(mapperConfig.getKeyStorePath()).thenReturn(TEST_PATH);
+ when(mapperConfig.getEnableHttp()).thenReturn(false);
+
+ SSLContextFactory sslContextFactory = new SSLContextFactory(mapperConfig);
+
+ assertThrows(MapperConfigException.class, () -> sslContextFactory.createSSLContext(mapperConfig));
+ }
+
+
+ @ParameterizedTest
+ @MethodSource("pathsAreNull")
+ void shouldReturnNullWhenOneCertPathIsNull(MapperConfig mapperConfig) throws IOException {
+ SSLContextFactory sslContextFactory = new SSLContextFactory(mapperConfig);
+ SSLContext sslContext = sslContextFactory.createSSLContext(mapperConfig);
+
+ assertNull(sslContext);
+ }
+
+ @ParameterizedTest
+ @MethodSource("pathsAreEmpty")
+ void shouldReturnNullWhenOneCertPathIsEmpty(MapperConfig mapperConfig) throws IOException {
+ SSLContextFactory sslContextFactory = new SSLContextFactory(mapperConfig);
+ SSLContext sslContext = sslContextFactory.createSSLContext(mapperConfig);
+
+ assertNull(sslContext);
+ }
+
+ private static List<MapperConfig> pathsAreNull() {
+ return mockMapperConfigList(null);
+ }
+
+ private static List<MapperConfig> pathsAreEmpty() {
+ return mockMapperConfigList("");
+ }
+
+ private static List<MapperConfig> mockMapperConfigList(String returnValue) {
+ List<MapperConfig> mapperConfigList = new ArrayList<>();
+
+ MapperConfig mapperConfig1 = mock(MapperConfig.class);
+ when(mapperConfig1.getKeyStorePath()).thenReturn(returnValue);
+ when(mapperConfig1.getEnableHttp()).thenReturn(true);
+ mapperConfigList.add(mapperConfig1);
+
+ MapperConfig mapperConfig2 = mock(MapperConfig.class);
+ when(mapperConfig2.getKeyStorePassPath()).thenReturn(returnValue);
+ when(mapperConfig2.getEnableHttp()).thenReturn(true);
+ mapperConfigList.add(mapperConfig2);
+
+ MapperConfig mapperConfig3 = mock(MapperConfig.class);
+ when(mapperConfig3.getTrustStorePath()).thenReturn(returnValue);
+ when(mapperConfig3.getEnableHttp()).thenReturn(true);
+ mapperConfigList.add(mapperConfig3);
+
+ MapperConfig mapperConfig4 = mock(MapperConfig.class);
+ when(mapperConfig4.getTrustStorePassPath()).thenReturn(returnValue);
+ when(mapperConfig4.getEnableHttp()).thenReturn(true);
+ mapperConfigList.add(mapperConfig4);
+
+ return mapperConfigList;
+ }
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
}
}
}
-}
\ No newline at end of file
+}
dmaap_dr_feed_name: "1"
aaf_identity: "aaf_admin@people.osaaf.org"
aaf_password: "demo123456!"
-enable_http: true,
+enable_http: true
streams_publishes:
dmaap_publisher:
type: "message_router"