All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.europa.esig.dss.service.crl.OnlineCRLSource Maven / Gradle / Ivy

/**
 * 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.service.crl;

import eu.europa.esig.dss.crl.CRLBinary;
import eu.europa.esig.dss.crl.CRLUtils;
import eu.europa.esig.dss.crl.CRLValidity;
import eu.europa.esig.dss.enumerations.RevocationOrigin;
import eu.europa.esig.dss.model.x509.CertificateToken;
import eu.europa.esig.dss.model.x509.revocation.crl.CRL;
import eu.europa.esig.dss.service.http.commons.CommonsDataLoader;
import eu.europa.esig.dss.spi.CertificateExtensionsUtils;
import eu.europa.esig.dss.spi.client.http.DataLoader;
import eu.europa.esig.dss.spi.client.http.Protocol;
import eu.europa.esig.dss.spi.exception.DSSExternalResourceException;
import eu.europa.esig.dss.spi.x509.revocation.RevocationSourceAlternateUrlsSupport;
import eu.europa.esig.dss.spi.x509.revocation.crl.CRLSource;
import eu.europa.esig.dss.spi.x509.revocation.crl.CRLToken;
import eu.europa.esig.dss.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * Online CRL repository. This CRL repository implementation will download the
 * CRLs from the given CRL URIs. Note that for the HTTP kind of URLs you can
 * provide dedicated data loader. If the data loader is not provided the
 * standard load from URI is provided. For FTP the standard load from URI is
 * provided. For LDAP kind of URLs an internal implementation using
 * apache-ldap-api is provided.
 *
 */
public class OnlineCRLSource implements CRLSource, RevocationSourceAlternateUrlsSupport {
	
	private static final long serialVersionUID = 6912729291417315212L;

	private static final Logger LOG = LoggerFactory.getLogger(OnlineCRLSource.class);

	/**
	 * If the multiple protocols are available to retrieve the revocation data,
	 * then that indicated by this variable is used first.
	 */
	private Protocol preferredProtocol;

	/**
	 * The component that allows to retrieve the data using any protocol: HTTP,
	 * HTTPS, FTP, LDAP.
	 */
	private DataLoader dataLoader;

	/**
	 * The default constructor. A {@code CommonsDataLoader is created}.
	 */
	public OnlineCRLSource() {
		dataLoader = new CommonsDataLoader();
		LOG.trace("+OnlineCRLSource with the default data loader.");
	}

	/**
	 * This constructor allows to set a specific {@code DataLoader}.
	 *
	 * @param dataLoader
	 *            the component that allows to retrieve the data using any
	 *            protocol: HTTP, HTTPS, FTP, LDAP.
	 */
	public OnlineCRLSource(final DataLoader dataLoader) {
		this.dataLoader = dataLoader;
		LOG.trace("+OnlineCRLSource with the specific data loader.");
	}

	/**
	 * This method allows to set the preferred protocol. This parameter is used
	 * when retrieving the CRL to choose the canal.
* Possible values are: http, ldap, ftp * * @param preferredProtocol * {@code Protocol} that is used first to retrieve the revocation * data */ public void setPreferredProtocol(final Protocol preferredProtocol) { this.preferredProtocol = preferredProtocol; } /** * Set the DataLoader to use for querying a revocation server. * * @param dataLoader * the component that allows to retrieve a CRL response using HTTP. */ public void setDataLoader(final DataLoader dataLoader) { this.dataLoader = dataLoader; } @Override public CRLToken getRevocationToken(CertificateToken certificateToken, CertificateToken issuerCertificateToken) { return getRevocationToken(certificateToken, issuerCertificateToken, Collections.emptyList()); } @Override public CRLToken getRevocationToken(final CertificateToken certificateToken, final CertificateToken issuerToken, List alternativeUrls) { Objects.requireNonNull(certificateToken, "CertificateToken cannot be null!"); Objects.requireNonNull(issuerToken, "Issuer CertificateToken cannot be null!"); Objects.requireNonNull(dataLoader, "DataLoader is not provided !"); LOG.trace("--> OnlineCRLSource queried for {}", certificateToken.getDSSIdAsString()); final List crlUrls = getCRLAccessURLs(certificateToken, alternativeUrls); if (Utils.isCollectionEmpty(crlUrls)) { throw new DSSExternalResourceException(String.format( "No CRL location found for certificate with Id '%s'", certificateToken.getDSSIdAsString())); } int nbTries = crlUrls.size(); for (String crlUrl : crlUrls) { if (LOG.isDebugEnabled()) { LOG.debug("Trying to retrieve a CRL from URL '{}'...", crlUrl); } nbTries--; try { final CRLBinary crlBinary = executeCRLRequest(crlUrl); final CRLValidity crlValidity = CRLUtils.buildCRLValidity(crlBinary, issuerToken); final CRLToken crlToken = new CRLToken(certificateToken, crlValidity); crlToken.setExternalOrigin(RevocationOrigin.EXTERNAL); crlToken.setSourceURL(crlUrl); if (LOG.isDebugEnabled()) { LOG.debug("CRL '{}' has been retrieved from a source with URL '{}'.", crlToken.getDSSIdAsString(), crlUrl); } return crlToken; } catch (Exception e) { if (nbTries == 0) { throw new DSSExternalResourceException(String.format( "Unable to retrieve CRL for certificate with Id '%s' from URL '%s'. Reason : %s", certificateToken.getDSSIdAsString(), crlUrl, e.getMessage()), e); } else { LOG.warn("Unable to retrieve CRL with URL '{}' : {}", crlUrl, e.getMessage()); } } } throw new IllegalStateException(String.format("Invalid state within OnlineCRLSource " + "for a certificate call with id '%s'", certificateToken.getDSSIdAsString())); } /** * Extracts a list of CRL distribution point URLs to be used in the provided order to retrieve a CRL * * @param certificateToken {@link CertificateToken} to retrieve CRL for * @param alternativeUrls a list of {@link String} representing alternative URL sources * @return a list of {@link String} urls */ protected List getCRLAccessURLs(CertificateToken certificateToken, List alternativeUrls) { if (Utils.isCollectionNotEmpty(alternativeUrls)) { LOG.info("CRL alternative urls : {}", alternativeUrls); } final List crlAccessUrls = CertificateExtensionsUtils.getCRLAccessUrls(certificateToken); final List crlUrls = new ArrayList<>(); crlUrls.addAll(crlAccessUrls); crlUrls.addAll(alternativeUrls); prioritize(crlUrls); return crlUrls; } /** * Download a CRL from given location * * @param crlUrl {@link String} url to download CRL from * @return {@link CRLBinary} */ protected CRLBinary executeCRLRequest(final String crlUrl) { byte[] bytes = dataLoader.get(crlUrl); if (Utils.isArrayNotEmpty(bytes)) { return CRLUtils.buildCRLBinary(bytes); } throw new DSSExternalResourceException(String.format("CRL DataLoader for certificate with url '%s' " + "responded with an empty byte array!", crlUrl)); } /** * if {@code preferredProtocol} is set then the list of urls is prioritize. * NOTE: This is not standard conformant! However in the major number of * cases LDAP is much slower then HTTP! * * @param urls * {@code List} of urls to prioritize */ private void prioritize(final List urls) { if (preferredProtocol != null) { final List priorityUrls = new ArrayList<>(); for (final String url : urls) { if (preferredProtocol.isTheSame(url)) { priorityUrls.add(url); } } urls.removeAll(priorityUrls); for (int ii = priorityUrls.size() - 1; ii >= 0; ii--) { urls.add(0, priorityUrls.get(ii)); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy