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

com.github.dtreskunov.easyssl.CertificateExpirationCheck Maven / Gradle / Ivy

Go to download

EasySSL is a small library to help create Spring Boot microservices that talk to each other over HTTPS with mutual authentication

There is a newer version: 2.3.2
Show newest version
package com.github.dtreskunov.easyssl;

import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.TemporalAmount;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

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

class CertificateExpirationCheck {
    private static final Logger LOG = LoggerFactory.getLogger(CertificateExpirationCheck.class);
    private static final ScheduledExecutorService SCHEDULER = Executors.newSingleThreadScheduledExecutor(
        ThreadFactoryFactory.createThreadFactory(true, CertificateExpirationCheck.class.getSimpleName() + " daemon"));

    /**
     * Logs an error when any certificate in the chain has expired, and a warning if it's close to expiring.
     * @param certificates
     * @param provenance added to the log message to help disambiguate which certificate is expiring
     * @param warningThreshold how close to expiring the certificate needs to be before a warning is logged (may be null)
     */
    public static void check(X509Certificate[] certificates, String provenance, Duration warningThreshold) {
        if (certificates == null || certificates.length == 0) {
            return;
        }
        Instant now = Instant.now();
        Instant warnIfExpiresBefore = (warningThreshold == null ? null : now.plus(warningThreshold));

        for (int i=0; i scheduleCheck(Certificate[] certificates, String provenance, Duration warningThreshold, Duration interval) {
        if (certificates == null || certificates.length == 0) {
            return null;
        }
        // this will throw an ArrayStoreException if any certificates are not X509Certificates, but this is quite a safe assumption
        X509Certificate[] x509Certificates = Arrays.copyOf(certificates, certificates.length, X509Certificate[].class);
        Runnable task = () -> {
            CertificateExpirationCheck.check(x509Certificates, provenance, warningThreshold);
        };
        // schedule first run just after the earliest-expiring cert becomes eligible for the warning
        Instant earliestExpiration = Stream.of(x509Certificates).map(X509Certificate::getNotAfter).sorted().findFirst().get().toInstant();
        Instant earliestRun = earliestExpiration.minus(warningThreshold == null ? Duration.ZERO : warningThreshold);
        Duration durationUntilEarliestRun = Duration.between(Instant.now(), earliestRun);
        Duration initialDelay = durationUntilEarliestRun.isNegative() ? Duration.ZERO : durationUntilEarliestRun;

        if (interval == null) {
            LOG.trace("Scheduling local certificate expiration check with delay {} (not repeated)", initialDelay);
            return SCHEDULER.schedule(task, initialDelay.getSeconds(), TimeUnit.SECONDS);
        } else {
            LOG.trace("Scheduling local certificate expiration check with delay {} (repeated with interval {})", initialDelay, interval);
            return SCHEDULER.scheduleAtFixedRate(task, initialDelay.getSeconds(), interval.getSeconds(), TimeUnit.SECONDS);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy