eu.europa.esig.dss.tsl.service.TSLRepository.java Source code

Java tutorial

Introduction

Here is the source code for eu.europa.esig.dss.tsl.service.TSLRepository.java

Source

/**
 * DSS - Digital Signature Services
 * Copyright (C) 2015 European Commission, provided under the CEF programme
 *
 * This file is part of the "DSS - Digital Signature Services" project.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package eu.europa.esig.dss.tsl.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import javax.security.auth.x500.X500Principal;
import javax.xml.bind.DatatypeConverter;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DSSUtils;
import eu.europa.esig.dss.DigestAlgorithm;
import eu.europa.esig.dss.tsl.Condition;
import eu.europa.esig.dss.tsl.ServiceInfo;
import eu.europa.esig.dss.tsl.TSLConditionsForQualifiers;
import eu.europa.esig.dss.tsl.TSLLoaderResult;
import eu.europa.esig.dss.tsl.TSLParserResult;
import eu.europa.esig.dss.tsl.TSLService;
import eu.europa.esig.dss.tsl.TSLServiceExtension;
import eu.europa.esig.dss.tsl.TSLServiceProvider;
import eu.europa.esig.dss.tsl.TSLValidationModel;
import eu.europa.esig.dss.tsl.TSLValidationResult;
import eu.europa.esig.dss.tsl.TSLValidationSummary;
import eu.europa.esig.dss.tsl.TrustedListsCertificateSource;
import eu.europa.esig.dss.x509.CertificateToken;

/**
 * This class is a repository which allows to store TSL loading/parsing/validation results.
 *
 */
public class TSLRepository {

    private static final Logger logger = LoggerFactory.getLogger(TSLRepository.class);

    private String cacheDirectoryPath = System.getProperty("java.io.tmpdir") + File.separator + "dss-cache-tsl"
            + File.separator;

    private boolean allowExpiredTSLs = false;

    private boolean allowInvalidSignatures = false;

    private boolean allowIndeterminateSignatures = false;

    private Map<String, TSLValidationModel> tsls = new HashMap<String, TSLValidationModel>();

    private TrustedListsCertificateSource trustedListsCertificateSource;

    public void setCacheDirectoryPath(String cacheDirectoryPath) {
        this.cacheDirectoryPath = cacheDirectoryPath;
    }

    public void setAllowExpiredTSLs(boolean allowExpiredTSLs) {
        this.allowExpiredTSLs = allowExpiredTSLs;
    }

    public void setAllowInvalidSignatures(boolean allowInvalidSignatures) {
        this.allowInvalidSignatures = allowInvalidSignatures;
    }

    public void setAllowIndeterminateSignatures(boolean allowIndeterminateSignatures) {
        this.allowIndeterminateSignatures = allowIndeterminateSignatures;
    }

    public void setTrustedListsCertificateSource(TrustedListsCertificateSource trustedListsCertificateSource) {
        this.trustedListsCertificateSource = trustedListsCertificateSource;
    }

    public TSLValidationModel getByCountry(String countryIsoCode) {
        return tsls.get(countryIsoCode);
    }

    public List<TSLValidationModel> getTSLValidationModels() {
        List<TSLValidationModel> result = new ArrayList<TSLValidationModel>();
        Date now = new Date();
        for (TSLValidationModel tslValidationModel : tsls.values()) {
            if (!allowExpiredTSLs) {
                TSLParserResult parseResult = tslValidationModel.getParseResult();
                if (parseResult != null) {
                    if (now.after(parseResult.getNextUpdateDate())) {
                        continue;
                    }
                }
            }
            if (!allowInvalidSignatures) {
                TSLValidationResult validationResult = tslValidationModel.getValidationResult();
                if (validationResult != null) {
                    if (validationResult.isInvalid()) {
                        continue;
                    }
                }
            }
            if (!allowIndeterminateSignatures) {
                TSLValidationResult validationResult = tslValidationModel.getValidationResult();
                if (validationResult != null) {
                    if (validationResult.isIndeterminate()) {
                        continue;
                    }
                }
            }
            result.add(tslValidationModel);
        }
        return Collections.unmodifiableList(result);
    }

    private List<TSLValidationModel> getSkippedTSLValidationModels() {
        List<TSLValidationModel> valids = getTSLValidationModels();
        Map<String, TSLValidationModel> all = getAllMapTSLValidationModels();
        List<TSLValidationModel> skippeds = new ArrayList<TSLValidationModel>();

        for (Entry<String, TSLValidationModel> entry : all.entrySet()) {
            boolean found = false;
            for (TSLValidationModel valid : valids) {
                if ((valid.getParseResult() != null)
                        && entry.getKey().equals(valid.getParseResult().getTerritory())) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                skippeds.add(entry.getValue());
            }
        }
        return skippeds;
    }

    public Map<String, TSLValidationModel> getAllMapTSLValidationModels() {
        return Collections.unmodifiableMap(new TreeMap<String, TSLValidationModel>(tsls));
    }

    public void clearRepository() {
        try {
            FileUtils.cleanDirectory(new File(cacheDirectoryPath));
            tsls.clear();
        } catch (IOException e) {
            logger.error("Unable to clean cache directory : " + e.getMessage(), e);
        }
    }

    boolean isLastVersion(TSLLoaderResult resultLoader) {
        TSLValidationModel validationModel = getByCountry(resultLoader.getCountryCode());
        if (validationModel == null) {
            return false;
        } else {
            // TODO Best place ? Download didn't work, we use previous version
            if (ArrayUtils.isEmpty(resultLoader.getContent())) {
                return true;
            }
            validationModel.setUrl(resultLoader.getUrl());
            validationModel.setLoadedDate(new Date());
            String lastSha256 = getSHA256(resultLoader.getContent());
            return StringUtils.equals(lastSha256, validationModel.getSha256FileContent());
        }
    }

    void updateParseResult(TSLParserResult tslParserResult) {
        TSLValidationModel validationModel = getByCountry(tslParserResult.getTerritory());
        if (validationModel != null) {
            validationModel.setParseResult(tslParserResult);
        }
    }

    void updateValidationResult(TSLValidationResult tslValidationResult) {
        TSLValidationModel validationModel = getByCountry(tslValidationResult.getCountryCode());
        if (validationModel != null) {
            validationModel.setValidationResult(tslValidationResult);
        }
    }

    TSLValidationModel storeInCache(TSLLoaderResult resultLoader) {
        TSLValidationModel validationModel = new TSLValidationModel();
        validationModel.setUrl(resultLoader.getUrl());
        validationModel.setSha256FileContent(getSHA256(resultLoader.getContent()));
        validationModel.setFilepath(storeOnFileSystem(resultLoader.getCountryCode(), resultLoader));
        validationModel.setLoadedDate(new Date());
        validationModel.setCertificateSourceSynchronized(false);
        add(resultLoader.getCountryCode(), validationModel);
        logger.info("New version of " + resultLoader.getCountryCode() + " TSL is stored in cache");
        return validationModel;
    }

    void addParsedResultFromCacheToMap(TSLParserResult tslParserResult) {
        TSLValidationModel validationModel = new TSLValidationModel();
        String countryCode = tslParserResult.getTerritory();
        String filePath = getFilePath(countryCode);
        validationModel.setFilepath(filePath);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            byte[] data = IOUtils.toByteArray(fis);
            validationModel.setSha256FileContent(getSHA256(data));
        } catch (Exception e) {
            logger.error("Unable to read '" + filePath + "' : " + e.getMessage());
        } finally {
            IOUtils.closeQuietly(fis);
        }
        validationModel.setParseResult(tslParserResult);
        validationModel.setCertificateSourceSynchronized(false);
        add(countryCode, validationModel);
    }

    private void add(String countryCode, TSLValidationModel tsl) {
        tsls.put(countryCode, tsl);
    }

    private String storeOnFileSystem(String countryCode, TSLLoaderResult resultLoader) {
        ensureCacheDirectoryExists();
        String filePath = getFilePath(countryCode);
        File fileToCreate = new File(filePath);
        OutputStream os = null;
        try {
            os = new FileOutputStream(fileToCreate);
            IOUtils.write(resultLoader.getContent(), os);
        } catch (Exception e) {
            throw new DSSException("Cannot create file in cache : " + e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(os);
        }
        return filePath;
    }

    private void ensureCacheDirectoryExists() {
        File cacheDir = new File(cacheDirectoryPath);
        if (!cacheDir.exists() || !cacheDir.isDirectory()) {
            cacheDir.mkdirs();
        }
    }

    private String getFilePath(String countryCode) {
        return cacheDirectoryPath + countryCode + ".xml";
    }

    private String getSHA256(byte[] data) {
        return DatatypeConverter.printBase64Binary(DSSUtils.digest(DigestAlgorithm.SHA256, data));
    }

    List<File> getStoredFiles() {
        ensureCacheDirectoryExists();
        File cacheDir = new File(cacheDirectoryPath);
        File[] listFiles = cacheDir.listFiles();
        return Arrays.asList(listFiles);
    }

    public boolean isOk() {
        List<TSLValidationModel> filteredList = getTSLValidationModels();
        Map<String, TSLValidationModel> allData = getAllMapTSLValidationModels();
        return filteredList.size() == allData.size();
    }

    void synchronize() {
        if (trustedListsCertificateSource != null) {
            // Returns valid and not expired depending of configuration
            List<TSLValidationModel> tslValidationModels = getTSLValidationModels();
            for (TSLValidationModel model : tslValidationModels) {
                if (!model.isCertificateSourceSynchronized()) {
                    boolean tlWellSigned = false;
                    TSLValidationResult validationResult = model.getValidationResult();
                    if ((validationResult != null) && validationResult.isValid()) {
                        tlWellSigned = true;
                    }

                    TSLParserResult parseResult = model.getParseResult();
                    if (parseResult != null) {
                        List<TSLServiceProvider> serviceProviders = parseResult.getServiceProviders();
                        for (TSLServiceProvider serviceProvider : serviceProviders) {
                            for (TSLService service : serviceProvider.getServices()) {
                                for (CertificateToken certificate : service.getCertificates()) {
                                    trustedListsCertificateSource.addCertificate(certificate,
                                            getServiceInfo(serviceProvider, service, tlWellSigned));
                                }

                                for (X500Principal x500Principal : service.getX500Principals()) {
                                    trustedListsCertificateSource.addX500Principal(x500Principal,
                                            getServiceInfo(serviceProvider, service, tlWellSigned));
                                }
                            }
                        }
                    }
                    model.setCertificateSourceSynchronized(true);
                }
            }

            List<TSLValidationModel> skippedTSLValidationModels = getSkippedTSLValidationModels();
            for (TSLValidationModel model : skippedTSLValidationModels) {
                if (!model.isCertificateSourceSynchronized()) {
                    TSLParserResult parseResult = model.getParseResult();
                    if (parseResult != null) {
                        List<TSLServiceProvider> serviceProviders = parseResult.getServiceProviders();
                        for (TSLServiceProvider serviceProvider : serviceProviders) {
                            for (TSLService service : serviceProvider.getServices()) {
                                for (CertificateToken certificate : service.getCertificates()) {
                                    if (trustedListsCertificateSource.removeCertificate(certificate)) {
                                        logger.info(certificate.getAbbreviation()
                                                + " is removed from trusted certificates");
                                    }
                                }
                                for (X500Principal x500Principal : service.getX500Principals()) {
                                    if (trustedListsCertificateSource.removeX500Principal(x500Principal)) {
                                        logger.info(
                                                x500Principal.getName() + " is removed from trusted certificates");
                                    }
                                }
                            }
                        }
                    }
                    model.setCertificateSourceSynchronized(true);
                }
            }

            logger.info("Nb of loaded trusted lists : " + tslValidationModels.size());
            logger.info("Nb of trusted certificates : "
                    + trustedListsCertificateSource.getNumberOfTrustedCertificates());
            logger.info("Nb of skipped trusted lists : " + skippedTSLValidationModels.size());
        }
    }

    private ServiceInfo getServiceInfo(TSLServiceProvider serviceProvider, TSLService service,
            boolean tlWellSigned) {
        ServiceInfo serviceInfo = new ServiceInfo();

        serviceInfo.setTspName(serviceProvider.getName());
        serviceInfo.setTspTradeName(serviceProvider.getTradeName());
        serviceInfo.setTspPostalAddress(serviceProvider.getPostalAddress());
        serviceInfo.setTspElectronicAddress(serviceProvider.getElectronicAddress());

        serviceInfo.setServiceName(service.getName());
        serviceInfo.setType(service.getType());
        serviceInfo.setStatus(service.getStatus());
        serviceInfo.setStatusStartDate(service.getStartDate());
        serviceInfo.setStatusEndDate(service.getEndDate());

        List<TSLServiceExtension> extensions = service.getExtensions();
        if (CollectionUtils.isNotEmpty(extensions)) {
            for (TSLServiceExtension tslServiceExtension : extensions) {
                List<TSLConditionsForQualifiers> conditionsForQualifiers = tslServiceExtension
                        .getConditionsForQualifiers();
                for (TSLConditionsForQualifiers tslConditionsForQualifiers : conditionsForQualifiers) {
                    Condition condition = tslConditionsForQualifiers.getCondition();
                    for (String qualifier : tslConditionsForQualifiers.getQualifiers()) {
                        serviceInfo.addQualifierAndCondition(qualifier, condition);
                    }
                }
            }
        }

        // TODO
        // service.setExpiredCertsRevocationInfo(expiredCertsRevocationInfo);

        serviceInfo.setTlWellSigned(tlWellSigned);
        return serviceInfo;
    }

    public List<TSLValidationSummary> getSummary() {
        Map<String, TSLValidationModel> map = getAllMapTSLValidationModels();
        List<TSLValidationSummary> summaries = new ArrayList<TSLValidationSummary>();
        for (Entry<String, TSLValidationModel> entry : map.entrySet()) {
            String country = entry.getKey();
            TSLValidationModel model = entry.getValue();
            TSLValidationSummary summary = new TSLValidationSummary();
            summary.setCountry(country);
            summary.setLoadedDate(model.getLoadedDate());
            summary.setTslUrl(model.getUrl());

            TSLParserResult parseResult = model.getParseResult();
            if (parseResult != null) {
                summary.setSequenceNumber(parseResult.getSequenceNumber());
                summary.setIssueDate(parseResult.getIssueDate());
                summary.setNextUpdateDate(parseResult.getNextUpdateDate());

                int nbServiceProviders = 0;
                int nbServices = 0;
                int nbCertificatesAndX500Principals = 0;
                List<TSLServiceProvider> serviceProviders = parseResult.getServiceProviders();
                if (serviceProviders != null) {
                    nbServiceProviders = serviceProviders.size();
                    for (TSLServiceProvider tslServiceProvider : serviceProviders) {
                        List<TSLService> services = tslServiceProvider.getServices();
                        if (services != null) {
                            nbServices += services.size();
                            for (TSLService tslService : services) {
                                List<CertificateToken> certificates = tslService.getCertificates();
                                List<X500Principal> x500Principals = tslService.getX500Principals();
                                nbCertificatesAndX500Principals += CollectionUtils.size(certificates);
                                nbCertificatesAndX500Principals += CollectionUtils.size(x500Principals);
                            }
                        }
                    }
                }
                summary.setNbServiceProviders(nbServiceProviders);
                summary.setNbServices(nbServices);
                summary.setNbCertificatesAndX500Principals(nbCertificatesAndX500Principals);
            }

            TSLValidationResult validationResult = model.getValidationResult();
            if (validationResult != null) {
                summary.setIndication(validationResult.getIndication());
            }

            summaries.add(summary);
        }
        return summaries;
    }

}