diff --git a/src/main/java/org/simplejavamail/mailer/config/TransportStrategy.java b/src/main/java/org/simplejavamail/mailer/config/TransportStrategy.java index 0ce7ab201..a077e0f18 100644 --- a/src/main/java/org/simplejavamail/mailer/config/TransportStrategy.java +++ b/src/main/java/org/simplejavamail/mailer/config/TransportStrategy.java @@ -10,23 +10,48 @@ * TransportStrategy implementation. * * @author Benny Bottema + * @author Christian Barcenas */ public enum TransportStrategy { /** - * Simplest possible form: only vanilla ".smtp." property names and no extra properties. Additionally the transport protocol is explicitly set to - * smtp. + * Vanilla SMTP with an insecure STARTTLS upgrade (if supported). + *

+ * This {@code TransportStrategy} falls back to plaintext when a mail server does not indicate support for + * STARTTLS. Additionally, even if a TLS session is negotiated, server certificates are not validated in + * any way. + *

+ * This {@code TransportStrategy} only offers protection against passive network eavesdroppers when the mail server + * indicates support for STARTTLS. Active network attackers can trivially bypass the encryption 1) by tampering with + * the STARTTLS indicator, 2) by presenting a self-signed certificate, 3) by presenting a certificate issued by an + * untrusted certificate authority; or 4) by presenting a certificate that was issued by a valid certificate + * authority to a domain other than the mail server's. + *

+ * For proper mail transport encryption, see {@link TransportStrategy#SMTP_SSL} or + * {@link TransportStrategy#SMTP_TLS}. + *

+ * Implementation notes: + *

*/ SMTP_PLAIN { /** - * Here protocol "mail.transport.protocol" is set to "smtp". - * * @see TransportStrategy#SMTP_PLAIN */ @Override public Properties generateProperties() { final Properties props = super.generateProperties(); props.put("mail.transport.protocol", "smtp"); + props.put("mail.smtp.starttls.enable", true); + props.put("mail.smtp.starttls.required", false); + props.put("mail.smtp.ssl.trust", "*"); + props.put("mail.smtp.ssl.checkserveridentity", false); return props; } @@ -63,9 +88,18 @@ public String propertyNameAuthenticate() { } }, /** - * SMTPS / SSL transport strategy, that returns the ".smtps." variation of the SMTP_PLAIN version. Additionally the transport protocol is - * explicitly set to smtps. Finally, he property "mail.smtps.quitwait" is set to false, to get rid of a strange SSL exception:
+ * SMTP entirely encapsulated by TLS. Commonly known as SMTPS. *

+ * Strict validation of server certificates is enabled. Server certificates must be issued 1) by a certificate + * authority in the system trust store; and 2) to a subject matching the identity of the remote SMTP server. + *

+ * Implementation notes: + *

*/ SMTP_SSL { /** - * Here protocol "mail.transport.protocol" is set to "smtps" and the quitwait property "mail.smtps.quitwait" is set to "false". - * * @see TransportStrategy#SMTP_SSL */ @Override public Properties generateProperties() { final Properties properties = super.generateProperties(); properties.put("mail.transport.protocol", "smtps"); + properties.put("mail.smtps.ssl.checkserveridentity", "true"); properties.put("mail.smtps.quitwait", "false"); return properties; } @@ -124,15 +159,24 @@ public String propertyNameAuthenticate() { } }, /** + * Plaintext SMTP with a mandatory, authenticated STARTTLS upgrade. + *

* NOTE: this code is in untested beta state *

- * Uses standard ".smtp." property names (like {@link TransportStrategy#SMTP_PLAIN}). Additionally the transport protocol is explicitly set to - * smtp. Finally, the property "mail.smtp.starttls.enable" is being set to true. + * Strict validation of server certificates is enabled. Server certificates must be issued 1) by a certificate + * authority in the system trust store; and 2) to a subject matching the identity of the remote SMTP server. + *

+ * Implementation notes: + *

*/ SMTP_TLS { /** - * Here protocol "mail.transport.protocol" is set to "smtp" and the tls property "mail.smtp.starttls.enable" is set to "true". - * * @see TransportStrategy#SMTP_TLS */ @Override @@ -140,6 +184,8 @@ public Properties generateProperties() { final Properties props = super.generateProperties(); props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.starttls.required", "true"); + props.put("mail.smtp.ssl.checkserveridentity", "true"); return props; } diff --git a/src/test/java/org/simplejavamail/mailer/MailerTest.java b/src/test/java/org/simplejavamail/mailer/MailerTest.java index 73e56bbd5..0e2d2166e 100644 --- a/src/test/java/org/simplejavamail/mailer/MailerTest.java +++ b/src/test/java/org/simplejavamail/mailer/MailerTest.java @@ -90,6 +90,8 @@ public void createMailSession_AnonymousProxyConstructor_WithoutConfig() assertThat(session.getProperty("mail.smtp.port")).isEqualTo("25"); assertThat(session.getProperty("mail.transport.protocol")).isEqualTo("smtp"); assertThat(session.getProperty("mail.smtp.starttls.enable")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.starttls.required")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.ssl.checkserveridentity")).isEqualTo("true"); assertThat(session.getProperty("mail.smtp.username")).isEqualTo("username smtp"); assertThat(session.getProperty("mail.smtp.auth")).isEqualTo("true"); assertThat(session.getProperty("mail.smtp.socks.host")).isEqualTo("proxy host"); @@ -112,6 +114,8 @@ public void createMailSession_MaximumConstructor_WithoutConfig() assertThat(session.getProperty("mail.smtp.port")).isEqualTo("25"); assertThat(session.getProperty("mail.transport.protocol")).isEqualTo("smtp"); assertThat(session.getProperty("mail.smtp.starttls.enable")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.starttls.required")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.ssl.checkserveridentity")).isEqualTo("true"); assertThat(session.getProperty("mail.smtp.username")).isEqualTo("username smtp"); assertThat(session.getProperty("mail.smtp.auth")).isEqualTo("true"); // the following two are because authentication is needed, otherwise proxy would be straightworward @@ -131,6 +135,8 @@ public void createMailSession_MinimalConstructor_WithConfig() { assertThat(session.getProperty("mail.smtp.port")).isEqualTo("25"); assertThat(session.getProperty("mail.transport.protocol")).isEqualTo("smtp"); assertThat(session.getProperty("mail.smtp.starttls.enable")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.starttls.required")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.ssl.checkserveridentity")).isEqualTo("true"); assertThat(session.getProperty("mail.smtp.username")).isEqualTo("username smtp"); assertThat(session.getProperty("mail.smtp.auth")).isEqualTo("true"); // the following two are because authentication is needed, otherwise proxy would be straightworward @@ -150,6 +156,8 @@ public void createMailSession_MaximumConstructor_WithConfig() assertThat(session.getProperty("mail.smtp.port")).isEqualTo("25"); assertThat(session.getProperty("mail.transport.protocol")).isEqualTo("smtp"); assertThat(session.getProperty("mail.smtp.starttls.enable")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.starttls.required")).isEqualTo("true"); + assertThat(session.getProperty("mail.smtp.ssl.checkserveridentity")).isEqualTo("true"); assertThat(session.getProperty("mail.smtp.username")).isEqualTo("overridden username smtp"); assertThat(session.getProperty("mail.smtp.auth")).isEqualTo("true"); // the following two are because authentication is needed, otherwise proxy would be straightworward