From 183774a2ea720747624a2059c0344e1170a0d6c3 Mon Sep 17 00:00:00 2001 From: Mark Rogers Date: Tue, 3 Jan 2012 11:45:05 +0000 Subject: [PATCH] ALF-11837 - Alfresco 4.0 SMTP Inbound does not work with messages without From and To Headers. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@33015 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../email/InboundSMTP/inboundSMTP-context.xml | 6 +++ .../email/InboundSMTP/inboundSMTP.properties | 3 ++ .../alfresco/email/server/EmailServer.java | 38 +++++++++++++++- .../email/server/EmailServiceImpl.java | 27 ++++++++--- .../handler/FolderEmailMessageHandler.java | 8 +++- .../impl/subetha/SubethaEmailMessage.java | 37 ++++++++------- .../impl/subetha/SubethaEmailServer.java | 45 ++++++++++++------- 7 files changed, 124 insertions(+), 40 deletions(-) diff --git a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml index ae8d6ee2c0..fff5561f95 100755 --- a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml +++ b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP-context.xml @@ -42,9 +42,15 @@ ${email.server.requireTLS} + + ${email.server.auth.enabled} + + + + diff --git a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP.properties b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP.properties index 4e89ec540f..6ef05e33d3 100755 --- a/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP.properties +++ b/config/alfresco/subsystems/email/InboundSMTP/inboundSMTP.properties @@ -24,5 +24,8 @@ email.server.enableTLS=true # Set this to true to require TLS email.server.requireTLS=false +# Is the user required to authenticate to use the smtp server? +email.server.auth.enabled=false + # Should duplicate messages to a folder overwrite each other or be named with a (number) email.handler.folder.overwriteDuplicates=true \ No newline at end of file diff --git a/source/java/org/alfresco/email/server/EmailServer.java b/source/java/org/alfresco/email/server/EmailServer.java index 3839199c43..de8abcc95c 100644 --- a/source/java/org/alfresco/email/server/EmailServer.java +++ b/source/java/org/alfresco/email/server/EmailServer.java @@ -24,6 +24,8 @@ import java.util.Set; import java.util.StringTokenizer; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.service.cmr.email.EmailMessageException; import org.alfresco.service.cmr.email.EmailService; import org.springframework.extensions.surf.util.AbstractLifecycleBean; @@ -50,9 +52,10 @@ public abstract class EmailServer extends AbstractLifecycleBean private boolean hideTLS = false; private boolean enableTLS = true; private boolean requireTLS = false; + private boolean authenticate = false; private EmailService emailService; - + private AuthenticationComponent authenticationComponent; /** * @param serverConfiguration Server configuration @@ -328,6 +331,19 @@ public abstract class EmailServer extends AbstractLifecycleBean System.err.println("Use: EmailServer configLocation1, configLocation2, ..."); System.err.println("\t configLocation - spring xml configs with EmailServer related beans (emailServer, emailServerConfiguration, emailService)"); } + + protected boolean authenticateUserNamePassword(String userName, char[] password) + { + try + { + getAuthenticationComponent().authenticate(userName, password); + return true; + } + catch (AuthenticationException e) + { + return false; + } + } /** Hide the TLS (Trusted Login Session) option * @@ -363,4 +379,24 @@ public abstract class EmailServer extends AbstractLifecycleBean return requireTLS; } + public void setAuthenticate(boolean enableAuthentication) + { + this.authenticate = enableAuthentication; + } + + public boolean isAuthenticate() + { + return authenticate; + } + + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + public AuthenticationComponent getAuthenticationComponent() + { + return authenticationComponent; + } + } diff --git a/source/java/org/alfresco/email/server/EmailServiceImpl.java b/source/java/org/alfresco/email/server/EmailServiceImpl.java index 6da5917147..f7059b2ce8 100644 --- a/source/java/org/alfresco/email/server/EmailServiceImpl.java +++ b/source/java/org/alfresco/email/server/EmailServiceImpl.java @@ -187,7 +187,7 @@ public class EmailServiceImpl implements EmailService // Get the username for the process using the system account final RetryingTransactionCallback getUsernameCallback = new RetryingTransactionCallback() { - + public String execute() throws Throwable { String userName = null; @@ -229,8 +229,6 @@ public class EmailServiceImpl implements EmailService } return userName; - - } }; RunAsWork getUsernameRunAsWork = new RunAsWork() @@ -240,7 +238,20 @@ public class EmailServiceImpl implements EmailService return retryingTransactionHelper.doInTransaction(getUsernameCallback, false); } }; - String username = AuthenticationUtil.runAs(getUsernameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME); + + + String username; + if(delivery.getAuth() != null) + { + // The user has authenticated. + username = delivery.getAuth(); + logger.debug("user has already authenticated as:" + username); + } + else + { + // Need to faff with old message stuff. + username = AuthenticationUtil.runAs(getUsernameRunAsWork, AuthenticationUtil.SYSTEM_USER_NAME); + } // Process the message using the username's account final RetryingTransactionCallback processMessageCallback = new RetryingTransactionCallback() @@ -279,7 +290,7 @@ public class EmailServiceImpl implements EmailService } catch (AccessDeniedException e) { - throw new EmailMessageException(ERR_ACCESS_DENIED, message.getFrom(), message.getTo()); + throw new EmailMessageException(ERR_ACCESS_DENIED, delivery.getFrom(), delivery.getRecipient()); } catch (IntegrityException e) { @@ -379,6 +390,12 @@ public class EmailServiceImpl implements EmailService private String getUsername(String from) { String userName = null; + + if(from == null) + { + return null; + } + StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); String query = "TYPE:cm\\:person +@cm\\:email:\"" + from + "\""; diff --git a/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java b/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java index 8710e45497..31ff5fc730 100644 --- a/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java +++ b/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java @@ -107,12 +107,18 @@ public class FolderEmailMessageHandler extends AbstractEmailMessageHandler Date now = new Date(); messageSubject = I18NUtil.getMessage(MSG_DEFAULT_SUBJECT, new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss").format(now)); } + + String messageFrom = message.getFrom(); + if(messageFrom == null) + { + messageFrom = ""; + } // Create main content node NodeRef contentNodeRef; contentNodeRef = addContentNode(getNodeService(), spaceNodeRef, messageSubject, overwriteDuplicates); // Add titled aspect - addTitledAspect(contentNodeRef, messageSubject, message.getFrom()); + addTitledAspect(contentNodeRef, messageSubject, messageFrom); // Add emailed aspect addEmailedAspect(contentNodeRef, message); // Write the message content diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java index 0c984469c9..c2a788f291 100644 --- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java +++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java @@ -131,17 +131,19 @@ public class SubethaEmailMessage implements EmailMessage } if (addresses == null || addresses.length == 0) { - throw new EmailMessageException(ERR_NO_FROM_ADDRESS); - } - if(addresses[0] instanceof InternetAddress) - { - from = ((InternetAddress)addresses[0]).getAddress(); + //throw new EmailMessageException(ERR_NO_FROM_ADDRESS); } else { - from = addresses[0].toString(); - } - + if(addresses[0] instanceof InternetAddress) + { + from = ((InternetAddress)addresses[0]).getAddress(); + } + else + { + from = addresses[0].toString(); + } + } } if (to == null) @@ -157,18 +159,19 @@ public class SubethaEmailMessage implements EmailMessage } if (addresses == null || addresses.length == 0) { - throw new EmailMessageException(ERR_NO_TO_ADDRESS); - } - if(addresses[0] instanceof InternetAddress) - { - to = ((InternetAddress)addresses[0]).getAddress(); + //throw new EmailMessageException(ERR_NO_TO_ADDRESS); } else { - to = addresses[0].toString(); - } - - to = addresses[0].toString(); + if(addresses[0] instanceof InternetAddress) + { + to = ((InternetAddress)addresses[0]).getAddress(); + } + else + { + to = addresses[0].toString(); + } + } } if (cc == null) diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java index c102cd7cec..2fc91cdb93 100644 --- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java +++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java @@ -33,11 +33,17 @@ import org.alfresco.service.cmr.email.EmailMessage; import org.alfresco.service.cmr.email.EmailMessageException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.subethamail.smtp.AuthenticationHandler; +import org.subethamail.smtp.AuthenticationHandlerFactory; import org.subethamail.smtp.MessageContext; import org.subethamail.smtp.MessageHandler; import org.subethamail.smtp.MessageHandlerFactory; import org.subethamail.smtp.RejectException; import org.subethamail.smtp.TooMuchDataException; +import org.subethamail.smtp.auth.EasyAuthenticationHandlerFactory; +import org.subethamail.smtp.auth.LoginFailedException; +import org.subethamail.smtp.auth.MultipleAuthenticationHandlerFactory; +import org.subethamail.smtp.auth.UsernamePasswordValidator; import org.subethamail.smtp.server.SMTPServer; /** @@ -66,6 +72,12 @@ public class SubethaEmailServer extends EmailServer serverImpl.setEnableTLS(isEnableTLS()); serverImpl.setRequireTLS(isRequireTLS()); + if(isAuthenticate()) + { + AuthenticationHandlerFactory authenticationHandler = new EasyAuthenticationHandlerFactory(new AlfrescoLoginUsernamePasswordValidator()); + serverImpl.setAuthenticationHandlerFactory(authenticationHandler); + } + serverImpl.start(); log.info("Inbound SMTP Email Server has started successfully, on hostName:" + getDomain() + "port:" + getPort()); } @@ -76,7 +88,20 @@ public class SubethaEmailServer extends EmailServer serverImpl.stop(); log.info("Inbound SMTP Email Server has stopped successfully"); } - + + class AlfrescoLoginUsernamePasswordValidator implements UsernamePasswordValidator + { + @Override + public void login(String username, String password) + throws LoginFailedException + { + if(authenticateUserNamePassword(username, password.toCharArray())) + { + throw new LoginFailedException("unable to log on"); + } + } + } + class HandlerFactory implements MessageHandlerFactory { public MessageHandler create(MessageContext messageContext) @@ -139,7 +164,9 @@ public class SubethaEmailServer extends EmailServer public void recipient(String recipient) throws RejectException { - deliveries.add(new EmailDelivery(recipient, from, null)); + AuthenticationHandler auth = messageContext.getAuthenticationHandler(); + + deliveries.add(new EmailDelivery(recipient, from, auth != null ? (String)auth.getIdentity(): null)); } public void data(InputStream data) throws TooMuchDataException, IOException, RejectException @@ -171,20 +198,6 @@ public class SubethaEmailServer extends EmailServer } } -// public List getAuthenticationMechanisms() -// { -// return EMPTY_LIST; -// } -// -// public boolean auth(String clientInput, StringBuffer response) throws RejectException -// { -// return true; -// } -// -// public void resetState() -// { -// } -// @Override public void done() {