mirror of https://github.com/shred/acme4j
Find certificates by issuer
parent
7f20545e14
commit
a648a513f6
|
@ -22,6 +22,7 @@ import java.io.Writer;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.security.Principal;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
@ -134,6 +135,43 @@ public class Certificate extends AcmeResource {
|
||||||
return alternateCerts;
|
return alternateCerts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this certificate was issued by the given issuer name.
|
||||||
|
*
|
||||||
|
* @param issuer
|
||||||
|
* Issuer name to check against, case-sensitive
|
||||||
|
* @return {@code true} if this issuer name was found in the certificate chain as
|
||||||
|
* issuer, {@code false} otherwise.
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public boolean isIssuedBy(String issuer) {
|
||||||
|
var issuerCn = "CN=" + issuer;
|
||||||
|
return getCertificateChain().stream()
|
||||||
|
.map(X509Certificate::getIssuerX500Principal)
|
||||||
|
.map(Principal::getName)
|
||||||
|
.anyMatch(issuerCn::equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a {@link Certificate} that was issued by the given issuer name.
|
||||||
|
*
|
||||||
|
* @param issuer
|
||||||
|
* Issuer name to check against, case-sensitive
|
||||||
|
* @return Certificate that was issued by that issuer, or {@code empty} if there was
|
||||||
|
* none. The returned {@link Certificate} may be this instance, or one of the
|
||||||
|
* {@link #getAlternateCertificates()} instances. If multiple certificates are issued
|
||||||
|
* by that issuer, the first one that was found is returned.
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public Optional<Certificate> findCertificate(String issuer) {
|
||||||
|
if (isIssuedBy(issuer)) {
|
||||||
|
return Optional.of(this);
|
||||||
|
}
|
||||||
|
return getAlternateCertificates().stream()
|
||||||
|
.filter(c -> c.isIssuedBy(issuer))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the certificate to the given writer. It is written in PEM format, with the
|
* Writes the certificate to the given writer. It is written in PEM format, with the
|
||||||
* end-entity cert coming first, followed by the intermediate certificates.
|
* end-entity cert coming first, followed by the intermediate certificates.
|
||||||
|
|
|
@ -15,8 +15,7 @@ package org.shredzone.acme4j;
|
||||||
|
|
||||||
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
|
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
|
import static org.shredzone.acme4j.toolbox.TestUtils.*;
|
||||||
import static org.shredzone.acme4j.toolbox.TestUtils.url;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -49,6 +48,8 @@ public class CertificateTest {
|
||||||
|
|
||||||
private final URL resourceUrl = url("http://example.com/acme/resource");
|
private final URL resourceUrl = url("http://example.com/acme/resource");
|
||||||
private final URL locationUrl = url("http://example.com/acme/certificate");
|
private final URL locationUrl = url("http://example.com/acme/certificate");
|
||||||
|
private final URL alternate1Url = url("https://example.com/acme/alt-cert/1");
|
||||||
|
private final URL alternate2Url = url("https://example.com/acme/alt-cert/2");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a certificate can be downloaded.
|
* Test that a certificate can be downloaded.
|
||||||
|
@ -56,26 +57,32 @@ public class CertificateTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDownload() throws Exception {
|
public void testDownload() throws Exception {
|
||||||
var originalCert = TestUtils.createCertificate("/cert.pem");
|
var originalCert = TestUtils.createCertificate("/cert.pem");
|
||||||
|
var alternateCert = TestUtils.createCertificate("/certid-cert.pem");
|
||||||
|
|
||||||
var provider = new TestableConnectionProvider() {
|
var provider = new TestableConnectionProvider() {
|
||||||
|
List<X509Certificate> sendCert;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int sendCertificateRequest(URL url, Login login) {
|
public int sendCertificateRequest(URL url, Login login) {
|
||||||
assertThat(url).isEqualTo(locationUrl);
|
assertThat(url).isIn(locationUrl, alternate1Url, alternate2Url);
|
||||||
assertThat(login).isNotNull();
|
assertThat(login).isNotNull();
|
||||||
|
if (locationUrl.equals(url)) {
|
||||||
|
sendCert = originalCert;
|
||||||
|
} else {
|
||||||
|
sendCert = alternateCert;
|
||||||
|
}
|
||||||
return HttpURLConnection.HTTP_OK;
|
return HttpURLConnection.HTTP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<X509Certificate> readCertificates() {
|
public List<X509Certificate> readCertificates() {
|
||||||
return originalCert;
|
return sendCert;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<URL> getLinks(String relation) {
|
public Collection<URL> getLinks(String relation) {
|
||||||
assertThat(relation).isEqualTo("alternate");
|
assertThat(relation).isEqualTo("alternate");
|
||||||
return Arrays.asList(
|
return Arrays.asList(alternate1Url, alternate2Url);
|
||||||
url("https://example.com/acme/alt-cert/1"),
|
|
||||||
url("https://example.com/acme/alt-cert/2"));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,21 +115,33 @@ public class CertificateTest {
|
||||||
}
|
}
|
||||||
assertThat(writtenPem).isEqualTo(originalPem);
|
assertThat(writtenPem).isEqualTo(originalPem);
|
||||||
|
|
||||||
|
assertThat(cert.isIssuedBy("The ACME CA X1")).isFalse();
|
||||||
|
assertThat(cert.isIssuedBy(CERT_ISSUER)).isTrue();
|
||||||
|
|
||||||
assertThat(cert.getAlternates()).isNotNull();
|
assertThat(cert.getAlternates()).isNotNull();
|
||||||
assertThat(cert.getAlternates()).hasSize(2);
|
assertThat(cert.getAlternates()).hasSize(2);
|
||||||
assertThat(cert.getAlternates()).element(0).isEqualTo(url("https://example.com/acme/alt-cert/1"));
|
assertThat(cert.getAlternates()).element(0).isEqualTo(alternate1Url);
|
||||||
assertThat(cert.getAlternates()).element(1).isEqualTo(url("https://example.com/acme/alt-cert/2"));
|
assertThat(cert.getAlternates()).element(1).isEqualTo(alternate2Url);
|
||||||
|
|
||||||
assertThat(cert.getAlternateCertificates()).isNotNull();
|
assertThat(cert.getAlternateCertificates()).isNotNull();
|
||||||
assertThat(cert.getAlternateCertificates()).hasSize(2);
|
assertThat(cert.getAlternateCertificates()).hasSize(2);
|
||||||
assertThat(cert.getAlternateCertificates())
|
assertThat(cert.getAlternateCertificates())
|
||||||
.element(0)
|
.element(0)
|
||||||
.extracting(Certificate::getLocation)
|
.extracting(Certificate::getLocation)
|
||||||
.isEqualTo(url("https://example.com/acme/alt-cert/1"));
|
.isEqualTo(alternate1Url);
|
||||||
assertThat(cert.getAlternateCertificates())
|
assertThat(cert.getAlternateCertificates())
|
||||||
.element(1)
|
.element(1)
|
||||||
.extracting(Certificate::getLocation)
|
.extracting(Certificate::getLocation)
|
||||||
.isEqualTo(url("https://example.com/acme/alt-cert/2"));
|
.isEqualTo(alternate2Url);
|
||||||
|
|
||||||
|
assertThat(cert.findCertificate("The ACME CA X1")).
|
||||||
|
isEmpty();
|
||||||
|
assertThat(cert.findCertificate(CERT_ISSUER).orElseThrow())
|
||||||
|
.isSameAs(cert);
|
||||||
|
assertThat(cert.findCertificate("minica root ca 3a1356").orElseThrow())
|
||||||
|
.isSameAs(cert.getAlternateCertificates().get(0));
|
||||||
|
assertThat(cert.getAlternateCertificates().get(0).isIssuedBy("minica root ca 3a1356"))
|
||||||
|
.isTrue();
|
||||||
|
|
||||||
provider.close();
|
provider.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ public final class TestUtils {
|
||||||
|
|
||||||
public static final String DUMMY_NONCE = Base64.getUrlEncoder().withoutPadding().encodeToString("foo-nonce-foo".getBytes());
|
public static final String DUMMY_NONCE = Base64.getUrlEncoder().withoutPadding().encodeToString("foo-nonce-foo".getBytes());
|
||||||
|
|
||||||
|
public static final String CERT_ISSUER = "Pebble Intermediate CA 645fc5";
|
||||||
|
|
||||||
public static final NetworkSettings DEFAULT_NETWORK_SETTINGS = new NetworkSettings();
|
public static final NetworkSettings DEFAULT_NETWORK_SETTINGS = new NetworkSettings();
|
||||||
|
|
||||||
private TestUtils() {
|
private TestUtils() {
|
||||||
|
|
Loading…
Reference in New Issue