1 /*============LICENSE_START=======================================================
 
   2  * oom-truststore-merger
 
   3  * ================================================================================
 
   4  * Copyright (C) 2020 Nokia. All rights reserved.
 
   5  * ================================================================================
 
   6  * Licensed under the Apache License, Version 2.0 (the "License");
 
   7  * you may not use this file except in compliance with the License.
 
   8  * You may obtain a copy of the License at
 
  10  *      http://www.apache.org/licenses/LICENSE-2.0
 
  12  * Unless required by applicable law or agreed to in writing, software
 
  13  * distributed under the License is distributed on an "AS IS" BASIS,
 
  14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  15  * See the License for the specific language governing permissions and
 
  16  * limitations under the License.
 
  17  * ============LICENSE_END=========================================================
 
  20 package org.onap.oom.certservice.postprocessor.merger.model;
 
  23 import java.io.FileInputStream;
 
  24 import java.io.FileOutputStream;
 
  25 import java.security.KeyStore;
 
  26 import java.security.KeyStoreException;
 
  27 import java.util.ArrayList;
 
  28 import java.util.Collections;
 
  29 import java.util.List;
 
  30 import org.onap.oom.certservice.postprocessor.merger.exception.AliasConflictException;
 
  31 import org.onap.oom.certservice.postprocessor.merger.exception.LoadTruststoreException;
 
  32 import org.onap.oom.certservice.postprocessor.merger.exception.MissingTruststoreException;
 
  33 import org.onap.oom.certservice.postprocessor.merger.exception.TruststoreDataOperationException;
 
  34 import org.onap.oom.certservice.postprocessor.merger.exception.WriteTruststoreFileException;
 
  35 import org.onap.oom.certservice.postprocessor.api.ExitableException;
 
  36 import org.onap.oom.certservice.postprocessor.common.FileTools;
 
  37 import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAlias;
 
  38 import org.onap.oom.certservice.postprocessor.merger.model.certificate.CertificateWithAliasFactory;
 
  39 import org.slf4j.Logger;
 
  40 import org.slf4j.LoggerFactory;
 
  42 public final class JavaTruststore extends Truststore {
 
  44     private static final Logger LOGGER = LoggerFactory.getLogger(JavaTruststore.class);
 
  46     private final CertificateWithAliasFactory factory = new CertificateWithAliasFactory();
 
  47     private final KeyStore keyStore;
 
  48     private final String password;
 
  51     private JavaTruststore(KeyStore keyStore, File storeFile, String password) {
 
  52         super(storeFile, new FileTools());
 
  53         this.keyStore = keyStore;
 
  54         this.password = password;
 
  57     public static JavaTruststore createWithLoadingFile(KeyStore keyStore, File storeFile, String password)
 
  58         throws LoadTruststoreException {
 
  59         JavaTruststore javaTruststore = new JavaTruststore(keyStore, storeFile, password);
 
  60         javaTruststore.loadFile();
 
  61         return javaTruststore;
 
  64     public List<CertificateWithAlias> getCertificates() throws ExitableException {
 
  65         LOGGER.debug("Attempt to read certificates from file: {}", storeFile.getPath());
 
  66         List<String> aliases = getTruststoreAliases();
 
  67         if (aliases.isEmpty()) {
 
  68             throw new MissingTruststoreException("Missing certificate aliases in file: " + storeFile.getPath());
 
  70         return getWrappedCertificates(aliases);
 
  73     public void addCertificates(List<CertificateWithAlias> certificatesWithAliases)
 
  74         throws ExitableException {
 
  75         LOGGER.debug("Attempt to add certificates for saving to file");
 
  76         if (getTruststoreAliases().isEmpty()) {
 
  77             throw new MissingTruststoreException("Missing certificate aliases in file: " + storeFile.getPath());
 
  79         for (CertificateWithAlias certificate : certificatesWithAliases) {
 
  80             addCertificate(certificate);
 
  84     public void saveFile() throws WriteTruststoreFileException {
 
  85         LOGGER.debug("Attempt to save file: {}", storeFile.getPath());
 
  86         try (FileOutputStream outputStream = new FileOutputStream(storeFile)) {
 
  87             keyStore.store(outputStream, this.password.toCharArray());
 
  88         } catch (Exception e) {
 
  89             LOGGER.error("Cannot write truststore file");
 
  90             throw new WriteTruststoreFileException(e);
 
  94     private void loadFile() throws LoadTruststoreException {
 
  96             keyStore.load(new FileInputStream(storeFile), this.password.toCharArray());
 
  97         } catch (Exception e) {
 
  98             LOGGER.error("Cannot load file: {}", storeFile.getPath());
 
  99             throw new LoadTruststoreException(e);
 
 103     private void addCertificate(CertificateWithAlias certificate)
 
 104         throws TruststoreDataOperationException, AliasConflictException {
 
 105         if (hasAliasConflict(certificate)) {
 
 106             LOGGER.error("Alias conflict detected");
 
 107             throw new AliasConflictException("Alias conflict detected. Alias conflicted: " + certificate.getAlias());
 
 110             keyStore.setCertificateEntry(certificate.getAlias(), certificate.getCertificate());
 
 111         } catch (KeyStoreException e) {
 
 112             LOGGER.error("Cannot merge certificate with alias: {}", certificate.getAlias());
 
 113             throw new TruststoreDataOperationException(e);
 
 117     private boolean hasAliasConflict(CertificateWithAlias certificate) throws TruststoreDataOperationException {
 
 119             return keyStore.containsAlias(certificate.getAlias());
 
 120         } catch (KeyStoreException e) {
 
 121             LOGGER.error("Cannot check alias conflict");
 
 122             throw new TruststoreDataOperationException(e);
 
 126     private List<CertificateWithAlias> getWrappedCertificates(List<String> aliases)
 
 127         throws TruststoreDataOperationException {
 
 129         List<CertificateWithAlias> certificateWrapped = new ArrayList<>();
 
 131         for (String alias : aliases) {
 
 132             certificateWrapped.add(createWrappedCertificate(alias));
 
 134         return certificateWrapped;
 
 137     private CertificateWithAlias createWrappedCertificate(String alias) throws TruststoreDataOperationException {
 
 139             return factory.createCertificateWithAlias(keyStore.getCertificate(alias), alias);
 
 140         } catch (KeyStoreException e) {
 
 141             LOGGER.warn("Cannot get certificate with alias: {} ", alias);
 
 142             throw new TruststoreDataOperationException(e);
 
 146     private List<String> getTruststoreAliases() throws TruststoreDataOperationException {
 
 148             List<String> aliases = Collections.list(keyStore.aliases());
 
 149             return getFilteredAlias(aliases);
 
 150         } catch (KeyStoreException e) {
 
 151             LOGGER.warn("Cannot read truststore aliases");
 
 152             throw new TruststoreDataOperationException(e);
 
 156     private List<String> getFilteredAlias(List<String> aliases) throws KeyStoreException {
 
 157         List<String> filteredAlias = new ArrayList<>();
 
 158         for (String alias : aliases) {
 
 159             if (keyStore.isCertificateEntry(alias)) {
 
 160                 filteredAlias.add(alias);
 
 163         return filteredAlias;