diff --git a/config/alfresco/messages/email-service.properties b/config/alfresco/messages/email-service.properties
index 49cbcec8fc..09f0bbe3fd 100644
--- a/config/alfresco/messages/email-service.properties
+++ b/config/alfresco/messages/email-service.properties
@@ -3,6 +3,7 @@ email.server.msg.default_subject=Email-{0}
email.server.err.duplicate_alias=Node with email alias ''{0}'' already exists. Duplicate isn't allowed.
email.server.err.sender_blocked=''{0}'' has been denied access.
+email.server.err.from_syntax=Syntax: MAIL FROM:
Error in parameters
email.server.err.inbound_mail_disabled=The Alfresco server is not configured to accept inbound emails.
email.server.err.access_denied=''{0}'' has been denied access to ''{1}''.
email.server.err.invalid_subject=The subject line must be a valid file name.
diff --git a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
index e073c627e0..c15cfc0bb0 100755
--- a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
+++ b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml
@@ -51,6 +51,9 @@
+
+ ${email.inbound.unknownUser}
+
diff --git a/source/java/org/alfresco/email/server/EmailServer.java b/source/java/org/alfresco/email/server/EmailServer.java
index 65d2d9cfcd..16824beb40 100644
--- a/source/java/org/alfresco/email/server/EmailServer.java
+++ b/source/java/org/alfresco/email/server/EmailServer.java
@@ -42,6 +42,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
public abstract class EmailServer extends AbstractLifecycleBean
{
private static final String ERR_SENDER_BLOCKED = "email.server.err.sender_blocked";
+ private static final String ERR_FROM_SYNTAX_INCORRECT = "email.server.err.from_syntax";
private boolean enabled;
private String domain;
@@ -56,6 +57,7 @@ public abstract class EmailServer extends AbstractLifecycleBean
private EmailService emailService;
private AuthenticationComponent authenticationComponent;
+ private String unknownUser;
protected EmailServer()
{
@@ -184,6 +186,20 @@ public abstract class EmailServer extends AbstractLifecycleBean
{
this.emailService = emailService;
}
+
+ /**
+ * Used only for check "isNullReversePatAllowed".
+ * @param unknownUser authority name
+ */
+ public void setUnknownUser(String unknownUser)
+ {
+ this.unknownUser = unknownUser;
+ }
+
+ protected boolean isNullReversePatAllowed()
+ {
+ return isAuthenticate() || (unknownUser != null && !unknownUser.isEmpty());
+ }
/**
* Filter incoming message by its sender e-mail address.
@@ -193,6 +209,19 @@ public abstract class EmailServer extends AbstractLifecycleBean
*/
protected void filterSender(String sender)
{
+ if (sender == null)
+ {
+ if (isNullReversePatAllowed())
+ {
+ // allow null reverse-path: e.g.: an undeliverable mail response
+ return;
+ }
+ else
+ {
+ throw new EmailMessageException(ERR_FROM_SYNTAX_INCORRECT);
+ }
+ }
+
// Check if the sender is in the blocked list
for (String blockedSender : blockedSenders)
{
diff --git a/source/test-java/org/alfresco/Repository01TestSuite.java b/source/test-java/org/alfresco/Repository01TestSuite.java
index 82ceeecbc4..e8d029a09a 100644
--- a/source/test-java/org/alfresco/Repository01TestSuite.java
+++ b/source/test-java/org/alfresco/Repository01TestSuite.java
@@ -52,6 +52,7 @@ public class Repository01TestSuite extends TestSuite
static void tests3(TestSuite suite) // tests="76" time="82.566"
{
suite.addTestSuite(org.alfresco.email.server.EmailServiceImplTest.class);
+ suite.addTestSuite(org.alfresco.email.server.EmailServerTest.class);
suite.addTestSuite(org.alfresco.filesys.FTPServerTest.class);
suite.addTestSuite(org.alfresco.filesys.repo.CifsIntegrationTest.class);
suite.addTestSuite(org.alfresco.filesys.repo.ContentDiskDriverTest.class);
diff --git a/source/test-java/org/alfresco/email/server/EmailServerTest.java b/source/test-java/org/alfresco/email/server/EmailServerTest.java
new file mode 100644
index 0000000000..20a68c0da1
--- /dev/null
+++ b/source/test-java/org/alfresco/email/server/EmailServerTest.java
@@ -0,0 +1,231 @@
+package org.alfresco.email.server;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.util.ArrayList;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.service.cmr.email.EmailService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+
+import junit.framework.TestCase;
+
+public class EmailServerTest extends TestCase
+{
+ /**
+ * Services used by the tests
+ */
+ private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
+
+ private EmailServer emailServer;
+
+ // Linux-based env. should use port bigger than 1024
+ private final int TEST_PORT = 2225;
+ private final String TEST_HOST = "localhost";
+ private final int TEST_CLIENT_TIMEOUT = 20000;
+
+ private EmailService emailService;
+
+ @Before
+ @Override
+ public void setUp() throws Exception
+ {
+ ChildApplicationContextFactory emailSubsystem = (ChildApplicationContextFactory) ctx.getBean("InboundSMTP");
+ assertNotNull("emailSubsystem", emailSubsystem);
+ ApplicationContext emailCtx = emailSubsystem.getApplicationContext();
+ emailServer = (EmailServer) emailCtx.getBean("emailServer");
+ emailService = (EmailService)emailCtx.getBean("emailService");
+ assertNotNull("emailService", emailService);
+ }
+
+ @After
+ public void tearDown() throws Exception
+ {
+ // nothing now
+ }
+
+ /*
+ * Check null reverse-path if
+ * email.server.auth.enabled=false
+ * and
+ * email.inbound.unknownUser isn't set
+ *
+ * Null reverse-path must be disallowed
+ */
+ @Test
+ public void testDisallowedNulableFromUser() throws Exception
+ {
+ emailServer.onShutdown(null);
+
+ emailServer.setEnableTLS(false);
+ emailServer.setEnabled(true);
+
+ emailServer.setAuthenticate(false);
+ emailServer.setUnknownUser(null);
+
+ emailServer.setPort(TEST_PORT);
+ emailServer.startup();
+
+ String[] response = getMailFromNullableResponse(TEST_HOST, TEST_PORT);
+ checkResponse(response);
+
+ // expects smth. like: "504 some data"
+ // we are expect error code first
+ assertTrue("Response should have error code", response[1].indexOf("5") == 0);
+ }
+
+ /*
+ * Check null reverse-path if
+ * email.server.auth.enabled=true
+ * and
+ * email.inbound.unknownUser isn't set
+ *
+ * Null reverse-path must be allowed
+ */
+ @Test
+ public void testAllowedNulableFromUserWithAuth() throws Exception
+ {
+ emailServer.onShutdown(null);
+
+ emailServer.setEnableTLS(false);
+ emailServer.setEnabled(true);
+
+ emailServer.setAuthenticate(true);
+ emailServer.setUnknownUser(null);
+
+ emailServer.setPort(TEST_PORT);
+ emailServer.startup();
+
+ String[] response = getMailFromNullableResponse(TEST_HOST, TEST_PORT);
+ checkResponse(response);
+
+ // expects smth. like: "250 some data"
+ // we aren't expect error code
+ assertTrue("Response should have error code", response[1].indexOf("2") == 0);
+ }
+
+ /*
+ * Check null reverse-path if
+ * email.server.auth.enabled=false
+ * and
+ * email.inbound.unknownUser is set
+ *
+ * Null reverse-path must be allowed
+ */
+ @Test
+ public void testAllowedNulableFromUserWithAnonymous() throws Exception
+ {
+ emailServer.onShutdown(null);
+
+ emailServer.setEnableTLS(false);
+ emailServer.setEnabled(true);
+
+ emailServer.setAuthenticate(false);
+ emailServer.setUnknownUser("anonymous");
+
+ emailServer.setPort(TEST_PORT);
+ emailServer.startup();
+
+ String[] response = getMailFromNullableResponse(TEST_HOST, TEST_PORT);
+ checkResponse(response);
+
+ // expects smth. like: "250 some data"
+ // we aren't expect error code
+ assertTrue("Response should have error code", response[1].indexOf("2") == 0);
+ }
+
+ /*
+ * Check for data accepting if "From" user absent
+ * and
+ * "email.inbound.unknownUser" isn't set
+ * email.server.auth.enabled=true
+ */
+ @Test
+ public void testForDataAcceptingIfUserIsEmpty() throws Exception
+ {
+ emailServer.onShutdown(null);
+
+ // we need to delete value from "email.inbound.unknownUser" in service too
+ if (emailService instanceof EmailServiceImpl)
+ {
+ ((EmailServiceImpl) emailService).setUnknownUser("");
+ }
+ emailServer.setUnknownUser(null);
+
+ emailServer.setAuthenticate(true);
+ emailServer.setEnableTLS(false);
+ emailServer.setEnabled(true);
+
+ emailServer.setPort(TEST_PORT);
+ emailServer.startup();
+
+ String[] request = new String[]
+ {
+ "MAIL FROM:<>\r\n",
+ "RCPT TO:\r\n",
+ "DATA\r\n",
+ "Hello world\r\n.\r\n",
+ "QUIT\r\n"
+ };
+ String[] response = getResponse(TEST_HOST, TEST_PORT, request);
+
+ checkResponse(response);
+
+ assertTrue("Response incorrect", response.length > 4);
+ // expects smth. like: "554 some data"
+ // we are expect error code
+ assertTrue("Response should have error code", response[4].indexOf("5") == 0);
+ }
+
+ private void checkResponse(String[] response)
+ {
+ assertNotNull("Client hasn't response", response);
+ assertNotNull("Client hasn empty response", response[0]);
+ }
+
+ private String[] getMailFromNullableResponse(String host, int port) throws Exception
+ {
+ // Send null reverse-path
+ return getResponse(host, port, new String[]{"MAIL FROM:<>\r\n", "QUIT\r\n"});
+ }
+
+ private String[] getResponse(String host, int port, String requestStrings[]) throws Exception
+ {
+ Socket sock = new Socket(host, port);
+ sock.setSoTimeout(TEST_CLIENT_TIMEOUT);
+ PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
+ BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
+ ArrayList response = new ArrayList();
+
+ try
+ {
+ // Read first server response. It is smth. like: ESMTP SubEthaSMTP 3.1.6
+ response.add(in.readLine());
+
+ for (String reqStr : requestStrings)
+ {
+ out.print(reqStr);
+ out.flush();
+ response.add(in.readLine());
+ }
+
+// for (String s : response)
+// {
+// System.out.println(s);
+// }
+ return response.toArray(new String[response.size()]);
+ }
+ finally
+ {
+ in.close();
+ out.close();
+ sock.close();
+ }
+ }
+}