Skip to content
Snippets Groups Projects
Commit d3cdcd25 authored by thorben.betten's avatar thorben.betten
Browse files

MWB-1862: Check probed hosts against configured black-list/white-list for mail...

MWB-1862: Check probed hosts against configured black-list/white-list for mail accounts prior to connect attempt

(cherry picked from commit 1b9786ae)
parent b9e64b55
Branches stable-8.5
No related tags found
No related merge requests found
...@@ -33,6 +33,7 @@ Import-Package: com.google.common.annotations, ...@@ -33,6 +33,7 @@ Import-Package: com.google.common.annotations,
com.openexchange.mail.mime, com.openexchange.mail.mime,
com.openexchange.mail.utils, com.openexchange.mail.utils,
com.openexchange.mailaccount, com.openexchange.mailaccount,
com.openexchange.mailaccount.utils,
com.openexchange.net, com.openexchange.net,
com.openexchange.net.ssl, com.openexchange.net.ssl,
com.openexchange.net.ssl.config, com.openexchange.net.ssl.config,
......
...@@ -26,6 +26,7 @@ import java.util.Arrays; ...@@ -26,6 +26,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import com.openexchange.config.cascade.ComposedConfigProperty; import com.openexchange.config.cascade.ComposedConfigProperty;
import com.openexchange.config.cascade.ConfigView; import com.openexchange.config.cascade.ConfigView;
import com.openexchange.config.cascade.ConfigViewFactory; import com.openexchange.config.cascade.ConfigViewFactory;
...@@ -45,13 +46,13 @@ import com.openexchange.tools.net.URIDefaults; ...@@ -45,13 +46,13 @@ import com.openexchange.tools.net.URIDefaults;
public class Guess extends AbstractConfigSource { public class Guess extends AbstractConfigSource {
static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Guess.class); static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Guess.class);
/** The property name for context identifier. Value is <code>java.lang.Integer</code> */ /** The property name for context identifier. Value is <code>java.lang.Integer</code> */
public static final String PROP_GENERAL_CONTEXT_ID = "general.context"; public static final String PROP_GENERAL_CONTEXT_ID = "general.context";
/** The property name for user identifier. Value is <code>java.lang.Integer</code> */ /** The property name for user identifier. Value is <code>java.lang.Integer</code> */
public static final String PROP_GENERAL_USER_ID = "general.user"; public static final String PROP_GENERAL_USER_ID = "general.user";
/** The property name for flag whether SMTP supports authentication. Value is <code>java.lang.Boolean</code> */ /** The property name for flag whether SMTP supports authentication. Value is <code>java.lang.Boolean</code> */
public static final String PROP_SMTP_AUTH_SUPPORTED = "smtp.auth-supported"; public static final String PROP_SMTP_AUTH_SUPPORTED = "smtp.auth-supported";
...@@ -113,13 +114,15 @@ public class Guess extends AbstractConfigSource { ...@@ -113,13 +114,15 @@ public class Guess extends AbstractConfigSource {
} }
private boolean fillProtocol(Protocol protocol, String emailLocalPart, String emailDomain, String password, DefaultAutoconfig config, Map<String, Object> properties, boolean forceSecure) { private boolean fillProtocol(Protocol protocol, String emailLocalPart, String emailDomain, String password, DefaultAutoconfig config, Map<String, Object> properties, boolean forceSecure) {
ConnectSettings connectSettings = guessHost(protocol, emailDomain); Optional<ConnectSettings> optConnectSettings = guessHost(protocol, emailDomain);
if (connectSettings == null) { if (optConnectSettings.isPresent() == false) {
return false; return false;
} }
String login = guessLogin(protocol, connectSettings.host, connectSettings.port, connectSettings.secure, forceSecure, emailLocalPart, emailDomain, password, properties); ConnectSettings connectSettings = optConnectSettings.get();
if (login == null) {
Optional<String> optLogin = guessLogin(protocol, connectSettings.host, connectSettings.port, connectSettings.secure, forceSecure, emailLocalPart, emailDomain, password, properties);
if (optLogin.isPresent() == false) {
return false; return false;
} }
...@@ -129,19 +132,19 @@ public class Guess extends AbstractConfigSource { ...@@ -129,19 +132,19 @@ public class Guess extends AbstractConfigSource {
config.setTransportSecure(connectSettings.secure); config.setTransportSecure(connectSettings.secure);
config.setTransportServer(connectSettings.host); config.setTransportServer(connectSettings.host);
config.setTransportStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point config.setTransportStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point
config.setUsername(login); config.setUsername(optLogin.get());
} else { } else {
config.setMailPort(connectSettings.port); config.setMailPort(connectSettings.port);
config.setMailProtocol(protocol.getProtocol()); config.setMailProtocol(protocol.getProtocol());
config.setMailSecure(connectSettings.secure); config.setMailSecure(connectSettings.secure);
config.setMailServer(connectSettings.host); config.setMailServer(connectSettings.host);
config.setMailStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point config.setMailStartTls(forceSecure); // Take over since end-point has been checked with proper STARTTLS setting if we reach this point
config.setUsername(login); config.setUsername(optLogin.get());
} }
return true; return true;
} }
private String guessLogin(Protocol protocol, String host, int port, boolean secure, boolean requireTls, String emailLocalPart, String emailDomain, String password, Map<String, Object> properties) { private Optional<String> guessLogin(Protocol protocol, String host, int port, boolean secure, boolean requireTls, String emailLocalPart, String emailDomain, String password, Map<String, Object> properties) {
List<String> logins = Arrays.asList(emailLocalPart, emailLocalPart+"@"+emailDomain); List<String> logins = Arrays.asList(emailLocalPart, emailLocalPart+"@"+emailDomain);
ConnectMode connectMode = ConnectMode.connectModeFor(secure, requireTls); ConnectMode connectMode = ConnectMode.connectModeFor(secure, requireTls);
...@@ -149,34 +152,33 @@ public class Guess extends AbstractConfigSource { ...@@ -149,34 +152,33 @@ public class Guess extends AbstractConfigSource {
switch (protocol) { switch (protocol) {
case IMAP: case IMAP:
if (MailValidator.validateImap(host, port, connectMode, login, password, properties)) { if (MailValidator.validateImap(host, port, connectMode, login, password, properties)) {
return login; Optional.ofNullable(login);
} }
break; break;
case POP3: case POP3:
if (MailValidator.validatePop3(host, port, connectMode, login, password, properties)) { if (MailValidator.validatePop3(host, port, connectMode, login, password, properties)) {
return login; Optional.ofNullable(login);
} }
break; break;
case SMTP: case SMTP:
if (MailValidator.validateSmtp(host, port, connectMode, login, password, properties)) { if (MailValidator.validateSmtp(host, port, connectMode, login, password, properties)) {
return login; return Optional.ofNullable(login);
} }
break; break;
} }
} }
return null; return Optional.empty();
} }
private static final List<String> IMAP_PREFIXES = Arrays.asList("", "imap.", "mail."); private static final List<String> IMAP_PREFIXES = Arrays.asList("", "imap.", "mail.");
private static final List<String> SMTP_PREFIXES = Arrays.asList("", "smtp.", "mail."); private static final List<String> SMTP_PREFIXES = Arrays.asList("", "smtp.", "mail.");
private static final List<String> POP3_PREFIXES = Arrays.asList("", "pop3.", "mail."); private static final List<String> POP3_PREFIXES = Arrays.asList("", "pop3.", "mail.");
private ConnectSettings guessHost(Protocol protocol, String emailDomain) { private Optional<ConnectSettings> guessHost(Protocol protocol, String emailDomain) {
URIDefaults uriDefaults = null; URIDefaults uriDefaults;
List<String> prefixes = null;
int altPort = 0; int altPort = 0;
List<String> prefixes;
switch (protocol) { switch (protocol) {
case IMAP: case IMAP:
prefixes = IMAP_PREFIXES; prefixes = IMAP_PREFIXES;
...@@ -192,34 +194,34 @@ public class Guess extends AbstractConfigSource { ...@@ -192,34 +194,34 @@ public class Guess extends AbstractConfigSource {
uriDefaults = URIDefaults.SMTP; uriDefaults = URIDefaults.SMTP;
break; break;
default: default:
return null; return Optional.empty();
} }
for (String prefix : prefixes) { for (String prefix : prefixes) {
String host = prefix + emailDomain; String host = prefix.length() > 0 ? prefix + emailDomain : emailDomain;
// Try SSL connect using default SSL port // Try SSL connect using default SSL port
if (tryConnect(protocol, host, uriDefaults.getSSLPort(), true)) { if (tryConnect(protocol, host, uriDefaults.getSSLPort(), true)) {
return new ConnectSettings(host, true, uriDefaults.getSSLPort()); return Optional.of(new ConnectSettings(host, true, uriDefaults.getSSLPort()));
} }
// Try SSL connect using default port // Try SSL connect using default port
if (tryConnect(protocol, host, uriDefaults.getPort(), true)) { if (tryConnect(protocol, host, uriDefaults.getPort(), true)) {
return new ConnectSettings(host, true, uriDefaults.getPort()); return Optional.of(new ConnectSettings(host, true, uriDefaults.getPort()));
} }
// Try plain connect using alternative port // Try plain connect using alternative port
if (altPort > 0 && tryConnect(protocol, host, altPort, false)) { if (altPort > 0 && tryConnect(protocol, host, altPort, false)) {
return new ConnectSettings(host, false, altPort); return Optional.of(new ConnectSettings(host, false, altPort));
} }
// Try plain connect using default port // Try plain connect using default port
if (tryConnect(protocol, host, uriDefaults.getPort(), false)) { if (tryConnect(protocol, host, uriDefaults.getPort(), false)) {
return new ConnectSettings(host, false, uriDefaults.getPort()); return Optional.of(new ConnectSettings(host, false, uriDefaults.getPort()));
} }
} }
return null; return Optional.empty();
} }
private boolean tryConnect(Protocol protocol, String emailDomain, int port, boolean secure) { private boolean tryConnect(Protocol protocol, String emailDomain, int port, boolean secure) {
......
...@@ -43,6 +43,7 @@ import com.openexchange.java.Streams; ...@@ -43,6 +43,7 @@ import com.openexchange.java.Streams;
import com.openexchange.java.Strings; import com.openexchange.java.Strings;
import com.openexchange.mail.mime.MimeDefaultSession; import com.openexchange.mail.mime.MimeDefaultSession;
import com.openexchange.mail.utils.NetUtils; import com.openexchange.mail.utils.NetUtils;
import com.openexchange.mailaccount.utils.MailAccountUtils;
import com.openexchange.net.ssl.SSLSocketFactoryProvider; import com.openexchange.net.ssl.SSLSocketFactoryProvider;
import com.openexchange.net.ssl.config.SSLConfigurationService; import com.openexchange.net.ssl.config.SSLConfigurationService;
import com.sun.mail.smtp.SMTPTransport; import com.sun.mail.smtp.SMTPTransport;
...@@ -326,8 +327,15 @@ public class MailValidator { ...@@ -326,8 +327,15 @@ public class MailValidator {
private static boolean tryConnect(String host, int port, boolean secure, String closePhrase, String name) { private static boolean tryConnect(String host, int port, boolean secure, String closePhrase, String name) {
Socket s = null; Socket s = null;
try { try {
// Check if black-listed
if (MailAccountUtils.isDenied(host, port)) {
return false;
}
// Establish socket connection // Establish socket connection
s = SocketFetcher.getSocket(host, port, createProps(name, port, secure), "mail." + name, false); Properties props = createProps(name, port, secure);
props.put("mail." + name + ".denyInternalAddress", "true");
s = SocketFetcher.getSocket(host, port, props, "mail." + name, false);
InputStream in = s.getInputStream(); InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream(); OutputStream out = s.getOutputStream();
if (null == in || null == out) { if (null == in || null == out) {
......
...@@ -683,6 +683,7 @@ Export-Package: com.openexchange.ajax, ...@@ -683,6 +683,7 @@ Export-Package: com.openexchange.ajax,
com.openexchange.mailaccount.json, com.openexchange.mailaccount.json,
com.openexchange.mailaccount.json.parser, com.openexchange.mailaccount.json.parser,
com.openexchange.mailaccount.json.writer, com.openexchange.mailaccount.json.writer,
com.openexchange.mailaccount.utils,
com.openexchange.multiple, com.openexchange.multiple,
com.openexchange.passwordchange, com.openexchange.passwordchange,
com.openexchange.policy.retry, com.openexchange.policy.retry,
......
...@@ -176,24 +176,57 @@ public class SocketFetcher { ...@@ -176,24 +176,57 @@ public class SocketFetcher {
private static Socket getSocket(String host, int port, Properties props, private static Socket getSocket(String host, int port, Properties props,
String prefix, boolean useSSL, boolean retryOnNoRouteToHost) throws IOException { String prefix, boolean useSSL, boolean retryOnNoRouteToHost) throws IOException {
try { try {
boolean denyInternalAddress = PropUtil.getBooleanProperty(props, prefix + ".denyInternalAddress", false);
InetAddress[] addresses = InetAddress.getAllByName(host); InetAddress[] addresses = InetAddress.getAllByName(host);
if (addresses.length == 1 || !PropUtil.getBooleanProperty(props, prefix + ".multiAddress.enabled", false)) { if (addresses.length == 1 || !PropUtil.getBooleanProperty(props, prefix + ".multiAddress.enabled", false)) {
if (denyInternalAddress && com.openexchange.java.InetAddresses.isInternalAddress(addresses[0])) {
throw new IOException("Denied to connect against internal address: " + host);
}
return getSocket(addresses[0], host, port, props, prefix, useSSL); return getSocket(addresses[0], host, port, props, prefix, useSSL);
} }
if (denyInternalAddress) {
java.util.List<InetAddress> validAddresses = null;
for (int i = 0; i < addresses.length; i++) {
boolean denied = com.openexchange.java.InetAddresses.isInternalAddress(addresses[i]);
if (validAddresses == null) {
if (denied) {
validAddresses = new java.util.ArrayList<>(addresses.length);
if (i > 0) {
// Add previous addresses to valid ones
for (int k = 0; k < i; k++) {
validAddresses.add(addresses[k]);
}
}
}
} else {
if (denied == false) {
validAddresses.add(addresses[i]);
}
}
}
if (validAddresses != null) {
if (validAddresses.isEmpty()) {
throw new IOException("Denied to connect against internal address: " + host);
}
addresses = validAddresses.toArray(new InetAddress[validAddresses.size()]);
}
}
AddressSelector selector = AddressSelector.getSelectorFor(host, addresses, props, prefix); AddressSelector selector = AddressSelector.getSelectorFor(host, addresses, props, prefix);
return new FailoverSocket(selector, host, port, props, prefix, useSSL); return new FailoverSocket(selector, host, port, props, prefix, useSSL);
} catch (java.net.UnknownHostException e) { } catch (java.net.UnknownHostException e) {
throw e; throw e;
} catch (IOException e) { } catch (IOException e) {
if (retryOnNoRouteToHost == false || isNoRouteToHostException(e) == false) { if (retryOnNoRouteToHost == false || isNoRouteToHostException(e) == false) {
throw e; throw e;
} }
if (clearDnsCache() == false) { if (clearDnsCache() == false) {
throw e; throw e;
} }
return getSocket(host, port, props, prefix, useSSL, false); return getSocket(host, port, props, prefix, useSSL, false);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment