Support SMTP over SSL/TLS
If sendemail.smtpEncryption is set to 'ssl' or 'tls' we now enable the proper encryption on top of the socket, permitting the client to use encryption when talking with the relay SMTP server. This might be necessary to protect the username/password used to authenticate prior to sending a message. Bug: issue 300 Change-Id: Idecb20326261cbc8951e2ff469b95ea7ee83e48c Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -760,7 +760,21 @@ By default, 127.0.0.1 (aka localhost).
|
||||
+
|
||||
Port number of the SMTP server in sendemail.smtpserver.
|
||||
+
|
||||
By default, 25.
|
||||
By default, 25, or 465 if smtpEncryption is 'ssl'.
|
||||
|
||||
[[sendemail.smtpEncryption]]sendemail.smtpEncryption::
|
||||
+
|
||||
Specify the encryption to use, either 'ssl' or 'tls'.
|
||||
+
|
||||
By default, 'none', indicating no encryption is used.
|
||||
|
||||
[[sendemail.sslVerify]]sendemail.sslVerify::
|
||||
+
|
||||
If false and sendemail.smtpEncryption is 'ssl' or 'tls', Gerrit
|
||||
will not verify the server certificate when it connects to send
|
||||
an email message.
|
||||
+
|
||||
By default, true, requiring the certificate to be verified.
|
||||
|
||||
[[sendemail.smtpUser]]sendemail.smtpUser::
|
||||
+
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.server.mail;
|
||||
|
||||
import com.google.gerrit.pgm.Version;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
@@ -34,12 +35,18 @@ import java.util.Map;
|
||||
/** Sends email via a nearby SMTP server. */
|
||||
@Singleton
|
||||
public class SmtpEmailSender implements EmailSender {
|
||||
public static enum Encryption {
|
||||
NONE, SSL, TLS;
|
||||
}
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
private String smtpHost;
|
||||
private int smtpPort;
|
||||
private String smtpUser;
|
||||
private String smtpPass;
|
||||
private Encryption smtpEncryption;
|
||||
private boolean sslVerify;
|
||||
private String[] allowrcpt;
|
||||
|
||||
@Inject
|
||||
@@ -50,7 +57,26 @@ public class SmtpEmailSender implements EmailSender {
|
||||
if (smtpHost == null) {
|
||||
smtpHost = "127.0.0.1";
|
||||
}
|
||||
smtpPort = cfg.getInt("sendemail", null, "smtpserverport", 25);
|
||||
|
||||
smtpEncryption =
|
||||
ConfigUtil.getEnum(cfg, "sendemail", null, "smtpencryption",
|
||||
Encryption.NONE);
|
||||
sslVerify = cfg.getBoolean("sendemail", null, "sslverify", true);
|
||||
|
||||
final int defaultPort;
|
||||
switch (smtpEncryption) {
|
||||
case SSL:
|
||||
defaultPort = 465;
|
||||
break;
|
||||
|
||||
case NONE:
|
||||
case TLS:
|
||||
default:
|
||||
defaultPort = 25;
|
||||
break;
|
||||
}
|
||||
smtpPort = cfg.getInt("sendemail", null, "smtpserverport", defaultPort);
|
||||
|
||||
smtpUser = cfg.getString("sendemail", null, "smtpuser");
|
||||
smtpPass = cfg.getString("sendemail", null, "smtpuserpass");
|
||||
allowrcpt = cfg.getStringList("sendemail", null, "allowrcpt");
|
||||
@@ -136,6 +162,11 @@ public class SmtpEmailSender implements EmailSender {
|
||||
private SMTPClient open() throws EmailException {
|
||||
final AuthSMTPClient client = new AuthSMTPClient("UTF-8");
|
||||
client.setAllowRcpt(allowrcpt);
|
||||
|
||||
if (smtpEncryption == Encryption.SSL) {
|
||||
client.enableSSL(sslVerify);
|
||||
}
|
||||
|
||||
try {
|
||||
client.connect(smtpHost, smtpPort);
|
||||
if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) {
|
||||
@@ -145,6 +176,17 @@ public class SmtpEmailSender implements EmailSender {
|
||||
String e = client.getReplyString();
|
||||
throw new EmailException("SMTP server rejected login: " + e);
|
||||
}
|
||||
|
||||
if (smtpEncryption == Encryption.TLS) {
|
||||
if (!client.startTLS(smtpHost, smtpPort, sslVerify)) {
|
||||
throw new EmailException("SMTP server does not support TLS");
|
||||
}
|
||||
if (!client.login()) {
|
||||
String e = client.getReplyString();
|
||||
throw new EmailException("SMTP server rejected login: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (smtpUser != null && !client.auth(smtpUser, smtpPass)) {
|
||||
String e = client.getReplyString();
|
||||
throw new EmailException("SMTP server rejected auth: " + e);
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
|
||||
package org.apache.commons.net.smtp;
|
||||
|
||||
import com.google.gerrit.server.ioutil.BlindSSLSocketFactory;
|
||||
|
||||
import org.eclipse.jgit.util.Base64;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.SocketException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
@@ -29,6 +32,7 @@ import java.util.Set;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
public class AuthSMTPClient extends SMTPClient {
|
||||
private static final Logger log =
|
||||
@@ -41,6 +45,29 @@ public class AuthSMTPClient extends SMTPClient {
|
||||
super(charset);
|
||||
}
|
||||
|
||||
public void enableSSL(final boolean verify) {
|
||||
_socketFactory_ = sslFactory(verify);
|
||||
}
|
||||
|
||||
public boolean startTLS(final String hostname, final int port,
|
||||
final boolean verify) throws SocketException, IOException {
|
||||
if (sendCommand("STARTTLS") != 220) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_socket_ = sslFactory(verify).createSocket(_socket_, hostname, port, true);
|
||||
_connectAction_();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static SSLSocketFactory sslFactory(final boolean verify) {
|
||||
if (verify) {
|
||||
return (SSLSocketFactory) SSLSocketFactory.getDefault();
|
||||
} else {
|
||||
return (SSLSocketFactory) BlindSSLSocketFactory.getDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllowRcpt(final String[] allowed) {
|
||||
if (allowed != null && allowed.length > 0) {
|
||||
if (allowedRcptTo == null) {
|
||||
|
||||
Reference in New Issue
Block a user