From f8ce5f7332bd79b584ddd45ed8062cfdb5a938f3 Mon Sep 17 00:00:00 2001 From: Jan Malkiewicz Date: Fri, 18 Sep 2020 09:53:12 +0200 Subject: [OOM-CMPv2] Rename module folder truststoreMerger -> certServicePostProcessor Issue-ID: DCAEGEN2-2253 Signed-off-by: Jan Malkiewicz Change-Id: I975f37507f7f79c238f1eac15f375fe64761c80c --- certServicePostProcessor/Dockerfile | 16 ++ certServicePostProcessor/README.md | 87 +++++++++ certServicePostProcessor/pom.xml | 177 ++++++++++++++++++ .../oom/certservice/postprocessor/AppExecutor.java | 54 ++++++ .../certservice/postprocessor/AppExitHandler.java | 34 ++++ .../postprocessor/CertificatePostProcessor.java | 47 +++++ .../oom/certservice/postprocessor/MainApp.java | 27 +++ .../postprocessor/api/CertificateConstants.java | 31 ++++ .../certservice/postprocessor/api/ExitStatus.java | 56 ++++++ .../postprocessor/api/ExitableException.java | 40 ++++ .../postprocessor/common/ExtensionResolver.java | 42 +++++ .../postprocessor/common/FileTools.java | 52 ++++++ .../postprocessor/common/PasswordReader.java | 41 ++++ .../configuration/AppConfigurationLoader.java | 33 ++++ .../configuration/AppConfigurationProvider.java | 82 ++++++++ .../CertificatesPathsValidationException.java | 30 +++ .../exception/ConfigurationException.java | 30 +++ .../configuration/model/AppConfiguration.java | 56 ++++++ .../configuration/model/EnvVariable.java | 51 +++++ .../configuration/path/DelimitedPathsSplitter.java | 49 +++++ .../configuration/path/env/EnvReader.java | 39 ++++ .../path/validation/ValidationFunctions.java | 57 ++++++ .../postprocessor/copier/KeystoreCopier.java | 74 ++++++++ .../exception/KeystoreFileCopyException.java | 31 ++++ .../exception/KeystoreNotExistException.java | 31 ++++ .../merger/TruststoreFilesProvider.java | 46 +++++ .../postprocessor/merger/TruststoreMerger.java | 54 ++++++ .../merger/exception/AliasConflictException.java | 31 ++++ .../merger/exception/CreateBackupException.java | 30 +++ .../exception/KeystoreInstanceException.java | 30 +++ .../merger/exception/LoadTruststoreException.java | 30 +++ .../exception/MissingTruststoreException.java | 30 +++ .../merger/exception/PasswordReaderException.java | 29 +++ .../TruststoreDataOperationException.java | 30 +++ .../exception/TruststoreFileFactoryException.java | 30 +++ .../exception/WriteTruststoreFileException.java | 31 ++++ .../postprocessor/merger/model/JavaTruststore.java | 166 +++++++++++++++++ .../merger/model/JavaTruststoreFactory.java | 48 +++++ .../postprocessor/merger/model/PemTruststore.java | 156 ++++++++++++++++ .../postprocessor/merger/model/Truststore.java | 47 +++++ .../merger/model/TruststoreFactory.java | 64 +++++++ .../model/certificate/CertificateWithAlias.java | 41 ++++ .../certificate/CertificateWithAliasFactory.java | 33 ++++ .../model/certificate/PemAliasGenerator.java | 42 +++++ .../src/main/resources/log4j2.xml | 30 +++ .../certservice/postprocessor/AppExecutorTest.java | 76 ++++++++ .../common/ExtensionResolverTest.java | 44 +++++ .../postprocessor/common/FileToolsTest.java | 71 +++++++ .../postprocessor/common/PasswordReaderTest.java | 43 +++++ .../AppConfigurationProviderTest.java | 141 ++++++++++++++ .../path/DelimitedPathsSplitterTest.java | 107 +++++++++++ .../configuration/path/env/EnvReaderTest.java | 62 +++++++ .../path/validation/ValidationFunctionsTest.java | 135 ++++++++++++++ .../postprocessor/copier/KeystoreCopierTest.java | 147 +++++++++++++++ .../merger/TruststoreFilesProviderTest.java | 63 +++++++ .../merger/model/JavaTruststoreTest.java | 56 ++++++ .../merger/model/PemTruststoreTest.java | 128 +++++++++++++ .../merger/model/TestCertificateProvider.java | 152 +++++++++++++++ .../merger/model/TruststoreFactoryTest.java | 109 +++++++++++ .../postprocessor/merger/model/TruststoreTest.java | 206 +++++++++++++++++++++ .../model/certificate/PemAliasGeneratorTest.java | 58 ++++++ .../src/test/resources/empty-truststore.pem | 1 + .../src/test/resources/keystore.p12 | Bin 0 -> 2873 bytes .../src/test/resources/keystore.pass | 1 + .../src/test/resources/truststore-jks-uniq.jks | Bin 0 -> 1530 bytes .../src/test/resources/truststore-jks.jks | Bin 0 -> 1285 bytes .../src/test/resources/truststore-jks.pass | 1 + .../src/test/resources/truststore-p12.p12 | Bin 0 -> 1530 bytes .../src/test/resources/truststore-p12.pass | 1 + .../test/resources/truststore-with-private-key.pem | 56 ++++++ .../src/test/resources/truststore.pem | 28 +++ 71 files changed, 3951 insertions(+) create mode 100644 certServicePostProcessor/Dockerfile create mode 100644 certServicePostProcessor/README.md create mode 100644 certServicePostProcessor/pom.xml create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExecutor.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExitHandler.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/CertificatePostProcessor.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/MainApp.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/CertificateConstants.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitStatus.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitableException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolver.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/FileTools.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/PasswordReader.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationLoader.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProvider.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/CertificatesPathsValidationException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/ConfigurationException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/AppConfiguration.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/EnvVariable.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitter.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReader.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctions.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopier.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreFileCopyException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreNotExistException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProvider.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreMerger.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/AliasConflictException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/CreateBackupException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/KeystoreInstanceException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/LoadTruststoreException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/MissingTruststoreException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/PasswordReaderException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreDataOperationException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreFileFactoryException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/WriteTruststoreFileException.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststore.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreFactory.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststore.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/Truststore.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactory.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAlias.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAliasFactory.java create mode 100644 certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGenerator.java create mode 100644 certServicePostProcessor/src/main/resources/log4j2.xml create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/AppExecutorTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolverTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/FileToolsTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/PasswordReaderTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProviderTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitterTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReaderTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctionsTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopierTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProviderTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststoreTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TestCertificateProvider.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactoryTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreTest.java create mode 100644 certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGeneratorTest.java create mode 100644 certServicePostProcessor/src/test/resources/empty-truststore.pem create mode 100644 certServicePostProcessor/src/test/resources/keystore.p12 create mode 100644 certServicePostProcessor/src/test/resources/keystore.pass create mode 100644 certServicePostProcessor/src/test/resources/truststore-jks-uniq.jks create mode 100644 certServicePostProcessor/src/test/resources/truststore-jks.jks create mode 100644 certServicePostProcessor/src/test/resources/truststore-jks.pass create mode 100644 certServicePostProcessor/src/test/resources/truststore-p12.p12 create mode 100644 certServicePostProcessor/src/test/resources/truststore-p12.pass create mode 100644 certServicePostProcessor/src/test/resources/truststore-with-private-key.pem create mode 100644 certServicePostProcessor/src/test/resources/truststore.pem (limited to 'certServicePostProcessor') diff --git a/certServicePostProcessor/Dockerfile b/certServicePostProcessor/Dockerfile new file mode 100644 index 00000000..8f0f2481 --- /dev/null +++ b/certServicePostProcessor/Dockerfile @@ -0,0 +1,16 @@ +FROM docker.io/openjdk:11-jre-slim + +ARG VERSION=${version} + +RUN groupadd onap && useradd -g onap truststoreMerger + +RUN chown -R truststoreMerger:onap /var/log + +USER truststoreMerger:onap + +COPY target/oom-truststore-merger-${VERSION}.jar ./opt/onap/oom/truststoremerger/oom-truststore-merger.jar + +#Run as root allow to manage certificates provided by other containers. It should be change in future +USER root + +ENTRYPOINT ["java","-jar","./opt/onap/oom/truststoremerger/oom-truststore-merger.jar"] diff --git a/certServicePostProcessor/README.md b/certServicePostProcessor/README.md new file mode 100644 index 00000000..5a2c2b47 --- /dev/null +++ b/certServicePostProcessor/README.md @@ -0,0 +1,87 @@ +# Truststore merger + +### Project building +``` +mvn clean package +``` + +### Install the package into the local repository +``` +mvn clean install +``` + +### Building Docker image and install the package into the local repository +``` +mvn clean install -P docker +``` + +### Nexus container image +``` +nexus3.onap.org:10001/onap/org.onap.oom.platform.cert-service.oom-truststore-merger:latest +``` + +### Running application as standalone docker container + +Exemplary config.env file with necessary envs +``` +TRUSTSTORES_PATHS=/var/certs/truststore.jks:/var/certs/truststore.pem +TRUSTSTORES_PASSWORDS_PATHS=/var/certs/truststoreJks.pass: +KEYSTORE_SOURCE_PATHS=/var/certs/external/keystore.jks:/var/certs/external/keystore.pass +KEYSTORE_DESTINATION_PATHS=/var/certs/cert.jks:/var/certs/jks.pass +``` +TRUSTSTORES_PATHS env indicates paths (separated by ":") where truststores files are located. + +TRUSTSTORES_PASSWORDS_PATHS env indicates paths (separated by ":") where files with passwords to truststores are located. +PEM is not protected by password so its value should be empty + +KEYSTORE_SOURCE_PATHS env (optional) indicates paths (separated by ":") where files to copy are located. + +KEYSTORE_DESTINATION_PATHS env (optional) indicates paths (separated by ":") to files which should be replaced. Before keystore files override, destination files will be copied with addition of .bak extension. + +Execute below command in order to run app as docker container +``` +docker run \ + --name oom-truststore-merger \ + --env-file ./config.env \ + --mount type=bind,src=,dst=/var/certs \ +onap/org.onap.oom.platform.cert-service.oom-truststore-merger:latest +``` +Before run replace with absolute path where you located truststores to merge (eg. /certs/resources/) + +Output from merger (when pointed more than one truststore to merge in TRUSTSTORES_PATHS env and provided optional envs) success execution should be: +1. Created backup file (with .bak ext) of first truststore pointed in TRUSTSTORES_PATHS env +2. Keystores files listed in KEYSTORE_SOURCE_PATHS env overrides corresponding to them files defined in KEYSTORE_DESTINATION_PATHS env. +3. Keystores listed in KEYSTORE_SOURCE_PATHS env are in locations taken from KEYSTORE_DESTINATION_PATHS env. Files listed in KEYSTORE_DESTINATION_PATHS env before application run, still exist with appended .bak extension. + +Remove docker container: +``` +docker rm oom-truststore-merger +``` + +### Logs locally + +path: +``` +var/log/onap/oom/truststore-merger/truststore-merger.log +``` +### Logs in Docker container +``` +docker logs oom-merger +``` +###Exit codes +``` +0 Success +1 Invalid paths in environment variables +2 Invalid merger configuration +3 Invalid truststore file-password pair +4 Cannot read password from file +5 Cannot create backup file +6 Cannot initialize keystore instance +7 Cannot load truststore file +8 Cannot operate on truststore data +9 Missing truststore certificates in provided file +10 Alias conflict detected +11 Cannot save truststore file +12 Cannot copy keystore file +13 Keystore file does not exist +99 Application exited abnormally diff --git a/certServicePostProcessor/pom.xml b/certServicePostProcessor/pom.xml new file mode 100644 index 00000000..d150a9b3 --- /dev/null +++ b/certServicePostProcessor/pom.xml @@ -0,0 +1,177 @@ + + + + oom-certservice + org.onap.oom.platform.cert-service + 2.0.0-SNAPSHOT + + 4.0.0 + + oom-truststore-merger + 2.0.0-SNAPSHOT + oom-truststore-merger + Truststore merging application + jar + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + docker-staging + + ${project.version}-STAGING-${maven.build.timestamp} + ${project.version}-STAGING-latest + + + + + docker + + false + + + linux + x86_64 + ${os.detected.name}-${os.detected.arch} + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + package + + shade + + + false + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + org.onap.oom.certservice.postprocessor.MainApp + + + + + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + docker-build-image + package + + build + + + + docker-push-image + deploy + + push + + + + + ${skipDockerPush} + true + IfNotPresent + + + ${project.artifactId} + ${docker-image.namespace}/${docker-image.name}:${docker-image.tag.latest} + + ${docker-image.registry} + + ${project.basedir} + + ${project.version}-${maven.build.timestamp}Z + + + + + + + + + + + + + + ecomp-releases + ONAP Release Repository + ${nexusproxy}${releaseNexusPath} + + + ecomp-snapshots + ONAP Snapshot Repository + ${nexusproxy}${snapshotNexusPath} + + + ecomp-site + dav:${nexusproxy}${sitePath} + + + + + + + commons-io + commons-io + + + org.assertj + assertj-core + + + org.junit.jupiter + junit-jupiter + + + org.mockito + mockito-core + + + org.mockito + mockito-junit-jupiter + + + org.slf4j + slf4j-api + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.bouncycastle + bcpkix-jdk15on + + + diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExecutor.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExecutor.java new file mode 100644 index 00000000..2ef30b68 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExecutor.java @@ -0,0 +1,54 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppExecutor { + + private static final Logger LOGGER = LoggerFactory.getLogger(AppExecutor.class); + + private AppExitHandler exitHandler; + + AppExecutor() { + this(new AppExitHandler()); + } + + AppExecutor(AppExitHandler exitHandler) { + this.exitHandler = exitHandler; + } + + + public void execute(Runnable logic) { + try { + logic.run(); + exitHandler.exit(ExitStatus.SUCCESS); + } catch (ExitableException e) { + LOGGER.error("Application failed: ", e); + exitHandler.exit(e.applicationExitStatus()); + } catch (Exception e) { + LOGGER.error("Application failed (unexpected error): ", e); + exitHandler.exit(ExitStatus.UNEXPECTED_EXCEPTION); + } + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExitHandler.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExitHandler.java new file mode 100644 index 00000000..15677dc4 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/AppExitHandler.java @@ -0,0 +1,34 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AppExitHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(AppExitHandler.class); + + public void exit(ExitStatus exitStatus) { + LOGGER.info("Application exits with code [{}] and message: {}", + exitStatus.getExitCodeValue(), exitStatus.getMessage()); + System.exit(exitStatus.getExitCodeValue()); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/CertificatePostProcessor.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/CertificatePostProcessor.java new file mode 100644 index 00000000..b9038227 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/CertificatePostProcessor.java @@ -0,0 +1,47 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor; + +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.configuration.AppConfigurationLoader; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.copier.KeystoreCopier; +import org.onap.oom.certservice.postprocessor.merger.TruststoreMerger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class CertificatePostProcessor implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(CertificatePostProcessor.class); + + private AppConfigurationLoader config = new AppConfigurationLoader(); + private TruststoreMerger merger = new TruststoreMerger(); + private KeystoreCopier copier = new KeystoreCopier(new FileTools()); + + public void run() { + LOGGER.debug("Loading configuration..."); + AppConfiguration configuration = config.loadConfiguration(); + LOGGER.debug("Starting TruststoreMerger..."); + merger.mergeTruststores(configuration); + LOGGER.debug("Starting KeystoreCopier..."); + copier.copyKeystores(configuration); + LOGGER.debug("Certificate post processing finished successfully."); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/MainApp.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/MainApp.java new file mode 100644 index 00000000..f815f489 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/MainApp.java @@ -0,0 +1,27 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor; + +public class MainApp { + + public static void main(String[] args) { + new AppExecutor().execute(new CertificatePostProcessor()); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/CertificateConstants.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/CertificateConstants.java new file mode 100644 index 00000000..3442621b --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/CertificateConstants.java @@ -0,0 +1,31 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.api; + +public class CertificateConstants { + + private CertificateConstants() { } + + public static final String JKS_TYPE = "JKS"; + public static final String PKCS12_TYPE = "PKCS12"; + public static final String X_509_CERTIFICATE = "X.509"; + public static final String BOUNCY_CASTLE_PROVIDER = "BC"; + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitStatus.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitStatus.java new file mode 100644 index 00000000..b6cebeb1 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitStatus.java @@ -0,0 +1,56 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.api; + +public enum ExitStatus { + + SUCCESS(0, "Success"), + CERTIFICATES_PATHS_VALIDATION_EXCEPTION(1, "Invalid paths in environment variables"), + CONFIGURATION_EXCEPTION(2, "Invalid merger configuration"), + TRUSTSTORE_FILE_FACTORY_EXCEPTION(3, "Invalid truststore file-password pair"), + PASSWORD_READER_EXCEPTION(4, "Cannot read password from file"), + CREATE_BACKUP_EXCEPTION(5, "Cannot create backup file"), + KEYSTORE_INSTANCE_EXCEPTION(6, "Cannot initialize keystore instance"), + TRUSTSTORE_LOAD_FILE_EXCEPTION(7, "Cannot load truststore file"), + TRUSTSTORE_DATA_OPERATION_EXCEPTION(8, "Cannot operate on truststore data"), + MISSING_TRUSTSTORE_EXCEPTION(9, "Missing truststore certificates in provided file"), + ALIAS_CONFLICT_EXCEPTION(10, "Alias conflict detected"), + WRITE_TRUSTSTORE_FILE_EXCEPTION(11, "Cannot save truststore file"), + KEYSTORE_FILE_COPY_EXCEPTION(12, "Cannot copy keystore file"), + KEYSTORE_NOT_EXIST_EXCEPTION(13, "Keystore file does not exist"), + UNEXPECTED_EXCEPTION(99, "Application exited abnormally"); + + + private final int value; + private final String message; + + ExitStatus(int value, String message) { + this.value = value; + this.message = message; + } + + public int getExitCodeValue() { + return value; + } + + public String getMessage() { + return message; + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitableException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitableException.java new file mode 100644 index 00000000..54a7c6a1 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/api/ExitableException.java @@ -0,0 +1,40 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.api; + +public class ExitableException extends RuntimeException { + + private final ExitStatus exitStatus; + + public ExitableException(Throwable cause, ExitStatus exitStatus) { + super(cause); + this.exitStatus = exitStatus; + } + + public ExitableException(String message, ExitStatus exitStatus) { + super(message); + this.exitStatus = exitStatus; + } + + public ExitStatus applicationExitStatus() { + return exitStatus; + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolver.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolver.java new file mode 100644 index 00000000..7a785ae1 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolver.java @@ -0,0 +1,42 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import java.io.File; + +public final class ExtensionResolver { + + private static final int INDEX_NOT_FOUND = -1; + + private ExtensionResolver() {} + + public static String get(File file) { + int extStartIndex = file.getName().lastIndexOf("."); + if (extStartIndex == INDEX_NOT_FOUND) { + return ""; + } + return file.getName().substring(extStartIndex).toLowerCase(); + } + + public static boolean checkIfFileExists(File file) { + return file.exists(); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/FileTools.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/FileTools.java new file mode 100644 index 00000000..620d8088 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/FileTools.java @@ -0,0 +1,52 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import java.io.File; +import java.io.IOException; +import org.apache.commons.io.FileUtils; +import org.onap.oom.certservice.postprocessor.merger.exception.CreateBackupException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class FileTools { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileTools.class); + private static final String BACKUP_EXTENSION = ".bak"; + + public void createBackup(File file) throws CreateBackupException { + LOGGER.debug("Try to create a backup of the file: {}", file.getPath()); + File backupFile = new File(file.getAbsolutePath() + BACKUP_EXTENSION); + try { + copy(file, backupFile); + } catch (IOException e) { + LOGGER.error("Could not create backup of the file: '{}'", file.getPath()); + throw new CreateBackupException(e); + } + LOGGER.debug("Backup file created: '{}'", backupFile.getAbsolutePath()); + } + + public void copy(File source, File destination) throws IOException { + LOGGER.debug("Try to copy from '{}' to '{}'.", source.getAbsolutePath(), destination.getAbsolutePath()); + FileUtils.copyFile(source, destination); + LOGGER.debug("File copied from '{}' to '{}'.", source.getAbsolutePath(), + destination.getAbsolutePath()); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/PasswordReader.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/PasswordReader.java new file mode 100644 index 00000000..6e4a5f3a --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/common/PasswordReader.java @@ -0,0 +1,41 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; + +public final class PasswordReader { + + private static final String COULD_NOT_READ_PASSWORD_FROM_FILE_MSG_TEMPLATE = "Could not read password from file: %s"; + + private PasswordReader() { + } + + public static String readPassword(File file) { + try { + return Files.readString(file.toPath()); + } catch (IOException e) { + throw new PasswordReaderException(String.format(COULD_NOT_READ_PASSWORD_FROM_FILE_MSG_TEMPLATE, file)); + } + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationLoader.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationLoader.java new file mode 100644 index 00000000..a3f49d86 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationLoader.java @@ -0,0 +1,33 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration; + +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.configuration.path.DelimitedPathsSplitter; +import org.onap.oom.certservice.postprocessor.configuration.path.env.EnvReader; + +public class AppConfigurationLoader { + + public AppConfiguration loadConfiguration() { + DelimitedPathsSplitter pathsSplitter = new DelimitedPathsSplitter(); + AppConfigurationProvider factory = new AppConfigurationProvider(pathsSplitter, new EnvReader()); + return factory.createConfiguration(); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProvider.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProvider.java new file mode 100644 index 00000000..1e9ef8a9 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProvider.java @@ -0,0 +1,82 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration; + + +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.KEYSTORE_DESTINATION_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.KEYSTORE_SOURCE_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PASSWORDS_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PATHS; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.onap.oom.certservice.postprocessor.configuration.path.env.EnvReader; +import org.onap.oom.certservice.postprocessor.configuration.exception.ConfigurationException; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable; +import org.onap.oom.certservice.postprocessor.configuration.path.DelimitedPathsSplitter; + +public class AppConfigurationProvider { + + private final EnvReader envReader; + private final DelimitedPathsSplitter pathsSplitter; + + public AppConfigurationProvider(DelimitedPathsSplitter pathsSplitter, EnvReader envReader) { + this.envReader = envReader; + this.pathsSplitter = pathsSplitter; + } + + public AppConfiguration createConfiguration() { + List truststoresPaths = getPaths(TRUSTSTORES_PATHS); + List truststoresPasswordsPaths = getPaths(TRUSTSTORES_PASSWORDS_PATHS); + List sourceKeystorePaths = getPaths(KEYSTORE_SOURCE_PATHS); + List destinationKeystorePaths = getPaths(KEYSTORE_DESTINATION_PATHS); + + ensureSameSize(truststoresPaths, truststoresPasswordsPaths, TRUSTSTORES_PATHS.name(), + TRUSTSTORES_PASSWORDS_PATHS.name()); + ensureSameSize(sourceKeystorePaths, destinationKeystorePaths, KEYSTORE_SOURCE_PATHS.name(), + KEYSTORE_DESTINATION_PATHS.name()); + + return new AppConfiguration(truststoresPaths, truststoresPasswordsPaths, sourceKeystorePaths, + destinationKeystorePaths); + } + + private List getPaths(EnvVariable envVariable) { + Optional envValue = envReader.getEnv(envVariable.name()); + isMandatoryEnvPresent(envVariable, envValue); + return envValue.isPresent() ? pathsSplitter.getValidatedPaths(envVariable, envValue) : Collections.emptyList(); + } + + private void isMandatoryEnvPresent(EnvVariable envVariable, Optional envValue) { + if (envVariable.isMandatory() && envValue.isEmpty()) { + throw new ConfigurationException(envVariable + " mandatory environment variable is not defined"); + } + } + + private void ensureSameSize(List firstList, List secondList, String firstListEnvName, + String secondListEnvName) { + if (firstList.size() != secondList.size()) { + throw new ConfigurationException( + "Size of " + firstListEnvName + + " does not match size of " + secondListEnvName + " environment variables"); + } + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/CertificatesPathsValidationException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/CertificatesPathsValidationException.java new file mode 100644 index 00000000..fb621017 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/CertificatesPathsValidationException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class CertificatesPathsValidationException extends ExitableException { + + public CertificatesPathsValidationException(String errorMessage) { + super(errorMessage, ExitStatus.CERTIFICATES_PATHS_VALIDATION_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/ConfigurationException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/ConfigurationException.java new file mode 100644 index 00000000..c9f9a416 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/exception/ConfigurationException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class ConfigurationException extends ExitableException { + + public ConfigurationException(String errorMessage) { + super(errorMessage, ExitStatus.CONFIGURATION_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/AppConfiguration.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/AppConfiguration.java new file mode 100644 index 00000000..d28dcac5 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/AppConfiguration.java @@ -0,0 +1,56 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.model; + +import java.util.Collections; +import java.util.List; + +public final class AppConfiguration { + private final List truststoreFilePaths; + private final List truststoreFilePasswordPaths; + private final List sourceKeystorePaths; + private final List destinationKeystorePaths; + + public AppConfiguration(List truststoreFilePaths, + List truststoreFilePasswordPaths, List sourceKeystorePaths, + List destinationKeystorePaths) { + this.truststoreFilePaths = List.copyOf(truststoreFilePaths); + this.truststoreFilePasswordPaths = List.copyOf(truststoreFilePasswordPaths); + this.sourceKeystorePaths = List.copyOf(sourceKeystorePaths); + this.destinationKeystorePaths = List.copyOf(destinationKeystorePaths); + } + + public List getTruststoreFilePaths() { + return Collections.unmodifiableList(truststoreFilePaths); + } + + public List getTruststoreFilePasswordPaths() { + return Collections.unmodifiableList(truststoreFilePasswordPaths); + } + + + public List getDestinationKeystorePaths() { + return Collections.unmodifiableList(destinationKeystorePaths); + } + + public List getSourceKeystorePaths() { + return Collections.unmodifiableList(sourceKeystorePaths); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/EnvVariable.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/EnvVariable.java new file mode 100644 index 00000000..be49d39c --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/model/EnvVariable.java @@ -0,0 +1,51 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.model; + +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidCertificatesPaths; +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidPasswordPaths; +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidPathsToCopy; + +import java.util.List; +import java.util.function.Predicate; + +public enum EnvVariable { + TRUSTSTORES_PATHS(true, doesItContainValidCertificatesPaths()), + TRUSTSTORES_PASSWORDS_PATHS(true, doesItContainValidPasswordPaths()), + KEYSTORE_SOURCE_PATHS(false, doesItContainValidPathsToCopy()), + KEYSTORE_DESTINATION_PATHS(false, doesItContainValidPathsToCopy()); + + boolean isMandatory; + + Predicate> validationFunction; + + EnvVariable(boolean isMandatory, Predicate> validationFunction) { + this.isMandatory = isMandatory; + this.validationFunction = validationFunction; + } + + public boolean isMandatory() { + return isMandatory; + } + + public Predicate> getValidationFunction() { + return validationFunction; + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitter.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitter.java new file mode 100644 index 00000000..b2e71cb3 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitter.java @@ -0,0 +1,49 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import org.onap.oom.certservice.postprocessor.configuration.exception.CertificatesPathsValidationException; +import org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable; + +public class DelimitedPathsSplitter { + + private static final String DELIMITER = ":"; + private static final int NEGATIVE_SPLIT_LIMIT = -1; + + public List getValidatedPaths(EnvVariable envVariable, Optional envValue) + throws CertificatesPathsValidationException { + return envValue.filter(this::hasValue) + .map(this::splitToList) + .filter(envVariable.getValidationFunction()) + .orElseThrow(() -> new CertificatesPathsValidationException( + envVariable + " environment variable does not contain valid paths")); + } + + private boolean hasValue(String envValue) { + return !envValue.isEmpty(); + } + + private List splitToList(String stringToSplit) { + return Arrays.asList(stringToSplit.split(DELIMITER, NEGATIVE_SPLIT_LIMIT)); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReader.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReader.java new file mode 100644 index 00000000..f30e43be --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReader.java @@ -0,0 +1,39 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path.env; + +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EnvReader { + + private static final Logger LOGGER = LoggerFactory.getLogger(EnvReader.class); + + public Optional getEnv(String name) { + return getSystemEnv(name); + } + + Optional getSystemEnv(String name) { + String value = System.getenv(name); + LOGGER.info("Read variable: {} , value: {}", name, value); + return Optional.ofNullable(value); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctions.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctions.java new file mode 100644 index 00000000..f65a21a0 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctions.java @@ -0,0 +1,57 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path.validation; + +import java.util.List; +import java.util.function.Predicate; + +public final class ValidationFunctions { + + private static final String CERTIFICATE_PATH_REGEX = "^(/[a-zA-Z0-9_-]+)+\\.(pem|jks|p12)"; + private static final String CERTIFICATE_PASSWORD_PATH_REGEX = "^(/[a-zA-Z0-9_-]+)+\\.pass"; + + private ValidationFunctions() { + } + + public static Predicate> doesItContainValidPasswordPaths() { + return paths -> paths.stream().allMatch(ValidationFunctions::isCertificatePasswordPathValid); + } + + public static Predicate> doesItContainValidCertificatesPaths() { + return paths -> paths.stream().allMatch(ValidationFunctions::isCertificatePathValid); + } + + public static Predicate> doesItContainValidPathsToCopy() { + return paths -> paths.stream().allMatch(path -> + doesMatch(path, CERTIFICATE_PASSWORD_PATH_REGEX) || isCertificatePathValid(path)); + } + + private static boolean isCertificatePathValid(String path) { + return doesMatch(path, CERTIFICATE_PATH_REGEX); + } + + private static boolean isCertificatePasswordPathValid(String path) { + return path.isEmpty() || doesMatch(path, CERTIFICATE_PASSWORD_PATH_REGEX); + } + + private static boolean doesMatch(String path, String regex) { + return path.matches(regex); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopier.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopier.java new file mode 100644 index 00000000..f5cea212 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopier.java @@ -0,0 +1,74 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.copier; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.copier.exception.KeystoreFileCopyException; +import org.onap.oom.certservice.postprocessor.copier.exception.KeystoreNotExistException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KeystoreCopier { + + private static final Logger LOGGER = LoggerFactory.getLogger(KeystoreCopier.class); + private final FileTools fileTools; + + public KeystoreCopier(FileTools fileTools) { + this.fileTools = fileTools; + } + + public void copyKeystores(AppConfiguration configuration) { + final List sources = configuration.getSourceKeystorePaths(); + final List destinations = configuration.getDestinationKeystorePaths(); + containsPaths(sources); + try { + for (int i = 0; i < sources.size(); i++) { + copy(sources.get(i), destinations.get(i)); + } + } catch (IOException e) { + throw new KeystoreFileCopyException(e); + } + } + + private void containsPaths(List sources) { + if (sources.isEmpty()) { + LOGGER.info("No Keystore files to copy"); + } + } + + private void copy(String sourcePath, String destinationPath) throws IOException { + final File source = new File(sourcePath); + final File destination = new File(destinationPath); + + if (!source.exists()) { + throw new KeystoreNotExistException("Keystore file does not exist '" + source.getAbsolutePath() + "'!"); + } + + if (destination.exists()) { + fileTools.createBackup(destination); + } + fileTools.copy(source, destination); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreFileCopyException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreFileCopyException.java new file mode 100644 index 00000000..66190965 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreFileCopyException.java @@ -0,0 +1,31 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.copier.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class KeystoreFileCopyException extends ExitableException { + + public KeystoreFileCopyException(Exception e) { + super(e, ExitStatus.KEYSTORE_FILE_COPY_EXCEPTION); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreNotExistException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreNotExistException.java new file mode 100644 index 00000000..37f2f537 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/copier/exception/KeystoreNotExistException.java @@ -0,0 +1,31 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.copier.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class KeystoreNotExistException extends ExitableException { + + public KeystoreNotExistException(String message) { + super(message, ExitStatus.KEYSTORE_NOT_EXIST_EXCEPTION); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProvider.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProvider.java new file mode 100644 index 00000000..9e30bd44 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProvider.java @@ -0,0 +1,46 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger; + +import java.util.ArrayList; +import java.util.List; +import org.onap.oom.certservice.postprocessor.merger.model.Truststore; +import org.onap.oom.certservice.postprocessor.merger.model.TruststoreFactory; + +public class TruststoreFilesProvider { + + + private TruststoreFilesProvider() { + } + + public static List getTruststoreFiles(List truststoreFilePaths, + List truststoreFilePasswordPaths) { + List truststoreFiles = new ArrayList<>(); + for (int i = 0; i < truststoreFilePaths.size(); i++) { + String truststorePath = truststoreFilePaths.get(i); + String passwordPath = truststoreFilePasswordPaths.get(i); + + Truststore truststore = TruststoreFactory.create(truststorePath, passwordPath); + truststoreFiles.add(truststore); + } + + return truststoreFiles; + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreMerger.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreMerger.java new file mode 100644 index 00000000..3cf60da1 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/TruststoreMerger.java @@ -0,0 +1,54 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger; + +import java.util.List; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.merger.model.Truststore; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; + +public class TruststoreMerger { + + private static final int FIRST_TRUSTSTORE_INDEX = 0; + private static final int SECOND_TRUSTSTORE_INDEX = 1; + + public void mergeTruststores(AppConfiguration configuration) { + List truststoreFilesList = getTruststoreFiles(configuration); + + Truststore baseFile = truststoreFilesList.get(FIRST_TRUSTSTORE_INDEX); + baseFile.createBackup(); + + for (int i = SECOND_TRUSTSTORE_INDEX; i < truststoreFilesList.size(); i++) { + Truststore truststore = truststoreFilesList.get(i); + List certificateWrappers = truststore.getCertificates(); + baseFile.addCertificates(certificateWrappers); + } + + baseFile.saveFile(); + } + + private List getTruststoreFiles(AppConfiguration configuration) { + return TruststoreFilesProvider + .getTruststoreFiles( + configuration.getTruststoreFilePaths(), + configuration.getTruststoreFilePasswordPaths() + ); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/AliasConflictException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/AliasConflictException.java new file mode 100644 index 00000000..2e7939b7 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/AliasConflictException.java @@ -0,0 +1,31 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class AliasConflictException extends ExitableException { + + public AliasConflictException(String errorMessage) { + super(errorMessage, ExitStatus.ALIAS_CONFLICT_EXCEPTION); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/CreateBackupException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/CreateBackupException.java new file mode 100644 index 00000000..8e99f993 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/CreateBackupException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class CreateBackupException extends ExitableException { + + public CreateBackupException(Exception cause) { + super(cause, ExitStatus.CREATE_BACKUP_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/KeystoreInstanceException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/KeystoreInstanceException.java new file mode 100644 index 00000000..1279dff7 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/KeystoreInstanceException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class KeystoreInstanceException extends ExitableException { + + public KeystoreInstanceException(Exception cause) { + super(cause, ExitStatus.KEYSTORE_INSTANCE_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/LoadTruststoreException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/LoadTruststoreException.java new file mode 100644 index 00000000..b3493fd6 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/LoadTruststoreException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class LoadTruststoreException extends ExitableException { + + public LoadTruststoreException(Exception cause) { + super(cause, ExitStatus.TRUSTSTORE_LOAD_FILE_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/MissingTruststoreException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/MissingTruststoreException.java new file mode 100644 index 00000000..51660f60 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/MissingTruststoreException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class MissingTruststoreException extends ExitableException { + + public MissingTruststoreException(String errorMessage) { + super(errorMessage, ExitStatus.MISSING_TRUSTSTORE_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/PasswordReaderException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/PasswordReaderException.java new file mode 100644 index 00000000..b1bdf1ea --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/PasswordReaderException.java @@ -0,0 +1,29 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class PasswordReaderException extends ExitableException { + public PasswordReaderException(String errorMessage) { + super(errorMessage, ExitStatus.PASSWORD_READER_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreDataOperationException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreDataOperationException.java new file mode 100644 index 00000000..77ae366e --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreDataOperationException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class TruststoreDataOperationException extends ExitableException { + + public TruststoreDataOperationException(Exception cause) { + super(cause, ExitStatus.TRUSTSTORE_DATA_OPERATION_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreFileFactoryException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreFileFactoryException.java new file mode 100644 index 00000000..a87a62a3 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/TruststoreFileFactoryException.java @@ -0,0 +1,30 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class TruststoreFileFactoryException extends ExitableException { + public TruststoreFileFactoryException(String errorMessage) { + super(errorMessage, ExitStatus.TRUSTSTORE_FILE_FACTORY_EXCEPTION); + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/WriteTruststoreFileException.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/WriteTruststoreFileException.java new file mode 100644 index 00000000..f9b772ca --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/exception/WriteTruststoreFileException.java @@ -0,0 +1,31 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.exception; + +import org.onap.oom.certservice.postprocessor.api.ExitStatus; +import org.onap.oom.certservice.postprocessor.api.ExitableException; + +public class WriteTruststoreFileException extends ExitableException { + + public WriteTruststoreFileException(Exception cause) { + super(cause, ExitStatus.WRITE_TRUSTSTORE_FILE_EXCEPTION); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststore.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststore.java new file mode 100644 index 00000000..d264d2f4 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststore.java @@ -0,0 +1,166 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.onap.oom.certservice.postprocessor.merger.exception.AliasConflictException; +import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException; +import org.onap.oom.certservice.postprocessor.merger.exception.WriteTruststoreFileException; +import org.onap.oom.certservice.postprocessor.api.ExitableException; +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAliasFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class JavaTruststore extends Truststore { + + private static final Logger LOGGER = LoggerFactory.getLogger(JavaTruststore.class); + + private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory(); + private final KeyStore keyStore; + private final String password; + + + private JavaTruststore(KeyStore keyStore, File storeFile, String password) { + super(storeFile, new FileTools()); + this.keyStore = keyStore; + this.password = password; + } + + public static JavaTruststore createWithLoadingFile(KeyStore keyStore, File storeFile, String password) + throws LoadTruststoreException { + JavaTruststore javaTruststore = new JavaTruststore(keyStore, storeFile, password); + javaTruststore.loadFile(); + return javaTruststore; + } + + public List getCertificates() throws ExitableException { + LOGGER.debug("Attempt to read certificates from file: {}", storeFile.getPath()); + List aliases = getTruststoreAliases(); + if (aliases.isEmpty()) { + throw new MissingTruststoreException("Missing certificate aliases in file: " + storeFile.getPath()); + } + return getWrappedCertificates(aliases); + } + + public void addCertificates(List certificatesWithAliases) + throws ExitableException { + LOGGER.debug("Attempt to add certificates for saving to file"); + if (getTruststoreAliases().isEmpty()) { + throw new MissingTruststoreException("Missing certificate aliases in file: " + storeFile.getPath()); + } + for (CertificateWithAlias certificate : certificatesWithAliases) { + addCertificate(certificate); + } + } + + public void saveFile() throws WriteTruststoreFileException { + LOGGER.debug("Attempt to save file: {}", storeFile.getPath()); + try (FileOutputStream outputStream = new FileOutputStream(storeFile)) { + keyStore.store(outputStream, this.password.toCharArray()); + } catch (Exception e) { + LOGGER.error("Cannot write truststore file"); + throw new WriteTruststoreFileException(e); + } + } + + private void loadFile() throws LoadTruststoreException { + try { + keyStore.load(new FileInputStream(storeFile), this.password.toCharArray()); + } catch (Exception e) { + LOGGER.error("Cannot load file: {}", storeFile.getPath()); + throw new LoadTruststoreException(e); + } + } + + private void addCertificate(CertificateWithAlias certificate) + throws TruststoreDataOperationException, AliasConflictException { + if (hasAliasConflict(certificate)) { + LOGGER.error("Alias conflict detected"); + throw new AliasConflictException("Alias conflict detected. Alias conflicted: " + certificate.getAlias()); + } + try { + keyStore.setCertificateEntry(certificate.getAlias(), certificate.getCertificate()); + } catch (KeyStoreException e) { + LOGGER.error("Cannot merge certificate with alias: {}", certificate.getAlias()); + throw new TruststoreDataOperationException(e); + } + } + + private boolean hasAliasConflict(CertificateWithAlias certificate) throws TruststoreDataOperationException { + try { + return keyStore.containsAlias(certificate.getAlias()); + } catch (KeyStoreException e) { + LOGGER.error("Cannot check alias conflict"); + throw new TruststoreDataOperationException(e); + } + } + + private List getWrappedCertificates(List aliases) + throws TruststoreDataOperationException { + + List certificateWrapped = new ArrayList<>(); + + for (String alias : aliases) { + certificateWrapped.add(createWrappedCertificate(alias)); + } + return certificateWrapped; + } + + private CertificateWithAlias createWrappedCertificate(String alias) throws TruststoreDataOperationException { + try { + return factory.createCertificateWithAlias(keyStore.getCertificate(alias), alias); + } catch (KeyStoreException e) { + LOGGER.warn("Cannot get certificate with alias: {} ", alias); + throw new TruststoreDataOperationException(e); + } + } + + private List getTruststoreAliases() throws TruststoreDataOperationException { + try { + List aliases = Collections.list(keyStore.aliases()); + return getFilteredAlias(aliases); + } catch (KeyStoreException e) { + LOGGER.warn("Cannot read truststore aliases"); + throw new TruststoreDataOperationException(e); + } + } + + private List getFilteredAlias(List aliases) throws KeyStoreException { + List filteredAlias = new ArrayList<>(); + for (String alias : aliases) { + if (keyStore.isCertificateEntry(alias)) { + filteredAlias.add(alias); + } + } + return filteredAlias; + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreFactory.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreFactory.java new file mode 100644 index 00000000..4740d0f6 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreFactory.java @@ -0,0 +1,48 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import java.io.File; +import java.security.KeyStore; +import java.security.KeyStoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.KeystoreInstanceException; +import org.onap.oom.certservice.postprocessor.common.PasswordReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JavaTruststoreFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(JavaTruststoreFactory.class); + + private JavaTruststoreFactory() { + } + + public static Truststore create(File certFile, String truststorePasswordPath, String keystoreType) { + String password = PasswordReader.readPassword(new File(truststorePasswordPath)); + try { + return JavaTruststore + .createWithLoadingFile(KeyStore.getInstance(keystoreType), certFile, password); + } catch (KeyStoreException e) { + LOGGER.error("Cannot initialize Java Keystore instance"); + throw new KeystoreInstanceException(e); + } + } +} + diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststore.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststore.java new file mode 100644 index 00000000..d7f4bfd2 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststore.java @@ -0,0 +1,156 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.BOUNCY_CASTLE_PROVIDER; +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.X_509_CERTIFICATE; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; +import org.bouncycastle.util.io.pem.PemObjectGenerator; +import org.bouncycastle.util.io.pem.PemWriter; +import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException; +import org.onap.oom.certservice.postprocessor.merger.exception.WriteTruststoreFileException; +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAliasFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PemTruststore extends Truststore { + + private static final Logger LOGGER = LoggerFactory.getLogger(PemTruststore.class); + + private static final boolean APPEND_TO_FILE = true; + + private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory(); + private final List certificatesToBeSaved = new ArrayList<>(); + + public PemTruststore(File storeFile) { + super(storeFile, new FileTools()); + } + + public List getCertificates() + throws TruststoreDataOperationException, MissingTruststoreException { + LOGGER.debug("Attempt to read certificates from file: {}", storeFile.getPath()); + if (isFileWithoutPemCertificate()) { + throw new MissingTruststoreException("File does not contain any certificate"); + } + List extractedCertificate = extractCertificatesFromFile(); + return wrapCertificates(extractedCertificate); + } + + public void addCertificates(List certificates) + throws TruststoreDataOperationException, MissingTruststoreException { + LOGGER.debug("Attempt to add certificates for saving to file"); + if (isFileWithoutPemCertificate()) { + LOGGER.error("File does not contain any certificate. File path: {} ", storeFile.getPath()); + throw new MissingTruststoreException("File does not contain any certificate"); + } + certificatesToBeSaved.addAll(certificates); + } + + public void saveFile() throws WriteTruststoreFileException, TruststoreDataOperationException { + LOGGER.debug("Attempt to save file: {}", storeFile.getPath()); + List certificates = certificatesToBeSaved.stream() + .map(CertificateWithAlias::getCertificate) + .collect(Collectors.toList()); + String certificatesAsString = transformToStringInPemFormat(certificates); + appendToFile(certificatesAsString); + } + + boolean isFileWithoutPemCertificate() throws TruststoreDataOperationException { + List certificateList = extractCertificatesFromFile(); + return certificateList.isEmpty(); + } + + String transformToStringInPemFormat(List certificates) throws TruststoreDataOperationException { + StringWriter sw = new StringWriter(); + List generators = transformToPemGenerators(certificates); + try (PemWriter pemWriter = new PemWriter(sw)) { + for (PemObjectGenerator generator : generators) { + pemWriter.writeObject(generator); + } + } catch (IOException e) { + LOGGER.error("Cannot convert certificates to PEM format"); + throw new TruststoreDataOperationException(e); + } + return sw.toString(); + } + + private List extractCertificatesFromFile() throws TruststoreDataOperationException { + try (FileInputStream inputStream = new FileInputStream(storeFile)) { + Security.addProvider(new BouncyCastleProvider()); + CertificateFactory factory = CertificateFactory.getInstance(X_509_CERTIFICATE, BOUNCY_CASTLE_PROVIDER); + return new ArrayList<>(factory.generateCertificates(inputStream)); + } catch (Exception e) { + LOGGER.error("Cannot read certificates from file: {}", storeFile.getPath()); + throw new TruststoreDataOperationException(e); + } + } + + private List transformToPemGenerators(List certificates) + throws TruststoreDataOperationException { + List generators = new ArrayList<>(); + for (Certificate certificate : certificates) { + PemObjectGenerator generator = createPemGenerator(certificate); + generators.add(generator); + } + return generators; + } + + private JcaMiscPEMGenerator createPemGenerator(Certificate certificate) + throws TruststoreDataOperationException { + try { + return new JcaMiscPEMGenerator(certificate); + } catch (IOException e) { + LOGGER.error("Cannot convert Certificate Object to PemGenerator Object"); + throw new TruststoreDataOperationException(e); + } + } + + private List wrapCertificates(List rawCertificates) { + return rawCertificates.stream() + .map(factory::createPemCertificate) + .collect(Collectors.toList()); + } + + private void appendToFile(String certificatesAsString) throws WriteTruststoreFileException { + try { + FileOutputStream fileOutputStream = new FileOutputStream(storeFile, APPEND_TO_FILE); + fileOutputStream.write(certificatesAsString.getBytes()); + } catch (Exception e) { + LOGGER.error("Cannot write certificates to file"); + throw new WriteTruststoreFileException(e); + } + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/Truststore.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/Truststore.java new file mode 100644 index 00000000..058613a9 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/Truststore.java @@ -0,0 +1,47 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import java.io.File; +import java.util.List; +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; + +public abstract class Truststore { + + final File storeFile; + + private final FileTools fileTools; + + public Truststore(File storeFile, FileTools fileTools) { + this.storeFile = storeFile; + this.fileTools = fileTools; + } + + public void createBackup() { + fileTools.createBackup(storeFile); + } + + public abstract List getCertificates(); + + public abstract void addCertificates(List certificates); + + public abstract void saveFile(); +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactory.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactory.java new file mode 100644 index 00000000..5167c301 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactory.java @@ -0,0 +1,64 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.JKS_TYPE; +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.PKCS12_TYPE; + +import java.io.File; +import org.onap.oom.certservice.postprocessor.common.ExtensionResolver; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreFileFactoryException; + +public class TruststoreFactory { + + private static final String JKS_EXTENSION = ".jks"; + private static final String P12_EXTENSION = ".p12"; + private static final String PEM_EXTENSION = ".pem"; + private static final String FILE_DOES_NOT_EXIST_MSG_TEMPLATE = "File: %s does not exist"; + private static final String UNKNOWN_TRUSTSTORE_TYPE_MSG_TEMPLATE = "Unknown truststore extension type: %s"; + + + private TruststoreFactory() { + } + + public static Truststore create(String truststoreFilePath, String truststorePasswordPath) { + File truststoreFile = new File(truststoreFilePath); + if (!ExtensionResolver.checkIfFileExists(truststoreFile)) { + throw new TruststoreFileFactoryException(String.format(FILE_DOES_NOT_EXIST_MSG_TEMPLATE, truststoreFile)); + } + return createTypedTruststore(truststoreFile, truststorePasswordPath); + } + + private static Truststore createTypedTruststore(File truststoreFile, String truststorePasswordPath) { + String extension = ExtensionResolver.get(truststoreFile); + switch (extension) { + case JKS_EXTENSION: + return JavaTruststoreFactory.create(truststoreFile, truststorePasswordPath, JKS_TYPE); + case P12_EXTENSION: + return JavaTruststoreFactory.create(truststoreFile, truststorePasswordPath, PKCS12_TYPE); + case PEM_EXTENSION: + return new PemTruststore(truststoreFile); + default: + throw new TruststoreFileFactoryException( + String.format(UNKNOWN_TRUSTSTORE_TYPE_MSG_TEMPLATE, extension)); + } + } + +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAlias.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAlias.java new file mode 100644 index 00000000..098ffcd0 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAlias.java @@ -0,0 +1,41 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model.certificate; + +import java.security.cert.Certificate; + +public class CertificateWithAlias { + + private final Certificate certificate; + private final String alias; + + public CertificateWithAlias(Certificate certificate, String alias) { + this.certificate = certificate; + this.alias = alias; + } + + public String getAlias() { + return this.alias; + } + + public Certificate getCertificate() { + return this.certificate; + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAliasFactory.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAliasFactory.java new file mode 100644 index 00000000..4ad2b417 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/CertificateWithAliasFactory.java @@ -0,0 +1,33 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model.certificate; + +import java.security.cert.Certificate; + +public class CertificateWithAliasFactory { + + public CertificateWithAlias createCertificateWithAlias(Certificate certificate, String alias) { + return new CertificateWithAlias(certificate, alias); + } + + public CertificateWithAlias createPemCertificate(Certificate certificate) { + return new CertificateWithAlias(certificate, PemAliasGenerator.getInstance().getAlias()); + } +} diff --git a/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGenerator.java b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGenerator.java new file mode 100644 index 00000000..a89b1031 --- /dev/null +++ b/certServicePostProcessor/src/main/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGenerator.java @@ -0,0 +1,42 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model.certificate; + + +import java.util.concurrent.atomic.AtomicInteger; + +public class PemAliasGenerator { + + private static final String PREFIX_ALIAS_NAME = "pem-trusted-certificate-"; + private static final PemAliasGenerator INSTANCE = new PemAliasGenerator(); + private static AtomicInteger counter = new AtomicInteger(0); + + private PemAliasGenerator() { + } + + public static PemAliasGenerator getInstance() { + return INSTANCE; + } + + public String getAlias() { + + return PREFIX_ALIAS_NAME + counter.getAndIncrement(); + } +} diff --git a/certServicePostProcessor/src/main/resources/log4j2.xml b/certServicePostProcessor/src/main/resources/log4j2.xml new file mode 100644 index 00000000..697017e3 --- /dev/null +++ b/certServicePostProcessor/src/main/resources/log4j2.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/AppExecutorTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/AppExecutorTest.java new file mode 100644 index 00000000..19833cb8 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/AppExecutorTest.java @@ -0,0 +1,76 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.onap.oom.certservice.postprocessor.api.ExitStatus.ALIAS_CONFLICT_EXCEPTION; +import static org.onap.oom.certservice.postprocessor.api.ExitStatus.SUCCESS; +import static org.onap.oom.certservice.postprocessor.api.ExitStatus.UNEXPECTED_EXCEPTION; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.oom.certservice.postprocessor.merger.exception.AliasConflictException; + +@ExtendWith(MockitoExtension.class) +class AppExecutorTest { + + @Mock + Runnable logic; + @Mock + AppExitHandler exitHandler; + @InjectMocks + AppExecutor executor = new AppExecutor(); + + @Test + void shouldExitWithUnexpectedException() { + doThrow(new NullPointerException()).when(logic).run(); + doNothing().when(exitHandler).exit(UNEXPECTED_EXCEPTION); + + executor.execute(logic); + + verify(exitHandler).exit(UNEXPECTED_EXCEPTION); + } + + @Test + void shouldExitWithKnownException() { + doThrow(new AliasConflictException("")).when(logic).run(); + doNothing().when(exitHandler).exit(ALIAS_CONFLICT_EXCEPTION); + + executor.execute(logic); + + verify(exitHandler).exit(ALIAS_CONFLICT_EXCEPTION); + } + + @Test + void shouldExitWithSuccess() { + doNothing().when(logic).run(); + doNothing().when(exitHandler).exit(SUCCESS); + + executor.execute(logic); + + verify(exitHandler).exit(SUCCESS); + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolverTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolverTest.java new file mode 100644 index 00000000..8450ab6d --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/ExtensionResolverTest.java @@ -0,0 +1,44 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +class ExtensionResolverTest { + + @ParameterizedTest + @CsvSource(value = { + "opt/app/truststore.jks:.jks", + "opt/app/truststore.p12:.p12", + "opt/app/truststore.pem:.pem", + "opt/app/truststore.PEM:.pem", + "opt/app/truststore:''", + }, delimiter = ':') + void shouldReturnCorrectExtension(String filePath, String expectedExtension) { + String extension = ExtensionResolver.get(new File(filePath)); + assertThat(extension).isEqualTo(expectedExtension); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/FileToolsTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/FileToolsTest.java new file mode 100644 index 00000000..7b3b28ae --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/FileToolsTest.java @@ -0,0 +1,71 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class FileToolsTest { + + public static final String BAK_EXTENSION = ".bak"; + + @TempDir + File dir; + + @Test + void shouldCreateBackupProvidedFile() throws Exception { + //given + File fileToBackup = createFile("truststore.pem", "arbitrary content"); + String backupFilePath = fileToBackup.getPath() + BAK_EXTENSION; + //when + new FileTools().createBackup(fileToBackup); + //then + assertThat(fileToBackup).hasSameBinaryContentAs(new File(backupFilePath)); + } + + @Test + void shouldCopyFile() throws IOException { + //given + File sourceFile = createFile("source.p12", "any content"); + File destinationFile = new File(dir.getAbsolutePath() + "destination.p12"); + //when + new FileTools().copy(sourceFile, destinationFile); + //then + assertThat(sourceFile).hasSameBinaryContentAs(destinationFile); + } + + + private File createFile(String name, String content) throws IOException { + File file = new File(dir.getAbsolutePath() + File.pathSeparator + name); + if (file.createNewFile()) { + FileUtils.write(file, content, Charset.defaultCharset()); + } else { + throw new IllegalStateException("File could not be created: " + file.getAbsolutePath()); + } + return file; + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/PasswordReaderTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/PasswordReaderTest.java new file mode 100644 index 00000000..697eaa83 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/common/PasswordReaderTest.java @@ -0,0 +1,43 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.common; + +import org.junit.jupiter.api.Test; + +import java.io.File; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +class PasswordReaderTest { + + @Test + void shouldReturnCorrectPasswordFromFile() throws PasswordReaderException { + String fileData = PasswordReader.readPassword(new File("src/test/resources/truststore-jks.pass")); + assertThat(fileData).isEqualTo("EOyuFbuYDyq_EhpboM72RHua"); + } + + @Test + void shouldThrowExceptionForNonExistingFile() { + assertThatExceptionOfType(PasswordReaderException.class) + .isThrownBy(() -> PasswordReader.readPassword(new File("src/test/resources/non-esisting-file.pass"))); + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProviderTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProviderTest.java new file mode 100644 index 00000000..24e2dab8 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/AppConfigurationProviderTest.java @@ -0,0 +1,141 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.when; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.KEYSTORE_DESTINATION_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.KEYSTORE_SOURCE_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PASSWORDS_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PATHS; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +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.oom.certservice.postprocessor.configuration.exception.CertificatesPathsValidationException; +import org.onap.oom.certservice.postprocessor.configuration.exception.ConfigurationException; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.configuration.path.DelimitedPathsSplitter; +import org.onap.oom.certservice.postprocessor.configuration.path.env.EnvReader; + +@ExtendWith(MockitoExtension.class) +class AppConfigurationProviderTest { + + private static final String BASE_TRUSTSTORE_PATH = "/opt/app/truststore_"; + private static final String JKS_EXTENSION = ".jks"; + private static final String PASS_EXTENSION = ".pass"; + private static final String SAMPLE_TRUSTSTORES_PATHS = "/opt/app/certificates/truststore.jks:/opt/app/certificates/truststore.pem"; + private static final String SAMPLE_TRUSTSTORES_PASSWORDS_PATHS = "/opt/app/certificates/truststore.pass:/trust.pass"; + + @Mock + private DelimitedPathsSplitter pathsSplitter; + @Mock + private EnvReader envReader; + private AppConfigurationProvider provider; + + @BeforeEach + void setUp() { + provider = new AppConfigurationProvider(pathsSplitter, envReader); + } + + @Test + void shouldThrowExceptionWhenMandatoryEnvNotPresent() { + // given + when(envReader.getEnv(TRUSTSTORES_PATHS.name())).thenReturn(Optional.empty()); + // when, then + assertThatExceptionOfType(ConfigurationException.class).isThrownBy(() -> provider.createConfiguration()) + .withMessageContaining(TRUSTSTORES_PATHS + " mandatory environment variable is not defined"); + } + + @Test + void shouldThrowExceptionWhenTrustorePathsSizesDoNotMatch() { + // given + List truststores = createListOfPathsWithExtension(2, JKS_EXTENSION); + List truststoresPasswords = createListOfPathsWithExtension(1, PASS_EXTENSION); + + mockTruststorePaths(truststores, truststoresPasswords); + // when, then + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(() -> provider.createConfiguration()) + .withMessageContaining("Size of " + TRUSTSTORES_PATHS + + " does not match size of " + TRUSTSTORES_PASSWORDS_PATHS + " environment variables"); + } + + @Test + void shouldReturnEmptyListWhenOptionalEnvNotPresent() { + // given + List truststores = createListOfPathsWithExtension(2, JKS_EXTENSION); + List truststoresPasswords = createListOfPathsWithExtension(2, PASS_EXTENSION); + mockTruststorePaths(truststores, truststoresPasswords); + mockKeystorePaths(Optional.empty(), Optional.empty()); + // when + AppConfiguration paths = provider.createConfiguration(); + // then + assertThat(paths.getDestinationKeystorePaths()).isEmpty(); + assertThat(paths.getSourceKeystorePaths()).isEmpty(); + } + + private void mockTruststorePaths(List truststores, List truststoresPasswords) { + mockTruststores(truststores); + mockTruststoresPasswords(truststoresPasswords); + } + + private void mockKeystorePaths(Optional sourceKeystoresPairPaths, Optional destKeystoresPairPaths) { + mockKeystoreCopierSourcePaths(sourceKeystoresPairPaths); + mockKeystoreCopierDestinationPaths(destKeystoresPairPaths); + } + + private void mockTruststores(List truststores) throws CertificatesPathsValidationException { + when(envReader.getEnv(TRUSTSTORES_PATHS.name())).thenReturn(Optional.of(SAMPLE_TRUSTSTORES_PATHS)); + when(pathsSplitter.getValidatedPaths(TRUSTSTORES_PATHS, Optional.of(SAMPLE_TRUSTSTORES_PATHS))) + .thenReturn(truststores); + } + + private void mockTruststoresPasswords(List truststoresPasswords) + throws CertificatesPathsValidationException { + Optional passwordsPaths = Optional.of(SAMPLE_TRUSTSTORES_PASSWORDS_PATHS); + when(envReader.getEnv(TRUSTSTORES_PASSWORDS_PATHS.name())).thenReturn(passwordsPaths); + when(pathsSplitter.getValidatedPaths(TRUSTSTORES_PASSWORDS_PATHS, passwordsPaths)) + .thenReturn(truststoresPasswords); + } + + private void mockKeystoreCopierSourcePaths(Optional paths) { + when(envReader.getEnv(KEYSTORE_SOURCE_PATHS.name())).thenReturn(paths); + } + + private void mockKeystoreCopierDestinationPaths(Optional paths) { + when(envReader.getEnv(KEYSTORE_DESTINATION_PATHS.name())).thenReturn(paths); + } + + private List createListOfPathsWithExtension(int numberOfPaths, String passwordExtension) { + List paths = new ArrayList<>(); + while (numberOfPaths-- > 0) { + paths.add(BASE_TRUSTSTORE_PATH + numberOfPaths + passwordExtension); + } + return paths; + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitterTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitterTest.java new file mode 100644 index 00000000..be1bc394 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/DelimitedPathsSplitterTest.java @@ -0,0 +1,107 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PASSWORDS_PATHS; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PATHS; + +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.oom.certservice.postprocessor.configuration.exception.CertificatesPathsValidationException; + +@ExtendWith(MockitoExtension.class) +class DelimitedPathsSplitterTest { + + private static final String VALID_TRUSTSTORES = "/opt/app/certificates/truststore.jks:/opt/app/certificates/truststore.pem"; + private static final String VALID_TRUSTSTORES_PASSWORDS = "/opt/app/certificates/truststore.pass:"; + private static final String VALID_TRUSTSTORES_PASSWORDS_WITH_EMPTY_IN_THE_MIDDLE = "/opt/app/certificates/truststore.pass::/etc/truststore.pass"; + private static final String INVALID_TRUSTSTORES = "/opt/app/certificates/truststore.jks:/opt/app/certificates/truststore.invalid"; + private static final String INVALID_TRUSTSTORES_PASSWORDS = "/opt/app/certificates/truststore.pass:/.pass"; + + private DelimitedPathsSplitter delimitedPathsSplitter; + + @BeforeEach + void setUp() { + delimitedPathsSplitter = new DelimitedPathsSplitter(); + } + + @Test + void shouldReturnCorrectListWhenTruststoresValid() { + // when, then + assertThat(delimitedPathsSplitter.getValidatedPaths(TRUSTSTORES_PATHS, Optional.of(VALID_TRUSTSTORES))) + .containsSequence("/opt/app/certificates/truststore.jks", + "/opt/app/certificates/truststore.pem"); + } + + @Test + void shouldThrowExceptionWhenTruststoresPathsEnvIsEmpty() { + // when, then + assertThatExceptionOfType(CertificatesPathsValidationException.class) + .isThrownBy(() -> delimitedPathsSplitter.getValidatedPaths(TRUSTSTORES_PATHS, Optional.of(""))); + } + + @Test + void shouldThrowExceptionWhenOneOfTruststoresPathsInvalid() { + // when, then + assertThatExceptionOfType(CertificatesPathsValidationException.class) + .isThrownBy(() -> delimitedPathsSplitter + .getValidatedPaths(TRUSTSTORES_PATHS, Optional.of(INVALID_TRUSTSTORES))); + } + + @Test + void shouldReturnCorrectListWhenTruststoresPasswordsValid() { + // when, then + assertThat(delimitedPathsSplitter + .getValidatedPaths(TRUSTSTORES_PASSWORDS_PATHS, Optional.of(VALID_TRUSTSTORES_PASSWORDS))) + .containsSequence("/opt/app/certificates/truststore.pass", ""); + } + + @Test + void shouldReturnCorrectListWhenTruststoresPasswordsContainsEmptyPathsInTheMiddle() { + // when, then + assertThat(delimitedPathsSplitter.getValidatedPaths(TRUSTSTORES_PASSWORDS_PATHS, + Optional.of(VALID_TRUSTSTORES_PASSWORDS_WITH_EMPTY_IN_THE_MIDDLE))).containsSequence( + "/opt/app/certificates/truststore.pass", + "", + "/etc/truststore.pass" + ); + } + + @Test + void shouldThrowExceptionWhenTruststoresPasswordsPathEnvIsEmpty() { + // when, then + assertThatExceptionOfType(CertificatesPathsValidationException.class) + .isThrownBy( + () -> delimitedPathsSplitter.getValidatedPaths(TRUSTSTORES_PASSWORDS_PATHS, Optional.of(""))); + } + + @Test + void shouldThrowExceptionWhenOneOfTruststorePasswordPathsInvalid() { + // when, then + assertThatExceptionOfType(CertificatesPathsValidationException.class) + .isThrownBy(() -> delimitedPathsSplitter + .getValidatedPaths(TRUSTSTORES_PASSWORDS_PATHS, Optional.of(INVALID_TRUSTSTORES_PASSWORDS))); + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReaderTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReaderTest.java new file mode 100644 index 00000000..343e5655 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/env/EnvReaderTest.java @@ -0,0 +1,62 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path.env; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; +import static org.onap.oom.certservice.postprocessor.configuration.model.EnvVariable.TRUSTSTORES_PASSWORDS_PATHS; + +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class EnvReaderTest { + + private static final String SAMPLE_PASS_PATH = "/sample/path/trust.pass"; + EnvReader provider; + + @BeforeEach + void setUp() { + provider = Mockito.spy(EnvReader.class); + } + + @Test + void shouldReturnOptionalWithEnv() { + // given + String envName = TRUSTSTORES_PASSWORDS_PATHS.name(); + when(provider.getSystemEnv(envName)).thenReturn(Optional.of(SAMPLE_PASS_PATH)); + // when + Optional result = provider.getEnv(envName); + // then + assertThat(result).isEqualTo(Optional.of(SAMPLE_PASS_PATH)); + } + + @Test + void shouldReturnEmptyOptional() { + // given + String envName = TRUSTSTORES_PASSWORDS_PATHS.name(); + // when + Optional result = provider.getEnv(envName); + // then + assertThat(result).isEmpty(); + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctionsTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctionsTest.java new file mode 100644 index 00000000..f65147a9 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/configuration/path/validation/ValidationFunctionsTest.java @@ -0,0 +1,135 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.configuration.path.validation; + + +import static org.assertj.core.api.Assertions.assertThat; +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidCertificatesPaths; +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidPasswordPaths; +import static org.onap.oom.certservice.postprocessor.configuration.path.validation.ValidationFunctions.doesItContainValidPathsToCopy; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +class ValidationFunctionsTest { + + @Test + void shouldValidateWithSuccessCorrectCertificatesPaths() { + // given + List certPaths = Arrays.asList("/opt/app/certificates/truststore.p12"); + // when + boolean result = doesItContainValidCertificatesPaths().test(certPaths); + // then + assertThat(result).isTrue(); + } + + @Test + void shouldValidateWithFailureCertificatesPathsWithOneEmptyPath() { + // given + List certPaths = Arrays.asList("/opt/app/certificates/truststore.p12", ""); + // when + boolean result = doesItContainValidCertificatesPaths().test(certPaths); + // then + assertThat(result).isFalse(); + } + + @Test + void shouldValidateWithFailureCertificatesPathsWithOnePathWhichHasIncorrectExtension() { + // given + List certPaths = Arrays.asList("/opt/app/certificates/truststore.txt", "/opt/cert.p12"); + // when + boolean result = doesItContainValidCertificatesPaths().test(certPaths); + // then + assertThat(result).isFalse(); + } + + @Test + void shouldValidateWithSuccessCertificatesPasswordPaths() { + // given + List passwordPaths = Arrays.asList("/opt/app/certificates/truststore.pass", ""); + // when + boolean result = doesItContainValidPasswordPaths().test(passwordPaths); + // then + assertThat(result).isTrue(); + } + + @Test + void shouldValidateWithSuccessCertificatePasswordsPathsWhichContainsEmptyPathsInTheMiddle() { + // given + List passwordPaths = Arrays.asList("/opt/app/certificates/truststore.pass", "", "/etc/truststore.pass"); + // when + boolean result = doesItContainValidPasswordPaths().test(passwordPaths); + // then + assertThat(result).isTrue(); + } + + @Test + void shouldValidateWithFailureCertificatesPasswordsPathsWithIncorrectExtension() { + // given + List passwordPaths = Arrays.asList("/pass.txt"); + // when + boolean result = doesItContainValidPasswordPaths().test(passwordPaths); + // then + assertThat(result).isFalse(); + } + + @Test + void shouldValidateWithFailureCertificatesPasswordPathsWithMissingPrecedingSlash() { + // given + List passwordPaths = Arrays.asList("jks.pass"); + // when + boolean result = doesItContainValidPasswordPaths().test(passwordPaths); + // then + assertThat(result).isFalse(); + } + + @Test + void shouldValidateWithSuccessSourcePathsToCopyFiles() { + // given + List sourcePaths = Arrays.asList("/opt/dcae/cacert/external/keystore.p12", + "/opt/dcae/cacert/external/keystore.pass"); + // when + boolean result = doesItContainValidPathsToCopy().test(sourcePaths); + // then + assertThat(result).isTrue(); + } + + @Test + void shouldValidateWithSuccessDestinationPathsToCopyFiles() { + // given + List sourcePaths = Arrays.asList("/opt/dcae/cacert/cert.p12","/opt/dcae/cacert/p12.pass"); + // when + boolean result = doesItContainValidPathsToCopy().test(sourcePaths); + // then + assertThat(result).isTrue(); + } + + @Test + void shouldValidateWithFailureDestinationPathsWithIncorrectExtension() { + // given + List sourcePaths = Arrays.asList("/opt/dcae/cacert/cert.txt","/opt/dcae/cacert/p12.other"); + // when + boolean result = doesItContainValidPathsToCopy().test(sourcePaths); + // then + assertThat(result).isFalse(); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopierTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopierTest.java new file mode 100644 index 00000000..99193a8d --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/copier/KeystoreCopierTest.java @@ -0,0 +1,147 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.copier; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Collections; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.onap.oom.certservice.postprocessor.common.FileTools; +import org.onap.oom.certservice.postprocessor.configuration.model.AppConfiguration; +import org.onap.oom.certservice.postprocessor.copier.exception.KeystoreFileCopyException; +import org.onap.oom.certservice.postprocessor.copier.exception.KeystoreNotExistException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +public class KeystoreCopierTest { + + private static final String SOURCE_CONTENT = "source content"; + private static final String DESTINATION_CONTENT = "destination content"; + + @TempDir + File dir; + + private KeystoreCopier copier = new KeystoreCopier(new FileTools()); + + @Test + void shouldDoNothingForEmptySourceFileList() { + AppConfiguration configuration = createEmptyConfiguration(); + + copier.copyKeystores(configuration); + + assertThat(dir.listFiles()).isEmpty(); + } + + + @Test + void shouldCopyFileAndCreateBackup() throws IOException { + File source = createFile("source.p12", SOURCE_CONTENT); + File destination = createFile("destination.p12", DESTINATION_CONTENT); + File backup = declareFile("destination.p12.bak"); + AppConfiguration configuration = createConfiguration(source, destination); + + copier.copyKeystores(configuration); + + assertThat(readFile(destination)).isEqualTo(readFile(source)); + assertThat(backup.exists()).isTrue(); + assertThat(readFile(backup)).isEqualTo(DESTINATION_CONTENT); + } + + @Test + void shouldCopyFileWithoutCreatingBackup() throws IOException { + File source = createFile("source.p12", SOURCE_CONTENT); + File destination = declareFile("destination.p12"); + File backup = declareFile("destination.p12.bak"); + AppConfiguration configuration = createConfiguration(source, destination); + + copier.copyKeystores(configuration); + + assertThat(destination.exists()).isTrue(); + assertThat(readFile(destination)).isEqualTo(readFile(source)); + assertThat(backup.exists()).isFalse(); + } + + @Test + void shouldThrowKeystoreNotExistException() throws IOException { + File source = declareFile("source.p12"); + File destination = declareFile("destination.p12"); + File backup = declareFile("destination.p12.bak"); + AppConfiguration configuration = createConfiguration(source, destination); + + assertThatExceptionOfType(KeystoreNotExistException.class).isThrownBy( () -> + copier.copyKeystores(configuration) + ); + + assertThat(source.exists()).isFalse(); + assertThat(destination.exists()).isFalse(); + assertThat(backup.exists()).isFalse(); + } + + @Test + void shouldThrowKeystoreFileCopyException() throws IOException { + File source = createFile("source.p12", SOURCE_CONTENT); + source.setReadable(false); + File destination = declareFile("destination.p12"); + File backup = declareFile("destination.p12.bak"); + AppConfiguration configuration = createConfiguration(source, destination); + + assertThatExceptionOfType(KeystoreFileCopyException.class).isThrownBy( () -> + copier.copyKeystores(configuration) + ); + + assertThat(source.exists()).isTrue(); + assertThat(destination.exists()).isFalse(); + assertThat(backup.exists()).isFalse(); + } + + private AppConfiguration createConfiguration(File source, File destination) { + return new AppConfiguration(Collections.emptyList(), Collections.emptyList(), + Collections.singletonList(source.getAbsolutePath()), + Collections.singletonList(destination.getAbsolutePath())); + } + + private AppConfiguration createEmptyConfiguration() { + return new AppConfiguration(Collections.emptyList(), Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList()); + } + + private String readFile(File file) throws IOException { + return FileUtils.readFileToString(file, Charset.defaultCharset()); + } + + private File declareFile(String name) { + return new File(dir.getAbsolutePath() + File.pathSeparator + name); + } + + private File createFile(String name, String content) throws IOException { + File file = new File(dir.getAbsolutePath() + File.pathSeparator + name); + if (file.createNewFile()) { + FileUtils.write(file, content, Charset.defaultCharset()); + } else { + throw new IllegalStateException("File could not be created: " + file.getAbsolutePath()); + } + return file; + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProviderTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProviderTest.java new file mode 100644 index 00000000..9040b53d --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/TruststoreFilesProviderTest.java @@ -0,0 +1,63 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.oom.certservice.postprocessor.merger.exception.KeystoreInstanceException; +import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreFileFactoryException; +import org.onap.oom.certservice.postprocessor.merger.model.Truststore; +import org.onap.oom.certservice.postprocessor.merger.model.TruststoreFactory; + +class TruststoreFilesProviderTest { + + private static final String TRUSTSTORE_JKS_PATH = "src/test/resources/truststore-jks.jks"; + private static final String TRUSTSTORE_JKS_PASS_PATH = "src/test/resources/truststore-jks.pass"; + private static final String TRUSTSTORE_P12_PATH = "src/test/resources/truststore-p12.p12"; + private static final String TRUSTSTORE_P12_PASS_PATH = "src/test/resources/truststore-p12.pass"; + private static final String TRUSTSTORE_PEM_PATH = "src/test/resources/truststore.pem"; + private static final String EMPTY_PASS_PATH = ""; + + @Test + void shouldReturnTruststoreFilesList() + throws TruststoreFileFactoryException, PasswordReaderException, LoadTruststoreException, KeystoreInstanceException { + //given + List truststorePaths = Arrays.asList(TRUSTSTORE_JKS_PATH, TRUSTSTORE_P12_PATH, TRUSTSTORE_PEM_PATH); + List truststorePasswordPaths = Arrays + .asList(TRUSTSTORE_JKS_PASS_PATH, TRUSTSTORE_P12_PASS_PATH, EMPTY_PASS_PATH); + + //when + List truststoreFilesList = TruststoreFilesProvider + .getTruststoreFiles(truststorePaths, truststorePasswordPaths); + + //then + assertThat(truststoreFilesList.size()).isEqualTo(3); + TruststoreFactory.create(TRUSTSTORE_JKS_PATH, TRUSTSTORE_JKS_PASS_PATH); + TruststoreFactory.create(TRUSTSTORE_P12_PATH, TRUSTSTORE_P12_PASS_PATH); + TruststoreFactory.create(TRUSTSTORE_PEM_PATH, EMPTY_PASS_PATH); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreTest.java new file mode 100644 index 00000000..93a5359b --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/JavaTruststoreTest.java @@ -0,0 +1,56 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.onap.oom.certservice.postprocessor.api.ExitableException; +import org.onap.oom.certservice.postprocessor.merger.exception.AliasConflictException; +import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; + +class JavaTruststoreTest { + + @Test + void throwExceptionWhenAliasConflictDetected() throws Exception { + //given + Truststore p12Truststore = TestCertificateProvider.getSampleP12Truststore(); + + List certificateFromJks = TestCertificateProvider + .getSampleJksTruststoreFile().getCertificates(); + + //when //then + assertThatExceptionOfType(AliasConflictException.class) + .isThrownBy(() -> p12Truststore.addCertificates(certificateFromJks)); + } + + @Test + void throwExceptionWhenFileNotContainsTruststoreEntry() throws ExitableException { + //given + Truststore p12Truststore = TestCertificateProvider.getSampleP12Keystore(); + + //when//then + assertThatExceptionOfType(MissingTruststoreException.class) + .isThrownBy(() -> p12Truststore.getCertificates()); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststoreTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststoreTest.java new file mode 100644 index 00000000..af254896 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/PemTruststoreTest.java @@ -0,0 +1,128 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreSpi; +import java.security.cert.Certificate; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.onap.oom.certservice.postprocessor.api.ExitableException; +import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException; +import org.onap.oom.certservice.postprocessor.merger.exception.WriteTruststoreFileException; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; + +class PemTruststoreTest { + + private static final int EXPECTED_ONE = 1; + + @Test + void getCertificatesShouldThrowExceptionWhenFileNotContainsCertificate() { + //given + File emptyPemFile = TestCertificateProvider.getEmptyPemFile(); + PemTruststore pemCertificate = new PemTruststore(emptyPemFile); + //when//then + assertThatExceptionOfType(MissingTruststoreException.class) + .isThrownBy(pemCertificate::getCertificates); + } + + @Test + void shouldThrowExceptionWhenCannotSaveFile() { + //given + KeyStoreSpi keyStoreSpi = mock(KeyStoreSpi.class); + KeyStore keyStore = new KeyStore(keyStoreSpi, null, "") { + }; + File pemFile = TestCertificateProvider.getEmptyPemFile(); + pemFile.setWritable(false); + PemTruststore pem = new PemTruststore(pemFile); + + //when. then + assertThatExceptionOfType(WriteTruststoreFileException.class) + .isThrownBy(pem::saveFile); + } + + @Test + void transformToStringInPemFormatShouldCorrectlyTransform() throws ExitableException, IOException { + //given + Truststore pemTruststore = TestCertificateProvider.getSamplePemTruststoreFile(); + + List wrappedCertificates = pemTruststore.getCertificates(); + List certificateList = unWrapCertificate(wrappedCertificates); + File notEmptyPemFile = TestCertificateProvider.getNotEmptyPemFile(); + PemTruststore pemCertificate = new PemTruststore(notEmptyPemFile); + + //when + String certificateTransformed = pemCertificate.transformToStringInPemFormat(certificateList); + + //then + String expected = TestCertificateProvider.getExpectedPemCertificateAsString(); + assertThat(certificateTransformed).isEqualTo(expected); + } + + @Test + void fileNotContainsPemCertificateShouldReturnTrueIfFileNotContainsCertificate() + throws TruststoreDataOperationException { + //given + File emptyPemFile = TestCertificateProvider.getEmptyPemFile(); + PemTruststore pemCertificate = new PemTruststore(emptyPemFile); + //when//then + assertThat(pemCertificate.isFileWithoutPemCertificate()).isTrue(); + } + + @Test + void fileNotContainsPemCertificateShouldReturnFalseIfFileContainsCertificate() + throws TruststoreDataOperationException { + //given + File notEmptyPemFile = TestCertificateProvider.getNotEmptyPemFile(); + PemTruststore pemCertificate = new PemTruststore(notEmptyPemFile); + + //when//then + assertThat(pemCertificate.isFileWithoutPemCertificate()).isFalse(); + } + + @Test + void privateKeyIsSkippedWhileReadingCertificates() throws ExitableException { + //given + File pemTruststoreFile = TestCertificateProvider.getPemWithPrivateKeyFile(); + PemTruststore pemCertificate = new PemTruststore(pemTruststoreFile); + + //when + List certificate = pemCertificate.getCertificates(); + + //then + assertThat(certificate).hasSize(EXPECTED_ONE); + } + + private List unWrapCertificate(List certificateWithAliases) { + return certificateWithAliases + .stream() + .map(CertificateWithAlias::getCertificate) + .collect(Collectors.toList()); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TestCertificateProvider.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TestCertificateProvider.java new file mode 100644 index 00000000..f32e09ce --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TestCertificateProvider.java @@ -0,0 +1,152 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.JKS_TYPE; +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.PKCS12_TYPE; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import org.onap.oom.certservice.postprocessor.merger.exception.KeystoreInstanceException; +import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; + +public final class TestCertificateProvider { + + public static final String SAMPLE_P12_TRUSTSTORE_FILE_PATH = "src/test/resources/truststore-p12.p12"; + public static final String SAMPLE_P12_TRUSTSTORE_PASSWORD_PATH = "src/test/resources/truststore-p12.pass"; + public static final String TMP_P12_TRUSTSTORE_FILE_PATH = "src/test/resources/tmp-truststore-p12.p12"; + + public static final String SAMPLE_P12_KEYSTORE_FILE_PATH = "src/test/resources/keystore.p12"; + public static final String SAMPLE_P12_KEYSTORE_PASSWORD_PATH = "src/test/resources/keystore.pass"; + + public static final String SAMPLE_JKS_TRUSTSTORE_FILE_PATH = "src/test/resources/truststore-jks.jks"; + public static final String SAMPLE_JKS_TRUSTSTORE_UNIQUE_ALIAS_FILE_PATH = "src/test/resources/truststore-jks-uniq.jks"; + public static final String SAMPLE_JKS_TRUSTSTORE_PASSWORD_PATH = "src/test/resources/truststore-jks.pass"; + public static final String TMP_JKS_TRUSTSTORE_FILE_PATH = "src/test/resources/tmp-truststore-jks.jks"; + + public static final String SAMPLE_PEM_TRUSTSTORE_FILE_PATH = "src/test/resources/truststore.pem"; + public static final String EMPTY_PEM_TRUSTSTORE_FILE_PATH = "src/test/resources/empty-truststore.pem"; + public static final String TMP_PEM_TRUSTSTORE_FILE_PATH = "src/test/resources/tmp-truststore.pem"; + public static final String SAMPLE_PEM_TRUSTSTORE_WITH_PRIVATE_KEY_FILE_PATH = "src/test/resources/truststore-with-private-key.pem"; + + public static final String PEM_FILE_PATH = "src/test/resources/truststore.pem"; + public static final String PEM_BACKUP_FILE_PATH = "src/test/resources/truststore.pem.bak"; + + private TestCertificateProvider() { + } + + public static Truststore getSampleP12Truststore() + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + return createJavaTruststore(SAMPLE_P12_TRUSTSTORE_FILE_PATH, SAMPLE_P12_TRUSTSTORE_PASSWORD_PATH, PKCS12_TYPE); + } + + public static Truststore getSampleP12Keystore() + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + return createJavaTruststore(SAMPLE_P12_KEYSTORE_FILE_PATH, SAMPLE_P12_KEYSTORE_PASSWORD_PATH, PKCS12_TYPE); + } + + public static Truststore createTmpP12TruststoreFile() + throws IOException, LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + copyFile(SAMPLE_P12_TRUSTSTORE_FILE_PATH, TMP_P12_TRUSTSTORE_FILE_PATH); + return createJavaTruststore(TMP_P12_TRUSTSTORE_FILE_PATH, SAMPLE_P12_TRUSTSTORE_PASSWORD_PATH, PKCS12_TYPE); + } + + public static Truststore getSamplePemTruststoreFile() { + return getPemTruststoreInstance(SAMPLE_PEM_TRUSTSTORE_FILE_PATH); + } + + public static Truststore createEmptyTmpPemTruststoreFile() + throws IOException { + copyFile(EMPTY_PEM_TRUSTSTORE_FILE_PATH, TMP_PEM_TRUSTSTORE_FILE_PATH); + return getPemTruststoreInstance(TMP_PEM_TRUSTSTORE_FILE_PATH); + } + + public static Truststore createTmpPemTruststoreFile() + throws IOException { + copyFile(SAMPLE_PEM_TRUSTSTORE_FILE_PATH, TMP_PEM_TRUSTSTORE_FILE_PATH); + return getPemTruststoreInstance(TMP_PEM_TRUSTSTORE_FILE_PATH); + } + + public static String getExpectedPemCertificateAsString() throws IOException { + Path samplePemFilePath = Paths.get(SAMPLE_PEM_TRUSTSTORE_FILE_PATH); + return Files.readString(samplePemFilePath); + } + + public static Truststore getSampleJksTruststoreFile() + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + return createJavaTruststore(SAMPLE_JKS_TRUSTSTORE_FILE_PATH, SAMPLE_JKS_TRUSTSTORE_PASSWORD_PATH, JKS_TYPE); + } + + public static Truststore getSampleJksTruststoreFileWithUniqueAlias() + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + return createJavaTruststore(SAMPLE_JKS_TRUSTSTORE_UNIQUE_ALIAS_FILE_PATH, SAMPLE_JKS_TRUSTSTORE_PASSWORD_PATH, + JKS_TYPE); + } + + public static Truststore createTmpJksTruststoreFileWithUniqAlias() + throws IOException, LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + copyFile(SAMPLE_JKS_TRUSTSTORE_UNIQUE_ALIAS_FILE_PATH, TMP_JKS_TRUSTSTORE_FILE_PATH); + return createJavaTruststore(TMP_JKS_TRUSTSTORE_FILE_PATH, SAMPLE_JKS_TRUSTSTORE_PASSWORD_PATH, JKS_TYPE); + } + + public static File getEmptyPemFile() { + return getFile(EMPTY_PEM_TRUSTSTORE_FILE_PATH); + } + + public static File getNotEmptyPemFile() { + return getFile(SAMPLE_PEM_TRUSTSTORE_FILE_PATH); + } + + public static File getPemWithPrivateKeyFile() { + return getFile(SAMPLE_PEM_TRUSTSTORE_WITH_PRIVATE_KEY_FILE_PATH); + } + + public static void removeTemporaryFiles() throws IOException { + Files.deleteIfExists(Paths.get(TMP_PEM_TRUSTSTORE_FILE_PATH)); + Files.deleteIfExists(Paths.get(TMP_JKS_TRUSTSTORE_FILE_PATH)); + Files.deleteIfExists(Paths.get(TMP_P12_TRUSTSTORE_FILE_PATH)); + Files.deleteIfExists(Paths.get(PEM_BACKUP_FILE_PATH)); + } + + private static Truststore createJavaTruststore(String filePath, String password, String instanceType) + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + File certFile = getFile(filePath); + return JavaTruststoreFactory.create(certFile, password, instanceType); + } + + private static Truststore getPemTruststoreInstance( + String tmpPemTruststoreFilePath) { + File file = getFile(tmpPemTruststoreFilePath); + return new PemTruststore(file); + } + + private static void copyFile(String sourcePath, String destPath) throws IOException { + Files.copy(Paths.get(sourcePath), Paths.get(destPath), StandardCopyOption.REPLACE_EXISTING); + } + + private static File getFile(String path) { + return new File(path); + } +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactoryTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactoryTest.java new file mode 100644 index 00000000..42bf533a --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreFactoryTest.java @@ -0,0 +1,109 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.onap.oom.certservice.postprocessor.merger.exception.KeystoreInstanceException; +import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreFileFactoryException; + +@ExtendWith(MockitoExtension.class) +class TruststoreFactoryTest { + + private static final String TRUSTSTORE_JKS_PATH = "src/test/resources/truststore-jks.jks"; + private static final String TRUSTSTORE_JKS_PASS_PATH = "src/test/resources/truststore-jks.pass"; + private static final String TRUSTSTORE_P12_PATH = "src/test/resources/truststore-p12.p12"; + private static final String TRUSTSTORE_P12_PASS_PATH = "src/test/resources/truststore-p12.pass"; + private static final String TRUSTSTORE_PEM_PATH = "src/test/resources/truststore.pem"; + private static final String EMPTY_PASS_PATH = ""; + private static final String TRUSTSTORE_UNKNOWN_EXTENSION_PATH = "src/test/resources/truststore-jks.unknown"; + private static final String NON_EXISTING_TRUSTSTORE_PATH = "src/test/resources/non-existing-truststore.jks"; + + @Test + void shouldReturnCorrectJksTruststoreForJksFile() + throws LoadTruststoreException, PasswordReaderException, TruststoreFileFactoryException, KeystoreInstanceException { + //given, when + Truststore truststore = TruststoreFactory + .create(TRUSTSTORE_JKS_PATH, TRUSTSTORE_JKS_PASS_PATH); + + //then + assertThat(truststore).isInstanceOf(Truststore.class); + } + + @Test + void shouldReturnCorrectP12TruststoreForP12File() + throws LoadTruststoreException, PasswordReaderException, TruststoreFileFactoryException, KeystoreInstanceException { + //given, when + Truststore truststore = TruststoreFactory + .create(TRUSTSTORE_P12_PATH, TRUSTSTORE_P12_PASS_PATH); + + //then + assertThat(truststore).isInstanceOf(Truststore.class); + } + + @Test + void shouldReturnCorrectPemTruststoreForPemFile() + throws LoadTruststoreException, PasswordReaderException, TruststoreFileFactoryException, KeystoreInstanceException { + //given, when + Truststore truststore = TruststoreFactory + .create(TRUSTSTORE_PEM_PATH, + EMPTY_PASS_PATH); + + //then + assertThat(truststore).isInstanceOf(Truststore.class); + } + + @Test + void shouldThrowExceptionForInvalidP12PassPath() { + assertThatExceptionOfType(PasswordReaderException.class).isThrownBy( + () -> TruststoreFactory.create(TRUSTSTORE_P12_PATH, EMPTY_PASS_PATH) + ); + } + + @Test + void shouldThrowExceptionForInvalidJksPassPath() { + assertThatExceptionOfType(PasswordReaderException.class).isThrownBy( + () -> TruststoreFactory.create(TRUSTSTORE_JKS_PATH, EMPTY_PASS_PATH) + ); + } + + @Test + void shouldThrowExceptionForUnknownTruststoreExtension() { + assertThatExceptionOfType(TruststoreFileFactoryException.class).isThrownBy( + () -> TruststoreFactory + .create(TRUSTSTORE_UNKNOWN_EXTENSION_PATH, TRUSTSTORE_JKS_PASS_PATH) + ); + } + + @Test + void shouldThrowExceptionForNonExistingTruststoreFile() { + assertThatExceptionOfType(TruststoreFileFactoryException.class).isThrownBy( + () -> TruststoreFactory.create(NON_EXISTING_TRUSTSTORE_PATH, TRUSTSTORE_JKS_PASS_PATH) + ); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreTest.java new file mode 100644 index 00000000..8ef148a8 --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/TruststoreTest.java @@ -0,0 +1,206 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.onap.oom.certservice.postprocessor.api.CertificateConstants.X_509_CERTIFICATE; +import static org.onap.oom.certservice.postprocessor.merger.model.TestCertificateProvider.PEM_BACKUP_FILE_PATH; + +import java.io.File; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.onap.oom.certservice.postprocessor.api.CertificateConstants; +import org.onap.oom.certservice.postprocessor.api.ExitableException; +import org.onap.oom.certservice.postprocessor.merger.exception.CreateBackupException; +import org.onap.oom.certservice.postprocessor.merger.exception.KeystoreInstanceException; +import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException; +import org.onap.oom.certservice.postprocessor.merger.exception.PasswordReaderException; +import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias; +import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAliasFactory; + +class TruststoreTest { + + private static final String BACKUP_EXTENSION = ".bak"; + + private static final int EXPECTED_ONE = 1; + public static final int EXPECTED_THREE = 3; + public static final int FIRST_ELEMENT = 0; + + private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory(); + + @Test + void createBackupShouldCreateFileWithExtension() throws CreateBackupException { + //given + File pemFile = new File(TestCertificateProvider.PEM_FILE_PATH); + Truststore truststore = new PemTruststore(pemFile); + //when + truststore.createBackup(); + + //then + File backupFile = new File(PEM_BACKUP_FILE_PATH); + assertThat(backupFile.getName().endsWith(BACKUP_EXTENSION)).isTrue(); + assertThat(backupFile.isFile()).isTrue(); + } + + @ParameterizedTest + @MethodSource("truststoreProvider") + void truststoreShouldReadCertificatesFromFile(Truststore truststore) throws ExitableException { + //when + + List certificates = truststore.getCertificates(); + Certificate certificate = certificates.get(FIRST_ELEMENT).getCertificate(); + + //then + assertThat(certificates).hasSize(EXPECTED_ONE); + assertThat(certificate.getType()).isEqualTo(X_509_CERTIFICATE); + } + + @Test + void jksTruststoreShouldAddDifferentCertificates() throws Exception { + //given + Truststore jksTruststore = TestCertificateProvider.createTmpJksTruststoreFileWithUniqAlias(); + + List certificateFromP12 = TestCertificateProvider.getSampleP12Truststore() + .getCertificates(); + + List certificateFromPem = TestCertificateProvider + .getSamplePemTruststoreFile().getCertificates(); + + //when + + jksTruststore.addCertificates(certificateFromP12); + + jksTruststore.addCertificates(certificateFromPem); + + jksTruststore.saveFile(); + + //then + + assertThat(jksTruststore.getCertificates()).hasSize(EXPECTED_THREE); + } + + @Test + void p12TruststoreShouldAddDifferentCertificates() throws Exception { + //given + Truststore p12Truststore = TestCertificateProvider.createTmpP12TruststoreFile(); + + List certificateFromJks = TestCertificateProvider + .getSampleJksTruststoreFileWithUniqueAlias().getCertificates(); + + List certificateFromPem = TestCertificateProvider + .getSamplePemTruststoreFile().getCertificates(); + + //when + + p12Truststore.addCertificates(certificateFromJks); + p12Truststore.addCertificates(certificateFromPem); + p12Truststore.saveFile(); + + //then + + assertThat(p12Truststore.getCertificates()).hasSize(EXPECTED_THREE); + } + + @Test + void pemTruststoreShouldAddDifferentCertificates() throws IOException, ExitableException { + //given + Truststore pemTruststore = TestCertificateProvider + .createTmpPemTruststoreFile(); + + List certificateFromJks = TestCertificateProvider + .getSampleJksTruststoreFileWithUniqueAlias().getCertificates(); + + List certificateFromP12 = TestCertificateProvider.getSampleP12Truststore() + .getCertificates(); + + //when + + pemTruststore.addCertificates(certificateFromJks); + + pemTruststore.addCertificates(certificateFromP12); + + pemTruststore.saveFile(); + + //then + + List addedCertificates = pemTruststore.getCertificates(); + Certificate certificate = addedCertificates.get(FIRST_ELEMENT).getCertificate(); + + assertThat(pemTruststore.getCertificates()).hasSize(EXPECTED_THREE); + assertThat(certificate.getType()).isEqualTo(X_509_CERTIFICATE); + } + + @Test + void shouldThrowExceptionWhenFileNotContainsCertificate() throws IOException { + //given + Truststore tmpPemTruststoreFile = TestCertificateProvider + .createEmptyTmpPemTruststoreFile(); + //when//then + assertThatExceptionOfType(MissingTruststoreException.class) + .isThrownBy(() -> tmpPemTruststoreFile.getCertificates()); + } + + @Test + void shouldThrowExceptionWhenCannotConvertCertificateToPem() throws Exception { + //given + Truststore pemTruststore = TestCertificateProvider.createTmpPemTruststoreFile(); + Certificate certificate = mock(Certificate.class); + + when(certificate.getEncoded()).thenThrow(new CertificateEncodingException()); + + List certificateFromPem = new ArrayList<>(); + certificateFromPem.add(factory.createPemCertificate(certificate)); + + pemTruststore.addCertificates(certificateFromPem); + + //when //then + assertThatExceptionOfType(TruststoreDataOperationException.class) + .isThrownBy(() -> pemTruststore.saveFile()); + } + + @AfterEach + void removeTemporaryFiles() throws IOException { + TestCertificateProvider.removeTemporaryFiles(); + } + + private static Stream truststoreProvider() + throws LoadTruststoreException, KeystoreInstanceException, PasswordReaderException { + return Stream.of( + Arguments.of(TestCertificateProvider.getSampleJksTruststoreFile()), + Arguments.of(TestCertificateProvider.getSampleP12Truststore()), + Arguments.of(TestCertificateProvider.getSamplePemTruststoreFile()) + ); + } + +} diff --git a/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGeneratorTest.java b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGeneratorTest.java new file mode 100644 index 00000000..03989f6f --- /dev/null +++ b/certServicePostProcessor/src/test/java/org/onap/oom/certservice/postprocessor/merger/model/certificate/PemAliasGeneratorTest.java @@ -0,0 +1,58 @@ +/*============LICENSE_START======================================================= + * oom-truststore-merger + * ================================================================================ + * Copyright (C) 2020 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 + * + * 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.oom.certservice.postprocessor.merger.model.certificate; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashSet; +import java.util.Set; +import org.junit.jupiter.api.Test; + +class PemAliasGeneratorTest { + + private static final String PREFIX_ALIAS_NAME = "pem-trusted-certificate-"; + static final int GENERATED_ALIASES_NUMBER = 100; + + @Test + void aliasHasPemPrefix() { + //given + PemAliasGenerator pemAliasGenerator = PemAliasGenerator.getInstance(); + //when + String alias = pemAliasGenerator.getAlias(); + //then + assertThat(alias).contains(PREFIX_ALIAS_NAME); + } + + @Test + void generatedAliasesHaveUniqNames() { + //given + PemAliasGenerator pemAliasGenerator = PemAliasGenerator.getInstance(); + Set aliases = new HashSet<>(); + + //when + for (int i = 0; i < GENERATED_ALIASES_NUMBER; i++) { + aliases.add(pemAliasGenerator.getAlias()); + } + + //then + assertThat(aliases).hasSize(GENERATED_ALIASES_NUMBER); + } + +} diff --git a/certServicePostProcessor/src/test/resources/empty-truststore.pem b/certServicePostProcessor/src/test/resources/empty-truststore.pem new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/certServicePostProcessor/src/test/resources/empty-truststore.pem @@ -0,0 +1 @@ + diff --git a/certServicePostProcessor/src/test/resources/keystore.p12 b/certServicePostProcessor/src/test/resources/keystore.p12 new file mode 100644 index 00000000..bc047a98 Binary files /dev/null and b/certServicePostProcessor/src/test/resources/keystore.p12 differ diff --git a/certServicePostProcessor/src/test/resources/keystore.pass b/certServicePostProcessor/src/test/resources/keystore.pass new file mode 100644 index 00000000..665ff8e6 --- /dev/null +++ b/certServicePostProcessor/src/test/resources/keystore.pass @@ -0,0 +1 @@ +Foh49MJNYI7S_pEzE9gvUDSu \ No newline at end of file diff --git a/certServicePostProcessor/src/test/resources/truststore-jks-uniq.jks b/certServicePostProcessor/src/test/resources/truststore-jks-uniq.jks new file mode 100644 index 00000000..76ce8bc4 Binary files /dev/null and b/certServicePostProcessor/src/test/resources/truststore-jks-uniq.jks differ diff --git a/certServicePostProcessor/src/test/resources/truststore-jks.jks b/certServicePostProcessor/src/test/resources/truststore-jks.jks new file mode 100644 index 00000000..38229811 Binary files /dev/null and b/certServicePostProcessor/src/test/resources/truststore-jks.jks differ diff --git a/certServicePostProcessor/src/test/resources/truststore-jks.pass b/certServicePostProcessor/src/test/resources/truststore-jks.pass new file mode 100644 index 00000000..7426fd4d --- /dev/null +++ b/certServicePostProcessor/src/test/resources/truststore-jks.pass @@ -0,0 +1 @@ +EOyuFbuYDyq_EhpboM72RHua \ No newline at end of file diff --git a/certServicePostProcessor/src/test/resources/truststore-p12.p12 b/certServicePostProcessor/src/test/resources/truststore-p12.p12 new file mode 100644 index 00000000..0fa8aecc Binary files /dev/null and b/certServicePostProcessor/src/test/resources/truststore-p12.p12 differ diff --git a/certServicePostProcessor/src/test/resources/truststore-p12.pass b/certServicePostProcessor/src/test/resources/truststore-p12.pass new file mode 100644 index 00000000..86cc5aac --- /dev/null +++ b/certServicePostProcessor/src/test/resources/truststore-p12.pass @@ -0,0 +1 @@ +88y9v5D8H3SG6bZWRVHDfOAo \ No newline at end of file diff --git a/certServicePostProcessor/src/test/resources/truststore-with-private-key.pem b/certServicePostProcessor/src/test/resources/truststore-with-private-key.pem new file mode 100644 index 00000000..95179062 --- /dev/null +++ b/certServicePostProcessor/src/test/resources/truststore-with-private-key.pem @@ -0,0 +1,56 @@ +-----BEGIN CERTIFICATE----- +MIIEszCCAxugAwIBAgIUE+27eIlr12tQ+AMxkJTf2Y+ycOEwDQYJKoZIhvcNAQEL +BQAwYTEjMCEGCgmSJomT8ixkAQEME2MtMDRjYmE2YjhhMDQ5ODEyNGQxFTATBgNV +BAMMDE1hbmFnZW1lbnRDQTEjMCEGA1UECgwaRUpCQ0EgQ29udGFpbmVyIFF1aWNr +c3RhcnQwHhcNMjAwNzA4MTIzODU4WhcNMzAwNzA4MTIzODU4WjBhMSMwIQYKCZIm +iZPyLGQBAQwTYy0wNGNiYTZiOGEwNDk4MTI0ZDEVMBMGA1UEAwwMTWFuYWdlbWVu +dENBMSMwIQYDVQQKDBpFSkJDQSBDb250YWluZXIgUXVpY2tzdGFydDCCAaIwDQYJ +KoZIhvcNAQEBBQADggGPADCCAYoCggGBALTlx22Ld87VO5QgkD7OJvx81a8xLRWt +b4cqmLSBRKw+jTjX4fHCtLh98hXNtYXJ9nxPa2t8MKR/I00Wf1razX1IYN9H/diV +uICjyMxDyK6nwEMpqaWiQgOQx1N4TjNhr19ULTbyFLQMVfXy1OrTsfoWQ2omvRxN +LIoVKwPHd92KG6iqJDZU14ErfA6UtypDV+4rOKQBh0JrfFI/KxKFKRH3e0oDxD8c +PIOUpYVccVv/4Gbc0ZRs8KK0uPZN73LlQccYzPrSk/VAUeuZ52Wqk6dNrq5FHSCe +EwPbx6aqgLwhTLlYAJqmYuDsGU9ZL09buCVKim1pjZiPaoaYAvv3KHdjEKAu9NxF +dezd4JZ24hqYCA7EGnKgyjHxA0SiD/B8f+aBdRGDZbMlH1gKFKivjuHSfPwRv6Op +p8ykEzk3yp0RcqSflVPg0mj+LPViYo/loLLOLybFFR7BetyFieN5QV7BKRyfc7Qi +Se6Idh1nLIrYR9ek8BDkEE9u/JiTT0gP3QIDAQABo2MwYTAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFDYtHGSe9lYaC9+WnNT91wuiMlkjMB0GA1UdDgQWBBQ2 +LRxknvZWGgvflpzU/dcLojJZIzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggGBAIcLj76GVhYSuVaWMMCVlVl8rHhYYufT9z2X7G/0D1G655/dAeAJLltL +S4T7SZI44XKfVH4ztc4TO6OEMLZzslcfDzv/tUzL4EOsXtBTpsK9JgHP2lzCE+aj +a7uxn5SGWlu0YmT/++2d+QYaVVAjqalal8NsppOYCh8GB84TXbQjOMWcR9YBozZf +DSy3/vDNMuggZfdEOMMP57M10NoOKor+8eMGB42k4NR+G2npYHZ4uh1Ifk+eoTAh +o5O0iz3+/8eMTkLavqpnfzBhWHfRTI8wUu6zgm+QI+tsqhPePRuwauD8r79JBnPW +0gayZI5jIWTwvufpweKMgLyQbiGVUDtsr2c43kJ6XHoEf0ACUzbJKtGDD3Y7H/G1 +5Q7hBWbQwhUpiVeRnofS9jHQPWu0Ueq4/784hy+yPWotBIeIWEy4KzKTS+GaRDm0 +OSYtta/BdU0iZO/PzzTC5yIzwrsaq+5Idp16mub7mCAW0B36x0Phmr0DQWpZwxmX +9envV9HcJw== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCeCRM315FGH1Fa +nlHRo/JfNwPi+xAor+cC4b/5qEIsGI9Zwgg9rzs/k9XOyUYoWMCNzn8c3nTYhd8h +8KzPu7o5thiHsr1z6luVPf9zF6K4UJupR0Vba812n7Z8Ye/uyOBu0TeE6RGL7Vxv +2cKDBLKHIRpexhic2+NkfhZGyfU5kB6IMQBs08LC4wmiPffCWhoWcLk9QbNlJL0d +3g389oWZQ2NVD2zCvkKe4+LfaNE1Rzk+1Wb+fHhLbL/2tFi9bbM8GjzVewREZekw +vS4fD8i/Sdx85m35QqzX33b1KbUPmZummmyC37l2oihfWrNKxcpC0alYvfwypHZp +E26Xy2D/AgMBAAECggEABUJeDlyxK/k81twv8t8W4M5O5c3fIst/z5u9rMxJr3f9 +xUnsxki/mwULd39BQ3R4q/90QXyxvMbvvwxoY91mfCcwN8vd/C6Pb68JgkYGF0Yv +d/m0OC+lPc5g31DPEE5FEcsKovSyrcpvahWAIKYWXuLeIstK5GV48s4zZZWxAIJa +7IhLst4I3Y7B6vmPHCutOxL6VXPllhe1gAI/tRWH0Hpbk/KiN0jGirTWo9FrNgAZ +aRLcrS+a4sZuVZBMe7/NR4qXs+NbafFcuWcgRdgZLoktnKyWk5/WuhRXVuTY6H5B +pBgrffaab+qMDuziQ2SyHlm1eCnQGbl/++9UPAHZ6QKBgQDQIpVwqzfDsGxsBFo5 +y6wL5uWP8oiDoAkTjX41tgFy5G+ccHaIle/N8U+yrMkgW4tKKYFdREfA9eNxLbsB +Dy6MkYlbE6cWbcf42QN7/Nn0jWBVrSNBssAPdQYtCJw+07/Qn1rWVIkTNHpqvEV7 +T9+JgLtSD9d3yMEeW/wWpF0PBQKBgQDCYQEQ2iwqyMtsd5GRZFXboBWAVdjfuEd9 +7sZ3SM6z3U1fkKXImdncnihlLN2Ll7tMftGLMF8yxT4OWHPC9Tn7qnatlc3oSVIm +82Kj0S0j0dr0V4tjpxAhcfuDh1n02A+JQX1gK/rQN/H8JMqpc5FySTV3lBswTvAs +Gdk7J2tHMwKBgDeX1TS39vglCoC7lOH1Heo77TtKu930hBgd5gUwrShkDc/KVk7b +RadLek8uSbaD3Suc9HnWABhxVSPo5Bc/V96iDP8vu6SJBC3awUx/2DOzA3U+/rjQ +pu46AsFKmHlLk+OEfP3crJRdowkZarGqPvn6UY50vse27qZOSYI+usCFAoGBAJhF +fZxCDY+GtTVHhdWsEEZ45d8fYUIBDqBsyTTw6Fym5NIUcorvW2gkzehUeUm9l5CZ +WHX9ctZHBhIe4LC9gqrQIyBg1mk95wl0aLWETCRfZXM8kYmDenN441tqUOIp0CHq +F9mbGmS7LuojuE9+pVYuW6BNee8iJ6ukpDRe8P9ZAoGAHbXYDvWfNgHE4w15uCpE +riR19yvlWk9tsswdefhyIb36/2qX7+4cQLZsD9b/nVF+GVwbXFgn/qjRQyds+YUD +dpD/KciWewZRhlQvWChEH/hZrzauBnkE0qcMURW6Xf7NHn/7d+jembEc3bkyjnEI +6yNDF7D4l5W6gvqgiN5VSM8= +-----END RSA PRIVATE KEY----- diff --git a/certServicePostProcessor/src/test/resources/truststore.pem b/certServicePostProcessor/src/test/resources/truststore.pem new file mode 100644 index 00000000..3268e3a6 --- /dev/null +++ b/certServicePostProcessor/src/test/resources/truststore.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEszCCAxugAwIBAgIUE+27eIlr12tQ+AMxkJTf2Y+ycOEwDQYJKoZIhvcNAQEL +BQAwYTEjMCEGCgmSJomT8ixkAQEME2MtMDRjYmE2YjhhMDQ5ODEyNGQxFTATBgNV +BAMMDE1hbmFnZW1lbnRDQTEjMCEGA1UECgwaRUpCQ0EgQ29udGFpbmVyIFF1aWNr +c3RhcnQwHhcNMjAwNzA4MTIzODU4WhcNMzAwNzA4MTIzODU4WjBhMSMwIQYKCZIm +iZPyLGQBAQwTYy0wNGNiYTZiOGEwNDk4MTI0ZDEVMBMGA1UEAwwMTWFuYWdlbWVu +dENBMSMwIQYDVQQKDBpFSkJDQSBDb250YWluZXIgUXVpY2tzdGFydDCCAaIwDQYJ +KoZIhvcNAQEBBQADggGPADCCAYoCggGBALTlx22Ld87VO5QgkD7OJvx81a8xLRWt +b4cqmLSBRKw+jTjX4fHCtLh98hXNtYXJ9nxPa2t8MKR/I00Wf1razX1IYN9H/diV +uICjyMxDyK6nwEMpqaWiQgOQx1N4TjNhr19ULTbyFLQMVfXy1OrTsfoWQ2omvRxN +LIoVKwPHd92KG6iqJDZU14ErfA6UtypDV+4rOKQBh0JrfFI/KxKFKRH3e0oDxD8c +PIOUpYVccVv/4Gbc0ZRs8KK0uPZN73LlQccYzPrSk/VAUeuZ52Wqk6dNrq5FHSCe +EwPbx6aqgLwhTLlYAJqmYuDsGU9ZL09buCVKim1pjZiPaoaYAvv3KHdjEKAu9NxF +dezd4JZ24hqYCA7EGnKgyjHxA0SiD/B8f+aBdRGDZbMlH1gKFKivjuHSfPwRv6Op +p8ykEzk3yp0RcqSflVPg0mj+LPViYo/loLLOLybFFR7BetyFieN5QV7BKRyfc7Qi +Se6Idh1nLIrYR9ek8BDkEE9u/JiTT0gP3QIDAQABo2MwYTAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFDYtHGSe9lYaC9+WnNT91wuiMlkjMB0GA1UdDgQWBBQ2 +LRxknvZWGgvflpzU/dcLojJZIzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggGBAIcLj76GVhYSuVaWMMCVlVl8rHhYYufT9z2X7G/0D1G655/dAeAJLltL +S4T7SZI44XKfVH4ztc4TO6OEMLZzslcfDzv/tUzL4EOsXtBTpsK9JgHP2lzCE+aj +a7uxn5SGWlu0YmT/++2d+QYaVVAjqalal8NsppOYCh8GB84TXbQjOMWcR9YBozZf +DSy3/vDNMuggZfdEOMMP57M10NoOKor+8eMGB42k4NR+G2npYHZ4uh1Ifk+eoTAh +o5O0iz3+/8eMTkLavqpnfzBhWHfRTI8wUu6zgm+QI+tsqhPePRuwauD8r79JBnPW +0gayZI5jIWTwvufpweKMgLyQbiGVUDtsr2c43kJ6XHoEf0ACUzbJKtGDD3Y7H/G1 +5Q7hBWbQwhUpiVeRnofS9jHQPWu0Ueq4/784hy+yPWotBIeIWEy4KzKTS+GaRDm0 +OSYtta/BdU0iZO/PzzTC5yIzwrsaq+5Idp16mub7mCAW0B36x0Phmr0DQWpZwxmX +9envV9HcJw== +-----END CERTIFICATE----- -- cgit 1.2.3-korg