From c34da6ea331e8b1b48273dd953e21943920242f0 Mon Sep 17 00:00:00 2001 From: Mark Rogers Date: Tue, 13 Dec 2011 14:53:18 +0000 Subject: [PATCH] ALF-11837 - now will authenticate via both from fields - also a refactor in anticipation of implemeting multiple recipeints and authentication. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32731 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../email/server/EmailServiceImpl.java | 93 ++++++++----- .../email/server/EmailServiceImplTest.java | 50 ++++--- .../email/server/EmailServiceRemotable.java | 9 +- .../impl/subetha/SubethaEmailServer.java | 130 +++++------------- .../service/cmr/email/EmailService.java | 8 +- 5 files changed, 134 insertions(+), 156 deletions(-) diff --git a/source/java/org/alfresco/email/server/EmailServiceImpl.java b/source/java/org/alfresco/email/server/EmailServiceImpl.java index 77e48aeef1..6da5917147 100644 --- a/source/java/org/alfresco/email/server/EmailServiceImpl.java +++ b/source/java/org/alfresco/email/server/EmailServiceImpl.java @@ -29,6 +29,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.email.EmailDelivery; import org.alfresco.service.cmr.email.EmailMessage; import org.alfresco.service.cmr.email.EmailMessageException; import org.alfresco.service.cmr.email.EmailService; @@ -155,27 +156,27 @@ public class EmailServiceImpl implements EmailService /** * {@inheritDoc} */ - public void importMessage(EmailMessage message) + public void importMessage(EmailDelivery delivery, EmailMessage message) { - processMessage(null, message); + processMessage(delivery, null, message); } /** * {@inheritDoc} */ - public void importMessage(NodeRef nodeRef, EmailMessage message) + public void importMessage(EmailDelivery delivery, NodeRef nodeRef, EmailMessage message) { - processMessage(nodeRef, message); + processMessage(delivery, nodeRef, message); } /** * Process the message. Method is called after filtering by sender's address. - * + * @param delivery - who gets the message and who is it from (may be different from the contents of the message) * @param nodeRef Addressed node (target node). * @param message Email message * @throws EmailMessageException Any exception occured inside the method will be converted and thrown as EmailMessageException */ - private void processMessage(final NodeRef nodeRef, final EmailMessage message) + private void processMessage(final EmailDelivery delivery, final NodeRef nodeRef, final EmailMessage message) { if (!emailInboundEnabled) { @@ -186,10 +187,50 @@ 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 from = message.getFrom(); - return getUsername(from); + String userName = null; + + userName = getUsername(delivery.getFrom()); + if(userName == null) + { + if(logger.isDebugEnabled()) + { + logger.debug("unable to find user for from: " + delivery.getFrom() + "trying message next"); + } + userName = getUsername(message.getFrom()); + } + + if (userName == null) + { + if(unknownUser.isEmpty()) + { + if(logger.isDebugEnabled()) + { + logger.debug("unable to find user for from: " + message.getFrom()); + } + throw new EmailMessageException(ERR_UNKNOWN_SOURCE_ADDRESS, message.getFrom()); + } + else + { + if(logger.isDebugEnabled()) + { + logger.debug("unable to find user for from - return anonymous: "); + } + userName = unknownUser; + } + } + + // Ensure that the user is part of the Email Contributors group + if (userName == null || !isEmailContributeUser(userName)) + { + throw new EmailMessageException(ERR_USER_NOT_EMAIL_CONTRIBUTOR, userName); + } + + return userName; + + } }; RunAsWork getUsernameRunAsWork = new RunAsWork() @@ -206,7 +247,8 @@ public class EmailServiceImpl implements EmailService { public Object execute() throws Throwable { - String recipient = message.getTo(); + //String recipient = message.getTo(); + String recipient = delivery.getRecipient(); NodeRef targetNodeRef = null; if (nodeRef == null) { @@ -331,7 +373,7 @@ public class EmailServiceImpl implements EmailService * Authenticate in Alfresco repository by sender's e-mail address. * * @param from Sender's email address - * @return User name + * @return User name or null if the user does not exist. * @throws EmailMessageException Exception will be thrown if authentication is failed. */ private String getUsername(String from) @@ -345,23 +387,7 @@ public class EmailServiceImpl implements EmailService { if (resultSet.length() == 0) { - if (unknownUser == null || unknownUser.length() == 0) - { - if(logger.isDebugEnabled()) - { - logger.debug("unable to find user for from: " + from); - } - throw new EmailMessageException(ERR_UNKNOWN_SOURCE_ADDRESS, from); - } - else - { - if(logger.isDebugEnabled()) - { - logger.debug("unable to find user for from - return anonymous: " + from); - } - - userName = unknownUser; - } + return null; } else { @@ -381,16 +407,15 @@ public class EmailServiceImpl implements EmailService } finally { - resultSet.close(); - } - // Ensure that the user is part of the Email Contributors group - if (userName == null || !isEmailContributeUser(userName)) - { - throw new EmailMessageException(ERR_USER_NOT_EMAIL_CONTRIBUTOR, userName); + if(resultSet != null) + { + resultSet.close(); + } } + return userName; } - + /** * Check that the user is the member in EMAIL_CONTRIBUTORS group * diff --git a/source/java/org/alfresco/email/server/EmailServiceImplTest.java b/source/java/org/alfresco/email/server/EmailServiceImplTest.java index 5aba66eaa4..6613fecbff 100644 --- a/source/java/org/alfresco/email/server/EmailServiceImplTest.java +++ b/source/java/org/alfresco/email/server/EmailServiceImplTest.java @@ -39,6 +39,7 @@ import org.alfresco.email.server.impl.subetha.SubethaEmailMessage; import org.alfresco.model.ContentModel; import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.email.EmailDelivery; import org.alfresco.service.cmr.email.EmailMessageException; import org.alfresco.service.cmr.email.EmailService; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -196,9 +197,11 @@ public class EmailServiceImplTest extends TestCase InputStream is = new StringInputStream(bos.toString()); assertNotNull("is is null", is); - SubethaEmailMessage m = new SubethaEmailMessage(is); + SubethaEmailMessage m = new SubethaEmailMessage(is); + + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery, m); fail("anonymous user not rejected"); } catch (EmailMessageException e) @@ -235,9 +238,11 @@ public class EmailServiceImplTest extends TestCase InputStream is = new StringInputStream(bos.toString()); assertNotNull("is is null", is); - SubethaEmailMessage m = new SubethaEmailMessage(is); + SubethaEmailMessage m = new SubethaEmailMessage(is); + + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery, m); } /** @@ -271,9 +276,11 @@ public class EmailServiceImplTest extends TestCase InputStream is = new StringInputStream(bos.toString()); assertNotNull("is is null", is); - SubethaEmailMessage m = new SubethaEmailMessage(is); + SubethaEmailMessage m = new SubethaEmailMessage(is); + + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery,m); } // /** @@ -385,8 +392,9 @@ public class EmailServiceImplTest extends TestCase assertNotNull("is is null", is); SubethaEmailMessage m = new SubethaEmailMessage(is); + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery, m); } @@ -474,12 +482,14 @@ public class EmailServiceImplTest extends TestCase */ logger.debug("Step 1: turn on Overwite Duplicates"); folderEmailMessageHandler.setOverwriteDuplicates(true); + + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 1", 1, assocs.size()); assertEquals("name of link not as expected", assocs.get(0).getQName(), QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, TEST_SUBJECT)); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 1", 1, assocs.size()); @@ -488,10 +498,10 @@ public class EmailServiceImplTest extends TestCase */ logger.debug("Step 2: turn off Overwite Duplicates"); folderEmailMessageHandler.setOverwriteDuplicates(false); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 2", 2, assocs.size()); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 3", 3, assocs.size()); @@ -507,10 +517,10 @@ public class EmailServiceImplTest extends TestCase m = new SubethaEmailMessage(is); folderEmailMessageHandler.setOverwriteDuplicates(false); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 4", 4, assocs.size()); - emailService.importMessage(m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); assertEquals("assocs not 5", 5, assocs.size()); @@ -528,9 +538,9 @@ public class EmailServiceImplTest extends TestCase assertNotNull("is is null", is); m = new SubethaEmailMessage(is); folderEmailMessageHandler.setOverwriteDuplicates(false); - emailService.importMessage(m); - emailService.importMessage(m); - emailService.importMessage(m); + emailService.importMessage(delivery, m); + emailService.importMessage(delivery, m); + emailService.importMessage(delivery, m); assocs = nodeService.getChildAssocs(testUserHomeFolder, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); List assocNames = new Vector(); @@ -624,9 +634,11 @@ public class EmailServiceImplTest extends TestCase InputStream is = new StringInputStream(bos.toString()); assertNotNull("is is null", is); - SubethaEmailMessage m = new SubethaEmailMessage(is); + SubethaEmailMessage m = new SubethaEmailMessage(is); + + EmailDelivery delivery = new EmailDelivery(to, from, null); - emailService.importMessage(m); + emailService.importMessage(delivery, m); /** * Step 2 @@ -638,7 +650,7 @@ public class EmailServiceImplTest extends TestCase { logger.debug("Step 2"); emailServiceImpl.setEmailContributorsAuthority("EMAIL_CONTRIBUTORS"); - emailService.importMessage(m); + emailService.importMessage(delivery, m); fail("not thrown out"); } catch (EmailMessageException e) diff --git a/source/java/org/alfresco/email/server/EmailServiceRemotable.java b/source/java/org/alfresco/email/server/EmailServiceRemotable.java index 70f60044a3..cb405eac38 100644 --- a/source/java/org/alfresco/email/server/EmailServiceRemotable.java +++ b/source/java/org/alfresco/email/server/EmailServiceRemotable.java @@ -20,6 +20,7 @@ package org.alfresco.email.server; import org.alfresco.email.server.impl.subetha.SubethaEmailMessage; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.email.EmailDelivery; import org.alfresco.service.cmr.email.EmailMessage; import org.alfresco.service.cmr.email.EmailService; import org.alfresco.service.cmr.repository.NodeRef; @@ -50,22 +51,22 @@ public class EmailServiceRemotable extends AbstractLifecycleBean implements Emai this.rmiRegistryPort = rmiRegistryPort; } - public void importMessage(EmailMessage message) + public void importMessage(EmailDelivery delivery, EmailMessage message) { if (message instanceof SubethaEmailMessage) { ((SubethaEmailMessage) message).setRmiRegistry(rmiRegistryHost, rmiRegistryPort); } - emailServiceProxy.importMessage(message); + emailServiceProxy.importMessage(delivery, message); } - public void importMessage(NodeRef nodeRef, EmailMessage message) + public void importMessage(EmailDelivery delivery, NodeRef nodeRef, EmailMessage message) { if (message instanceof SubethaEmailMessage) { ((SubethaEmailMessage) message).setRmiRegistry(rmiRegistryHost, rmiRegistryPort); } - emailServiceProxy.importMessage(nodeRef, message); + emailServiceProxy.importMessage(delivery, nodeRef, message); } @Override 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 792e05aada..c102cd7cec 100644 --- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java +++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java @@ -28,6 +28,7 @@ import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import org.alfresco.email.server.EmailServer; +import org.alfresco.service.cmr.email.EmailDelivery; import org.alfresco.service.cmr.email.EmailMessage; import org.alfresco.service.cmr.email.EmailMessageException; import org.apache.commons.logging.Log; @@ -95,7 +96,10 @@ public class SubethaEmailServer extends EmailServer private List EMPTY_LIST = new LinkedList(); private MessageContext messageContext; - List deliveries = new ArrayList(); + + private String from; + + List deliveries = new ArrayList(); public Handler(MessageContext messageContext) { @@ -107,13 +111,12 @@ public class SubethaEmailServer extends EmailServer return messageContext; } + public void from(String fromString) throws RejectException { - String from = fromString; - try { - InternetAddress a = new InternetAddress(from); + InternetAddress a = new InternetAddress(fromString); from = a.getAddress(); } catch (AddressException e) @@ -136,79 +139,30 @@ public class SubethaEmailServer extends EmailServer public void recipient(String recipient) throws RejectException { - deliveries.add(new Delivery(recipient)); + deliveries.add(new EmailDelivery(recipient, from, null)); } public void data(InputStream data) throws TooMuchDataException, IOException, RejectException - { - try - { - if (deliveries.size() > 0) - { - Delivery delivery = deliveries.get(0); - processDelivery(delivery, data); - } - } - finally - { -// // DH: As per comments in ETHREEOH-2252, I am very concerned about the need to do the clear() here. -// // If this message is stateful (as it must be, given the API) then the need to clear -// // the list of delivery recipients ('deliveries') implies that Subetha is re-using -// // the instance. -// // Later versions of Subetha appear to define the behaviour better. Un upgrade of -// // the library would be a good idea. - deliveries.clear(); - } -// See ALFCOM-3165: Support multiple recipients for inbound Subetha email messages -// -// Duplicate messages coming in -// http://www.subethamail.org/se/archive_msg.jsp?msgId=20938 -// if (deliveries.size() == 1) -// { -// Delivery delivery = deliveries.get(0); -// processDelivery(delivery, data); -// } -// else if (deliveries.size() > 1) -// { -// DeferredFileOutputStream dfos = null; -// try -// { -// dfos = new DeferredFileOutputStream(DEFAULT_DATA_DEFERRED_SIZE); -// -// byte[] bytes = new byte[1024 * 8]; -// for (int len = -1; (len = data.read(bytes)) != -1;) -// { -// dfos.write(bytes, 0, len); -// } -// for (Delivery delivery : deliveries) -// { -// processDelivery(delivery, dfos.getInputStream()); -// } -// } -// finally -// { -// try -// { -// dfos.close(); -// } -// catch (Exception e) -// { -// } -// } -// } - } - - private void processDelivery(Delivery delivery, InputStream data) throws RejectException { EmailMessage emailMessage; try { emailMessage = new SubethaEmailMessage(data); - getEmailService().importMessage(emailMessage); + + // Only send to the first receipient - TODO send to all recipients + if (deliveries.size() > 0) + { + EmailDelivery delivery = deliveries.get(0); + getEmailService().importMessage(delivery, emailMessage); + } } catch (EmailMessageException e) { - throw new RejectException(554, e.getMessage()); + if(log.isDebugEnabled()) + { + log.debug("about to raise EmailMessageException", e); + } + throw new RejectException(554, e.getMessage()); } catch (Throwable e) { @@ -217,40 +171,26 @@ 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() - { - } - +// public List getAuthenticationMechanisms() +// { +// return EMPTY_LIST; +// } +// +// public boolean auth(String clientInput, StringBuffer response) throws RejectException +// { +// return true; +// } +// +// public void resetState() +// { +// } +// @Override public void done() { - + deliveries.clear(); } }; - class Delivery - { - private String recipient; - - public Delivery(String recipient) - { - this.recipient = recipient; - } - - public String getRecipient() - { - return recipient; - } - }; } diff --git a/source/java/org/alfresco/service/cmr/email/EmailService.java b/source/java/org/alfresco/service/cmr/email/EmailService.java index 9408724730..a3b2e53c20 100644 --- a/source/java/org/alfresco/service/cmr/email/EmailService.java +++ b/source/java/org/alfresco/service/cmr/email/EmailService.java @@ -40,20 +40,20 @@ public interface EmailService /** * Processes an email message. The message's content is intended for a node found by * examining the email's target address. - * + * @param delivery instructions - who gets the message and who is it from * @param message the email message * @throws EmailMessageRejectException if the message is rejected for any reason */ @Auditable(parameters = { "message" }) - void importMessage(EmailMessage message); + void importMessage(EmailDelivery delivery, EmailMessage message); /** * Process an email message. The message's content is intended for a specific node. - * + * @param delivery instructions - who gets the message and who is it from * @param nodeRef the node to import the message to * @param message the email message * @throws EmailMessageRejectException if the message is rejected for any reason */ @Auditable(parameters = { "nodeRef", "message" }) - void importMessage(NodeRef nodeRef, EmailMessage message); + void importMessage(EmailDelivery delivery, NodeRef nodeRef, EmailMessage message); }