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

de.mklinger.qetcher.liferay.client.impl.QetcherClientCertificateInfo Maven / Gradle / Ivy

package de.mklinger.qetcher.liferay.client.impl;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Clock;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Enumeration;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.mklinger.micro.annotations.VisibleForTesting;

/**
 * @author Marc Klinger - mklinger[at]mklinger[dot]de
 */
public class QetcherClientCertificateInfo {
	private static final Logger LOG = LoggerFactory.getLogger(QetcherClientCertificateInfo.class);

	private static final Duration WARN_THRESHOLD = Duration.ofDays(14);

	private final KeyStore keyStore;
	private final Clock clock;

	public QetcherClientCertificateInfo(final KeyStore keyStore) {
		this(keyStore, Clock.systemUTC());
	}

	@VisibleForTesting
	protected QetcherClientCertificateInfo(final KeyStore keyStore, final Clock clock) {
		this.keyStore = keyStore;
		this.clock = clock;
	}

	public void log() {
		log(LOG);
	}

	@VisibleForTesting
	protected void log(final Logger logger) {
		final Optional notAfter = getNotAfter(keyStore);
		if (notAfter.isPresent()) {
			logger.info("Qetcher client certificate is valid until {}", notAfter.get());
			final ZonedDateTime now = ZonedDateTime.now(clock);
			if (now.isAfter(notAfter.get())) {
				logExpired(logger);
			} else if (now.plus(WARN_THRESHOLD).isAfter(notAfter.get())) {
				final Duration validDuration = Duration.between(now, notAfter.get());
				logAboutToExpire(logger, validDuration);
			}
		} else {
			logger.warn("Unable to lookup Qetcher client certificate validity");
		}
	}

	private static Optional getNotAfter(final KeyStore keyStore) {
		try {
			return Optional.ofNullable(getEarliestNotAfter(keyStore));
		} catch (final Exception e) {
			LOG.warn("Error looking up Qetcher client certificate validity", e);
			return Optional.empty();
		}
	}

	private static ZonedDateTime getEarliestNotAfter(final KeyStore keyStore) throws KeyStoreException {
		ZonedDateTime earliestNotAfter = null;

		final Enumeration aliases = keyStore.aliases();
		while (aliases.hasMoreElements()) {
			final String alias = aliases.nextElement();
			if (keyStore.isKeyEntry(alias)) {
				final Certificate[] certificateChain = keyStore.getCertificateChain(alias);
				for (final Certificate c : certificateChain) {
					final X509Certificate certificate = (X509Certificate) c;
					final ZonedDateTime notAfter = ZonedDateTime.ofInstant(certificate.getNotAfter().toInstant(), ZoneId.of("UTC"));
					if (earliestNotAfter == null || earliestNotAfter.isAfter(notAfter)) {
						earliestNotAfter = notAfter;
					}
				}
			}
		}

		return earliestNotAfter;
	}

	private void logExpired(final Logger logger) {
		logger.error("*********************************************************************");
		logger.error("* Qetcher client certificate is expired.");
		logger.error("*");
		logger.error("* Please contact Qetcher support to obtain a new certificate.");
		logger.error("*********************************************************************");
	}

	private void logAboutToExpire(final Logger logger, final Duration validDuration) {
		logger.warn("*********************************************************************");
		logger.warn("* Qetcher client certificate is about to expire.");
		logger.warn("*");
		logger.warn("* It will expire in {} day(s)", validDuration.toDays());
		logger.warn("*");
		logger.warn("* Please contact Qetcher support to obtain a new certificate.");
		logger.warn("*********************************************************************");
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy