Polish "Add SslInfoContributor and SslHealthIndicator"
See gh-41205
This commit is contained in:
@@ -17,8 +17,6 @@
|
||||
package org.springframework.boot.actuate.ssl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
@@ -26,12 +24,10 @@ import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.info.SslInfo;
|
||||
import org.springframework.boot.info.SslInfo.CertificateChain;
|
||||
import org.springframework.boot.info.SslInfo.CertificateInfo.Validity;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} that checks the certificates the application uses and reports
|
||||
* {@link Status#OUT_OF_SERVICE} when a certificate is invalid or "WILL_EXPIRE_SOON" if it
|
||||
* will expire within the configurable threshold.
|
||||
* {@link Status#OUT_OF_SERVICE} when a certificate is invalid.
|
||||
*
|
||||
* @author Jonatan Ivanov
|
||||
* @since 3.4.0
|
||||
@@ -46,43 +42,38 @@ public class SslHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Builder builder) throws Exception {
|
||||
List<CertificateChain> notValidCertificateChains = this.sslInfo.getBundles()
|
||||
List<CertificateChain> certificateChains = this.sslInfo.getBundles()
|
||||
.stream()
|
||||
.flatMap((bundle) -> bundle.getCertificateChains().stream())
|
||||
.filter(this::containsNotValidCertificate)
|
||||
.toList();
|
||||
|
||||
if (notValidCertificateChains.isEmpty()) {
|
||||
List<CertificateChain> validCertificateChains = certificateChains.stream()
|
||||
.filter(this::containsOnlyValidCertificates)
|
||||
.toList();
|
||||
List<CertificateChain> invalidCertificateChains = certificateChains.stream()
|
||||
.filter(this::containsInvalidCertificate)
|
||||
.toList();
|
||||
builder.withDetail("validChains", validCertificateChains);
|
||||
builder.withDetail("invalidChains", invalidCertificateChains);
|
||||
if (invalidCertificateChains.isEmpty()) {
|
||||
builder.status(Status.UP);
|
||||
}
|
||||
else {
|
||||
Set<Validity.Status> statuses = collectCertificateStatuses(notValidCertificateChains);
|
||||
if (statuses.contains(Validity.Status.EXPIRED) || statuses.contains(Validity.Status.NOT_YET_VALID)) {
|
||||
builder.status(Status.OUT_OF_SERVICE);
|
||||
}
|
||||
else if (statuses.contains(Validity.Status.WILL_EXPIRE_SOON)) {
|
||||
builder.status(Status.UP);
|
||||
}
|
||||
else {
|
||||
builder.status(Status.OUT_OF_SERVICE);
|
||||
}
|
||||
builder.withDetail("certificateChains", notValidCertificateChains);
|
||||
builder.status(Status.OUT_OF_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsNotValidCertificate(CertificateChain certificateChain) {
|
||||
private boolean containsOnlyValidCertificates(CertificateChain certificateChain) {
|
||||
return certificateChain.getCertificates()
|
||||
.stream()
|
||||
.filter((certificate) -> certificate.getValidity() != null)
|
||||
.anyMatch((certificate) -> certificate.getValidity().getStatus() != Validity.Status.VALID);
|
||||
.allMatch((certificate) -> certificate.getValidity().getStatus().isValid());
|
||||
}
|
||||
|
||||
private Set<Validity.Status> collectCertificateStatuses(List<CertificateChain> certificateChains) {
|
||||
return certificateChains.stream()
|
||||
.flatMap((certificateChain) -> certificateChain.getCertificates().stream())
|
||||
private boolean containsInvalidCertificate(CertificateChain certificateChain) {
|
||||
return certificateChain.getCertificates()
|
||||
.stream()
|
||||
.filter((certificate) -> certificate.getValidity() != null)
|
||||
.map((certificate) -> certificate.getValidity().getStatus())
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
.anyMatch((certificate) -> !certificate.getValidity().getStatus().isValid());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,59 +66,66 @@ class SslHealthIndicatorTests {
|
||||
given(this.validity.getStatus()).willReturn(Validity.Status.VALID);
|
||||
Health health = this.healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
assertDetailsKeys(health);
|
||||
List<CertificateChain> validChains = getValidChains(health);
|
||||
assertThat(validChains).hasSize(1);
|
||||
assertThat(validChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
List<CertificateChain> invalidChains = getInvalidChains(health);
|
||||
assertThat(invalidChains).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldBeOutOfServiceIfACertificateIsExpired() {
|
||||
given(this.validity.getStatus()).willReturn(Validity.Status.EXPIRED);
|
||||
Health health = this.healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
|
||||
assertThat(health.getDetails()).hasSize(1);
|
||||
List<CertificateChain> certificateChains = (List<CertificateChain>) health.getDetails()
|
||||
.get("certificateChains");
|
||||
assertThat(certificateChains).hasSize(1);
|
||||
assertThat(certificateChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
assertDetailsKeys(health);
|
||||
List<CertificateChain> validChains = getValidChains(health);
|
||||
assertThat(validChains).isEmpty();
|
||||
List<CertificateChain> invalidChains = getInvalidChains(health);
|
||||
assertThat(invalidChains).hasSize(1);
|
||||
assertThat(invalidChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldBeOutOfServiceIfACertificateIsNotYetValid() {
|
||||
given(this.validity.getStatus()).willReturn(Validity.Status.NOT_YET_VALID);
|
||||
Health health = this.healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
|
||||
assertThat(health.getDetails()).hasSize(1);
|
||||
List<CertificateChain> certificateChains = (List<CertificateChain>) health.getDetails()
|
||||
.get("certificateChains");
|
||||
assertThat(certificateChains).hasSize(1);
|
||||
assertThat(certificateChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
assertDetailsKeys(health);
|
||||
List<CertificateChain> validChains = getValidChains(health);
|
||||
assertThat(validChains).isEmpty();
|
||||
List<CertificateChain> invalidChains = getInvalidChains(health);
|
||||
assertThat(invalidChains).hasSize(1);
|
||||
assertThat(invalidChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldReportWarningIfACertificateWillExpireSoon() {
|
||||
given(this.validity.getStatus()).willReturn(Validity.Status.WILL_EXPIRE_SOON);
|
||||
Health health = this.healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).hasSize(1);
|
||||
List<CertificateChain> certificateChains = (List<CertificateChain>) health.getDetails()
|
||||
.get("certificateChains");
|
||||
assertThat(certificateChains).hasSize(1);
|
||||
assertThat(certificateChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
assertDetailsKeys(health);
|
||||
List<CertificateChain> validChains = getValidChains(health);
|
||||
assertThat(validChains).hasSize(1);
|
||||
assertThat(validChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
List<CertificateChain> invalidChains = getInvalidChains(health);
|
||||
assertThat(invalidChains).isEmpty();
|
||||
}
|
||||
|
||||
private static void assertDetailsKeys(Health health) {
|
||||
assertThat(health.getDetails()).containsOnlyKeys("validChains", "invalidChains");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void shouldBeOutOfServiceIfACertificateHasUnMappedValidityStatus() {
|
||||
given(this.validity.getStatus()).willReturn(mock(Validity.Status.class));
|
||||
Health health = this.healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
|
||||
assertThat(health.getDetails()).hasSize(1);
|
||||
List<CertificateChain> certificateChains = (List<CertificateChain>) health.getDetails()
|
||||
.get("certificateChains");
|
||||
assertThat(certificateChains).hasSize(1);
|
||||
assertThat(certificateChains.get(0)).isInstanceOf(CertificateChain.class);
|
||||
private static List<CertificateChain> getInvalidChains(Health health) {
|
||||
return (List<CertificateChain>) health.getDetails().get("invalidChains");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<CertificateChain> getValidChains(Health health) {
|
||||
return (List<CertificateChain>) health.getDetails().get("validChains");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user