diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java index 5fecb40a6179..8ac597ab6497 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailProperties.java @@ -76,6 +76,11 @@ public class MailProperties { */ private String jndiName; + /** + * SSL configuration. + */ + private final Ssl ssl = new Ssl(); + public String getHost() { return this.host; } @@ -136,4 +141,45 @@ public String getJndiName() { return this.jndiName; } + public Ssl getSsl() { + return this.ssl; + } + + public static class Ssl { + + /** + * Whether to enable SSL support. If enabled, {@code mail..ssl.enable} + * property is set to {@code true}. + */ + private boolean enabled = false; + + /** + * SSL bundle name. If not null, {@code mail..ssl.socketFactory} + * property is set to a {@code SSLSocketFactory} obtained from the corresponding + * SSL bundle. + *

+ * Note that the {@code STARTTLS} command can use the corresponding + * {@code SSLSocketFactory}, even if {@code mail..ssl.enable} property + * is not set. + */ + private String bundle; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getBundle() { + return this.bundle; + } + + public void setBundle(String bundle) { + this.bundle = bundle; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderPropertiesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderPropertiesConfiguration.java index 5c5bd795949e..e41b8fd397fc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderPropertiesConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mail/MailSenderPropertiesConfiguration.java @@ -19,8 +19,11 @@ import java.util.Map; import java.util.Properties; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.ssl.SslBundle; +import org.springframework.boot.ssl.SslBundles; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mail.MailSender; @@ -38,6 +41,12 @@ @ConditionalOnProperty(prefix = "spring.mail", name = "host") class MailSenderPropertiesConfiguration { + private final ObjectProvider sslBundles; + + MailSenderPropertiesConfiguration(ObjectProvider sslBundles) { + this.sslBundles = sslBundles; + } + @Bean @ConditionalOnMissingBean(JavaMailSender.class) JavaMailSenderImpl mailSender(MailProperties properties) { @@ -57,8 +66,21 @@ private void applyProperties(MailProperties properties, JavaMailSenderImpl sende if (properties.getDefaultEncoding() != null) { sender.setDefaultEncoding(properties.getDefaultEncoding().name()); } - if (!properties.getProperties().isEmpty()) { - sender.setJavaMailProperties(asProperties(properties.getProperties())); + Properties javaMailProperties = asProperties(properties.getProperties()); + String protocol = properties.getProtocol(); + if (protocol == null || protocol.isEmpty()) { + protocol = "smtp"; + } + if (properties.getSsl().isEnabled()) { + javaMailProperties.setProperty("mail." + protocol + ".ssl.enable", "true"); + } + if (properties.getSsl().getBundle() != null) { + SslBundle sslBundle = this.sslBundles.getObject().getBundle(properties.getSsl().getBundle()); + javaMailProperties.put("mail." + protocol + ".ssl.socketFactory", + sslBundle.createSslContext().getSocketFactory()); + } + if (!javaMailProperties.isEmpty()) { + sender.setJavaMailProperties(javaMailProperties); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationIntegrationTests.java new file mode 100644 index 000000000000..42ca27545551 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationIntegrationTests.java @@ -0,0 +1,232 @@ +/* + * Copyright 2012-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.mail; + +import java.net.SocketTimeoutException; +import java.security.cert.CertPathBuilderException; +import java.time.Duration; +import java.util.Arrays; + +import javax.net.ssl.SSLException; + +import jakarta.mail.Folder; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Session; +import jakarta.mail.Store; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.MountableFile; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.testsupport.testcontainers.MailpitContainer; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; + +/** + * Integration tests for {@link MailSenderAutoConfiguration}. + * + * @author Rui Figueira + */ +@Testcontainers(disabledWithoutDocker = true) +class MailSenderAutoConfigurationIntegrationTests { + + private SimpleMailMessage createMessage(String subject) { + SimpleMailMessage msg = new SimpleMailMessage(); + msg.setFrom("from@example.com"); + msg.setTo("to@example.com"); + msg.setSubject(subject); + msg.setText("Subject: " + subject); + return msg; + } + + private String getSubject(Message message) { + try { + return message.getSubject(); + } + catch (MessagingException ex) { + throw new RuntimeException(ex); + } + } + + private void assertMessagesContainSubject(Session session, String subject) { + try (Store store = session.getStore("pop3")) { + String host = session.getProperty("mail.pop3.host"); + int port = Integer.parseInt(session.getProperty("mail.pop3.port")); + store.connect(host, port, "user", "pass"); + try (Folder folder = store.getFolder("inbox")) { + folder.open(Folder.READ_ONLY); + Awaitility.await() + .atMost(Duration.ofSeconds(5)) + .ignoreExceptions() + .untilAsserted(() -> assertThat(Arrays.stream(folder.getMessages()).map(this::getSubject)) + .contains(subject)); + } + } + catch (MessagingException ex) { + throw new RuntimeException(ex); + } + } + + @Nested + class ImplicitTlsTests { + + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class)); + + @Container + static final MailpitContainer mailpit = new MailpitContainer() + // force ssl connection + .withSmtpRequireTls(true) + .withSmtpTlsCert(MountableFile + .forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt")) + .withSmtpTlsKey(MountableFile + .forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key")) + .withPop3Auth("user:pass"); + + @Test + void sendEmailWithSslEnabledAndCert() { + this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true", + "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key", + // pop3 + "spring.mail.properties.mail.pop3.host:" + mailpit.getHost(), + "spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port()) + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + mailSender.send(createMessage("Hello World!")); + + assertMessagesContainSubject(mailSender.getSession(), "Hello World!"); + }); + } + + @Test + void sendEmailWithSslEnabledWithoutCert() { + this.contextRunner + .withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true") + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail"))) + .withRootCauseInstanceOf(CertPathBuilderException.class); + }); + } + + @Test + void sendEmailWithoutSslWithCert() { + this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.properties.mail.smtp.timeout:1000", + "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key") + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail"))) + .withRootCauseInstanceOf(SocketTimeoutException.class); + }); + } + + } + + @Nested + class StarttlsTests { + + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class)); + + @Container + static final MailpitContainer mailpit = new MailpitContainer().withSmtpRequireStarttls(true) + .withSmtpTlsCert(MountableFile + .forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt")) + .withSmtpTlsKey(MountableFile + .forClasspathResource("/org/springframework/boot/autoconfigure/mail/ssl/test-server.key")) + .withPop3Auth("user:pass"); + + @Test + void sendEmailWithStarttlsAndCertAndSslDisabled() { + this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), + "spring.mail.properties.mail.smtp.starttls.enable:true", + "spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key", + // pop3 + "spring.mail.properties.mail.pop3.host:" + mailpit.getHost(), + "spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port()) + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + mailSender.send(createMessage("Sent with STARTTLS")); + + assertMessagesContainSubject(mailSender.getSession(), "Sent with STARTTLS"); + }); + } + + @Test + void sendEmailWithStarttlsAndCertAndSslEnabled() { + this.contextRunner.withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), "spring.mail.ssl.enabled:true", + "spring.mail.properties.mail.smtp.starttls.enable:true", + "spring.mail.properties.mail.smtp.starttls.required:true", "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.crt", + "spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/autoconfigure/mail/ssl/test-client.key", + // pop3 + "spring.mail.properties.mail.pop3.host:" + mailpit.getHost(), + "spring.mail.properties.mail.pop3.port:" + mailpit.getPop3Port()) + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail"))) + .withRootCauseInstanceOf(SSLException.class); + }); + } + + @Test + void sendEmailWithStarttlsWithoutCert() { + this.contextRunner + .withPropertyValues("spring.mail.host:" + mailpit.getHost(), + "spring.mail.port:" + mailpit.getSmtpPort(), + "spring.mail.properties.mail.smtp.starttls.enable:true", + "spring.mail.properties.mail.smtp.starttls.required:true") + .run((context) -> { + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + + assertThatException().isThrownBy(() -> mailSender.send(createMessage("Should fail"))) + .withRootCauseInstanceOf(CertPathBuilderException.class); + }); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java index 6fd720cbbaa0..8bf0ba25c598 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mail/MailSenderAutoConfigurationTests.java @@ -19,6 +19,7 @@ import java.util.Properties; import javax.naming.Context; +import javax.net.ssl.SSLSocketFactory; import jakarta.mail.Session; import org.junit.jupiter.api.AfterEach; @@ -29,6 +30,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader; import org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory; +import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -49,8 +51,9 @@ */ class MailSenderAutoConfigurationTests { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of(MailSenderAutoConfiguration.class, MailSenderValidatorAutoConfiguration.class)); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, + MailSenderValidatorAutoConfiguration.class, SslAutoConfiguration.class)); private ClassLoader threadContextClassLoader; @@ -240,6 +243,61 @@ void connectionOnStartupNotCalled() { }); } + @Test + void smtpSslEnabled() { + this.contextRunner.withPropertyValues("spring.mail.host:localhost", "spring.mail.ssl.enabled:true") + .run((context) -> { + assertThat(context).hasSingleBean(JavaMailSenderImpl.class); + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + assertThat(mailSender.getJavaMailProperties()).containsEntry("mail.smtp.ssl.enable", "true"); + }); + } + + @Test + void smtpSslBundle() { + this.contextRunner + .withPropertyValues("spring.mail.host:localhost", "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks", + "spring.ssl.bundle.jks.test-bundle.keystore.password:secret", + "spring.ssl.bundle.jks.test-bundle.key.password:password") + .run((context) -> { + assertThat(context).hasSingleBean(JavaMailSenderImpl.class); + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + assertThat(mailSender.getJavaMailProperties()).doesNotContainKey("mail.smtp.ssl.enable"); + Object property = mailSender.getJavaMailProperties().get("mail.smtp.ssl.socketFactory"); + assertThat(property).isInstanceOf(SSLSocketFactory.class); + }); + } + + @Test + void smtpsSslEnabled() { + this.contextRunner + .withPropertyValues("spring.mail.host:localhost", "spring.mail.protocol:smtps", + "spring.mail.ssl.enabled:true") + .run((context) -> { + assertThat(context).hasSingleBean(JavaMailSenderImpl.class); + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + assertThat(mailSender.getJavaMailProperties()).containsEntry("mail.smtps.ssl.enable", "true"); + }); + } + + @Test + void smtpsSslBundle() { + this.contextRunner + .withPropertyValues("spring.mail.host:localhost", "spring.mail.protocol:smtps", + "spring.mail.ssl.bundle:test-bundle", + "spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks", + "spring.ssl.bundle.jks.test-bundle.keystore.password:secret", + "spring.ssl.bundle.jks.test-bundle.key.password:password") + .run((context) -> { + assertThat(context).hasSingleBean(JavaMailSenderImpl.class); + JavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class); + assertThat(mailSender.getJavaMailProperties()).doesNotContainKey("mail.smtps.ssl.enable"); + Object property = mailSender.getJavaMailProperties().get("mail.smtps.ssl.socketFactory"); + assertThat(property).isInstanceOf(SSLSocketFactory.class); + }); + } + private Session configureJndiSession(String name) { Properties properties = new Properties(); Session session = Session.getDefaultInstance(properties); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt new file mode 100644 index 000000000000..beed250b132b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL +BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow +OzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2 +KzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH +cyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK +j2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9 +OmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj +X8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq +XZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v +8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ +xLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW +nUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE +VLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4 +2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW +BBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL +9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t +gglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j +2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj +7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM +f4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ +BpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy +R3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q +QqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw +Y3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws +OYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG +UaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ +T0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6 +Dyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU= +-----END CERTIFICATE----- diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.key b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.key new file mode 100644 index 000000000000..1142d91aceed --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +lTLiho2DATppaxNUQKh/5k70hzbipDg= +-----END PRIVATE KEY----- diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.crt b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.crt new file mode 100644 index 000000000000..811d880fcbd3 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL +BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow +LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh +sRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7 +b8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0 +mnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV ++m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf +NNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5 +dwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud +DgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6 +GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF +N5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e +MN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5 +1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs +j9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3 +WyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO +BJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM +IEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS +hlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I +LVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8 +ptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW +pgywiOifs5JbcCt0ZQ0= +-----END CERTIFICATE----- diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.key b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.key new file mode 100644 index 000000000000..2ae0f49bf4a4 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N +5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N +gml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv +P5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9 +0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry +nAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh +0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD +w3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk +tb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b +fOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ +zBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS +bUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5 +FgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi +tn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX +GAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy +vfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs +RpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q +F32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3 +womWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b +pbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ +QMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX +LRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp +KpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t +p/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77 +v16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6 +Odl4vjNOncXMZCLPHQ+bKWaf +-----END PRIVATE KEY----- diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt new file mode 100644 index 000000000000..57c66cc78a3b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL +BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow +LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b +CIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV +j5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte +N0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT +//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a +DnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs +MwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud +DgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6 +GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6 +OOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ +R0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx +t2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo +jJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC +f1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G +9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG +HSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK +jaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+ +x8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg +/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE +etL+7y0mkeQhVF+Kmy4= +-----END CERTIFICATE----- diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.key b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.key new file mode 100644 index 000000000000..95e2ef3e8b31 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/mail/ssl/test-server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0 +cx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS +55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl +E5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL +7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ +GD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71 +pHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ +uY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0 +2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD +8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU +ZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c +CrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG +aTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k +NccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb +IR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+ +jetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ +yVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi +Y+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y +V4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ +1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2 +X/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb +YFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q +MYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm +CZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1 +vsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH +r5O3ZAgigZs/ZtKW/U4= +-----END PRIVATE KEY----- diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java index a5b5365ab1b8..bed6e6095397 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java @@ -42,6 +42,8 @@ public final class DockerImageNames { private static final String KAFKA_VERSION = "7.4.0"; + private static final String MAILPIT_VERSION = "v1.18.1"; + private static final String MARIADB_VERSION = "10.10"; private static final String MONGO_VERSION = "5.0.17"; @@ -147,6 +149,14 @@ public static DockerImageName openLdap() { return DockerImageName.parse("osixia/openldap").withTag(OPEN_LDAP_VERSION); } + /** + * Return a {@link DockerImageName} suitable for running Mailpit. + * @return a docker image name for running Mailpit + */ + public static DockerImageName mailpit() { + return DockerImageName.parse("axllent/mailpit").withTag(MAILPIT_VERSION); + } + /** * Return a {@link DockerImageName} suitable for running MariaDB. * @return a docker image name for running MariaDB diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/MailpitContainer.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/MailpitContainer.java new file mode 100644 index 000000000000..cc18675862eb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/MailpitContainer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.testsupport.testcontainers; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.MountableFile; + +/** + * A {@link GenericContainer} for MailDev. + * + * @author Rui Figueira + */ +public class MailpitContainer extends GenericContainer { + + private static final int DEFAULT_SMTP_PORT = 1025; + + private static final int DEFAULT_POP3_PORT = 1110; + + public MailpitContainer() { + super(DockerImageNames.mailpit()); + addExposedPorts(DEFAULT_SMTP_PORT, DEFAULT_POP3_PORT); + } + + public int getSmtpPort() { + return getMappedPort(DEFAULT_SMTP_PORT); + } + + public int getPop3Port() { + return getMappedPort(DEFAULT_POP3_PORT); + } + + public MailpitContainer withSmtpTlsCert(MountableFile cert) { + this.withCopyFileToContainer(cert, "/tmp/ssl/public.crt"); + this.withEnv("MP_SMTP_TLS_CERT", "/tmp/ssl/public.crt"); + return this.self(); + } + + public MailpitContainer withSmtpTlsKey(MountableFile key) { + this.withCopyFileToContainer(key, "/tmp/ssl/private.key"); + this.withEnv("MP_SMTP_TLS_KEY", "/tmp/ssl/private.key"); + return this.self(); + } + + public MailpitContainer withSmtpRequireTls(boolean requireTls) { + if (requireTls) { + this.withEnv("MP_SMTP_REQUIRE_TLS", "true"); + } + return this.self(); + } + + public MailpitContainer withSmtpRequireStarttls(boolean requireStarttls) { + if (requireStarttls) { + this.withEnv("MP_SMTP_REQUIRE_STARTTLS", "true"); + } + return this.self(); + } + + public MailpitContainer withPop3Auth(String... auths) { + this.withEnv("MP_POP3_AUTH", String.join(" ", auths)); + return this.self(); + } + +}