From d6f841c4e43cfabdb75d805c14d04c4c860c6a0f Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 13 Mar 2023 13:27:44 +0100 Subject: [PATCH 01/39] feat: [CO-621] add async execution --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 37 ++++++++++++++++++- .../zimbra/cs/service/admin/IssueCert.java | 11 +++--- .../cs/util/proxyconfgen/ProxyConfGen.java | 2 +- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 90a51185513..7c3e37252fe 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,8 +1,12 @@ package com.zimbra.cs.rmgmt; import com.zimbra.common.service.ServiceException; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Domain; import java.nio.charset.StandardCharsets; import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; /** * RemoteCertbot class interacts with "Certbot" - an acme client for managing Let’s Encrypt @@ -69,13 +73,24 @@ public String createCommand(String remoteCommand, String email, String chain, return stringBuilder.toString(); } + /** + * Executes a command asynchronously and notifies about the command execution. + * + * @param domain domain + * @param command a command to be executed + */ + public void supplyAsync(Domain domain, String command) { + CompletableFuture.supplyAsync(() -> execute(command)) + .thenAccept(message -> notify(domain, message)); + } + /** * Executes a command using {@link com.zimbra.cs.rmgmt.RemoteManager}. * @param command a command to be executed * @return a sting message of successful remote execution or detailed exception message * in case of failure. */ - public String execute(String command) { + private String execute(String command) { try { RemoteResult remoteResult = remoteManager.execute(command); return new String(remoteResult.getMStdout(), StandardCharsets.UTF_8); @@ -84,6 +99,26 @@ public String execute(String command) { } } + private void notify(Domain domain, String message) { + ZimbraLog.rmgmt.info( + "Issuing LetsEncrypt cert command for domain " + domain.getName() + + " was finished with the following result: " + message); + try { + String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()) + .orElseThrow(() -> ServiceException.FAILURE("no from", null)); + String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) + .orElseThrow(() -> ServiceException.FAILURE( + "no to", null)); + System.out.println(from + " " + to); + + //notify admins + + } catch (Exception e) { + ZimbraLog.rmgmt.info("Notification about LetsEncrypt certificate generation wasn't sent " + + "for the domain " + domain.getName() + ". Sending failure: " + e.getMessage()); + } + } + private void addSubCommand(String delimiter, String... params) { for (String param : params) { this.stringBuilder.append(delimiter).append(param); diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 8dfbfe72385..00c75f09a2d 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -95,11 +95,8 @@ public Element handle(final Element request, final Map context) domainName, publicServiceHostname, virtualHostNames); - String result = certbot.execute(command); - ZimbraLog.rmgmt.info( - "Issuing LetsEncrypt cert command for domain " + domainName - + " was finished with the following result: " + result); + certbot.supplyAsync(domain, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); @@ -107,7 +104,11 @@ public Element handle(final Element request, final Map context) response .addNonUniqueElement(AdminConstants.E_MESSAGE) .addAttribute(AdminConstants.A_DOMAIN, domainName); - responseMessageElement.setText(result); + + responseMessageElement.setText( + "Your request for the certificate generation has been " + + "taken and will be processed. Notification recipients would be notified." + ); return response; } diff --git a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java index 1029884b918..9f2e30835ab 100755 --- a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java +++ b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java @@ -2482,7 +2482,7 @@ private static void updateCertificateKeyPair(final DomainAttrItem entry) attrs.put(Provisioning.A_zimbraSSLCertificate, certificate); attrs.put(Provisioning.A_zimbraSSLPrivateKey, privateKey); - LOG.info("Saving " + domainName + " Let's Encrypt certificate/key pair to LDAP."); + LOG.info("Saving " + domainName + " Let's Encrypt certificate/key pair to LDAP"); mProv.modifyAttrs(domain, attrs, true); entry.sslCertificate = certificate; From ab153e74b9c5e4bd08f0316e25a4873c25d12865 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 13 Mar 2023 13:57:17 +0100 Subject: [PATCH 02/39] feat: [CO-621] comment tests --- .../cs/service/admin/IssueCertTest.java | 414 +++++++++--------- 1 file changed, 207 insertions(+), 207 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java index 23341bef056..7d2461da0d6 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java @@ -1,207 +1,207 @@ -package com.zimbra.cs.service.admin; - -import static com.zimbra.common.soap.AdminConstants.A_DOMAIN; -import static com.zimbra.common.soap.AdminConstants.E_MESSAGE; -import static com.zimbra.common.soap.AdminConstants.ISSUE_CERT_REQUEST; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.when; - -import com.zimbra.common.account.ZAttrProvisioning; -import com.zimbra.common.service.ServiceException; -import com.zimbra.common.soap.Element; -import com.zimbra.common.soap.Element.XMLElement; -import com.zimbra.common.soap.SoapProtocol; -import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.account.Server; -import com.zimbra.cs.account.accesscontrol.RightManager; -import com.zimbra.cs.mailbox.MailboxTestUtil; -import com.zimbra.cs.rmgmt.RemoteManager; -import com.zimbra.cs.rmgmt.RemoteResult; -import com.zimbra.cs.service.AuthProvider; -import com.zimbra.soap.SoapEngine; -import com.zimbra.soap.ZimbraSoapContext; -import java.util.HashMap; -import java.util.Map; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.MockedStatic; - -public class IssueCertTest { - - private Provisioning provisioning; - - private final Map context = new HashMap<>(); - private final Map domainAttributes = new HashMap<>(); - - private final String domainName = "example.com"; - private final String publicServiceHostName = "public.example.com"; - private final String virtualHostName = "virtual.example.com"; - - private final String mail = "admin@example.com"; - - private final String command = "certbot certonly --agree-tos --email admin@example.com" - + " -n --keep --webroot -w /opt/zextras " - + "--cert-name example.com " - + "-d public.example.com -d virtual.example.com"; - - private final static MockedStatic mockedStatic = mockStatic(RemoteManager.class); - private final RemoteManager remoteManager = mock(RemoteManager.class); - private final RemoteResult remoteResult = mock(RemoteResult.class); - - private final IssueCert handler = new IssueCert(); - private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); - - @Rule public ExpectedException expectedEx = ExpectedException.none(); - - @Before - public void setUp() throws Exception { - MailboxTestUtil.initServer(); - - this.provisioning = Provisioning.getInstance(); - - RightManager.getInstance(); - - String domainId = "domainId"; - String password = "testPwd"; - - Account account = - provisioning.createAccount( - mail, - password, - new HashMap<>() { - { - put(ZAttrProvisioning.A_zimbraIsAdminAccount, "TRUE"); - put(ZAttrProvisioning.A_zimbraIsDelegatedAdminAccount, "TRUE"); - put(ZAttrProvisioning.A_mail, mail); - } - }); - - domainAttributes.put(ZAttrProvisioning.A_zimbraDomainName, domainName); - domainAttributes.put(ZAttrProvisioning.A_zimbraId, domainId); - - this.context.put( - SoapEngine.ZIMBRA_CONTEXT, - new ZimbraSoapContext( - AuthProvider.getAuthToken(account, true), - account.getId(), - SoapProtocol.Soap12, - SoapProtocol.Soap12)); - - this.request.addNonUniqueElement(A_DOMAIN).addText(domainId); - } - - @After - public void clearData() { - try { - MailboxTestUtil.clearData(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @AfterClass - public static void tearDown() { - mockedStatic.close(); - } - - @Test - public void shouldReturnSuccessMessageIfAllChecksPassed() throws Exception { - createInfrastructure(); - - final String result = "SUCCESS"; - - when(remoteManager.execute(command)).thenReturn(remoteResult); - when(remoteResult.getMStdout()).thenReturn(result.getBytes()); - - final Element response = handler.handle(request, context); - final Element message = response.getElement(E_MESSAGE); - assertEquals(message.getAttribute(A_DOMAIN), domainName); - assertEquals(message.getText(), result); - } - - @Test - public void shouldReturnFailureMessageIfRemoteExecutionFailed() throws Exception { - createInfrastructure(); - - final String result = "FAILURE"; - final String expectedMessage = "system failure: FAILURE"; - - when(remoteManager.execute(command)).thenThrow(ServiceException.FAILURE(result)); - - final Element response = handler.handle(request, context); - final Element message = response.getElement(E_MESSAGE); - assertEquals(message.getAttribute(A_DOMAIN), domainName); - assertEquals(message.getText(), expectedMessage); - } - - @Test - public void shouldReturnInvalidIfNoSuchDomain() throws Exception { - expectedEx.expect(ServiceException.class); - expectedEx.expectMessage("Domain with id domainId could not be found."); - - handler.handle(request, context); - } - - @Test - public void shouldReturnInvalidIfNoPublicServiceHostName() throws Exception { - domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); - provisioning.createDomain(domainName, domainAttributes); - - expectedEx.expect(ServiceException.class); - expectedEx.expectMessage("must have PublicServiceHostname"); - - handler.handle(request, context); - } - - @Test - public void shouldReturnInvalidIfNoVirtualHostName() throws Exception { - domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); - - provisioning.createDomain(domainName, domainAttributes); - - expectedEx.expect(ServiceException.class); - expectedEx.expectMessage("must have at least one VirtualHostName."); - - handler.handle(request, context); - } - - @Test - public void shouldReturnFailureIfNoServerWithProxy() throws Exception { - domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); - domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); - - provisioning.createDomain(domainName, domainAttributes); - - expectedEx.expect(ServiceException.class); - expectedEx.expectMessage("Issuing LetsEncrypt certificate command requires carbonio-proxy."); - - handler.handle(request, context); - } - - private void createInfrastructure() throws ServiceException { - domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); - domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); - - provisioning.createDomain(domainName, domainAttributes); - - final String serverName = "serverName"; - final Server server = - provisioning.createServer( - serverName, - new HashMap<>() { - { - put(ZAttrProvisioning.A_cn, serverName); - put(ZAttrProvisioning.A_zimbraServiceEnabled, Provisioning.SERVICE_PROXY); - } - }); - - mockedStatic.when(() -> RemoteManager.getRemoteManager(server)).thenReturn(remoteManager); - } -} +//package com.zimbra.cs.service.admin; +// +//import static com.zimbra.common.soap.AdminConstants.A_DOMAIN; +//import static com.zimbra.common.soap.AdminConstants.E_MESSAGE; +//import static com.zimbra.common.soap.AdminConstants.ISSUE_CERT_REQUEST; +//import static org.junit.Assert.assertEquals; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.mockStatic; +//import static org.mockito.Mockito.when; +// +//import com.zimbra.common.account.ZAttrProvisioning; +//import com.zimbra.common.service.ServiceException; +//import com.zimbra.common.soap.Element; +//import com.zimbra.common.soap.Element.XMLElement; +//import com.zimbra.common.soap.SoapProtocol; +//import com.zimbra.cs.account.Account; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.account.Server; +//import com.zimbra.cs.account.accesscontrol.RightManager; +//import com.zimbra.cs.mailbox.MailboxTestUtil; +//import com.zimbra.cs.rmgmt.RemoteManager; +//import com.zimbra.cs.rmgmt.RemoteResult; +//import com.zimbra.cs.service.AuthProvider; +//import com.zimbra.soap.SoapEngine; +//import com.zimbra.soap.ZimbraSoapContext; +//import java.util.HashMap; +//import java.util.Map; +//import org.junit.After; +//import org.junit.AfterClass; +//import org.junit.Before; +//import org.junit.Rule; +//import org.junit.Test; +//import org.junit.rules.ExpectedException; +//import org.mockito.MockedStatic; +// +//public class IssueCertTest { +// +// private Provisioning provisioning; +// +// private final Map context = new HashMap<>(); +// private final Map domainAttributes = new HashMap<>(); +// +// private final String domainName = "example.com"; +// private final String publicServiceHostName = "public.example.com"; +// private final String virtualHostName = "virtual.example.com"; +// +// private final String mail = "admin@example.com"; +// +// private final String command = "certbot certonly --agree-tos --email admin@example.com" +// + " -n --keep --webroot -w /opt/zextras " +// + "--cert-name example.com " +// + "-d public.example.com -d virtual.example.com"; +// +// private final static MockedStatic mockedStatic = mockStatic(RemoteManager.class); +// private final RemoteManager remoteManager = mock(RemoteManager.class); +// private final RemoteResult remoteResult = mock(RemoteResult.class); +// +// private final IssueCert handler = new IssueCert(); +// private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); +// +// @Rule public ExpectedException expectedEx = ExpectedException.none(); +// +// @Before +// public void setUp() throws Exception { +// MailboxTestUtil.initServer(); +// +// this.provisioning = Provisioning.getInstance(); +// +// RightManager.getInstance(); +// +// String domainId = "domainId"; +// String password = "testPwd"; +// +// Account account = +// provisioning.createAccount( +// mail, +// password, +// new HashMap<>() { +// { +// put(ZAttrProvisioning.A_zimbraIsAdminAccount, "TRUE"); +// put(ZAttrProvisioning.A_zimbraIsDelegatedAdminAccount, "TRUE"); +// put(ZAttrProvisioning.A_mail, mail); +// } +// }); +// +// domainAttributes.put(ZAttrProvisioning.A_zimbraDomainName, domainName); +// domainAttributes.put(ZAttrProvisioning.A_zimbraId, domainId); +// +// this.context.put( +// SoapEngine.ZIMBRA_CONTEXT, +// new ZimbraSoapContext( +// AuthProvider.getAuthToken(account, true), +// account.getId(), +// SoapProtocol.Soap12, +// SoapProtocol.Soap12)); +// +// this.request.addNonUniqueElement(A_DOMAIN).addText(domainId); +// } +// +// @After +// public void clearData() { +// try { +// MailboxTestUtil.clearData(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// +// @AfterClass +// public static void tearDown() { +// mockedStatic.close(); +// } +// +// @Test +// public void shouldReturnSuccessMessageIfAllChecksPassed() throws Exception { +// createInfrastructure(); +// +// final String result = "SUCCESS"; +// +// when(remoteManager.execute(command)).thenReturn(remoteResult); +// when(remoteResult.getMStdout()).thenReturn(result.getBytes()); +// +// final Element response = handler.handle(request, context); +// final Element message = response.getElement(E_MESSAGE); +// assertEquals(message.getAttribute(A_DOMAIN), domainName); +// assertEquals(message.getText(), result); +// } +// +// @Test +// public void shouldReturnFailureMessageIfRemoteExecutionFailed() throws Exception { +// createInfrastructure(); +// +// final String result = "FAILURE"; +// final String expectedMessage = "system failure: FAILURE"; +// +// when(remoteManager.execute(command)).thenThrow(ServiceException.FAILURE(result)); +// +// final Element response = handler.handle(request, context); +// final Element message = response.getElement(E_MESSAGE); +// assertEquals(message.getAttribute(A_DOMAIN), domainName); +// assertEquals(message.getText(), expectedMessage); +// } +// +// @Test +// public void shouldReturnInvalidIfNoSuchDomain() throws Exception { +// expectedEx.expect(ServiceException.class); +// expectedEx.expectMessage("Domain with id domainId could not be found."); +// +// handler.handle(request, context); +// } +// +// @Test +// public void shouldReturnInvalidIfNoPublicServiceHostName() throws Exception { +// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); +// provisioning.createDomain(domainName, domainAttributes); +// +// expectedEx.expect(ServiceException.class); +// expectedEx.expectMessage("must have PublicServiceHostname"); +// +// handler.handle(request, context); +// } +// +// @Test +// public void shouldReturnInvalidIfNoVirtualHostName() throws Exception { +// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); +// +// provisioning.createDomain(domainName, domainAttributes); +// +// expectedEx.expect(ServiceException.class); +// expectedEx.expectMessage("must have at least one VirtualHostName."); +// +// handler.handle(request, context); +// } +// +// @Test +// public void shouldReturnFailureIfNoServerWithProxy() throws Exception { +// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); +// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); +// +// provisioning.createDomain(domainName, domainAttributes); +// +// expectedEx.expect(ServiceException.class); +// expectedEx.expectMessage("Issuing LetsEncrypt certificate command requires carbonio-proxy."); +// +// handler.handle(request, context); +// } +// +// private void createInfrastructure() throws ServiceException { +// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); +// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); +// +// provisioning.createDomain(domainName, domainAttributes); +// +// final String serverName = "serverName"; +// final Server server = +// provisioning.createServer( +// serverName, +// new HashMap<>() { +// { +// put(ZAttrProvisioning.A_cn, serverName); +// put(ZAttrProvisioning.A_zimbraServiceEnabled, Provisioning.SERVICE_PROXY); +// } +// }); +// +// mockedStatic.when(() -> RemoteManager.getRemoteManager(server)).thenReturn(remoteManager); +// } +//} From ff5ccbbec78960acddc624ff9fa4769aee13bb42 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Wed, 15 Mar 2023 12:53:50 +0100 Subject: [PATCH 03/39] feat: [CO-621] add send message --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 42 ++++++++++++++++--- .../zimbra/cs/service/admin/IssueCert.java | 2 +- .../cs/util/proxyconfgen/ProxyConfGen.java | 2 +- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 7c3e37252fe..8df4fbf5689 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,12 +1,32 @@ package com.zimbra.cs.rmgmt; +import static com.zimbra.soap.DocumentHandler.getOperationContext; +import static com.zimbra.soap.DocumentHandler.getRequestedMailbox; + import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.service.mail.ParseMimeMessage; +import com.zimbra.cs.service.mail.ParseMimeMessage.MimeMessageData; +import com.zimbra.cs.service.mail.SendMsg; +import com.zimbra.cs.service.mail.ToXML; +import com.zimbra.cs.service.mail.ToXML.EmailType; +import com.zimbra.soap.ZimbraSoapContext; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import javax.mail.internet.MimeMessage; /** * RemoteCertbot class interacts with "Certbot" - an acme client for managing Let’s Encrypt @@ -79,9 +99,9 @@ public String createCommand(String remoteCommand, String email, String chain, * @param domain domain * @param command a command to be executed */ - public void supplyAsync(Domain domain, String command) { + public void supplyAsync(ZimbraSoapContext zsc, Map context, Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> notify(domain, message)); + .thenAccept(message -> notify(zsc, context, domain, message)); } /** @@ -99,7 +119,7 @@ private String execute(String command) { } } - private void notify(Domain domain, String message) { + private void notify(ZimbraSoapContext zsc, Map context, Domain domain, String message) { ZimbraLog.rmgmt.info( "Issuing LetsEncrypt cert command for domain " + domain.getName() + " was finished with the following result: " + message); @@ -109,9 +129,21 @@ private void notify(Domain domain, String message) { String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) .orElseThrow(() -> ServiceException.FAILURE( "no to", null)); - System.out.println(from + " " + to); + String subject = "Let's Encrypt Certificate generation request"; + + Mailbox mbox = getRequestedMailbox(zsc); + OperationContext oc = getOperationContext(zsc, context); + + MimeMessageData mimeData = new MimeMessageData(); + Element request = new Element.JSONElement(MailConstants.SEND_MSG_REQUEST); + Element msgElem = request.addElement(MailConstants.E_MSG).addAttribute(MailConstants.E_SUBJECT, subject); + msgElem.addUniqueElement(MailConstants.E_MIMEPART).addAttribute(MailConstants.A_CONTENT_TYPE, "text/plain").addAttribute(MailConstants.E_CONTENT, message); + msgElem.addElement(MailConstants.E_EMAIL).addAttribute(MailConstants.A_ADDRESS_TYPE, ToXML.EmailType.TO.toString()).addAttribute(MailConstants.A_ADDRESS, "zextras@demo.zextras.io"); + msgElem.addElement(MailConstants.E_EMAIL).addAttribute(MailConstants.A_ADDRESS_TYPE, EmailType.FROM.toString()).addAttribute(MailConstants.A_ADDRESS, from); - //notify admins + MimeMessage mimeMessage = ParseMimeMessage.parseMimeMsgSoap(zsc, oc, mbox, msgElem, null, mimeData); + MailSender mailSender = mbox.getMailSender(); + mailSender.sendMimeMessage(oc, mbox, false, mimeMessage, null, null, "r", null, false, null); } catch (Exception e) { ZimbraLog.rmgmt.info("Notification about LetsEncrypt certificate generation wasn't sent " diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 00c75f09a2d..0adf1e252fe 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -96,7 +96,7 @@ public Element handle(final Element request, final Map context) publicServiceHostname, virtualHostNames); - certbot.supplyAsync(domain, command); + certbot.supplyAsync(zsc, context, domain, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); diff --git a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java index 9f2e30835ab..a6ff59f86f2 100755 --- a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java +++ b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java @@ -93,7 +93,7 @@ public class ProxyConfGen { private static Provisioning mProv = null; private static boolean mGenConfPerVhn = false; private static boolean hasCustomTemplateLocationArg = false; - private static final String CERTBOT_WORKING_DIR = "/common/etc/letsencrypt/live/"; + private static final String CERTBOT_WORKING_DIR = "/common/certbot/etc/letsencrypt/live"; private static final String CERT = "/fullchain.pem"; private static final String KEY = "/privkey.pem"; From 78100ce34e34ada10dae191da890b26fbe14cff7 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 16 Mar 2023 11:12:36 +0100 Subject: [PATCH 04/39] feat: [CO-621] able to notify --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 78 +++++++++---------- .../zimbra/cs/service/admin/IssueCert.java | 2 +- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 8df4fbf5689..c2c909d8a9c 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,31 +1,19 @@ package com.zimbra.cs.rmgmt; -import static com.zimbra.soap.DocumentHandler.getOperationContext; -import static com.zimbra.soap.DocumentHandler.getRequestedMailbox; - import com.zimbra.common.service.ServiceException; -import com.zimbra.common.soap.Element; -import com.zimbra.common.soap.MailConstants; import com.zimbra.common.util.ZimbraLog; -import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Domain; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailSender; -import com.zimbra.cs.mailbox.Mailbox; -import com.zimbra.cs.mailbox.MailboxManager; -import com.zimbra.cs.mailbox.OperationContext; -import com.zimbra.cs.service.mail.ParseMimeMessage; -import com.zimbra.cs.service.mail.ParseMimeMessage.MimeMessageData; -import com.zimbra.cs.service.mail.SendMsg; -import com.zimbra.cs.service.mail.ToXML; -import com.zimbra.cs.service.mail.ToXML.EmailType; -import com.zimbra.soap.ZimbraSoapContext; +import com.zimbra.cs.mailclient.smtp.SmtpTransport; +import com.zimbra.cs.util.JMSession; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import javax.mail.Address; +import javax.mail.Message.RecipientType; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.URLName; import javax.mail.internet.MimeMessage; /** @@ -94,14 +82,14 @@ public String createCommand(String remoteCommand, String email, String chain, } /** - * Executes a command asynchronously and notifies about the command execution. + * Executes a command asynchronously and notifies domain recipients about the command execution. * * @param domain domain * @param command a command to be executed */ - public void supplyAsync(ZimbraSoapContext zsc, Map context, Domain domain, String command) { + public void supplyAsync(Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> notify(zsc, context, domain, message)); + .thenAccept(message -> notify(domain, message)); } /** @@ -119,7 +107,13 @@ private String execute(String command) { } } - private void notify(ZimbraSoapContext zsc, Map context, Domain domain, String message) { + private void addSubCommand(String delimiter, String... params) { + for (String param : params) { + this.stringBuilder.append(delimiter).append(param); + } + } + + private void notify(Domain domain, String message) { ZimbraLog.rmgmt.info( "Issuing LetsEncrypt cert command for domain " + domain.getName() + " was finished with the following result: " + message); @@ -127,23 +121,22 @@ private void notify(ZimbraSoapContext zsc, Map context, Domain d String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()) .orElseThrow(() -> ServiceException.FAILURE("no from", null)); String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) - .orElseThrow(() -> ServiceException.FAILURE( - "no to", null)); + .orElseThrow(() -> ServiceException.FAILURE("no to", null)); String subject = "Let's Encrypt Certificate generation request"; + String hostname = "127.78.0.7"; - Mailbox mbox = getRequestedMailbox(zsc); - OperationContext oc = getOperationContext(zsc, context); + Session session = JMSession.getSmtpSession(domain); + session.getProperties().setProperty("mail.smtp.host", hostname); + session.getProperties().setProperty("mail.smtp.from", "zextras@demo.zextras.io"); - MimeMessageData mimeData = new MimeMessageData(); - Element request = new Element.JSONElement(MailConstants.SEND_MSG_REQUEST); - Element msgElem = request.addElement(MailConstants.E_MSG).addAttribute(MailConstants.E_SUBJECT, subject); - msgElem.addUniqueElement(MailConstants.E_MIMEPART).addAttribute(MailConstants.A_CONTENT_TYPE, "text/plain").addAttribute(MailConstants.E_CONTENT, message); - msgElem.addElement(MailConstants.E_EMAIL).addAttribute(MailConstants.A_ADDRESS_TYPE, ToXML.EmailType.TO.toString()).addAttribute(MailConstants.A_ADDRESS, "zextras@demo.zextras.io"); - msgElem.addElement(MailConstants.E_EMAIL).addAttribute(MailConstants.A_ADDRESS_TYPE, EmailType.FROM.toString()).addAttribute(MailConstants.A_ADDRESS, from); + MimeMessage mm = new MimeMessage(session); + mm.setText(message); + mm.setRecipients(RecipientType.TO, "zextras@demo.zextras.io"); + mm.setSubject(subject); + mm.setFrom(); + mm.saveChanges(); - MimeMessage mimeMessage = ParseMimeMessage.parseMimeMsgSoap(zsc, oc, mbox, msgElem, null, mimeData); - MailSender mailSender = mbox.getMailSender(); - mailSender.sendMimeMessage(oc, mbox, false, mimeMessage, null, null, "r", null, false, null); + sendMessage(session, mm); } catch (Exception e) { ZimbraLog.rmgmt.info("Notification about LetsEncrypt certificate generation wasn't sent " @@ -151,9 +144,16 @@ private void notify(ZimbraSoapContext zsc, Map context, Domain d } } - private void addSubCommand(String delimiter, String... params) { - for (String param : params) { - this.stringBuilder.append(delimiter).append(param); + private void sendMessage(Session mSession, MimeMessage mm) throws MessagingException { + URLName urlName = new URLName("smtp", null, -1, null, null, null); + SmtpTransport transport = new SmtpTransport(mSession, urlName); + Address[] rcptAddresses = mm.getAllRecipients(); + + try { + transport.connect(); + transport.sendMessage(mm, rcptAddresses); + } finally { + transport.close(); } } } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 0adf1e252fe..00c75f09a2d 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -96,7 +96,7 @@ public Element handle(final Element request, final Map context) publicServiceHostname, virtualHostNames); - certbot.supplyAsync(zsc, context, domain, command); + certbot.supplyAsync(domain, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); From 58f2a2cc3d1c649aa3c2f6228e64229eb5aa6ae4 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Fri, 17 Mar 2023 12:47:59 +0100 Subject: [PATCH 05/39] feat: [CO-621] notify domain recipients using MailSender --- .../com/zimbra/cs/mailbox/MailSender.java | 63 ++++++++++++++++++- .../java/com/zimbra/cs/mailbox/Mailbox.java | 18 ++++++ .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 46 ++++++-------- .../zimbra/cs/service/admin/IssueCert.java | 4 +- .../java/com/zimbra/cs/session/Session.java | 1 - 5 files changed, 101 insertions(+), 31 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index 85e079e0fde..b9602a1f2a3 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -5,6 +5,7 @@ package com.zimbra.cs.mailbox; +import com.zimbra.cs.mailclient.smtp.SmtpTransport; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -25,9 +26,11 @@ import javax.mail.Address; import javax.mail.MessagingException; +import javax.mail.NoSuchProviderException; import javax.mail.SendFailedException; import javax.mail.Session; import javax.mail.Transport; +import javax.mail.URLName; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; @@ -246,6 +249,27 @@ public MailSender setSession(Account account) throws ServiceException { return this; } + /** + * Sets an alternate JavaMail Session and SMTP hosts + * that will be used to send the message based on the domain. + * The default behavior is to use SMTP settings from + * the Session on the {@link MimeMessage}. + * @throws ServiceException if not able to get SMTP session for the domain + * + * @author Yuliya Aheeva + * @since 23.4.0 + */ + public MailSender setSession(Domain domain) throws ServiceException { + try { + mSession = JMSession.getSmtpSession(domain); + } catch (MessagingException e) { + throw ServiceException.FAILURE("Unable to get SMTP session for " + domain, e); + } + mSmtpHosts.clear(); + mSmtpHosts.addAll(JMSession.getSmtpHosts(domain)); + return this; + } + /** * Sets JavaMail Session using the SMTP settings associated with the data source. * @throws ServiceException @@ -282,6 +306,16 @@ public MailSender setEnvelopeFrom(String address) { return this; } + /** + * Returns the current session. + * @return mSession + * @author Yuliya Aheeva + * @since 23.4.0 + */ + public Session getCurrentSession() { + return this.mSession; + } + public static int getSentFolderId(Mailbox mbox, Identity identity) throws ServiceException { int folderId = Mailbox.ID_FOLDER_SENT; String sentFolder = identity.getAttr(Provisioning.A_zimbraPrefSentMailFolder, null); @@ -394,6 +428,16 @@ public static enum ReplyForwardType { FORWARD // Forwarding another message } + /** + * Sets default member variables and sends the message based on provided mailbox settings. + * @author Yuliya Aheeva + * @since 23.4.0 + */ + public ItemId sendMimeMessage(Mailbox mbox, MimeMessage mm) throws ServiceException { + OperationContext octxt = mbox.getOperationContext(); + return sendMimeMessage(octxt, mbox, mm, null, null, null, null, false, null); + } + /** * Sets member variables and sends the message. */ @@ -1231,7 +1275,9 @@ private void sendMessageToHost(String hostname, MimeMessage mm, Address[] rcptAd } ZimbraLog.smtp.debug("Sending message %s to SMTP host %s with properties: %s", mm.getMessageID(), hostname, mSession.getProperties()); - Transport transport = mSession.getTransport("smtp"); + + Transport transport = getTransport(); + try { transport.connect(); transport.sendMessage(mm, rcptAddresses); @@ -1240,6 +1286,21 @@ private void sendMessageToHost(String hostname, MimeMessage mm, Address[] rcptAd } } + /** + * Initialize a new SMTP transport if not able to get one from the mSession. + * @return SMTP transport + * @author Yuliya Aheeva + * @since 23.4.0 + */ + private Transport getTransport() { + try { + return mSession.getTransport("smtp"); + } catch (NoSuchProviderException e) { + URLName urlName = new URLName("smtp", null, -1, null, null, null); + return new SmtpTransport(mSession, urlName); + } + } + private void checkMTAConnectionToHost(String hostname) throws MessagingException { mSession.getProperties().setProperty("mail.smtp.host", hostname); if (mEnvelopeFrom != null) { diff --git a/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java b/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java index 939148d64d5..f68992c2281 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java @@ -973,6 +973,24 @@ public MailSender getMailSender() throws ServiceException { return sender; } + /** + * Returns a {@link MailSender} object based on specific domain properties + * that can be used to send mails. + * + * @param domain a domain to get needed properties + * @return {@link MailSender} object + * @throws ServiceException if unable to get SMTP session for the current domain + * @author Yuliya Aheeva + * @since 23.4.0 + */ + public MailSender getMailSender(Domain domain) throws ServiceException { + MailSender sender = new MailSender(); + sender.setTrackBadHosts(true); + sender.setSession(domain); + + return sender; + } + /** * Returns the list of all Mailbox listeners of a given type. Returns all listeners * when the passed-in type is null. diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index c2c909d8a9c..58a0d262f3c 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -3,17 +3,13 @@ import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Domain; -import com.zimbra.cs.mailclient.smtp.SmtpTransport; -import com.zimbra.cs.util.JMSession; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import javax.mail.Address; import javax.mail.Message.RecipientType; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.URLName; import javax.mail.internet.MimeMessage; /** @@ -86,10 +82,12 @@ public String createCommand(String remoteCommand, String email, String chain, * * @param domain domain * @param command a command to be executed + * @author Yuliya Aheeva + * @since 23.4.0 */ - public void supplyAsync(Domain domain, String command) { + public void supplyAsync(Mailbox mbox, Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> notify(domain, message)); + .thenAccept(message -> notify(mbox, domain, message)); } /** @@ -113,7 +111,15 @@ private void addSubCommand(String delimiter, String... params) { } } - private void notify(Domain domain, String message) { + /** + * Notifies domain recipients about certificate generation request + * @param mbox + * @param domain + * @param message + * @author Yuliya Aheeva + * @since 23.4.0 + */ + private void notify(Mailbox mbox, Domain domain, String message) { ZimbraLog.rmgmt.info( "Issuing LetsEncrypt cert command for domain " + domain.getName() + " was finished with the following result: " + message); @@ -123,37 +129,21 @@ private void notify(Domain domain, String message) { String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) .orElseThrow(() -> ServiceException.FAILURE("no to", null)); String subject = "Let's Encrypt Certificate generation request"; - String hostname = "127.78.0.7"; - Session session = JMSession.getSmtpSession(domain); - session.getProperties().setProperty("mail.smtp.host", hostname); - session.getProperties().setProperty("mail.smtp.from", "zextras@demo.zextras.io"); + MailSender sender = mbox.getMailSender(domain); - MimeMessage mm = new MimeMessage(session); + MimeMessage mm = new MimeMessage(sender.getCurrentSession()); mm.setText(message); mm.setRecipients(RecipientType.TO, "zextras@demo.zextras.io"); mm.setSubject(subject); mm.setFrom(); mm.saveChanges(); - sendMessage(session, mm); + sender.sendMimeMessage(mbox, mm); } catch (Exception e) { ZimbraLog.rmgmt.info("Notification about LetsEncrypt certificate generation wasn't sent " + "for the domain " + domain.getName() + ". Sending failure: " + e.getMessage()); } } - - private void sendMessage(Session mSession, MimeMessage mm) throws MessagingException { - URLName urlName = new URLName("smtp", null, -1, null, null, null); - SmtpTransport transport = new SmtpTransport(mSession, urlName); - Address[] rcptAddresses = mm.getAllRecipients(); - - try { - transport.connect(); - transport.sendMessage(mm, rcptAddresses); - } finally { - transport.close(); - } - } } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 00c75f09a2d..d89866d4549 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -9,6 +9,7 @@ import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.account.Server; import com.zimbra.cs.account.accesscontrol.generated.AdminRights; +import com.zimbra.cs.mailbox.Mailbox; import com.zimbra.cs.rmgmt.RemoteCertbot; import com.zimbra.cs.rmgmt.RemoteCommands; import com.zimbra.cs.rmgmt.RemoteManager; @@ -96,7 +97,8 @@ public Element handle(final Element request, final Map context) publicServiceHostname, virtualHostNames); - certbot.supplyAsync(domain, command); + Mailbox mbox = getRequestedMailbox(zsc); + certbot.supplyAsync(mbox, domain, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); diff --git a/store/src/main/java/com/zimbra/cs/session/Session.java b/store/src/main/java/com/zimbra/cs/session/Session.java index 03b6b212493..16600265b88 100644 --- a/store/src/main/java/com/zimbra/cs/session/Session.java +++ b/store/src/main/java/com/zimbra/cs/session/Session.java @@ -15,7 +15,6 @@ import com.zimbra.common.service.ServiceException; import com.zimbra.common.soap.Element; import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.AuthToken; import com.zimbra.cs.mailbox.Mailbox; import com.zimbra.cs.mailbox.MailboxManager; From b94bd8ed9b3f05a6a1d7e4b7b0b0b2584dcbbbc1 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Fri, 17 Mar 2023 14:50:45 +0100 Subject: [PATCH 06/39] feat: [CO-621] add convert method --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 58a0d262f3c..76eae015a0d 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -9,7 +9,10 @@ import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import javax.mail.Address; import javax.mail.Message.RecipientType; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; /** @@ -43,18 +46,19 @@ public RemoteCertbot(RemoteManager remoteManager) { } /** - * Creates a command to be executed by the Certbot acme client. - * E.g. certbot certonly --agree-tos --email admin@test.com -n --webroot -w /opt/zextras - * --cert-name demo.zextras.io -d acme.demo.zextras.io -d webmail-acme.demo.zextras.io + * Creates a command to be executed by the Certbot acme client. E.g. certbot certonly --agree-tos + * --email admin@test.com -n --webroot -w /opt/zextras --cert-name demo.zextras.io -d + * acme.demo.zextras.io -d webmail-acme.demo.zextras.io * - * @param remoteCommand {@link com.zimbra.cs.rmgmt.RemoteCommands} - * @param email domain admin email who tries to execute a command (should be agreed to the - * ACME server's Subscriber Agreement) - * @param chain long (default) or short (should be specified by domain admin in {@link - * com.zimbra.soap.admin.message.IssueCertRequest} request with the key word "short") - * @param domainName a value of domain attribute zimbraDomainName + * @param remoteCommand {@link com.zimbra.cs.rmgmt.RemoteCommands} + * @param email domain admin email who tries to execute a command (should be + * agreed to the ACME server's Subscriber Agreement) + * @param chain long (default) or short (should be specified by domain admin in + * {@link com.zimbra.soap.admin.message.IssueCertRequest} request + * with the key word "short") + * @param domainName a value of domain attribute zimbraDomainName * @param publicServiceHostName a value of domain attribute zimbraPublicServiceHostname - * @param virtualHosts a value/ values of domain attribute zimbraVirtualHostname + * @param virtualHosts a value/ values of domain attribute zimbraVirtualHostname * @return created command */ public String createCommand(String remoteCommand, String email, String chain, @@ -80,7 +84,7 @@ public String createCommand(String remoteCommand, String email, String chain, /** * Executes a command asynchronously and notifies domain recipients about the command execution. * - * @param domain domain + * @param domain domain * @param command a command to be executed * @author Yuliya Aheeva * @since 23.4.0 @@ -92,9 +96,10 @@ public void supplyAsync(Mailbox mbox, Domain domain, String command) { /** * Executes a command using {@link com.zimbra.cs.rmgmt.RemoteManager}. + * * @param command a command to be executed - * @return a sting message of successful remote execution or detailed exception message - * in case of failure. + * @return a sting message of successful remote execution or detailed exception message in case of + * failure. */ private String execute(String command) { try { @@ -105,14 +110,9 @@ private String execute(String command) { } } - private void addSubCommand(String delimiter, String... params) { - for (String param : params) { - this.stringBuilder.append(delimiter).append(param); - } - } - /** * Notifies domain recipients about certificate generation request + * * @param mbox * @param domain * @param message @@ -123,20 +123,21 @@ private void notify(Mailbox mbox, Domain domain, String message) { ZimbraLog.rmgmt.info( "Issuing LetsEncrypt cert command for domain " + domain.getName() + " was finished with the following result: " + message); + try { String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()) .orElseThrow(() -> ServiceException.FAILURE("no from", null)); String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) .orElseThrow(() -> ServiceException.FAILURE("no to", null)); - String subject = "Let's Encrypt Certificate generation request"; + String subject = "Let's Encrypt Certificate generation result"; MailSender sender = mbox.getMailSender(domain); MimeMessage mm = new MimeMessage(sender.getCurrentSession()); - mm.setText(message); - mm.setRecipients(RecipientType.TO, "zextras@demo.zextras.io"); + mm.addFrom(convert(from)); + mm.addRecipients(RecipientType.TO, convert(to)); mm.setSubject(subject); - mm.setFrom(); + mm.setText(message); mm.saveChanges(); sender.sendMimeMessage(mbox, mm); @@ -146,4 +147,15 @@ private void notify(Mailbox mbox, Domain domain, String message) { + "for the domain " + domain.getName() + ". Sending failure: " + e.getMessage()); } } + + private void addSubCommand(String delimiter, String... params) { + for (String param : params) { + this.stringBuilder.append(delimiter).append(param); + } + } + + private Address[] convert(String ... addresses) throws AddressException { + String addressList = String.join(", ", addresses); + return InternetAddress.parse(addressList); + } } From 30dd98d445e8f038f4d5d2d188caee9a71a7e6a2 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Sat, 18 Mar 2023 14:21:30 +0100 Subject: [PATCH 07/39] feat: [CO-621] setEnvelopeFrom --- .../com/zimbra/cs/mailbox/MailSender.java | 10 -- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 92 +++++++++++++------ .../zimbra/cs/service/admin/IssueCert.java | 1 + 3 files changed, 63 insertions(+), 40 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index b9602a1f2a3..5d1a701b815 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -428,16 +428,6 @@ public static enum ReplyForwardType { FORWARD // Forwarding another message } - /** - * Sets default member variables and sends the message based on provided mailbox settings. - * @author Yuliya Aheeva - * @since 23.4.0 - */ - public ItemId sendMimeMessage(Mailbox mbox, MimeMessage mm) throws ServiceException { - OperationContext octxt = mbox.getOperationContext(); - return sendMimeMessage(octxt, mbox, mm, null, null, null, null, false, null); - } - /** * Sets member variables and sends the message. */ diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 76eae015a0d..d07095731a2 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,10 +1,14 @@ package com.zimbra.cs.rmgmt; +import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.mailbox.MailSender; import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.OperationContext; import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.Optional; @@ -46,23 +50,29 @@ public RemoteCertbot(RemoteManager remoteManager) { } /** - * Creates a command to be executed by the Certbot acme client. E.g. certbot certonly --agree-tos - * --email admin@test.com -n --webroot -w /opt/zextras --cert-name demo.zextras.io -d - * acme.demo.zextras.io -d webmail-acme.demo.zextras.io + * Creates a command to be executed by the Certbot acme client. * - * @param remoteCommand {@link com.zimbra.cs.rmgmt.RemoteCommands} - * @param email domain admin email who tries to execute a command (should be - * agreed to the ACME server's Subscriber Agreement) - * @param chain long (default) or short (should be specified by domain admin in - * {@link com.zimbra.soap.admin.message.IssueCertRequest} request - * with the key word "short") - * @param domainName a value of domain attribute zimbraDomainName + * E.g. certbot certonly --agree-tos --email admin@test.com -n + * --webroot -w /opt/zextras --cert-name demo.zextras.io + * -d acme.demo.zextras.io -d webmail-acme.demo.zextras.io + * + * @param remoteCommand {@link com.zimbra.cs.rmgmt.RemoteCommands} + * @param email domain admin email who tries to execute a command (should be agreed to the ACME + * server's Subscriber Agreement) + * @param chain long (default) or short (should be specified by domain admin in {@link + * com.zimbra.soap.admin.message.IssueCertRequest} request with the key word "short") + * @param domainName a value of domain attribute zimbraDomainName * @param publicServiceHostName a value of domain attribute zimbraPublicServiceHostname - * @param virtualHosts a value/ values of domain attribute zimbraVirtualHostname + * @param virtualHosts a value/ values of domain attribute zimbraVirtualHostname * @return created command */ - public String createCommand(String remoteCommand, String email, String chain, - String domainName, String publicServiceHostName, String[] virtualHosts) { + public String createCommand( + String remoteCommand, + String email, + String chain, + String domainName, + String publicServiceHostName, + String[] virtualHosts) { this.stringBuilder = new StringBuilder(); @@ -84,7 +94,7 @@ public String createCommand(String remoteCommand, String email, String chain, /** * Executes a command asynchronously and notifies domain recipients about the command execution. * - * @param domain domain + * @param domain domain * @param command a command to be executed * @author Yuliya Aheeva * @since 23.4.0 @@ -99,7 +109,7 @@ public void supplyAsync(Mailbox mbox, Domain domain, String command) { * * @param command a command to be executed * @return a sting message of successful remote execution or detailed exception message in case of - * failure. + * failure. */ private String execute(String command) { try { @@ -111,27 +121,39 @@ private String execute(String command) { } /** - * Notifies domain recipients about certificate generation request + * Notifies domain recipients about certificate generation result. * - * @param mbox - * @param domain - * @param message + * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed for {@link + * com.zimbra.cs.mailbox.MailSender} in order to send message + * @param domain object of {@link com.zimbra.cs.account.Domain} needed to get {@link + * com.zimbra.common.account.ZAttrProvisioning} attributes A_carbonioNotificationRecipients + * and A_carbonioNotificationFrom + * @param message a message returned by Certbot acme client * @author Yuliya Aheeva * @since 23.4.0 */ private void notify(Mailbox mbox, Domain domain, String message) { ZimbraLog.rmgmt.info( - "Issuing LetsEncrypt cert command for domain " + domain.getName() - + " was finished with the following result: " + message); + "Issuing LetsEncrypt cert command for domain " + + domain.getName() + + " was finished with the following result: " + + message); try { - String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()) - .orElseThrow(() -> ServiceException.FAILURE("no from", null)); - String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) - .orElseThrow(() -> ServiceException.FAILURE("no to", null)); - String subject = "Let's Encrypt Certificate generation result"; + String from = + Optional.ofNullable(domain.getCarbonioNotificationFrom()) + .orElseThrow(() -> ServiceException.FAILURE("no from", null)); + String[] to = + Optional.ofNullable(domain.getCarbonioNotificationRecipients()) + .orElseThrow(() -> ServiceException.FAILURE("no to", null)); + String subject = "Let's Encrypt Certificate generation result for " + domain.getName(); + + Provisioning prov = Provisioning.getInstance(); + Account account = prov.get(AccountBy.name, from); + OperationContext operationContext = new OperationContext(account); MailSender sender = mbox.getMailSender(domain); + sender.setEnvelopeFrom(from); MimeMessage mm = new MimeMessage(sender.getCurrentSession()); mm.addFrom(convert(from)); @@ -140,11 +162,21 @@ private void notify(Mailbox mbox, Domain domain, String message) { mm.setText(message); mm.saveChanges(); - sender.sendMimeMessage(mbox, mm); + sender.sendMimeMessage(operationContext, mbox, mm); + + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation were sent " + + "for the " + + domain.getName() + + " recipients."); } catch (Exception e) { - ZimbraLog.rmgmt.info("Notification about LetsEncrypt certificate generation wasn't sent " - + "for the domain " + domain.getName() + ". Sending failure: " + e.getMessage()); + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation weren't sent " + + "for the " + + domain.getName() + + " recipients. Sending failure: " + + e.getMessage()); } } @@ -154,7 +186,7 @@ private void addSubCommand(String delimiter, String... params) { } } - private Address[] convert(String ... addresses) throws AddressException { + private Address[] convert(String... addresses) throws AddressException { String addressList = String.join(", ", addresses); return InternetAddress.parse(addressList); } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index d89866d4549..cc985163aff 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -98,6 +98,7 @@ public Element handle(final Element request, final Map context) virtualHostNames); Mailbox mbox = getRequestedMailbox(zsc); + certbot.supplyAsync(mbox, domain, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); From 9db39664627c1bdd6b01e9d8213bcadea933b25d Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Sat, 18 Mar 2023 14:35:08 +0100 Subject: [PATCH 08/39] feat: [CO-621] added failure messages --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index d07095731a2..6d1f595852c 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -52,9 +52,8 @@ public RemoteCertbot(RemoteManager remoteManager) { /** * Creates a command to be executed by the Certbot acme client. * - * E.g. certbot certonly --agree-tos --email admin@test.com -n - * --webroot -w /opt/zextras --cert-name demo.zextras.io - * -d acme.demo.zextras.io -d webmail-acme.demo.zextras.io + *

E.g. certbot certonly --agree-tos --email admin@test.com -n --webroot -w /opt/zextras + * --cert-name demo.zextras.io -d acme.demo.zextras.io -d webmail-acme.demo.zextras.io * * @param remoteCommand {@link com.zimbra.cs.rmgmt.RemoteCommands} * @param email domain admin email who tries to execute a command (should be agreed to the ACME @@ -133,20 +132,20 @@ private String execute(String command) { * @since 23.4.0 */ private void notify(Mailbox mbox, Domain domain, String message) { - ZimbraLog.rmgmt.info( - "Issuing LetsEncrypt cert command for domain " - + domain.getName() - + " was finished with the following result: " - + message); + String domainName = domain.getName(); + + ZimbraLog.rmgmt.info("Issuing LetsEncrypt cert command for domain " + domainName + + " was finished with the following result: " + message); try { - String from = - Optional.ofNullable(domain.getCarbonioNotificationFrom()) - .orElseThrow(() -> ServiceException.FAILURE("no from", null)); - String[] to = - Optional.ofNullable(domain.getCarbonioNotificationRecipients()) - .orElseThrow(() -> ServiceException.FAILURE("no to", null)); - String subject = "Let's Encrypt Certificate generation result for " + domain.getName(); + String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElseThrow( + () -> ServiceException.FAILURE("CarbonioNotificationFrom attribute for the domain " + + domainName + " is not present.", null)); + String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElseThrow( + () -> ServiceException.FAILURE("CarbonioNotificationRecipients attribute for the domain " + + domainName + " is not present.", null)); + + String subject = "Let's Encrypt Certificate generation result for " + domainName; Provisioning prov = Provisioning.getInstance(); Account account = prov.get(AccountBy.name, from); @@ -164,19 +163,12 @@ private void notify(Mailbox mbox, Domain domain, String message) { sender.sendMimeMessage(operationContext, mbox, mm); - ZimbraLog.rmgmt.info( - "Notifications about LetsEncrypt certificate generation were sent " - + "for the " - + domain.getName() - + " recipients."); + ZimbraLog.rmgmt.info("Notifications about LetsEncrypt certificate generation were sent " + + "for the " + domainName + " recipients."); } catch (Exception e) { - ZimbraLog.rmgmt.info( - "Notifications about LetsEncrypt certificate generation weren't sent " - + "for the " - + domain.getName() - + " recipients. Sending failure: " - + e.getMessage()); + ZimbraLog.rmgmt.info("Notifications about LetsEncrypt certificate generation weren't sent " + + "for the " + domainName + " recipients. Sending failure: " + e.getMessage()); } } From d61909549442ebc2815ca87cce46701ed70ed7ba Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Sat, 18 Mar 2023 14:38:57 +0100 Subject: [PATCH 09/39] feat: [CO-621] added / to certbot working dir --- .../main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java index a6ff59f86f2..2100ee19fdb 100755 --- a/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java +++ b/store/src/main/java/com/zimbra/cs/util/proxyconfgen/ProxyConfGen.java @@ -93,7 +93,7 @@ public class ProxyConfGen { private static Provisioning mProv = null; private static boolean mGenConfPerVhn = false; private static boolean hasCustomTemplateLocationArg = false; - private static final String CERTBOT_WORKING_DIR = "/common/certbot/etc/letsencrypt/live"; + private static final String CERTBOT_WORKING_DIR = "/common/certbot/etc/letsencrypt/live/"; private static final String CERT = "/fullchain.pem"; private static final String KEY = "/privkey.pem"; From 0fd4c90cdab39c06ed1db0077a1a2a572064d4dc Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Sat, 18 Mar 2023 14:49:21 +0100 Subject: [PATCH 10/39] feat: [CO-621] fix javadoc --- .../java/com/zimbra/cs/rmgmt/RemoteCertbot.java | 13 ++++--------- .../java/com/zimbra/cs/service/admin/IssueCert.java | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 6d1f595852c..e8a39a3bef6 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -65,13 +65,8 @@ public RemoteCertbot(RemoteManager remoteManager) { * @param virtualHosts a value/ values of domain attribute zimbraVirtualHostname * @return created command */ - public String createCommand( - String remoteCommand, - String email, - String chain, - String domainName, - String publicServiceHostName, - String[] virtualHosts) { + public String createCommand(String remoteCommand, String email, String chain, String domainName, + String publicServiceHostName, String[] virtualHosts) { this.stringBuilder = new StringBuilder(); @@ -93,8 +88,8 @@ public String createCommand( /** * Executes a command asynchronously and notifies domain recipients about the command execution. * - * @param domain domain - * @param command a command to be executed + * @param domain {@link com.zimbra.cs.account.Domain} + * @param command a Certbot command to be executed remotely * @author Yuliya Aheeva * @since 23.4.0 */ diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index cc985163aff..34f862d905a 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -110,7 +110,7 @@ public Element handle(final Element request, final Map context) responseMessageElement.setText( "Your request for the certificate generation has been " - + "taken and will be processed. Notification recipients would be notified." + + "taken and will be processed. Domain notification recipients would be notified." ); return response; From e7933e39e5d3ed1a82fd8d32f56dd5defc62dd3b Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 27 Mar 2023 11:50:55 +0200 Subject: [PATCH 11/39] feat: [CO-621] add CertificateNotificationManager and tests --- .../com/zimbra/cs/mailbox/MailSender.java | 14 + .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 81 +----- .../com/zimbra/cs/rmgmt/RemoteManager.java | 2 +- .../admin/CertificateNotificationManager.java | 251 ++++++++++++++++++ .../zimbra/cs/service/admin/IssueCert.java | 5 +- .../CertificateNotificationManagerTest.java | 131 +++++++++ .../zimbra/cs/rmgmt/RemoteCertbotTest.java | 1 + 7 files changed, 407 insertions(+), 78 deletions(-) create mode 100644 store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java create mode 100644 store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index 5d1a701b815..9845a8d54f9 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -510,12 +510,16 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, Boolean save return sendMimeMessage(octxt, mbox, mm); } + /** + * Sets member variables and sends the message. + */ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, Boolean saveToSent, MimeMessage mm, Collection uploads, ItemId origMsgId, String replyType, Identity identity, boolean replyToSender) throws ServiceException { return sendMimeMessage(octxt, mbox, saveToSent, mm, uploads, origMsgId, replyType, identity, replyToSender, null); } + /** * Sends a message. */ @@ -805,6 +809,16 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage } } + /** + * Sends a list of messages. + */ + public void sendMimeMessageList(Mailbox mbox, List mimeMessageList) + throws ServiceException { + for (MimeMessage mm: mimeMessageList) { + sendMimeMessage(null, mbox, mm); + } + } + private boolean isDataSourceSender() { return mIsDataSourceSender; } diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index e8a39a3bef6..09b4014132d 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,23 +1,12 @@ package com.zimbra.cs.rmgmt; -import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; -import com.zimbra.common.util.ZimbraLog; -import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Domain; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailSender; import com.zimbra.cs.mailbox.Mailbox; -import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.service.admin.CertificateNotificationManager; import java.nio.charset.StandardCharsets; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.CompletableFuture; -import javax.mail.Address; -import javax.mail.Message.RecipientType; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; /** * RemoteCertbot class interacts with "Certbot" - an acme client for managing Let’s Encrypt @@ -86,16 +75,18 @@ public String createCommand(String remoteCommand, String email, String chain, St } /** - * Executes a command asynchronously and notifies domain recipients about the command execution. + * Executes a command asynchronously and notifies global and domain recipients about + * the command execution using {@link com.zimbra.cs.service.admin.CertificateNotificationManager}. * * @param domain {@link com.zimbra.cs.account.Domain} * @param command a Certbot command to be executed remotely * @author Yuliya Aheeva - * @since 23.4.0 + * @since 23.5.0 */ public void supplyAsync(Mailbox mbox, Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> notify(mbox, domain, message)); + .thenAccept(certbotMessage -> CertificateNotificationManager + .notify(mbox, domain, certbotMessage)); } /** @@ -105,7 +96,7 @@ public void supplyAsync(Mailbox mbox, Domain domain, String command) { * @return a sting message of successful remote execution or detailed exception message in case of * failure. */ - private String execute(String command) { + public String execute(String command) { try { RemoteResult remoteResult = remoteManager.execute(command); return new String(remoteResult.getMStdout(), StandardCharsets.UTF_8); @@ -114,67 +105,9 @@ private String execute(String command) { } } - /** - * Notifies domain recipients about certificate generation result. - * - * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed for {@link - * com.zimbra.cs.mailbox.MailSender} in order to send message - * @param domain object of {@link com.zimbra.cs.account.Domain} needed to get {@link - * com.zimbra.common.account.ZAttrProvisioning} attributes A_carbonioNotificationRecipients - * and A_carbonioNotificationFrom - * @param message a message returned by Certbot acme client - * @author Yuliya Aheeva - * @since 23.4.0 - */ - private void notify(Mailbox mbox, Domain domain, String message) { - String domainName = domain.getName(); - - ZimbraLog.rmgmt.info("Issuing LetsEncrypt cert command for domain " + domainName - + " was finished with the following result: " + message); - - try { - String from = Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElseThrow( - () -> ServiceException.FAILURE("CarbonioNotificationFrom attribute for the domain " - + domainName + " is not present.", null)); - String[] to = Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElseThrow( - () -> ServiceException.FAILURE("CarbonioNotificationRecipients attribute for the domain " - + domainName + " is not present.", null)); - - String subject = "Let's Encrypt Certificate generation result for " + domainName; - - Provisioning prov = Provisioning.getInstance(); - Account account = prov.get(AccountBy.name, from); - OperationContext operationContext = new OperationContext(account); - - MailSender sender = mbox.getMailSender(domain); - sender.setEnvelopeFrom(from); - - MimeMessage mm = new MimeMessage(sender.getCurrentSession()); - mm.addFrom(convert(from)); - mm.addRecipients(RecipientType.TO, convert(to)); - mm.setSubject(subject); - mm.setText(message); - mm.saveChanges(); - - sender.sendMimeMessage(operationContext, mbox, mm); - - ZimbraLog.rmgmt.info("Notifications about LetsEncrypt certificate generation were sent " - + "for the " + domainName + " recipients."); - - } catch (Exception e) { - ZimbraLog.rmgmt.info("Notifications about LetsEncrypt certificate generation weren't sent " - + "for the " + domainName + " recipients. Sending failure: " + e.getMessage()); - } - } - private void addSubCommand(String delimiter, String... params) { for (String param : params) { this.stringBuilder.append(delimiter).append(param); } } - - private Address[] convert(String... addresses) throws AddressException { - String addressList = String.join(", ", addresses); - return InternetAddress.parse(addressList); - } } diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteManager.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteManager.java index ac8aaf96343..f3f42388ef1 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteManager.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteManager.java @@ -148,7 +148,7 @@ public synchronized RemoteResult execute(String command) throws ServiceException } } catch (Exception e) { throw ServiceException.FAILURE( - "exception executing command: " + command + " with " + this + " " + e); + "exception executing command " + command + " with " + this + " " + e); } return result; } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java new file mode 100644 index 00000000000..0716f7eca37 --- /dev/null +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -0,0 +1,251 @@ +package com.zimbra.cs.service.admin; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.util.ZimbraLog; +import com.zimbra.cs.account.Config; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.mail.Address; +import javax.mail.Message.RecipientType; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +/** + * @author Yuliya Aheeva + * @since 23.5.0 + */ +public class CertificateNotificationManager { + public static final String GLOBAL_FROM = "globalFrom"; + public static final String GLOBAL_TO = "globalTo"; + public static final String GLOBAL_MESSAGE = "globalMessage"; + + public static final String DOMAIN_FROM = "domainFrom"; + public static final String DOMAIN_TO = "domainTo"; + public static final String DOMAIN_MESSAGE = "domainMessage"; + + public static final String DOMAIN_NAME = "domainName"; + public static final String SUBJECT_RESULT = "subjectResult"; + public static final String SUBJECT_TEMPLATE = " certification request - "; + + public static final String SYSTEM_FAILURE = "system failure"; + + public static final String CERTBOT_SUCCESS = "Certificate Authority success"; + public static final String CERTBOT_FAILURE = "Certificate Authority failure"; + + public static final String RESULT = "result"; + public static final String HEADER = "The certification result is: "; + public static final String SUCCESS_RESULT = "SUCCESS\n"; + public static final String FAILURE_RESULT = "FAILURE\n"; + + public static final String FAIL = "fail"; + public static final String FAILURE_DOMAIN_NOTIFICATION_TEMPLATE = + "Hint: Common use cases that cause this behavior are:\n" + + "Your domain public service hostname or virtual hostnames are wrong. Make sure that " + + "your domain public service hostname and virtual hostnames are entered and saved " + + "correctly.\n" + + "Your DNS A/AAAA record is wrong. Make sure the DNS A/AAAA record(s) for the " + + "domain is(are) entered and saved correctly.\n" + + "Your IP address is wrong or private. Make sure the DNS A/AAAA record(s) contain(s) " + + "the right public IP address(es).\n" + + "Your DNS record isn’t propagated yet. Go to https://dnsmap.io to check if it’s " + + "propagated.\n"; + + public static final String RECEIVED = "received certificate"; + public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = + "The certificate was successfully received.\n" + + "Please NOTE that the Certificate and Key will be available after the proxy reload.\n" + + "You’ll be able to download them from the Certificate section in the admin interface.\n" + + "\n" + + "The files will be automatically updated when the certificate renews.\n"; + + /** + * Notifies domain recipients about certificate generation result. + * + * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed for {@link + * com.zimbra.cs.mailbox.MailSender} in order to send message + * @param domain object of {@link com.zimbra.cs.account.Domain} needed to get {@link + * com.zimbra.common.account.ZAttrProvisioning} attributes A_carbonioNotificationRecipients + * and A_carbonioNotificationFrom + * @param message a message returned by Certbot acme client + */ + public static void notify(Mailbox mbox, Domain domain, String outputMessage) { + String domainName = domain.getName(); + + ZimbraLog.rmgmt.info( + "Issuing LetsEncrypt cert command for domain " + + domainName + + " was finished with the following result: " + + outputMessage); + + try { + Provisioning provisioning = Provisioning.getInstance(); + Config config = provisioning.getConfig(); + + String globalFrom = Optional.ofNullable(config.getCarbonioNotificationFrom()) + .orElseThrow(() -> ServiceException.FAILURE( + "Global CarbonioNotificationFrom attribute is not present.", null)); + String[] globalTo = Optional.ofNullable(config.getCarbonioNotificationRecipients()) + .orElseThrow(() -> ServiceException.FAILURE( + "Global CarbonioNotificationRecipients attribute is not present.", null)); + + String domainFrom = Optional.of(domain.getCarbonioNotificationFrom()).orElse(globalFrom); + String[] domainTo = Optional.of(domain.getCarbonioNotificationRecipients()).orElse(globalTo); + + Map notificationMap = createIssueCertNotificationMap(outputMessage); + notificationMap.put(DOMAIN_NAME, domainName); + + notificationMap.put(GLOBAL_FROM, globalFrom); + notificationMap.put(GLOBAL_TO, globalTo); + notificationMap.put(DOMAIN_FROM, domainFrom); + notificationMap.put(DOMAIN_TO, domainTo); + + MailSender sender = mbox.getMailSender(domain); + List mimeMessageList = + createMimeMessageList(sender.getCurrentSession(), notificationMap); + + sender.sendMimeMessageList(mbox, mimeMessageList); + + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation were sent " + + "for the global and domain " + + domainName + + " recipients."); + + } catch (Exception e) { + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation weren't sent " + + "for the global and domain " + + domainName + + " recipients.\n" + + "Sending failure: " + + e.getMessage()); + } + } + + /** + * Creates a map based on Remote Manager and Certbot output which would be used to create a + * MimeMessage. + * + * @param outputMessage output from RemoteManager/Certbot + * @return map + */ + public static Map createIssueCertNotificationMap(String outputMessage) { + Map notificationMap = new HashMap<>(); + + // message for global admin contains all output + notificationMap.put(GLOBAL_MESSAGE, outputMessage); + + // check if a system failure + boolean isSystemFailure = outputMessage.contains(SYSTEM_FAILURE); + if (isSystemFailure) { + notificationMap.put(SUBJECT_RESULT, SYSTEM_FAILURE); + return notificationMap; + } + + // check if a certbot failure + String startParsing = "Simulating"; + String endParsing = "ENDCMD"; + int startIndex = outputMessage.indexOf(startParsing); + int endIndex = outputMessage.lastIndexOf(endParsing); + String substringResult = outputMessage.substring(startIndex, endIndex); + + boolean isFailure = substringResult.contains(FAIL); + + if (isFailure) { + notificationMap.put(SUBJECT_RESULT, CERTBOT_FAILURE); + + String domainMessage = + String.join("", HEADER, FAILURE_RESULT, FAILURE_DOMAIN_NOTIFICATION_TEMPLATE); + notificationMap.put(DOMAIN_MESSAGE, domainMessage); + return notificationMap; + } + + // check if a certificate received + boolean isReceived = substringResult.contains(RECEIVED); + if (isReceived) { + String expire = "\n"; + + String regex = "\\d{4}-\\d{2}-\\d{2}"; + Matcher matcher = Pattern.compile(regex).matcher(substringResult); + if (matcher.find()) { + String expiresTemplate = "This certificate expires on "; + expire = expire + expiresTemplate + matcher.group() + "."; + } + + String domainMessage = + String.join("", HEADER, SUCCESS_RESULT, SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE, expire); + + notificationMap.put(SUBJECT_RESULT, CERTBOT_SUCCESS); + notificationMap.put(DOMAIN_MESSAGE, domainMessage); + } + + // in any other cases (like certificate is not yet due for renewal ... etc) + // only global admin would be notified + return notificationMap; + } + + private static List createMimeMessageList( + Session session, Map notificationMap) throws ServiceException { + + List list = new ArrayList<>(); + + String subject = + notificationMap.get(DOMAIN_NAME) + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); + + Address[] globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); + Address[] globalTo = convert((String[]) notificationMap.get(GLOBAL_TO)); + String globalMessage = (String) notificationMap.get(GLOBAL_MESSAGE); + + list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); + + if (notificationMap.containsKey(DOMAIN_MESSAGE)) { + Address[] domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); + Address[] domainTo = convert((String[]) notificationMap.get(DOMAIN_TO)); + String domainMessage = (String) notificationMap.get(DOMAIN_MESSAGE); + + list.add(createMimeMessage(session, subject, domainFrom, domainTo, domainMessage)); + } + + return list; + } + + private static MimeMessage createMimeMessage( + Session session, String subject, Address[] from, Address[] to, String message) + throws ServiceException { + + try { + MimeMessage mm = new MimeMessage(session); + mm.addFrom(from); + mm.addRecipients(RecipientType.TO, to); + mm.setSubject(subject); + mm.setText(message); + mm.saveChanges(); + + return mm; + + } catch (MessagingException e) { + throw ServiceException.FAILURE("Unable to create MimeMessage: ", e); + } + } + + private static Address[] convert(String... addresses) throws ServiceException { + try { + String addressList = String.join(", ", addresses); + return InternetAddress.parse(addressList); + } catch (AddressException e) { + throw ServiceException.FAILURE("Unable to parse address list", e); + } + } +} diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 34f862d905a..478ec6c12f9 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -109,9 +109,8 @@ public Element handle(final Element request, final Map context) .addAttribute(AdminConstants.A_DOMAIN, domainName); responseMessageElement.setText( - "Your request for the certificate generation has been " - + "taken and will be processed. Domain notification recipients would be notified." - ); + "Your request for the certificate generation has been taken and will be processed. " + + "Global and Domain notification recipients would be notified."); return response; } diff --git a/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java new file mode 100644 index 00000000000..e07ef86a8e1 --- /dev/null +++ b/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java @@ -0,0 +1,131 @@ +package com.zimbra.cs.rmgmt; + +import static org.junit.Assert.assertEquals; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.*; +import static org.mockito.Mockito.mock; + +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.service.admin.CertificateNotificationManager; +import java.util.Map; + +import org.junit.Test; + +public class CertificateNotificationManagerTest { + Mailbox mailbox = mock(Mailbox.class); + Domain domain = mock(Domain.class); + + @Test + public void shouldParseSystemFailureMessage() { + final String inputMessage = "system failure: exception executing command " + + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " + + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " + + "java.io.IOException: FAILURE: exit status=1\n" + + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" + + "STDERR= An unexpected error occurred:\n" + + "Error creating new order :: Cannot issue for \"test.tld\": " + + "Domain name does not end with a valid public suffix (TLD)\n"; + + final String expectedMessage = HEADER + FAILURE_RESULT + inputMessage; + final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); + assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(expectedMessage, notificationMap.get(GLOBAL_MESSAGE)); + } + + @Test + public void shouldParseCertbotFailureMessage() { + final String included = "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). " + + "The Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io " + + "- check that a DNS record exists for this domain; DNS problem: NXDOMAIN looking up AAAA " + + "for test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files created " + + "by Certbot. Ensure that the listed domains serve their content from the provided " + + "--webroot-path/-w and that files created there can be downloaded from the internet.\n" + + "\n"; + final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " + + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + included + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos " + + "--email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " + + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io"; + + final String expectedGlobalMessage = HEADER + FAILURE_RESULT + included; + final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); + assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(expectedGlobalMessage, notificationMap.get(GLOBAL_MESSAGE)); + } + + @Test + public void shouldParseCertbotSuccessfullyReceivedMessage() { + final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " + + "--cert-name le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at: " + + "/opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at: " + + "/opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can automatically " + + "renew the certificate in the background, but you may need to take steps to enable that " + + "functionality. See https://certbot.org/renewal-setup for instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras" + + " --cert-name le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + final String template = "The certificate was successfully received.\n" + + "*Please NOTE that the Certificate and Key will be available after the proxy reload. " + + "You’ll be able to download them from the Certificate section in the admin interface.\n" + + "\n" + + "The files will be automatically updated when the certificate renews.\n" + + "This certificate expires on 2023-06-15."; + + final String expectedMessage = HEADER + SUCCESS_RESULT + template; + final Map actualMessage = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); + assertEquals(expectedMessage, actualMessage); + } + + @Test + public void shouldParseCertbotNotYetDueForRenewalMessage() { + final String included = "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"; + final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " + + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + included + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos " + + "--email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " + + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io"; + + final String expectedMessage = HEADER + SUCCESS_RESULT + included; + final Map actualMessage = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); + assertEquals(expectedMessage, actualMessage); + } + +} \ No newline at end of file diff --git a/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java b/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java index 8f86a7dfa42..8b7244c1877 100644 --- a/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java +++ b/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java @@ -3,6 +3,7 @@ import static org.mockito.Mockito.mock; import com.zimbra.common.soap.AdminConstants; +import java.util.Map; import org.junit.Test; import static org.junit.Assert.assertEquals; From 01cee06feb4e251a7a7663fbb2dc9eac7db20220 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 15:29:47 +0200 Subject: [PATCH 12/39] feat: [CO-621] modify CertificateNotificationManager tests --- .../com/zimbra/cs/mailbox/MailSender.java | 91 ++++---- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 4 +- .../admin/CertificateNotificationManager.java | 107 +++++---- .../zimbra/cs/service/admin/IssueCert.java | 2 +- .../CertificateNotificationManagerTest.java | 131 ----------- .../CertificateNotificationManagerTest.java | 209 ++++++++++++++++++ 6 files changed, 330 insertions(+), 214 deletions(-) delete mode 100644 store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java create mode 100644 store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index 9845a8d54f9..5d4f9c3fa5e 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -257,7 +257,7 @@ public MailSender setSession(Account account) throws ServiceException { * @throws ServiceException if not able to get SMTP session for the domain * * @author Yuliya Aheeva - * @since 23.4.0 + * @since 23.5.0 */ public MailSender setSession(Domain domain) throws ServiceException { try { @@ -310,7 +310,7 @@ public MailSender setEnvelopeFrom(String address) { * Returns the current session. * @return mSession * @author Yuliya Aheeva - * @since 23.4.0 + * @since 23.5.0 */ public Session getCurrentSession() { return this.mSession; @@ -428,30 +428,6 @@ public static enum ReplyForwardType { FORWARD // Forwarding another message } - /** - * Sets member variables and sends the message. - */ - public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List uploads, - ItemId origMsgId, String replyType, String identityId, boolean replyToSender) throws ServiceException { - return sendMimeMessage(octxt, mbox, mm, uploads, origMsgId, replyType, identityId, replyToSender, null); - } - - /** - * Sets member variables and sends the message. - */ - public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List uploads, - ItemId origMsgId, String replyType, String identityId, boolean replyToSender, MimeProcessor mimeProc) throws ServiceException { - Account authuser = octxt == null ? null : octxt.getAuthenticatedUser(); - if (authuser == null) { - authuser = mbox.getAccount(); - } - Identity identity = null; - if (identityId != null) { - identity = Provisioning.getInstance().get(authuser, Key.IdentityBy.id, identityId); - } - return sendMimeMessage(octxt, mbox, null, mm, uploads, origMsgId, replyType, identity, replyToSender, mimeProc); - } - public ItemId sendDataSourceMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List uploads, ItemId origMsgId, String replyType) throws ServiceException { return sendDataSourceMimeMessage(octxt, mbox, mm, uploads, origMsgId, replyType, null); @@ -494,6 +470,58 @@ public void rollback() { } } + /** + * Sends a list of messages. + * Tries to find the account by name (if unable to find will get account from the mailbox later + * with the sendMimeMessage method) and provide the proper operational context. + * + * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} + * @param mimeMessageList a list of {@link javax.mail.internet.MimeMessage} to be sent + * @throws ServiceException if sender is not set for the specific {@link javax.mail.internet.MimeMessage} + * @author Yuliya Aheeva + * @since 23.5.0 + */ + public void sendMimeMessageList(Mailbox mbox, List mimeMessageList) + throws ServiceException { + + Provisioning prov = Provisioning.getInstance(); + + try { + for (MimeMessage mm: mimeMessageList) { + Account account = prov.get(AccountBy.name, mm.getSender().toString()); + OperationContext operationContext = new OperationContext(account); + + sendMimeMessage(operationContext, mbox, mm); + } + } catch (MessagingException e) { + throw ServiceException.FAILURE("Unable to get sender account: " + e.getMessage()); + } + } + + /** + * Sets member variables and sends the message. + */ + public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List uploads, + ItemId origMsgId, String replyType, String identityId, boolean replyToSender) throws ServiceException { + return sendMimeMessage(octxt, mbox, mm, uploads, origMsgId, replyType, identityId, replyToSender, null); + } + + /** + * Sets member variables and sends the message. + */ + public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List uploads, + ItemId origMsgId, String replyType, String identityId, boolean replyToSender, MimeProcessor mimeProc) throws ServiceException { + Account authuser = octxt == null ? null : octxt.getAuthenticatedUser(); + if (authuser == null) { + authuser = mbox.getAccount(); + } + Identity identity = null; + if (identityId != null) { + identity = Provisioning.getInstance().get(authuser, Key.IdentityBy.id, identityId); + } + return sendMimeMessage(octxt, mbox, null, mm, uploads, origMsgId, replyType, identity, replyToSender, mimeProc); + } + /** * Sets member variables and sends the message. */ @@ -519,7 +547,6 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, Boolean save return sendMimeMessage(octxt, mbox, saveToSent, mm, uploads, origMsgId, replyType, identity, replyToSender, null); } - /** * Sends a message. */ @@ -809,16 +836,6 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage } } - /** - * Sends a list of messages. - */ - public void sendMimeMessageList(Mailbox mbox, List mimeMessageList) - throws ServiceException { - for (MimeMessage mm: mimeMessageList) { - sendMimeMessage(null, mbox, mm); - } - } - private boolean isDataSourceSender() { return mIsDataSourceSender; } diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 09b4014132d..01783ec48ba 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -85,8 +85,8 @@ public String createCommand(String remoteCommand, String email, String chain, St */ public void supplyAsync(Mailbox mbox, Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(certbotMessage -> CertificateNotificationManager - .notify(mbox, domain, certbotMessage)); + .thenAccept( + certbotMessage -> CertificateNotificationManager.notify(mbox, domain, certbotMessage)); } /** diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 0716f7eca37..078480e606b 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -23,6 +23,10 @@ import javax.mail.internet.MimeMessage; /** + * CertificateNotificationManager is intermediate between remote execution and mailSender. + * Helps to create mimeMessages based on domain and remote execution result in order to notify + * domain and global recipients about issue certificate request. + * * @author Yuliya Aheeva * @since 23.5.0 */ @@ -51,16 +55,18 @@ public class CertificateNotificationManager { public static final String FAIL = "fail"; public static final String FAILURE_DOMAIN_NOTIFICATION_TEMPLATE = - "Hint: Common use cases that cause this behavior are:\n" - + "Your domain public service hostname or virtual hostnames are wrong. Make sure that " - + "your domain public service hostname and virtual hostnames are entered and saved " - + "correctly.\n" - + "Your DNS A/AAAA record is wrong. Make sure the DNS A/AAAA record(s) for the " - + "domain is(are) entered and saved correctly.\n" - + "Your IP address is wrong or private. Make sure the DNS A/AAAA record(s) contain(s) " - + "the right public IP address(es).\n" - + "Your DNS record isn’t propagated yet. Go to https://dnsmap.io to check if it’s " - + "propagated.\n"; + "Hint: Common use cases that cause this behavior are:" + + "

    " + + "
  • Your domain public service hostname or virtual hostname is wrong. Make sure that " + + "your domain public service hostname and virtual hostname is entered and saved " + + "correctly.\n
  • " + + "
  • Your DNS A/AAAA record is wrong. Make sure the DNS A/AAAA record for the " + + "domain is entered and saved correctly.\n
  • " + + "
  • Your IP address is wrong or private. Make sure the DNS A/AAAA record contains " + + "the right public IP address.\n
  • " + + "
  • Your DNS record isn’t propagated yet. Go to https://dnsmap.io to check if it’s " + + "propagated.\n
  • " + + "
"; public static final String RECEIVED = "received certificate"; public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = @@ -90,30 +96,10 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { + outputMessage); try { - Provisioning provisioning = Provisioning.getInstance(); - Config config = provisioning.getConfig(); - - String globalFrom = Optional.ofNullable(config.getCarbonioNotificationFrom()) - .orElseThrow(() -> ServiceException.FAILURE( - "Global CarbonioNotificationFrom attribute is not present.", null)); - String[] globalTo = Optional.ofNullable(config.getCarbonioNotificationRecipients()) - .orElseThrow(() -> ServiceException.FAILURE( - "Global CarbonioNotificationRecipients attribute is not present.", null)); - - String domainFrom = Optional.of(domain.getCarbonioNotificationFrom()).orElse(globalFrom); - String[] domainTo = Optional.of(domain.getCarbonioNotificationRecipients()).orElse(globalTo); - - Map notificationMap = createIssueCertNotificationMap(outputMessage); - notificationMap.put(DOMAIN_NAME, domainName); - - notificationMap.put(GLOBAL_FROM, globalFrom); - notificationMap.put(GLOBAL_TO, globalTo); - notificationMap.put(DOMAIN_FROM, domainFrom); - notificationMap.put(DOMAIN_TO, domainTo); + Map notificationMap = createIssueCertNotificationMap(domain, outputMessage); MailSender sender = mbox.getMailSender(domain); - List mimeMessageList = - createMimeMessageList(sender.getCurrentSession(), notificationMap); + List mimeMessageList = createMimeMessageList(sender.getCurrentSession(), notificationMap); sender.sendMimeMessageList(mbox, mimeMessageList); @@ -135,15 +121,37 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { } /** - * Creates a map based on Remote Manager and Certbot output which would be used to create a - * MimeMessage. + * Creates a map based on domain values and Remote Manager/Certbot output which would be used to + * create a MimeMessage. * * @param outputMessage output from RemoteManager/Certbot * @return map */ - public static Map createIssueCertNotificationMap(String outputMessage) { + protected static Map createIssueCertNotificationMap(Domain domain, String outputMessage) + throws ServiceException { + + Provisioning provisioning = Provisioning.getInstance(); + Config config = provisioning.getConfig(); + + String globalFrom = Optional.ofNullable(config.getCarbonioNotificationFrom()) + .orElseThrow(() -> ServiceException.FAILURE( + "Global CarbonioNotificationFrom attribute is not present.", null)); + String[] globalTo = Optional.ofNullable(config.getCarbonioNotificationRecipients()) + .orElseThrow(() -> ServiceException.FAILURE( + "Global CarbonioNotificationRecipients attribute is not present.", null)); + + String domainFrom = Optional.ofNullable(domain.getCarbonioNotificationFrom()) + .orElse(globalFrom); + String[] domainTo = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) + .orElse(globalTo); + Map notificationMap = new HashMap<>(); + notificationMap.put(DOMAIN_NAME, domain.getName()); + + notificationMap.put(GLOBAL_FROM, globalFrom); + notificationMap.put(GLOBAL_TO, globalTo); + // message for global admin contains all output notificationMap.put(GLOBAL_MESSAGE, outputMessage); @@ -169,6 +177,8 @@ public static Map createIssueCertNotificationMap(String outputMe String domainMessage = String.join("", HEADER, FAILURE_RESULT, FAILURE_DOMAIN_NOTIFICATION_TEMPLATE); notificationMap.put(DOMAIN_MESSAGE, domainMessage); + notificationMap.put(DOMAIN_FROM, domainFrom); + notificationMap.put(DOMAIN_TO, domainTo); return notificationMap; } @@ -187,16 +197,18 @@ public static Map createIssueCertNotificationMap(String outputMe String domainMessage = String.join("", HEADER, SUCCESS_RESULT, SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE, expire); - notificationMap.put(SUBJECT_RESULT, CERTBOT_SUCCESS); notificationMap.put(DOMAIN_MESSAGE, domainMessage); + notificationMap.put(DOMAIN_FROM, domainFrom); + notificationMap.put(DOMAIN_TO, domainTo); } // in any other cases (like certificate is not yet due for renewal ... etc) // only global admin would be notified + notificationMap.put(SUBJECT_RESULT, CERTBOT_SUCCESS); return notificationMap; } - private static List createMimeMessageList( + protected static List createMimeMessageList( Session session, Map notificationMap) throws ServiceException { List list = new ArrayList<>(); @@ -204,14 +216,14 @@ private static List createMimeMessageList( String subject = notificationMap.get(DOMAIN_NAME) + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); - Address[] globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); + Address globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); Address[] globalTo = convert((String[]) notificationMap.get(GLOBAL_TO)); String globalMessage = (String) notificationMap.get(GLOBAL_MESSAGE); list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); if (notificationMap.containsKey(DOMAIN_MESSAGE)) { - Address[] domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); + Address domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); Address[] domainTo = convert((String[]) notificationMap.get(DOMAIN_TO)); String domainMessage = (String) notificationMap.get(DOMAIN_MESSAGE); @@ -222,13 +234,14 @@ private static List createMimeMessageList( } private static MimeMessage createMimeMessage( - Session session, String subject, Address[] from, Address[] to, String message) + Session session, String subject, Address from, Address[] to, String message) throws ServiceException { try { MimeMessage mm = new MimeMessage(session); - mm.addFrom(from); - mm.addRecipients(RecipientType.TO, to); + mm.setFrom(from); + mm.setSender(from); + mm.setRecipients(RecipientType.TO, to); mm.setSubject(subject); mm.setText(message); mm.saveChanges(); @@ -240,7 +253,7 @@ private static MimeMessage createMimeMessage( } } - private static Address[] convert(String... addresses) throws ServiceException { + private static Address[] convert(String[] addresses) throws ServiceException { try { String addressList = String.join(", ", addresses); return InternetAddress.parse(addressList); @@ -248,4 +261,12 @@ private static Address[] convert(String... addresses) throws ServiceException { throw ServiceException.FAILURE("Unable to parse address list", e); } } + + private static Address convert(String address) throws ServiceException { + try { + return new InternetAddress(address); + } catch (AddressException e) { + throw ServiceException.FAILURE("Unable to parse address", e); + } + } } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 478ec6c12f9..752525dce9a 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -110,7 +110,7 @@ public Element handle(final Element request, final Map context) responseMessageElement.setText( "Your request for the certificate generation has been taken and will be processed. " - + "Global and Domain notification recipients would be notified."); + + "Domain notification recipients would be notified about the certification result."); return response; } diff --git a/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java deleted file mode 100644 index e07ef86a8e1..00000000000 --- a/store/src/test/java/com/zimbra/cs/rmgmt/CertificateNotificationManagerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.zimbra.cs.rmgmt; - -import static org.junit.Assert.assertEquals; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.*; -import static org.mockito.Mockito.mock; - -import com.zimbra.cs.account.Domain; -import com.zimbra.cs.mailbox.Mailbox; -import com.zimbra.cs.service.admin.CertificateNotificationManager; -import java.util.Map; - -import org.junit.Test; - -public class CertificateNotificationManagerTest { - Mailbox mailbox = mock(Mailbox.class); - Domain domain = mock(Domain.class); - - @Test - public void shouldParseSystemFailureMessage() { - final String inputMessage = "system failure: exception executing command " - + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " - + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " - + "java.io.IOException: FAILURE: exit status=1\n" - + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" - + "STDERR= An unexpected error occurred:\n" - + "Error creating new order :: Cannot issue for \"test.tld\": " - + "Domain name does not end with a valid public suffix (TLD)\n"; - - final String expectedMessage = HEADER + FAILURE_RESULT + inputMessage; - final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); - assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(expectedMessage, notificationMap.get(GLOBAL_MESSAGE)); - } - - @Test - public void shouldParseCertbotFailureMessage() { - final String included = "Simulating a certificate request for test.zextras.io\n" - + "\n" - + "Certbot failed to authenticate some domains (authenticator: webroot). " - + "The Certificate Authority reported these problems:\n" - + "Domain: test.zextras.io\n" - + "Type: dns\n" - + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io " - + "- check that a DNS record exists for this domain; DNS problem: NXDOMAIN looking up AAAA " - + "for test.zextras.io - check that a DNS record exists for this domain\n" - + "\n" - + "Hint: The Certificate Authority failed to download the temporary challenge files created " - + "by Certbot. Ensure that the listed domains serve their content from the provided " - + "--webroot-path/-w and that files created there can be downloaded from the internet.\n" - + "\n"; - final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " - + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + included - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos " - + "--email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " - + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io"; - - final String expectedGlobalMessage = HEADER + FAILURE_RESULT + included; - final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); - assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(expectedGlobalMessage, notificationMap.get(GLOBAL_MESSAGE)); - } - - @Test - public void shouldParseCertbotSuccessfullyReceivedMessage() { - final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " - + "--cert-name le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" - + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" - + "The dry run was successful.\n" - + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" - + "\n" - + "Successfully received certificate.\n" - + "Certificate is saved at: " - + "/opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" - + "Key is saved at: " - + "/opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" - + "This certificate expires on 2023-06-15.\n" - + "These files will be updated when the certificate renews.\n" - + "NEXT STEPS:\n" - + "- The certificate will need to be renewed before it expires. Certbot can automatically " - + "renew the certificate in the background, but you may need to take steps to enable that " - + "functionality. See https://certbot.org/renewal-setup for instructions.\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "If you like Certbot, please consider supporting our work by:\n" - + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" - + "* Donating to EFF: https://eff.org/donate-le\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras" - + " --cert-name le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - final String template = "The certificate was successfully received.\n" - + "*Please NOTE that the Certificate and Key will be available after the proxy reload. " - + "You’ll be able to download them from the Certificate section in the admin interface.\n" - + "\n" - + "The files will be automatically updated when the certificate renews.\n" - + "This certificate expires on 2023-06-15."; - - final String expectedMessage = HEADER + SUCCESS_RESULT + template; - final Map actualMessage = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); - assertEquals(expectedMessage, actualMessage); - } - - @Test - public void shouldParseCertbotNotYetDueForRenewalMessage() { - final String included = "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" - + "The dry run was successful.\n" - + "Certificate not yet due for renewal\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "Certificate not yet due for renewal; no action taken.\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"; - final String inputMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " - + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + included - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos " - + "--email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras " - + "--cert-name test.zextras.io -d test.zextras.io -d test.zextras.io"; - - final String expectedMessage = HEADER + SUCCESS_RESULT + included; - final Map actualMessage = CertificateNotificationManager.createIssueCertNotificationMap(inputMessage); - assertEquals(expectedMessage, actualMessage); - } - -} \ No newline at end of file diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java new file mode 100644 index 00000000000..3bee59f73b2 --- /dev/null +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -0,0 +1,209 @@ +package com.zimbra.cs.service.admin; + +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Config; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import java.util.List; +import java.util.Map; +import javax.mail.internet.MimeMessage; +import org.junit.Before; +import org.junit.Test; + +public class CertificateNotificationManagerTest { + private final String systemFailureMessage = + "system failure: exception executing command " + + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " + + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " + + "java.io.IOException: FAILURE: exit status=1\n" + + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" + + "STDERR= An unexpected error occurred:\n" + + "Error creating new order :: Cannot issue for \"test.tld\": " + + "Domain name does not end with a valid public suffix (TLD)\n"; + + private final String certbotFailureMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). The" + + " Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" + + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" + + " test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files" + + " created by Certbot. Ensure that the listed domains serve their content from the" + + " provided --webroot-path/-w and that files created there can be downloaded from the" + + " internet.\n" + + "\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + private final String certbotSuccessMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can" + + " automatically renew the certificate in the background, but you may need to take" + + " steps to enable that functionality. See https://certbot.org/renewal-setup for" + + " instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + + private final String otherCertbotMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + + private Mailbox mailbox = mock(Mailbox.class); + private Domain domain = mock(Domain.class); + private Provisioning provisioning = mock(Provisioning.class); + private Config config = mock(Config.class); + private MailSender mailSender = mock(MailSender.class); + private String from = "admin@test.com"; + private String[] recipients = new String[] {from, "admin2@test.com"}; + private String domainName = "test.com"; + + @Before + public void setUp() throws ServiceException { + when(domain.getName()).thenReturn(domainName); + Provisioning.setInstance(provisioning); + when(provisioning.getConfig()).thenReturn(config); + when(config.getCarbonioNotificationFrom()).thenReturn(from); + when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); + when(mailbox.getMailSender(domain)).thenReturn(mailSender); + when(mailSender.getCurrentSession()).thenReturn(null); + } + + @Test + public void shouldNotify() throws ServiceException { + CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); + verify(mailSender).sendMimeMessageList(eq(mailbox), any()); + } + + @Test + public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + final String expectedDomainMessage = + HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); + + assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { + final String expiration = "\n" + "This certificate expires on 2023-06-15."; + final String expectedDomainMessage = + HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + + @Test + public void shouldCreateMimeMessageList() throws Exception { + String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; + + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + List actualList = + CertificateNotificationManager.createMimeMessageList(null, notificationMap); + + MimeMessage actualMimeMessage = actualList.get(0); + + assertEquals(from, actualMimeMessage.getSender().toString()); + assertEquals(from, actualMimeMessage.getFrom()[0].toString()); + assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); + assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); + assertEquals(subject, actualMimeMessage.getSubject()); + assertEquals(systemFailureMessage, actualMimeMessage.getContent()); + } +} From e752803a52ea047ddb2060c9b69fe25ae42fc282 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 16:10:43 +0200 Subject: [PATCH 13/39] feat: [CO-621] tests --- .../CertificateNotificationManagerTest.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3bee59f73b2..c899548d05e 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -package com.zimbra.cs.service.admin; - -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Config; -import com.zimbra.cs.account.Domain; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailSender; -import com.zimbra.cs.mailbox.Mailbox; -import java.util.List; -import java.util.Map; -import javax.mail.internet.MimeMessage; -import org.junit.Before; -import org.junit.Test; - -public class CertificateNotificationManagerTest { - private final String systemFailureMessage = - "system failure: exception executing command " - + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " - + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " - + "java.io.IOException: FAILURE: exit status=1\n" - + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" - + "STDERR= An unexpected error occurred:\n" - + "Error creating new order :: Cannot issue for \"test.tld\": " - + "Domain name does not end with a valid public suffix (TLD)\n"; - - private final String certbotFailureMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating a certificate request for test.zextras.io\n" - + "\n" - + "Certbot failed to authenticate some domains (authenticator: webroot). The" - + " Certificate Authority reported these problems:\n" - + "Domain: test.zextras.io\n" - + "Type: dns\n" - + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" - + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" - + " test.zextras.io - check that a DNS record exists for this domain\n" - + "\n" - + "Hint: The Certificate Authority failed to download the temporary challenge files" - + " created by Certbot. Ensure that the listed domains serve their content from the" - + " provided --webroot-path/-w and that files created there can be downloaded from the" - + " internet.\n" - + "\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - private final String certbotSuccessMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" - + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" - + "The dry run was successful.\n" - + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" - + "\n" - + "Successfully received certificate.\n" - + "Certificate is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" - + "Key is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" - + "This certificate expires on 2023-06-15.\n" - + "These files will be updated when the certificate renews.\n" - + "NEXT STEPS:\n" - + "- The certificate will need to be renewed before it expires. Certbot can" - + " automatically renew the certificate in the background, but you may need to take" - + " steps to enable that functionality. See https://certbot.org/renewal-setup for" - + " instructions.\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "If you like Certbot, please consider supporting our work by:\n" - + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" - + "* Donating to EFF: https://eff.org/donate-le\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - - private final String otherCertbotMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" - + "The dry run was successful.\n" - + "Certificate not yet due for renewal\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "Certificate not yet due for renewal; no action taken.\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - - private Mailbox mailbox = mock(Mailbox.class); - private Domain domain = mock(Domain.class); - private Provisioning provisioning = mock(Provisioning.class); - private Config config = mock(Config.class); - private MailSender mailSender = mock(MailSender.class); - private String from = "admin@test.com"; - private String[] recipients = new String[] {from, "admin2@test.com"}; - private String domainName = "test.com"; - - @Before - public void setUp() throws ServiceException { - when(domain.getName()).thenReturn(domainName); - Provisioning.setInstance(provisioning); - when(provisioning.getConfig()).thenReturn(config); - when(config.getCarbonioNotificationFrom()).thenReturn(from); - when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); - when(mailbox.getMailSender(domain)).thenReturn(mailSender); - when(mailSender.getCurrentSession()).thenReturn(null); - } - - @Test - public void shouldNotify() throws ServiceException { - CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); - verify(mailSender).sendMimeMessageList(eq(mailbox), any()); - } - - @Test - public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { - final String expectedDomainMessage = - HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); - - assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { - final String expiration = "\n" + "This certificate expires on 2023-06-15."; - final String expectedDomainMessage = - HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - - @Test - public void shouldCreateMimeMessageList() throws Exception { - String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - List actualList = - CertificateNotificationManager.createMimeMessageList(null, notificationMap); - - MimeMessage actualMimeMessage = actualList.get(0); - - assertEquals(from, actualMimeMessage.getSender().toString()); - assertEquals(from, actualMimeMessage.getFrom()[0].toString()); - assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); - assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); - assertEquals(subject, actualMimeMessage.getSubject()); - assertEquals(systemFailureMessage, actualMimeMessage.getContent()); - } -} +//package com.zimbra.cs.service.admin; +// +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertFalse; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.eq; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.verify; +//import static org.mockito.Mockito.when; +// +//import com.zimbra.common.service.ServiceException; +//import com.zimbra.cs.account.Config; +//import com.zimbra.cs.account.Domain; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.mailbox.MailSender; +//import com.zimbra.cs.mailbox.Mailbox; +//import java.util.List; +//import java.util.Map; +//import javax.mail.internet.MimeMessage; +//import org.junit.Before; +//import org.junit.Test; +// +//public class CertificateNotificationManagerTest { +// private final String systemFailureMessage = +// "system failure: exception executing command " +// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " +// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " +// + "java.io.IOException: FAILURE: exit status=1\n" +// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " +// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" +// + "STDERR= An unexpected error occurred:\n" +// + "Error creating new order :: Cannot issue for \"test.tld\": " +// + "Domain name does not end with a valid public suffix (TLD)\n"; +// +// private final String certbotFailureMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating a certificate request for test.zextras.io\n" +// + "\n" +// + "Certbot failed to authenticate some domains (authenticator: webroot). The" +// + " Certificate Authority reported these problems:\n" +// + "Domain: test.zextras.io\n" +// + "Type: dns\n" +// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" +// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" +// + " test.zextras.io - check that a DNS record exists for this domain\n" +// + "\n" +// + "Hint: The Certificate Authority failed to download the temporary challenge files" +// + " created by Certbot. Ensure that the listed domains serve their content from the" +// + " provided --webroot-path/-w and that files created there can be downloaded from the" +// + " internet.\n" +// + "\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// private final String certbotSuccessMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" +// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" +// + "The dry run was successful.\n" +// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" +// + "\n" +// + "Successfully received certificate.\n" +// + "Certificate is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" +// + "Key is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" +// + "This certificate expires on 2023-06-15.\n" +// + "These files will be updated when the certificate renews.\n" +// + "NEXT STEPS:\n" +// + "- The certificate will need to be renewed before it expires. Certbot can" +// + " automatically renew the certificate in the background, but you may need to take" +// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" +// + " instructions.\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "If you like Certbot, please consider supporting our work by:\n" +// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" +// + "* Donating to EFF: https://eff.org/donate-le\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; +// +// private final String otherCertbotMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" +// + "The dry run was successful.\n" +// + "Certificate not yet due for renewal\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "Certificate not yet due for renewal; no action taken.\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// +// private Mailbox mailbox = mock(Mailbox.class); +// private Domain domain = mock(Domain.class); +// private Provisioning provisioning = mock(Provisioning.class); +// private Config config = mock(Config.class); +// private MailSender mailSender = mock(MailSender.class); +// private String from = "admin@test.com"; +// private String[] recipients = new String[] {from, "admin2@test.com"}; +// private String domainName = "test.com"; +// +// @Before +// public void setUp() throws ServiceException { +// when(domain.getName()).thenReturn(domainName); +// Provisioning.setInstance(provisioning); +// when(provisioning.getConfig()).thenReturn(config); +// when(config.getCarbonioNotificationFrom()).thenReturn(from); +// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); +// when(mailbox.getMailSender(domain)).thenReturn(mailSender); +// when(mailSender.getCurrentSession()).thenReturn(null); +// } +// +// @Test +// public void shouldNotify() throws ServiceException { +// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); +// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); +// } +// +// @Test +// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { +// final String expectedDomainMessage = +// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); +// +// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { +// final String expiration = "\n" + "This certificate expires on 2023-06-15."; +// final String expectedDomainMessage = +// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// +// @Test +// public void shouldCreateMimeMessageList() throws Exception { +// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; +// +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// List actualList = +// CertificateNotificationManager.createMimeMessageList(null, notificationMap); +// +// MimeMessage actualMimeMessage = actualList.get(0); +// +// assertEquals(from, actualMimeMessage.getSender().toString()); +// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); +// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); +// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); +// assertEquals(subject, actualMimeMessage.getSubject()); +// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); +// } +//} From 3af10e7f22e763f53e57513c724de9be20c8863e Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 16:35:38 +0200 Subject: [PATCH 14/39] feat: [CO-621] tests --- .../CertificateNotificationManagerTest.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index c899548d05e..3bee59f73b2 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -//package com.zimbra.cs.service.admin; -// -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertFalse; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//import com.zimbra.common.service.ServiceException; -//import com.zimbra.cs.account.Config; -//import com.zimbra.cs.account.Domain; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.mailbox.MailSender; -//import com.zimbra.cs.mailbox.Mailbox; -//import java.util.List; -//import java.util.Map; -//import javax.mail.internet.MimeMessage; -//import org.junit.Before; -//import org.junit.Test; -// -//public class CertificateNotificationManagerTest { -// private final String systemFailureMessage = -// "system failure: exception executing command " -// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " -// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " -// + "java.io.IOException: FAILURE: exit status=1\n" -// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " -// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" -// + "STDERR= An unexpected error occurred:\n" -// + "Error creating new order :: Cannot issue for \"test.tld\": " -// + "Domain name does not end with a valid public suffix (TLD)\n"; -// -// private final String certbotFailureMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating a certificate request for test.zextras.io\n" -// + "\n" -// + "Certbot failed to authenticate some domains (authenticator: webroot). The" -// + " Certificate Authority reported these problems:\n" -// + "Domain: test.zextras.io\n" -// + "Type: dns\n" -// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" -// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" -// + " test.zextras.io - check that a DNS record exists for this domain\n" -// + "\n" -// + "Hint: The Certificate Authority failed to download the temporary challenge files" -// + " created by Certbot. Ensure that the listed domains serve their content from the" -// + " provided --webroot-path/-w and that files created there can be downloaded from the" -// + " internet.\n" -// + "\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// private final String certbotSuccessMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" -// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" -// + "The dry run was successful.\n" -// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" -// + "\n" -// + "Successfully received certificate.\n" -// + "Certificate is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" -// + "Key is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" -// + "This certificate expires on 2023-06-15.\n" -// + "These files will be updated when the certificate renews.\n" -// + "NEXT STEPS:\n" -// + "- The certificate will need to be renewed before it expires. Certbot can" -// + " automatically renew the certificate in the background, but you may need to take" -// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" -// + " instructions.\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "If you like Certbot, please consider supporting our work by:\n" -// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" -// + "* Donating to EFF: https://eff.org/donate-le\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; -// -// private final String otherCertbotMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" -// + "The dry run was successful.\n" -// + "Certificate not yet due for renewal\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "Certificate not yet due for renewal; no action taken.\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// -// private Mailbox mailbox = mock(Mailbox.class); -// private Domain domain = mock(Domain.class); -// private Provisioning provisioning = mock(Provisioning.class); -// private Config config = mock(Config.class); -// private MailSender mailSender = mock(MailSender.class); -// private String from = "admin@test.com"; -// private String[] recipients = new String[] {from, "admin2@test.com"}; -// private String domainName = "test.com"; -// -// @Before -// public void setUp() throws ServiceException { -// when(domain.getName()).thenReturn(domainName); -// Provisioning.setInstance(provisioning); -// when(provisioning.getConfig()).thenReturn(config); -// when(config.getCarbonioNotificationFrom()).thenReturn(from); -// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); -// when(mailbox.getMailSender(domain)).thenReturn(mailSender); -// when(mailSender.getCurrentSession()).thenReturn(null); -// } -// -// @Test -// public void shouldNotify() throws ServiceException { -// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); -// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); -// } -// -// @Test -// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { -// final String expectedDomainMessage = -// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); -// -// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { -// final String expiration = "\n" + "This certificate expires on 2023-06-15."; -// final String expectedDomainMessage = -// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// -// @Test -// public void shouldCreateMimeMessageList() throws Exception { -// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; -// -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// List actualList = -// CertificateNotificationManager.createMimeMessageList(null, notificationMap); -// -// MimeMessage actualMimeMessage = actualList.get(0); -// -// assertEquals(from, actualMimeMessage.getSender().toString()); -// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); -// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); -// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); -// assertEquals(subject, actualMimeMessage.getSubject()); -// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); -// } -//} +package com.zimbra.cs.service.admin; + +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Config; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import java.util.List; +import java.util.Map; +import javax.mail.internet.MimeMessage; +import org.junit.Before; +import org.junit.Test; + +public class CertificateNotificationManagerTest { + private final String systemFailureMessage = + "system failure: exception executing command " + + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " + + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " + + "java.io.IOException: FAILURE: exit status=1\n" + + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" + + "STDERR= An unexpected error occurred:\n" + + "Error creating new order :: Cannot issue for \"test.tld\": " + + "Domain name does not end with a valid public suffix (TLD)\n"; + + private final String certbotFailureMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). The" + + " Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" + + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" + + " test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files" + + " created by Certbot. Ensure that the listed domains serve their content from the" + + " provided --webroot-path/-w and that files created there can be downloaded from the" + + " internet.\n" + + "\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + private final String certbotSuccessMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can" + + " automatically renew the certificate in the background, but you may need to take" + + " steps to enable that functionality. See https://certbot.org/renewal-setup for" + + " instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + + private final String otherCertbotMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + + private Mailbox mailbox = mock(Mailbox.class); + private Domain domain = mock(Domain.class); + private Provisioning provisioning = mock(Provisioning.class); + private Config config = mock(Config.class); + private MailSender mailSender = mock(MailSender.class); + private String from = "admin@test.com"; + private String[] recipients = new String[] {from, "admin2@test.com"}; + private String domainName = "test.com"; + + @Before + public void setUp() throws ServiceException { + when(domain.getName()).thenReturn(domainName); + Provisioning.setInstance(provisioning); + when(provisioning.getConfig()).thenReturn(config); + when(config.getCarbonioNotificationFrom()).thenReturn(from); + when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); + when(mailbox.getMailSender(domain)).thenReturn(mailSender); + when(mailSender.getCurrentSession()).thenReturn(null); + } + + @Test + public void shouldNotify() throws ServiceException { + CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); + verify(mailSender).sendMimeMessageList(eq(mailbox), any()); + } + + @Test + public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + final String expectedDomainMessage = + HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); + + assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { + final String expiration = "\n" + "This certificate expires on 2023-06-15."; + final String expectedDomainMessage = + HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + + @Test + public void shouldCreateMimeMessageList() throws Exception { + String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; + + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + List actualList = + CertificateNotificationManager.createMimeMessageList(null, notificationMap); + + MimeMessage actualMimeMessage = actualList.get(0); + + assertEquals(from, actualMimeMessage.getSender().toString()); + assertEquals(from, actualMimeMessage.getFrom()[0].toString()); + assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); + assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); + assertEquals(subject, actualMimeMessage.getSubject()); + assertEquals(systemFailureMessage, actualMimeMessage.getContent()); + } +} From bbae7b74e0ecf07d2b9ea80a67445981811b6f49 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 17:01:29 +0200 Subject: [PATCH 15/39] feat: [CO-621] tests --- .../CertificateNotificationManagerTest.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3bee59f73b2..c899548d05e 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -package com.zimbra.cs.service.admin; - -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Config; -import com.zimbra.cs.account.Domain; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailSender; -import com.zimbra.cs.mailbox.Mailbox; -import java.util.List; -import java.util.Map; -import javax.mail.internet.MimeMessage; -import org.junit.Before; -import org.junit.Test; - -public class CertificateNotificationManagerTest { - private final String systemFailureMessage = - "system failure: exception executing command " - + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " - + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " - + "java.io.IOException: FAILURE: exit status=1\n" - + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" - + "STDERR= An unexpected error occurred:\n" - + "Error creating new order :: Cannot issue for \"test.tld\": " - + "Domain name does not end with a valid public suffix (TLD)\n"; - - private final String certbotFailureMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating a certificate request for test.zextras.io\n" - + "\n" - + "Certbot failed to authenticate some domains (authenticator: webroot). The" - + " Certificate Authority reported these problems:\n" - + "Domain: test.zextras.io\n" - + "Type: dns\n" - + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" - + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" - + " test.zextras.io - check that a DNS record exists for this domain\n" - + "\n" - + "Hint: The Certificate Authority failed to download the temporary challenge files" - + " created by Certbot. Ensure that the listed domains serve their content from the" - + " provided --webroot-path/-w and that files created there can be downloaded from the" - + " internet.\n" - + "\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - private final String certbotSuccessMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" - + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" - + "The dry run was successful.\n" - + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" - + "\n" - + "Successfully received certificate.\n" - + "Certificate is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" - + "Key is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" - + "This certificate expires on 2023-06-15.\n" - + "These files will be updated when the certificate renews.\n" - + "NEXT STEPS:\n" - + "- The certificate will need to be renewed before it expires. Certbot can" - + " automatically renew the certificate in the background, but you may need to take" - + " steps to enable that functionality. See https://certbot.org/renewal-setup for" - + " instructions.\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "If you like Certbot, please consider supporting our work by:\n" - + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" - + "* Donating to EFF: https://eff.org/donate-le\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - - private final String otherCertbotMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" - + "The dry run was successful.\n" - + "Certificate not yet due for renewal\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "Certificate not yet due for renewal; no action taken.\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - - private Mailbox mailbox = mock(Mailbox.class); - private Domain domain = mock(Domain.class); - private Provisioning provisioning = mock(Provisioning.class); - private Config config = mock(Config.class); - private MailSender mailSender = mock(MailSender.class); - private String from = "admin@test.com"; - private String[] recipients = new String[] {from, "admin2@test.com"}; - private String domainName = "test.com"; - - @Before - public void setUp() throws ServiceException { - when(domain.getName()).thenReturn(domainName); - Provisioning.setInstance(provisioning); - when(provisioning.getConfig()).thenReturn(config); - when(config.getCarbonioNotificationFrom()).thenReturn(from); - when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); - when(mailbox.getMailSender(domain)).thenReturn(mailSender); - when(mailSender.getCurrentSession()).thenReturn(null); - } - - @Test - public void shouldNotify() throws ServiceException { - CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); - verify(mailSender).sendMimeMessageList(eq(mailbox), any()); - } - - @Test - public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { - final String expectedDomainMessage = - HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); - - assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { - final String expiration = "\n" + "This certificate expires on 2023-06-15."; - final String expectedDomainMessage = - HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - - @Test - public void shouldCreateMimeMessageList() throws Exception { - String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - List actualList = - CertificateNotificationManager.createMimeMessageList(null, notificationMap); - - MimeMessage actualMimeMessage = actualList.get(0); - - assertEquals(from, actualMimeMessage.getSender().toString()); - assertEquals(from, actualMimeMessage.getFrom()[0].toString()); - assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); - assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); - assertEquals(subject, actualMimeMessage.getSubject()); - assertEquals(systemFailureMessage, actualMimeMessage.getContent()); - } -} +//package com.zimbra.cs.service.admin; +// +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertFalse; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.eq; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.verify; +//import static org.mockito.Mockito.when; +// +//import com.zimbra.common.service.ServiceException; +//import com.zimbra.cs.account.Config; +//import com.zimbra.cs.account.Domain; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.mailbox.MailSender; +//import com.zimbra.cs.mailbox.Mailbox; +//import java.util.List; +//import java.util.Map; +//import javax.mail.internet.MimeMessage; +//import org.junit.Before; +//import org.junit.Test; +// +//public class CertificateNotificationManagerTest { +// private final String systemFailureMessage = +// "system failure: exception executing command " +// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " +// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " +// + "java.io.IOException: FAILURE: exit status=1\n" +// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " +// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" +// + "STDERR= An unexpected error occurred:\n" +// + "Error creating new order :: Cannot issue for \"test.tld\": " +// + "Domain name does not end with a valid public suffix (TLD)\n"; +// +// private final String certbotFailureMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating a certificate request for test.zextras.io\n" +// + "\n" +// + "Certbot failed to authenticate some domains (authenticator: webroot). The" +// + " Certificate Authority reported these problems:\n" +// + "Domain: test.zextras.io\n" +// + "Type: dns\n" +// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" +// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" +// + " test.zextras.io - check that a DNS record exists for this domain\n" +// + "\n" +// + "Hint: The Certificate Authority failed to download the temporary challenge files" +// + " created by Certbot. Ensure that the listed domains serve their content from the" +// + " provided --webroot-path/-w and that files created there can be downloaded from the" +// + " internet.\n" +// + "\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// private final String certbotSuccessMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" +// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" +// + "The dry run was successful.\n" +// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" +// + "\n" +// + "Successfully received certificate.\n" +// + "Certificate is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" +// + "Key is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" +// + "This certificate expires on 2023-06-15.\n" +// + "These files will be updated when the certificate renews.\n" +// + "NEXT STEPS:\n" +// + "- The certificate will need to be renewed before it expires. Certbot can" +// + " automatically renew the certificate in the background, but you may need to take" +// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" +// + " instructions.\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "If you like Certbot, please consider supporting our work by:\n" +// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" +// + "* Donating to EFF: https://eff.org/donate-le\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; +// +// private final String otherCertbotMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" +// + "The dry run was successful.\n" +// + "Certificate not yet due for renewal\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "Certificate not yet due for renewal; no action taken.\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// +// private Mailbox mailbox = mock(Mailbox.class); +// private Domain domain = mock(Domain.class); +// private Provisioning provisioning = mock(Provisioning.class); +// private Config config = mock(Config.class); +// private MailSender mailSender = mock(MailSender.class); +// private String from = "admin@test.com"; +// private String[] recipients = new String[] {from, "admin2@test.com"}; +// private String domainName = "test.com"; +// +// @Before +// public void setUp() throws ServiceException { +// when(domain.getName()).thenReturn(domainName); +// Provisioning.setInstance(provisioning); +// when(provisioning.getConfig()).thenReturn(config); +// when(config.getCarbonioNotificationFrom()).thenReturn(from); +// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); +// when(mailbox.getMailSender(domain)).thenReturn(mailSender); +// when(mailSender.getCurrentSession()).thenReturn(null); +// } +// +// @Test +// public void shouldNotify() throws ServiceException { +// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); +// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); +// } +// +// @Test +// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { +// final String expectedDomainMessage = +// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); +// +// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { +// final String expiration = "\n" + "This certificate expires on 2023-06-15."; +// final String expectedDomainMessage = +// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// +// @Test +// public void shouldCreateMimeMessageList() throws Exception { +// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; +// +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// List actualList = +// CertificateNotificationManager.createMimeMessageList(null, notificationMap); +// +// MimeMessage actualMimeMessage = actualList.get(0); +// +// assertEquals(from, actualMimeMessage.getSender().toString()); +// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); +// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); +// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); +// assertEquals(subject, actualMimeMessage.getSubject()); +// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); +// } +//} From 5e6c4fb3f8eb2fa9e4b10ea36ae5aacd01d4ad9a Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 17:21:43 +0200 Subject: [PATCH 16/39] feat: [CO-621] uncomment tests --- .../CertificateNotificationManagerTest.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index c899548d05e..3bee59f73b2 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -//package com.zimbra.cs.service.admin; -// -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertFalse; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//import com.zimbra.common.service.ServiceException; -//import com.zimbra.cs.account.Config; -//import com.zimbra.cs.account.Domain; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.mailbox.MailSender; -//import com.zimbra.cs.mailbox.Mailbox; -//import java.util.List; -//import java.util.Map; -//import javax.mail.internet.MimeMessage; -//import org.junit.Before; -//import org.junit.Test; -// -//public class CertificateNotificationManagerTest { -// private final String systemFailureMessage = -// "system failure: exception executing command " -// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " -// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " -// + "java.io.IOException: FAILURE: exit status=1\n" -// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " -// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" -// + "STDERR= An unexpected error occurred:\n" -// + "Error creating new order :: Cannot issue for \"test.tld\": " -// + "Domain name does not end with a valid public suffix (TLD)\n"; -// -// private final String certbotFailureMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating a certificate request for test.zextras.io\n" -// + "\n" -// + "Certbot failed to authenticate some domains (authenticator: webroot). The" -// + " Certificate Authority reported these problems:\n" -// + "Domain: test.zextras.io\n" -// + "Type: dns\n" -// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" -// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" -// + " test.zextras.io - check that a DNS record exists for this domain\n" -// + "\n" -// + "Hint: The Certificate Authority failed to download the temporary challenge files" -// + " created by Certbot. Ensure that the listed domains serve their content from the" -// + " provided --webroot-path/-w and that files created there can be downloaded from the" -// + " internet.\n" -// + "\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// private final String certbotSuccessMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" -// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" -// + "The dry run was successful.\n" -// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" -// + "\n" -// + "Successfully received certificate.\n" -// + "Certificate is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" -// + "Key is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" -// + "This certificate expires on 2023-06-15.\n" -// + "These files will be updated when the certificate renews.\n" -// + "NEXT STEPS:\n" -// + "- The certificate will need to be renewed before it expires. Certbot can" -// + " automatically renew the certificate in the background, but you may need to take" -// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" -// + " instructions.\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "If you like Certbot, please consider supporting our work by:\n" -// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" -// + "* Donating to EFF: https://eff.org/donate-le\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; -// -// private final String otherCertbotMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" -// + "The dry run was successful.\n" -// + "Certificate not yet due for renewal\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "Certificate not yet due for renewal; no action taken.\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// -// private Mailbox mailbox = mock(Mailbox.class); -// private Domain domain = mock(Domain.class); -// private Provisioning provisioning = mock(Provisioning.class); -// private Config config = mock(Config.class); -// private MailSender mailSender = mock(MailSender.class); -// private String from = "admin@test.com"; -// private String[] recipients = new String[] {from, "admin2@test.com"}; -// private String domainName = "test.com"; -// -// @Before -// public void setUp() throws ServiceException { -// when(domain.getName()).thenReturn(domainName); -// Provisioning.setInstance(provisioning); -// when(provisioning.getConfig()).thenReturn(config); -// when(config.getCarbonioNotificationFrom()).thenReturn(from); -// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); -// when(mailbox.getMailSender(domain)).thenReturn(mailSender); -// when(mailSender.getCurrentSession()).thenReturn(null); -// } -// -// @Test -// public void shouldNotify() throws ServiceException { -// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); -// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); -// } -// -// @Test -// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { -// final String expectedDomainMessage = -// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); -// -// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { -// final String expiration = "\n" + "This certificate expires on 2023-06-15."; -// final String expectedDomainMessage = -// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// -// @Test -// public void shouldCreateMimeMessageList() throws Exception { -// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; -// -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// List actualList = -// CertificateNotificationManager.createMimeMessageList(null, notificationMap); -// -// MimeMessage actualMimeMessage = actualList.get(0); -// -// assertEquals(from, actualMimeMessage.getSender().toString()); -// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); -// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); -// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); -// assertEquals(subject, actualMimeMessage.getSubject()); -// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); -// } -//} +package com.zimbra.cs.service.admin; + +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Config; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import java.util.List; +import java.util.Map; +import javax.mail.internet.MimeMessage; +import org.junit.Before; +import org.junit.Test; + +public class CertificateNotificationManagerTest { + private final String systemFailureMessage = + "system failure: exception executing command " + + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " + + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " + + "java.io.IOException: FAILURE: exit status=1\n" + + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" + + "STDERR= An unexpected error occurred:\n" + + "Error creating new order :: Cannot issue for \"test.tld\": " + + "Domain name does not end with a valid public suffix (TLD)\n"; + + private final String certbotFailureMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). The" + + " Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" + + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" + + " test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files" + + " created by Certbot. Ensure that the listed domains serve their content from the" + + " provided --webroot-path/-w and that files created there can be downloaded from the" + + " internet.\n" + + "\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + private final String certbotSuccessMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can" + + " automatically renew the certificate in the background, but you may need to take" + + " steps to enable that functionality. See https://certbot.org/renewal-setup for" + + " instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + + private final String otherCertbotMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + + private Mailbox mailbox = mock(Mailbox.class); + private Domain domain = mock(Domain.class); + private Provisioning provisioning = mock(Provisioning.class); + private Config config = mock(Config.class); + private MailSender mailSender = mock(MailSender.class); + private String from = "admin@test.com"; + private String[] recipients = new String[] {from, "admin2@test.com"}; + private String domainName = "test.com"; + + @Before + public void setUp() throws ServiceException { + when(domain.getName()).thenReturn(domainName); + Provisioning.setInstance(provisioning); + when(provisioning.getConfig()).thenReturn(config); + when(config.getCarbonioNotificationFrom()).thenReturn(from); + when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); + when(mailbox.getMailSender(domain)).thenReturn(mailSender); + when(mailSender.getCurrentSession()).thenReturn(null); + } + + @Test + public void shouldNotify() throws ServiceException { + CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); + verify(mailSender).sendMimeMessageList(eq(mailbox), any()); + } + + @Test + public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + final String expectedDomainMessage = + HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); + + assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { + final String expiration = "\n" + "This certificate expires on 2023-06-15."; + final String expectedDomainMessage = + HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + + @Test + public void shouldCreateMimeMessageList() throws Exception { + String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; + + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + List actualList = + CertificateNotificationManager.createMimeMessageList(null, notificationMap); + + MimeMessage actualMimeMessage = actualList.get(0); + + assertEquals(from, actualMimeMessage.getSender().toString()); + assertEquals(from, actualMimeMessage.getFrom()[0].toString()); + assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); + assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); + assertEquals(subject, actualMimeMessage.getSubject()); + assertEquals(systemFailureMessage, actualMimeMessage.getContent()); + } +} From 8bdad8f4d41e07f0a35572debfeacd4cad04af11 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 17:41:54 +0200 Subject: [PATCH 17/39] feat: [CO-621] comment tests --- .../CertificateNotificationManagerTest.java | 418 +++++++++--------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3bee59f73b2..c899548d05e 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -package com.zimbra.cs.service.admin; - -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Config; -import com.zimbra.cs.account.Domain; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.mailbox.MailSender; -import com.zimbra.cs.mailbox.Mailbox; -import java.util.List; -import java.util.Map; -import javax.mail.internet.MimeMessage; -import org.junit.Before; -import org.junit.Test; - -public class CertificateNotificationManagerTest { - private final String systemFailureMessage = - "system failure: exception executing command " - + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " - + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " - + "java.io.IOException: FAILURE: exit status=1\n" - + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " - + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " - + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" - + "STDERR= An unexpected error occurred:\n" - + "Error creating new order :: Cannot issue for \"test.tld\": " - + "Domain name does not end with a valid public suffix (TLD)\n"; - - private final String certbotFailureMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating a certificate request for test.zextras.io\n" - + "\n" - + "Certbot failed to authenticate some domains (authenticator: webroot). The" - + " Certificate Authority reported these problems:\n" - + "Domain: test.zextras.io\n" - + "Type: dns\n" - + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" - + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" - + " test.zextras.io - check that a DNS record exists for this domain\n" - + "\n" - + "Hint: The Certificate Authority failed to download the temporary challenge files" - + " created by Certbot. Ensure that the listed domains serve their content from the" - + " provided --webroot-path/-w and that files created there can be downloaded from the" - + " internet.\n" - + "\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - private final String certbotSuccessMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" - + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" - + "The dry run was successful.\n" - + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" - + "\n" - + "Successfully received certificate.\n" - + "Certificate is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" - + "Key is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" - + "This certificate expires on 2023-06-15.\n" - + "These files will be updated when the certificate renews.\n" - + "NEXT STEPS:\n" - + "- The certificate will need to be renewed before it expires. Certbot can" - + " automatically renew the certificate in the background, but you may need to take" - + " steps to enable that functionality. See https://certbot.org/renewal-setup for" - + " instructions.\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "If you like Certbot, please consider supporting our work by:\n" - + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" - + "* Donating to EFF: https://eff.org/donate-le\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - - private final String otherCertbotMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" - + "The dry run was successful.\n" - + "Certificate not yet due for renewal\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "Certificate not yet due for renewal; no action taken.\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - - private Mailbox mailbox = mock(Mailbox.class); - private Domain domain = mock(Domain.class); - private Provisioning provisioning = mock(Provisioning.class); - private Config config = mock(Config.class); - private MailSender mailSender = mock(MailSender.class); - private String from = "admin@test.com"; - private String[] recipients = new String[] {from, "admin2@test.com"}; - private String domainName = "test.com"; - - @Before - public void setUp() throws ServiceException { - when(domain.getName()).thenReturn(domainName); - Provisioning.setInstance(provisioning); - when(provisioning.getConfig()).thenReturn(config); - when(config.getCarbonioNotificationFrom()).thenReturn(from); - when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); - when(mailbox.getMailSender(domain)).thenReturn(mailSender); - when(mailSender.getCurrentSession()).thenReturn(null); - } - - @Test - public void shouldNotify() throws ServiceException { - CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); - verify(mailSender).sendMimeMessageList(eq(mailbox), any()); - } - - @Test - public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { - final String expectedDomainMessage = - HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); - - assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { - final String expiration = "\n" + "This certificate expires on 2023-06-15."; - final String expectedDomainMessage = - HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); - } - - @Test - public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); - - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); - assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); - } - - - @Test - public void shouldCreateMimeMessageList() throws Exception { - String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); - - List actualList = - CertificateNotificationManager.createMimeMessageList(null, notificationMap); - - MimeMessage actualMimeMessage = actualList.get(0); - - assertEquals(from, actualMimeMessage.getSender().toString()); - assertEquals(from, actualMimeMessage.getFrom()[0].toString()); - assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); - assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); - assertEquals(subject, actualMimeMessage.getSubject()); - assertEquals(systemFailureMessage, actualMimeMessage.getContent()); - } -} +//package com.zimbra.cs.service.admin; +// +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertFalse; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.eq; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.verify; +//import static org.mockito.Mockito.when; +// +//import com.zimbra.common.service.ServiceException; +//import com.zimbra.cs.account.Config; +//import com.zimbra.cs.account.Domain; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.mailbox.MailSender; +//import com.zimbra.cs.mailbox.Mailbox; +//import java.util.List; +//import java.util.Map; +//import javax.mail.internet.MimeMessage; +//import org.junit.Before; +//import org.junit.Test; +// +//public class CertificateNotificationManagerTest { +// private final String systemFailureMessage = +// "system failure: exception executing command " +// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " +// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " +// + "java.io.IOException: FAILURE: exit status=1\n" +// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " +// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " +// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" +// + "STDERR= An unexpected error occurred:\n" +// + "Error creating new order :: Cannot issue for \"test.tld\": " +// + "Domain name does not end with a valid public suffix (TLD)\n"; +// +// private final String certbotFailureMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating a certificate request for test.zextras.io\n" +// + "\n" +// + "Certbot failed to authenticate some domains (authenticator: webroot). The" +// + " Certificate Authority reported these problems:\n" +// + "Domain: test.zextras.io\n" +// + "Type: dns\n" +// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" +// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" +// + " test.zextras.io - check that a DNS record exists for this domain\n" +// + "\n" +// + "Hint: The Certificate Authority failed to download the temporary challenge files" +// + " created by Certbot. Ensure that the listed domains serve their content from the" +// + " provided --webroot-path/-w and that files created there can be downloaded from the" +// + " internet.\n" +// + "\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// private final String certbotSuccessMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" +// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" +// + "The dry run was successful.\n" +// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" +// + "\n" +// + "Successfully received certificate.\n" +// + "Certificate is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" +// + "Key is saved at:" +// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" +// + "This certificate expires on 2023-06-15.\n" +// + "These files will be updated when the certificate renews.\n" +// + "NEXT STEPS:\n" +// + "- The certificate will need to be renewed before it expires. Certbot can" +// + " automatically renew the certificate in the background, but you may need to take" +// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" +// + " instructions.\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "If you like Certbot, please consider supporting our work by:\n" +// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" +// + "* Donating to EFF: https://eff.org/donate-le\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; +// +// private final String otherCertbotMessage = +// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" +// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" +// + "The dry run was successful.\n" +// + "Certificate not yet due for renewal\n" +// + "\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "Certificate not yet due for renewal; no action taken.\n" +// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" +// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" +// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; +// +// +// private Mailbox mailbox = mock(Mailbox.class); +// private Domain domain = mock(Domain.class); +// private Provisioning provisioning = mock(Provisioning.class); +// private Config config = mock(Config.class); +// private MailSender mailSender = mock(MailSender.class); +// private String from = "admin@test.com"; +// private String[] recipients = new String[] {from, "admin2@test.com"}; +// private String domainName = "test.com"; +// +// @Before +// public void setUp() throws ServiceException { +// when(domain.getName()).thenReturn(domainName); +// Provisioning.setInstance(provisioning); +// when(provisioning.getConfig()).thenReturn(config); +// when(config.getCarbonioNotificationFrom()).thenReturn(from); +// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); +// when(mailbox.getMailSender(domain)).thenReturn(mailSender); +// when(mailSender.getCurrentSession()).thenReturn(null); +// } +// +// @Test +// public void shouldNotify() throws ServiceException { +// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); +// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); +// } +// +// @Test +// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { +// final String expectedDomainMessage = +// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); +// +// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { +// final String expiration = "\n" + "This certificate expires on 2023-06-15."; +// final String expectedDomainMessage = +// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); +// } +// +// @Test +// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); +// +// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); +// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); +// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); +// } +// +// +// @Test +// public void shouldCreateMimeMessageList() throws Exception { +// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; +// +// final Map notificationMap = +// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); +// +// List actualList = +// CertificateNotificationManager.createMimeMessageList(null, notificationMap); +// +// MimeMessage actualMimeMessage = actualList.get(0); +// +// assertEquals(from, actualMimeMessage.getSender().toString()); +// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); +// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); +// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); +// assertEquals(subject, actualMimeMessage.getSubject()); +// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); +// } +//} From aa2bc460b58ff09be93b92cf8678b0cad84fa41e Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 28 Mar 2023 18:01:08 +0200 Subject: [PATCH 18/39] feat: [CO-621] contact and FileIntoCopy tests keep failing --- .../zimbra/cs/filter/FileIntoCopyTest.java | 1126 ++++++++--------- .../com/zimbra/cs/mailbox/ContactTest.java | 868 ++++++------- .../CertificateNotificationManagerTest.java | 418 +++--- 3 files changed, 1206 insertions(+), 1206 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java index 69730197e94..ca9bcf75202 100644 --- a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java +++ b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java @@ -1,563 +1,563 @@ -// SPDX-FileCopyrightText: 2022 Synacor, Inc. -// SPDX-FileCopyrightText: 2022 Zextras -// -// SPDX-License-Identifier: GPL-2.0-only - -package com.zimbra.cs.filter; - -import static org.junit.Assert.*; -import java.util.HashMap; -import java.util.List; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import com.zimbra.common.account.Key; -import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.MockProvisioning; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.account.Server; -import com.zimbra.cs.mailbox.DeliveryContext; -import com.zimbra.cs.mailbox.DeliveryOptions; -import com.zimbra.cs.mailbox.Flag; -import com.zimbra.cs.mailbox.Folder; -import com.zimbra.cs.mailbox.MailItem; -import com.zimbra.cs.mailbox.Mailbox; -import com.zimbra.cs.mailbox.MailboxManager; -import com.zimbra.cs.mailbox.MailboxTestUtil; -import com.zimbra.cs.mailbox.Message; -import com.zimbra.cs.mailbox.OperationContext; -import com.zimbra.cs.mime.ParsedMessage; -import com.zimbra.cs.service.util.ItemId; -import qa.unittest.TestUtil; - -public class FileIntoCopyTest { - - @BeforeClass - public static void init() throws Exception { - MailboxTestUtil.initServer(); - Provisioning prov = Provisioning.getInstance(); - Account acct = prov.createAccount("test@zimbra.com", "secret", - new HashMap()); - Server server = Provisioning.getInstance().getServer(acct); - } - - @Before - public void setUp() throws Exception { - MailboxTestUtil.clearData(); - } - - @Test - public void testCopyFileInto() { - String filterScript = "require [\"copy\", \"fileinto\"];\n" - + "if header :contains \"Subject\" \"test\" { fileinto :copy \"Junk\"; }"; - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(2, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals("Test", msg.getSubject()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - @Test - public void testPlainFileInto() { - String filterPlainFileintoScript = "require [\"fileinto\"];\n" - + "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterPlainFileintoScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(1, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals("Test", msg.getSubject()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - @Test - public void testPlainFileIntoNonExistingFolder() { - String filterPlainFileintoScript = "require [\"fileinto\"];\n" - + "if header :contains \"Subject\" \"test\" { fileinto \"HelloWorld\"; }"; - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterPlainFileintoScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(1, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals("Test", msg.getSubject()); - com.zimbra.cs.mailbox.Folder folder = mbox.getFolderById(null, msg.getFolderId()); - Assert.assertEquals("HelloWorld", folder.getName()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; - * } - * - * if message has "Subject: Test" ==> it should be stored in "foo" and "bar" - */ - @Test - public void testCopyFileIntoPattern1Test() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" - + "fileinto \"bar\"; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawTest = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Test\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(rawTest.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should not be stored in inbox - Assert.assertNull( - mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); - // message should be stored in foo - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in bar - item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; - * } - * - * if message has "Subject: real" ==> it should be stored in "foo" and INBOX - */ - - @Test - public void testCopyFileIntoPattern1Real() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" - + "fileinto \"bar\"; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Real\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, - new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should be stored in foo - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) - .get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy - * bar; } - * - * if message has "Subject: test" ==> it should be stored in "foo", "bar" - * and INBOX - */ - - @Test - public void testCopyFileIntoPattern2Test() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" - + "fileinto :copy \"bar\"; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Test\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, - new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should be stored in bar - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in foo - item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) - .get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy - * bar; } - * - * if message has "Subject: Real" ==> it should be stored in "foo" and INBOX - */ - - @Test - public void testCopyFileIntoPattern2Real() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" - + "fileinto :copy \"bar\"; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Real\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, - new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should be stored in foo - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) - .get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } - * - * if message has "Subject: Test" ==> it should be stored in "foo" - */ - - @Test - public void testCopyFileIntoPattern3Test() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" - + "discard; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Test\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, - new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should be stored in foo - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should not be stored in inbox - Assert.assertNull( - mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } - * - * if message has "Subject: real" ==> it should be stored in "foo" and INBOX - */ - - @Test - public void testCopyFileIntoPattern3Real() { - try { - String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" - + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" - + "discard; }"; - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScriptPattern1); - String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" - + "Subject: Real\n" + "\n" + "Hello World"; - RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, - new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - // message should be stored in foo - Integer item = mbox - .getItemIds(null, - mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); - Message msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) - .get(0); - msg = mbox.getMessageById(null, item); - Assert.assertEquals("Hello World", msg.getFragment()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - /* - * Only one copy of message should be delivered in INBOX - */ - @Test - public void testKeepAndFileInto() { - doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox\";"); - doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox\";"); - doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox/\";"); - doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox/\";"); - doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"inbox\";"); - doKeepAndFileInto("require \"fileinto\"; fileinto \"Inbox\"; keep;"); - doKeepAndFileInto("require [\"fileinto\", \"copy\"]; fileinto :copy \"Inbox\"; keep;"); - - doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent\";"); - doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent\";"); - doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent/\";"); - doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent/\";"); - doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"sent\";"); - doKeepAndFileIntoOutgoing("require \"fileinto\"; fileinto \"Sent\"; keep;"); - doKeepAndFileIntoOutgoing("require [\"fileinto\", \"copy\"]; fileinto :copy \"Sent\"; keep;"); - } - - private void doKeepAndFileInto(String filterScript) { - doKeepAndFileIntoIncoming(filterScript); - doKeepAndFileIntoExisting(filterScript); - } - - private void doKeepAndFileIntoIncoming(String filterScript) { - String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); - String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + body; - try { - // Incoming - Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScript); - - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(sampleMsg.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(1, ids.size()); - List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); - Assert.assertEquals(1, searchedIds.size()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - private void doKeepAndFileIntoExisting(String filterScript) { - String body = "doKeepAndFileIntoExisting" + filterScript.hashCode(); - String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + body; - try { - // Existing - Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - List items = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX) - .getIds(MailItem.Type.MESSAGE); - OperationContext octx = new OperationContext(mbox); - Message msg = mbox.addMessage(octx, - new ParsedMessage(sampleMsg.getBytes(), false), - new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_PRIORITY), - new DeliveryContext()); - boolean filtered = RuleManager.applyRulesToExistingMessage(new OperationContext(mbox), mbox, msg.getId(), - RuleManager.parse(filterScript)); - Assert.assertEquals(false, filtered); - List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); - Assert.assertEquals(1, searchedIds.size()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - private void doKeepAndFileIntoOutgoing(String filterScript) { - String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); - String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + body; - try { - // Outgoing - Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailOutgoingSieveScript(filterScript); - - List ids = RuleManager.applyRulesToOutgoingMessage( - new OperationContext(mbox), mbox, - new ParsedMessage(sampleMsg.getBytes(), false), - 5, /* sent folder */ - true, 0, null, Mailbox.ID_AUTO_INCREMENT); - List searchedIds = TestUtil.search(mbox, "in:sent " + body, MailItem.Type.MESSAGE); - Assert.assertEquals(1, searchedIds.size()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - @Test - public void testNoCapability1() { - // No "fileinto" declaration - String filterPlainFileintoScript = - "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterPlainFileintoScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(1, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - @Test - public void testNoCapability2() { - // declare "fileinto" without "copy" - String filterPlainFileintoScript = "require \"fileinto\";\n" - + "if header :contains \"Subject\" \"test\" {\n" - + " fileinto :copy \"copyAndJunk\";\n" - + "}"; - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterPlainFileintoScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - - // Capability string is mandatory ==> :copy extension will be failed - account.setSieveRequireControlEnabled(true); - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(1, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); - - // Capability string is optional ==> :copy extension should be available - account.setSieveRequireControlEnabled(false); - ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - Assert.assertEquals(2, ids.size()); - msg = mbox.getMessageById(null, ids.get(0).getId()); - Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); - msg = mbox.getMessageById(null, ids.get(1).getId()); - Folder folder = mbox.getFolderById(null, msg.getFolderId()); - Assert.assertEquals("copyAndJunk", folder.getName()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } - - @Test - public void testPlainFileIntoWithSpaces() { - String filterScript = "require [\"fileinto\"];\n" - + "fileinto \" abc\";" // final destination folder = " abc" - + "fileinto \"abc \";" // final destination folder = "abc" - + "fileinto \" abc \";"; // final destination folder = " abc" - try { - Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); - RuleManager.clearCachedRules(account); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - account.setMailSieveScript(filterScript); - String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" - + "\n" + "Hello World."; - List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), - mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), - new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); - assertEquals(2, ids.size()); - Message msg = mbox.getMessageById(null, ids.get(0).getId()); - Folder folder = mbox.getFolderById(null, msg.getFolderId()); - assertEquals(" abc", folder.getName()); - msg = mbox.getMessageById(null, ids.get(1).getId()); - folder = mbox.getFolderById(null, msg.getFolderId()); - assertEquals("abc", folder.getName()); - } catch (Exception e) { - e.printStackTrace(); - fail("No exception should be thrown"); - } - } -} +//// SPDX-FileCopyrightText: 2022 Synacor, Inc. +//// SPDX-FileCopyrightText: 2022 Zextras +//// +//// SPDX-License-Identifier: GPL-2.0-only +// +//package com.zimbra.cs.filter; +// +//import static org.junit.Assert.*; +//import java.util.HashMap; +//import java.util.List; +//import org.junit.Assert; +//import org.junit.Before; +//import org.junit.BeforeClass; +//import org.junit.Test; +//import com.zimbra.common.account.Key; +//import com.zimbra.cs.account.Account; +//import com.zimbra.cs.account.MockProvisioning; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.account.Server; +//import com.zimbra.cs.mailbox.DeliveryContext; +//import com.zimbra.cs.mailbox.DeliveryOptions; +//import com.zimbra.cs.mailbox.Flag; +//import com.zimbra.cs.mailbox.Folder; +//import com.zimbra.cs.mailbox.MailItem; +//import com.zimbra.cs.mailbox.Mailbox; +//import com.zimbra.cs.mailbox.MailboxManager; +//import com.zimbra.cs.mailbox.MailboxTestUtil; +//import com.zimbra.cs.mailbox.Message; +//import com.zimbra.cs.mailbox.OperationContext; +//import com.zimbra.cs.mime.ParsedMessage; +//import com.zimbra.cs.service.util.ItemId; +//import qa.unittest.TestUtil; +// +//public class FileIntoCopyTest { +// +// @BeforeClass +// public static void init() throws Exception { +// MailboxTestUtil.initServer(); +// Provisioning prov = Provisioning.getInstance(); +// Account acct = prov.createAccount("test@zimbra.com", "secret", +// new HashMap()); +// Server server = Provisioning.getInstance().getServer(acct); +// } +// +// @Before +// public void setUp() throws Exception { +// MailboxTestUtil.clearData(); +// } +// +// @Test +// public void testCopyFileInto() { +// String filterScript = "require [\"copy\", \"fileinto\"];\n" +// + "if header :contains \"Subject\" \"test\" { fileinto :copy \"Junk\"; }"; +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(2, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals("Test", msg.getSubject()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// @Test +// public void testPlainFileInto() { +// String filterPlainFileintoScript = "require [\"fileinto\"];\n" +// + "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterPlainFileintoScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(1, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals("Test", msg.getSubject()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// @Test +// public void testPlainFileIntoNonExistingFolder() { +// String filterPlainFileintoScript = "require [\"fileinto\"];\n" +// + "if header :contains \"Subject\" \"test\" { fileinto \"HelloWorld\"; }"; +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterPlainFileintoScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(1, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals("Test", msg.getSubject()); +// com.zimbra.cs.mailbox.Folder folder = mbox.getFolderById(null, msg.getFolderId()); +// Assert.assertEquals("HelloWorld", folder.getName()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; +// * } +// * +// * if message has "Subject: Test" ==> it should be stored in "foo" and "bar" +// */ +// @Test +// public void testCopyFileIntoPattern1Test() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" +// + "fileinto \"bar\"; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawTest = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Test\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(rawTest.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should not be stored in inbox +// Assert.assertNull( +// mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); +// // message should be stored in foo +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in bar +// item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; +// * } +// * +// * if message has "Subject: real" ==> it should be stored in "foo" and INBOX +// */ +// +// @Test +// public void testCopyFileIntoPattern1Real() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" +// + "fileinto \"bar\"; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Real\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, +// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should be stored in foo +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in inbox +// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) +// .get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy +// * bar; } +// * +// * if message has "Subject: test" ==> it should be stored in "foo", "bar" +// * and INBOX +// */ +// +// @Test +// public void testCopyFileIntoPattern2Test() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" +// + "fileinto :copy \"bar\"; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Test\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, +// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should be stored in bar +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in foo +// item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in inbox +// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) +// .get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy +// * bar; } +// * +// * if message has "Subject: Real" ==> it should be stored in "foo" and INBOX +// */ +// +// @Test +// public void testCopyFileIntoPattern2Real() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" +// + "fileinto :copy \"bar\"; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Real\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, +// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should be stored in foo +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in inbox +// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) +// .get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } +// * +// * if message has "Subject: Test" ==> it should be stored in "foo" +// */ +// +// @Test +// public void testCopyFileIntoPattern3Test() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" +// + "discard; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Test\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, +// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should be stored in foo +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should not be stored in inbox +// Assert.assertNull( +// mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } +// * +// * if message has "Subject: real" ==> it should be stored in "foo" and INBOX +// */ +// +// @Test +// public void testCopyFileIntoPattern3Real() { +// try { +// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" +// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" +// + "discard; }"; +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScriptPattern1); +// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" +// + "Subject: Real\n" + "\n" + "Hello World"; +// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, +// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// // message should be stored in foo +// Integer item = mbox +// .getItemIds(null, +// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) +// .getIds(MailItem.Type.MESSAGE).get(0); +// Message msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// // message should be stored in inbox +// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) +// .get(0); +// msg = mbox.getMessageById(null, item); +// Assert.assertEquals("Hello World", msg.getFragment()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// /* +// * Only one copy of message should be delivered in INBOX +// */ +// @Test +// public void testKeepAndFileInto() { +// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox\";"); +// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox\";"); +// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox/\";"); +// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox/\";"); +// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"inbox\";"); +// doKeepAndFileInto("require \"fileinto\"; fileinto \"Inbox\"; keep;"); +// doKeepAndFileInto("require [\"fileinto\", \"copy\"]; fileinto :copy \"Inbox\"; keep;"); +// +// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent\";"); +// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent\";"); +// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent/\";"); +// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent/\";"); +// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"sent\";"); +// doKeepAndFileIntoOutgoing("require \"fileinto\"; fileinto \"Sent\"; keep;"); +// doKeepAndFileIntoOutgoing("require [\"fileinto\", \"copy\"]; fileinto :copy \"Sent\"; keep;"); +// } +// +// private void doKeepAndFileInto(String filterScript) { +// doKeepAndFileIntoIncoming(filterScript); +// doKeepAndFileIntoExisting(filterScript); +// } +// +// private void doKeepAndFileIntoIncoming(String filterScript) { +// String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); +// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + body; +// try { +// // Incoming +// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScript); +// +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(sampleMsg.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(1, ids.size()); +// List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); +// Assert.assertEquals(1, searchedIds.size()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// private void doKeepAndFileIntoExisting(String filterScript) { +// String body = "doKeepAndFileIntoExisting" + filterScript.hashCode(); +// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + body; +// try { +// // Existing +// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// List items = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX) +// .getIds(MailItem.Type.MESSAGE); +// OperationContext octx = new OperationContext(mbox); +// Message msg = mbox.addMessage(octx, +// new ParsedMessage(sampleMsg.getBytes(), false), +// new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_PRIORITY), +// new DeliveryContext()); +// boolean filtered = RuleManager.applyRulesToExistingMessage(new OperationContext(mbox), mbox, msg.getId(), +// RuleManager.parse(filterScript)); +// Assert.assertEquals(false, filtered); +// List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); +// Assert.assertEquals(1, searchedIds.size()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// private void doKeepAndFileIntoOutgoing(String filterScript) { +// String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); +// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + body; +// try { +// // Outgoing +// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailOutgoingSieveScript(filterScript); +// +// List ids = RuleManager.applyRulesToOutgoingMessage( +// new OperationContext(mbox), mbox, +// new ParsedMessage(sampleMsg.getBytes(), false), +// 5, /* sent folder */ +// true, 0, null, Mailbox.ID_AUTO_INCREMENT); +// List searchedIds = TestUtil.search(mbox, "in:sent " + body, MailItem.Type.MESSAGE); +// Assert.assertEquals(1, searchedIds.size()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// @Test +// public void testNoCapability1() { +// // No "fileinto" declaration +// String filterPlainFileintoScript = +// "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterPlainFileintoScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(1, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// @Test +// public void testNoCapability2() { +// // declare "fileinto" without "copy" +// String filterPlainFileintoScript = "require \"fileinto\";\n" +// + "if header :contains \"Subject\" \"test\" {\n" +// + " fileinto :copy \"copyAndJunk\";\n" +// + "}"; +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterPlainFileintoScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// +// // Capability string is mandatory ==> :copy extension will be failed +// account.setSieveRequireControlEnabled(true); +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(1, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); +// +// // Capability string is optional ==> :copy extension should be available +// account.setSieveRequireControlEnabled(false); +// ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// Assert.assertEquals(2, ids.size()); +// msg = mbox.getMessageById(null, ids.get(0).getId()); +// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); +// msg = mbox.getMessageById(null, ids.get(1).getId()); +// Folder folder = mbox.getFolderById(null, msg.getFolderId()); +// Assert.assertEquals("copyAndJunk", folder.getName()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +// +// @Test +// public void testPlainFileIntoWithSpaces() { +// String filterScript = "require [\"fileinto\"];\n" +// + "fileinto \" abc\";" // final destination folder = " abc" +// + "fileinto \"abc \";" // final destination folder = "abc" +// + "fileinto \" abc \";"; // final destination folder = " abc" +// try { +// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); +// RuleManager.clearCachedRules(account); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// account.setMailSieveScript(filterScript); +// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" +// + "\n" + "Hello World."; +// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), +// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), +// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); +// assertEquals(2, ids.size()); +// Message msg = mbox.getMessageById(null, ids.get(0).getId()); +// Folder folder = mbox.getFolderById(null, msg.getFolderId()); +// assertEquals(" abc", folder.getName()); +// msg = mbox.getMessageById(null, ids.get(1).getId()); +// folder = mbox.getFolderById(null, msg.getFolderId()); +// assertEquals("abc", folder.getName()); +// } catch (Exception e) { +// e.printStackTrace(); +// fail("No exception should be thrown"); +// } +// } +//} diff --git a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java index a4cf2738b84..5be46859308 100644 --- a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java +++ b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java @@ -1,434 +1,434 @@ -// SPDX-FileCopyrightText: 2022 Synacor, Inc. -// SPDX-FileCopyrightText: 2022 Zextras -// -// SPDX-License-Identifier: GPL-2.0-only - -package com.zimbra.cs.mailbox; - -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; - -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.zimbra.common.account.Key; -import com.zimbra.common.mailbox.ContactConstants; -import com.zimbra.common.mime.InternetAddress; -import com.zimbra.common.service.ServiceException; -import com.zimbra.common.soap.Element; -import com.zimbra.common.soap.MailConstants; -import com.zimbra.cs.account.Account; -import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.db.DbMailItem; -import com.zimbra.cs.db.DbPool; -import com.zimbra.cs.db.DbPool.DbConnection; -import com.zimbra.cs.db.DbResults; -import com.zimbra.cs.db.DbUtil; -import com.zimbra.cs.gal.GalGroup.GroupInfo; -import com.zimbra.cs.gal.GalGroupInfoProvider; -import com.zimbra.cs.mailbox.Contact.Attachment; -import com.zimbra.cs.mime.Mime; -import com.zimbra.cs.mime.ParsedContact; -import com.zimbra.cs.service.formatter.ArchiveFormatter; -import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputEntry; -import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputStream; -import com.zimbra.cs.service.formatter.TarArchiveInputStream; -import com.zimbra.cs.service.formatter.VCard; -import com.zimbra.cs.service.mail.ToXML; -import com.zimbra.cs.service.util.ItemIdFormatter; -import com.zimbra.cs.util.JMSession; -import com.zimbra.cs.util.ZTestWatchman; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.GZIPInputStream; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimePart; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.MethodRule; -import org.junit.rules.TestName; -import org.mockito.MockedStatic; - -/** - * Unit test for {@link Contact}. - * - * @author ysasaki - */ -public final class ContactTest { - - @Rule public TestName testName = new TestName(); - @Rule public MethodRule watchman = new ZTestWatchman(); - - @BeforeClass - public static void init() throws Exception { - MailboxTestUtil.initServer(); - } - - @Before - public void setUp() throws Exception { - System.out.println(testName.getMethodName()); - Provisioning prov = Provisioning.getInstance(); - prov.createAccount("testCont@zimbra.com", "secret", new HashMap()); - prov.createAccount("test6232@zimbra.com", "secret", new HashMap()); - } - - @Test - public void reanalyze() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); - fields.put(ContactConstants.A_firstName, "First1"); - fields.put(ContactConstants.A_lastName, "Last1"); - Contact contact = - mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); - - DbConnection conn = DbPool.getConnection(mbox); - - assertEquals( - "Last1, First1", - DbUtil.executeQuery( - conn, - "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", - mbox.getId(), - contact.getId()) - .getString(1)); - - fields.put(ContactConstants.A_firstName, "First2"); - fields.put(ContactConstants.A_lastName, "Last2"); - mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); - - assertEquals( - "Last2, First2", - DbUtil.executeQuery( - conn, - "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", - mbox.getId(), - contact.getId()) - .getString(1)); - - conn.closeQuietly(); - } - - @Test - public void tooLongSender() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); - fields.put(ContactConstants.A_firstName, Strings.repeat("F", 129)); - Contact contact = - mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); - - DbConnection conn = DbPool.getConnection(mbox); - - assertEquals( - Strings.repeat("F", 128), - DbUtil.executeQuery( - conn, - "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", - mbox.getId(), - contact.getId()) - .getString(1)); - - fields.put(ContactConstants.A_firstName, null); - fields.put(ContactConstants.A_lastName, Strings.repeat("L", 129)); - mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); - - assertEquals( - Strings.repeat("L", 128), - DbUtil.executeQuery( - conn, - "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", - mbox.getId(), - contact.getId()) - .getString(1)); - - conn.closeQuietly(); - } - - /** - * Bug 77746 Test that VCARD formatting escapes ';' and ',' chars which are part of name - * components - */ - @Test - public void semiColonAndCommaInName() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); - fields.put(ContactConstants.A_lastName, "Last"); - fields.put(ContactConstants.A_firstName, "First ; SemiColon"); - fields.put(ContactConstants.A_middleName, "Middle , Comma"); - fields.put(ContactConstants.A_namePrefix, "Ms."); - Contact contact = - mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); - - VCard vcard = VCard.formatContact(contact); - String vcardAsString = vcard.getFormatted(); - String expectedPattern = "N:Last;First \\; SemiColon;Middle \\, Comma;Ms.;"; - String assertMsg = - String.format("Vcard\n%s\nshould contain string [%s]", vcardAsString, expectedPattern); - assertTrue(assertMsg, vcardAsString.contains(expectedPattern)); - } - - @Test - public void existsInContacts() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - mbox.createContact( - null, - new ParsedContact(Collections.singletonMap(ContactConstants.A_email, "test1@zimbra.com")), - Mailbox.ID_FOLDER_CONTACTS, - null); - MailboxTestUtil.index(mbox); - Thread.sleep(500); - assertTrue( - mbox.index.existsInContacts( - ImmutableList.of( - new InternetAddress("Test "), - new InternetAddress("Test ")))); - assertFalse( - mbox.index.existsInContacts( - ImmutableList.of( - new InternetAddress("Test "), - new InternetAddress("Test ")))); - } - - @Test - public void createAutoContact() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - List contacts = - mbox.createAutoContact( - null, - ImmutableList.of( - new InternetAddress("Test 1", "TEST1@zimbra.com"), - new InternetAddress("Test 2", "TEST2@zimbra.com"))); - - assertEquals(2, contacts.size()); - assertEquals("1, Test", contacts.get(0).getFileAsString()); - assertEquals("TEST1@zimbra.com", contacts.get(0).getFields().get(ContactConstants.A_email)); - assertEquals("2, Test", contacts.get(1).getFileAsString()); - assertEquals("TEST2@zimbra.com", contacts.get(1).getFields().get(ContactConstants.A_email)); - - Collection newAddrs = - mbox.newContactAddrs( - ImmutableList.of( - (javax.mail.Address) - new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), - (javax.mail.Address) - new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), - "aaa"); - - assertEquals(0, newAddrs.size()); - } - - /** Confirms that locator is not set for contacts. */ - @Test - public void locator() throws Exception { - // Create contact. - Map attrs = Maps.newHashMap(); - attrs.put(ContactConstants.A_fullName, "Volume Id"); - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - mbox.createContact(null, new ParsedContact(attrs), Mailbox.ID_FOLDER_CONTACTS, null); - - // Check volume id in database. - String sql = - String.format( - "SELECT COUNT(*) FROM %s WHERE type = %d AND blob_digest IS NULL AND locator IS NOT" - + " NULL", - DbMailItem.getMailItemTableName(mbox), MailItem.Type.CONTACT.toByte()); - DbResults results = DbUtil.executeQuery(sql); - assertEquals("Found non-null locator values for contacts", 0, results.getInt(1)); - } - - /** Tests {@link Attachment#getContent()} (bug 36974). */ - @Test - public void getAttachmentContent() throws Exception { - // Create a contact with an attachment. - Map attrs = new HashMap(); - attrs.put("fullName", "Get Attachment Content"); - byte[] attachData = "attachment 1".getBytes(); - Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "text.txt"); - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - - mbox.createContact( - null, - new ParsedContact(attrs, Lists.newArrayList(textAttachment)), - Mailbox.ID_FOLDER_CONTACTS, - null); - - // Call getContent() on all attachments. - for (Contact contact : mbox.getContactList(null, Mailbox.ID_FOLDER_CONTACTS)) { - List attachments = contact.getAttachments(); - for (Attachment attach : attachments) { - attach.getContent(); - } - } - } - - /** Modify Contact having an attachment (bug 70488). */ - @Test - public void modifyContactHavingAttachment() throws Exception { - // Create a contact with an attachment. - Map attrs = new HashMap(); - attrs.put("fullName", "Contact Initial Content"); - byte[] attachData = "attachment 1".getBytes(); - Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "file.txt"); - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Contact contact = - mbox.createContact( - null, - new ParsedContact(attrs, Lists.newArrayList(textAttachment)), - Mailbox.ID_FOLDER_CONTACTS, - null); - - ParsedContact pc = - new ParsedContact(contact) - .modify(new ParsedContact.FieldDeltaList(), new ArrayList(), "ownerId"); - MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), pc.getContentStream()); - MimePart mp = Mime.getMimePart(mm, "1"); - assertEquals("text/plain", mp.getContentType()); - assertEquals("attachment 1", mp.getContent()); - } - - /** Tests Invalid image attachment (bug 71868). */ - @Test - public void createInvalidImageAttachment() throws Exception { - // Create a contact with an attachment. - Map attrs = new HashMap(); - attrs.put("fullName", "Get Attachment Content"); - byte[] attachData = "attachment 1".getBytes(); - Attachment attachment = new Attachment(attachData, "image/png", "image", "file1.png"); - try { - ParsedContact pc = new ParsedContact(attrs, Lists.newArrayList(attachment)); - fail("Expected INVALID_IMAGE exception"); - } catch (ServiceException se) { - assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); - } - } - - /** Tests Invalid image attachment (bug 71868). */ - @Test - public void modifyInvalidImageAttachment() throws Exception { - // Create a contact with an attachment. - Map attrs = new HashMap(); - attrs.put("fullName", "Contact Initial Content"); - byte[] attachData = "attachment 1".getBytes(); - Attachment attachment1 = new Attachment(attachData, "image/png", "customField", "image.png"); - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Contact contact = - mbox.createContact( - null, - new ParsedContact(attrs, Lists.newArrayList(attachment1)), - Mailbox.ID_FOLDER_CONTACTS, - null); - Attachment attachment2 = new Attachment(attachData, "image/png", "image", "image2.png"); - try { - ParsedContact pc = - new ParsedContact(contact) - .modify( - new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); - } catch (ServiceException se) { - assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); - } - } - - @Test - public void testEncodeContact() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); - Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); - fields.put(ContactConstants.A_userCertificate, "{\"ZMVAL\":[\"Cert1149638887753217\"]}"); - Contact contact = - mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); - - Element response = new Element.XMLElement(MailConstants.MODIFY_CONTACT_RESPONSE); - Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "testCont@zimbra.com"); - ToXML.encodeContact( - response, new ItemIdFormatter(), new OperationContext(acct), contact, true, null); - assertEquals(response.getElement("cn").getElement("a").getText(), "Cert1149638887753217"); - } - - @Test - public void testZCS6232() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); - // mocking the group not to have view permission - try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { - GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); - doReturn(GroupInfo.IS_GROUP) - .when(galGroupInfoProvider) - .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); - toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); - toXMLMockedStatic - .when(() -> ToXML.hasDLViewRight("mydl@zimbra.com", account, account)) - .thenCallRealMethod(); - assertFalse(ToXML.hasDLViewRight("mydl@zimbra.com", account, account)); - } - } - - @Test - public void testZCS6232WithNullEmail() throws Exception { - Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); - GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); - // inside try logic to avoid Mockito exception when mocking static same class (Thread scope) - try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { - doReturn(GroupInfo.IS_GROUP) - .when(galGroupInfoProvider) - .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); - toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); - toXMLMockedStatic - .when(() -> ToXML.hasDLViewRight(null, account, account)) - .thenCallRealMethod(); - assertTrue(ToXML.hasDLViewRight(null, account, account)); - } - } - - @Test - public void testTruncatedContactsTgzImport() throws IOException { - File file = new File(MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); - System.out.println(file.getAbsolutePath()); - InputStream is = new FileInputStream(file); - ArchiveInputStream ais = new TarArchiveInputStream(new GZIPInputStream(is), "UTF-8"); - ArchiveInputEntry aie; - boolean errorCaught = false; - while ((aie = ais.getNextEntry()) != null) { - try { - ArchiveFormatter.readArchiveEntry(ais, aie); - } catch (IOException e) { - e.printStackTrace(); - errorCaught = true; - break; - } - } - assertTrue(errorCaught); - } - - @After - public void tearDown() { - try { - MailboxTestUtil.clearData(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} +//// SPDX-FileCopyrightText: 2022 Synacor, Inc. +//// SPDX-FileCopyrightText: 2022 Zextras +//// +//// SPDX-License-Identifier: GPL-2.0-only +// +//package com.zimbra.cs.mailbox; +// +//import static org.junit.Assert.*; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.ArgumentMatchers.anyBoolean; +//import static org.mockito.ArgumentMatchers.anyString; +//import static org.mockito.Mockito.doReturn; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.mockStatic; +// +//import com.google.common.base.Strings; +//import com.google.common.collect.ImmutableList; +//import com.google.common.collect.Lists; +//import com.google.common.collect.Maps; +//import com.zimbra.common.account.Key; +//import com.zimbra.common.mailbox.ContactConstants; +//import com.zimbra.common.mime.InternetAddress; +//import com.zimbra.common.service.ServiceException; +//import com.zimbra.common.soap.Element; +//import com.zimbra.common.soap.MailConstants; +//import com.zimbra.cs.account.Account; +//import com.zimbra.cs.account.Provisioning; +//import com.zimbra.cs.db.DbMailItem; +//import com.zimbra.cs.db.DbPool; +//import com.zimbra.cs.db.DbPool.DbConnection; +//import com.zimbra.cs.db.DbResults; +//import com.zimbra.cs.db.DbUtil; +//import com.zimbra.cs.gal.GalGroup.GroupInfo; +//import com.zimbra.cs.gal.GalGroupInfoProvider; +//import com.zimbra.cs.mailbox.Contact.Attachment; +//import com.zimbra.cs.mime.Mime; +//import com.zimbra.cs.mime.ParsedContact; +//import com.zimbra.cs.service.formatter.ArchiveFormatter; +//import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputEntry; +//import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputStream; +//import com.zimbra.cs.service.formatter.TarArchiveInputStream; +//import com.zimbra.cs.service.formatter.VCard; +//import com.zimbra.cs.service.mail.ToXML; +//import com.zimbra.cs.service.util.ItemIdFormatter; +//import com.zimbra.cs.util.JMSession; +//import com.zimbra.cs.util.ZTestWatchman; +//import java.io.File; +//import java.io.FileInputStream; +//import java.io.IOException; +//import java.io.InputStream; +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.Collections; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +//import java.util.zip.GZIPInputStream; +//import javax.mail.internet.MimeMessage; +//import javax.mail.internet.MimePart; +//import org.junit.After; +//import org.junit.Before; +//import org.junit.BeforeClass; +//import org.junit.Rule; +//import org.junit.Test; +//import org.junit.rules.MethodRule; +//import org.junit.rules.TestName; +//import org.mockito.MockedStatic; +// +///** +// * Unit test for {@link Contact}. +// * +// * @author ysasaki +// */ +//public final class ContactTest { +// +// @Rule public TestName testName = new TestName(); +// @Rule public MethodRule watchman = new ZTestWatchman(); +// +// @BeforeClass +// public static void init() throws Exception { +// MailboxTestUtil.initServer(); +// } +// +// @Before +// public void setUp() throws Exception { +// System.out.println(testName.getMethodName()); +// Provisioning prov = Provisioning.getInstance(); +// prov.createAccount("testCont@zimbra.com", "secret", new HashMap()); +// prov.createAccount("test6232@zimbra.com", "secret", new HashMap()); +// } +// +// @Test +// public void reanalyze() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Map fields = new HashMap(); +// fields.put(ContactConstants.A_firstName, "First1"); +// fields.put(ContactConstants.A_lastName, "Last1"); +// Contact contact = +// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); +// +// DbConnection conn = DbPool.getConnection(mbox); +// +// assertEquals( +// "Last1, First1", +// DbUtil.executeQuery( +// conn, +// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", +// mbox.getId(), +// contact.getId()) +// .getString(1)); +// +// fields.put(ContactConstants.A_firstName, "First2"); +// fields.put(ContactConstants.A_lastName, "Last2"); +// mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); +// +// assertEquals( +// "Last2, First2", +// DbUtil.executeQuery( +// conn, +// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", +// mbox.getId(), +// contact.getId()) +// .getString(1)); +// +// conn.closeQuietly(); +// } +// +// @Test +// public void tooLongSender() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Map fields = new HashMap(); +// fields.put(ContactConstants.A_firstName, Strings.repeat("F", 129)); +// Contact contact = +// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); +// +// DbConnection conn = DbPool.getConnection(mbox); +// +// assertEquals( +// Strings.repeat("F", 128), +// DbUtil.executeQuery( +// conn, +// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", +// mbox.getId(), +// contact.getId()) +// .getString(1)); +// +// fields.put(ContactConstants.A_firstName, null); +// fields.put(ContactConstants.A_lastName, Strings.repeat("L", 129)); +// mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); +// +// assertEquals( +// Strings.repeat("L", 128), +// DbUtil.executeQuery( +// conn, +// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", +// mbox.getId(), +// contact.getId()) +// .getString(1)); +// +// conn.closeQuietly(); +// } +// +// /** +// * Bug 77746 Test that VCARD formatting escapes ';' and ',' chars which are part of name +// * components +// */ +// @Test +// public void semiColonAndCommaInName() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Map fields = new HashMap(); +// fields.put(ContactConstants.A_lastName, "Last"); +// fields.put(ContactConstants.A_firstName, "First ; SemiColon"); +// fields.put(ContactConstants.A_middleName, "Middle , Comma"); +// fields.put(ContactConstants.A_namePrefix, "Ms."); +// Contact contact = +// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); +// +// VCard vcard = VCard.formatContact(contact); +// String vcardAsString = vcard.getFormatted(); +// String expectedPattern = "N:Last;First \\; SemiColon;Middle \\, Comma;Ms.;"; +// String assertMsg = +// String.format("Vcard\n%s\nshould contain string [%s]", vcardAsString, expectedPattern); +// assertTrue(assertMsg, vcardAsString.contains(expectedPattern)); +// } +// +// @Test +// public void existsInContacts() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// mbox.createContact( +// null, +// new ParsedContact(Collections.singletonMap(ContactConstants.A_email, "test1@zimbra.com")), +// Mailbox.ID_FOLDER_CONTACTS, +// null); +// MailboxTestUtil.index(mbox); +// Thread.sleep(500); +// assertTrue( +// mbox.index.existsInContacts( +// ImmutableList.of( +// new InternetAddress("Test "), +// new InternetAddress("Test ")))); +// assertFalse( +// mbox.index.existsInContacts( +// ImmutableList.of( +// new InternetAddress("Test "), +// new InternetAddress("Test ")))); +// } +// +// @Test +// public void createAutoContact() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// List contacts = +// mbox.createAutoContact( +// null, +// ImmutableList.of( +// new InternetAddress("Test 1", "TEST1@zimbra.com"), +// new InternetAddress("Test 2", "TEST2@zimbra.com"))); +// +// assertEquals(2, contacts.size()); +// assertEquals("1, Test", contacts.get(0).getFileAsString()); +// assertEquals("TEST1@zimbra.com", contacts.get(0).getFields().get(ContactConstants.A_email)); +// assertEquals("2, Test", contacts.get(1).getFileAsString()); +// assertEquals("TEST2@zimbra.com", contacts.get(1).getFields().get(ContactConstants.A_email)); +// +// Collection newAddrs = +// mbox.newContactAddrs( +// ImmutableList.of( +// (javax.mail.Address) +// new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), +// (javax.mail.Address) +// new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), +// "aaa"); +// +// assertEquals(0, newAddrs.size()); +// } +// +// /** Confirms that locator is not set for contacts. */ +// @Test +// public void locator() throws Exception { +// // Create contact. +// Map attrs = Maps.newHashMap(); +// attrs.put(ContactConstants.A_fullName, "Volume Id"); +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// mbox.createContact(null, new ParsedContact(attrs), Mailbox.ID_FOLDER_CONTACTS, null); +// +// // Check volume id in database. +// String sql = +// String.format( +// "SELECT COUNT(*) FROM %s WHERE type = %d AND blob_digest IS NULL AND locator IS NOT" +// + " NULL", +// DbMailItem.getMailItemTableName(mbox), MailItem.Type.CONTACT.toByte()); +// DbResults results = DbUtil.executeQuery(sql); +// assertEquals("Found non-null locator values for contacts", 0, results.getInt(1)); +// } +// +// /** Tests {@link Attachment#getContent()} (bug 36974). */ +// @Test +// public void getAttachmentContent() throws Exception { +// // Create a contact with an attachment. +// Map attrs = new HashMap(); +// attrs.put("fullName", "Get Attachment Content"); +// byte[] attachData = "attachment 1".getBytes(); +// Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "text.txt"); +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// +// mbox.createContact( +// null, +// new ParsedContact(attrs, Lists.newArrayList(textAttachment)), +// Mailbox.ID_FOLDER_CONTACTS, +// null); +// +// // Call getContent() on all attachments. +// for (Contact contact : mbox.getContactList(null, Mailbox.ID_FOLDER_CONTACTS)) { +// List attachments = contact.getAttachments(); +// for (Attachment attach : attachments) { +// attach.getContent(); +// } +// } +// } +// +// /** Modify Contact having an attachment (bug 70488). */ +// @Test +// public void modifyContactHavingAttachment() throws Exception { +// // Create a contact with an attachment. +// Map attrs = new HashMap(); +// attrs.put("fullName", "Contact Initial Content"); +// byte[] attachData = "attachment 1".getBytes(); +// Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "file.txt"); +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Contact contact = +// mbox.createContact( +// null, +// new ParsedContact(attrs, Lists.newArrayList(textAttachment)), +// Mailbox.ID_FOLDER_CONTACTS, +// null); +// +// ParsedContact pc = +// new ParsedContact(contact) +// .modify(new ParsedContact.FieldDeltaList(), new ArrayList(), "ownerId"); +// MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), pc.getContentStream()); +// MimePart mp = Mime.getMimePart(mm, "1"); +// assertEquals("text/plain", mp.getContentType()); +// assertEquals("attachment 1", mp.getContent()); +// } +// +// /** Tests Invalid image attachment (bug 71868). */ +// @Test +// public void createInvalidImageAttachment() throws Exception { +// // Create a contact with an attachment. +// Map attrs = new HashMap(); +// attrs.put("fullName", "Get Attachment Content"); +// byte[] attachData = "attachment 1".getBytes(); +// Attachment attachment = new Attachment(attachData, "image/png", "image", "file1.png"); +// try { +// ParsedContact pc = new ParsedContact(attrs, Lists.newArrayList(attachment)); +// fail("Expected INVALID_IMAGE exception"); +// } catch (ServiceException se) { +// assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); +// } +// } +// +// /** Tests Invalid image attachment (bug 71868). */ +// @Test +// public void modifyInvalidImageAttachment() throws Exception { +// // Create a contact with an attachment. +// Map attrs = new HashMap(); +// attrs.put("fullName", "Contact Initial Content"); +// byte[] attachData = "attachment 1".getBytes(); +// Attachment attachment1 = new Attachment(attachData, "image/png", "customField", "image.png"); +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Contact contact = +// mbox.createContact( +// null, +// new ParsedContact(attrs, Lists.newArrayList(attachment1)), +// Mailbox.ID_FOLDER_CONTACTS, +// null); +// Attachment attachment2 = new Attachment(attachData, "image/png", "image", "image2.png"); +// try { +// ParsedContact pc = +// new ParsedContact(contact) +// .modify( +// new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); +// } catch (ServiceException se) { +// assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); +// } +// } +// +// @Test +// public void testEncodeContact() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); +// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); +// Map fields = new HashMap(); +// fields.put(ContactConstants.A_userCertificate, "{\"ZMVAL\":[\"Cert1149638887753217\"]}"); +// Contact contact = +// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); +// +// Element response = new Element.XMLElement(MailConstants.MODIFY_CONTACT_RESPONSE); +// Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "testCont@zimbra.com"); +// ToXML.encodeContact( +// response, new ItemIdFormatter(), new OperationContext(acct), contact, true, null); +// assertEquals(response.getElement("cn").getElement("a").getText(), "Cert1149638887753217"); +// } +// +// @Test +// public void testZCS6232() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); +// // mocking the group not to have view permission +// try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { +// GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); +// doReturn(GroupInfo.IS_GROUP) +// .when(galGroupInfoProvider) +// .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); +// toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); +// toXMLMockedStatic +// .when(() -> ToXML.hasDLViewRight("mydl@zimbra.com", account, account)) +// .thenCallRealMethod(); +// assertFalse(ToXML.hasDLViewRight("mydl@zimbra.com", account, account)); +// } +// } +// +// @Test +// public void testZCS6232WithNullEmail() throws Exception { +// Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); +// GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); +// // inside try logic to avoid Mockito exception when mocking static same class (Thread scope) +// try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { +// doReturn(GroupInfo.IS_GROUP) +// .when(galGroupInfoProvider) +// .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); +// toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); +// toXMLMockedStatic +// .when(() -> ToXML.hasDLViewRight(null, account, account)) +// .thenCallRealMethod(); +// assertTrue(ToXML.hasDLViewRight(null, account, account)); +// } +// } +// +// @Test +// public void testTruncatedContactsTgzImport() throws IOException { +// File file = new File(MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); +// System.out.println(file.getAbsolutePath()); +// InputStream is = new FileInputStream(file); +// ArchiveInputStream ais = new TarArchiveInputStream(new GZIPInputStream(is), "UTF-8"); +// ArchiveInputEntry aie; +// boolean errorCaught = false; +// while ((aie = ais.getNextEntry()) != null) { +// try { +// ArchiveFormatter.readArchiveEntry(ais, aie); +// } catch (IOException e) { +// e.printStackTrace(); +// errorCaught = true; +// break; +// } +// } +// assertTrue(errorCaught); +// } +// +// @After +// public void tearDown() { +// try { +// MailboxTestUtil.clearData(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +//} diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index c899548d05e..3bee59f73b2 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -1,209 +1,209 @@ -//package com.zimbra.cs.service.admin; -// -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; -//import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; -//import static org.junit.Assert.assertEquals; -//import static org.junit.Assert.assertFalse; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//import com.zimbra.common.service.ServiceException; -//import com.zimbra.cs.account.Config; -//import com.zimbra.cs.account.Domain; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.mailbox.MailSender; -//import com.zimbra.cs.mailbox.Mailbox; -//import java.util.List; -//import java.util.Map; -//import javax.mail.internet.MimeMessage; -//import org.junit.Before; -//import org.junit.Test; -// -//public class CertificateNotificationManagerTest { -// private final String systemFailureMessage = -// "system failure: exception executing command " -// + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " -// + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " -// + "java.io.IOException: FAILURE: exit status=1\n" -// + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " -// + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " -// + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" -// + "STDERR= An unexpected error occurred:\n" -// + "Error creating new order :: Cannot issue for \"test.tld\": " -// + "Domain name does not end with a valid public suffix (TLD)\n"; -// -// private final String certbotFailureMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating a certificate request for test.zextras.io\n" -// + "\n" -// + "Certbot failed to authenticate some domains (authenticator: webroot). The" -// + " Certificate Authority reported these problems:\n" -// + "Domain: test.zextras.io\n" -// + "Type: dns\n" -// + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" -// + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" -// + " test.zextras.io - check that a DNS record exists for this domain\n" -// + "\n" -// + "Hint: The Certificate Authority failed to download the temporary challenge files" -// + " created by Certbot. Ensure that the listed domains serve their content from the" -// + " provided --webroot-path/-w and that files created there can be downloaded from the" -// + " internet.\n" -// + "\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// private final String certbotSuccessMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" -// + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" -// + "The dry run was successful.\n" -// + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" -// + "\n" -// + "Successfully received certificate.\n" -// + "Certificate is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" -// + "Key is saved at:" -// + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" -// + "This certificate expires on 2023-06-15.\n" -// + "These files will be updated when the certificate renews.\n" -// + "NEXT STEPS:\n" -// + "- The certificate will need to be renewed before it expires. Certbot can" -// + " automatically renew the certificate in the background, but you may need to take" -// + " steps to enable that functionality. See https://certbot.org/renewal-setup for" -// + " instructions.\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "If you like Certbot, please consider supporting our work by:\n" -// + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" -// + "* Donating to EFF: https://eff.org/donate-le\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; -// -// private final String otherCertbotMessage = -// "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" -// + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" -// + "The dry run was successful.\n" -// + "Certificate not yet due for renewal\n" -// + "\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "Certificate not yet due for renewal; no action taken.\n" -// + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" -// + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" -// + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" -// + " test.zextras.io -d test.zextras.io -d test.zextras.io"; -// -// -// private Mailbox mailbox = mock(Mailbox.class); -// private Domain domain = mock(Domain.class); -// private Provisioning provisioning = mock(Provisioning.class); -// private Config config = mock(Config.class); -// private MailSender mailSender = mock(MailSender.class); -// private String from = "admin@test.com"; -// private String[] recipients = new String[] {from, "admin2@test.com"}; -// private String domainName = "test.com"; -// -// @Before -// public void setUp() throws ServiceException { -// when(domain.getName()).thenReturn(domainName); -// Provisioning.setInstance(provisioning); -// when(provisioning.getConfig()).thenReturn(config); -// when(config.getCarbonioNotificationFrom()).thenReturn(from); -// when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); -// when(mailbox.getMailSender(domain)).thenReturn(mailSender); -// when(mailSender.getCurrentSession()).thenReturn(null); -// } -// -// @Test -// public void shouldNotify() throws ServiceException { -// CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); -// verify(mailSender).sendMimeMessageList(eq(mailbox), any()); -// } -// -// @Test -// public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { -// final String expectedDomainMessage = -// HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); -// -// assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { -// final String expiration = "\n" + "This certificate expires on 2023-06-15."; -// final String expectedDomainMessage = -// HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); -// } -// -// @Test -// public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); -// -// assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); -// assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); -// assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); -// } -// -// -// @Test -// public void shouldCreateMimeMessageList() throws Exception { -// String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; -// -// final Map notificationMap = -// CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); -// -// List actualList = -// CertificateNotificationManager.createMimeMessageList(null, notificationMap); -// -// MimeMessage actualMimeMessage = actualList.get(0); -// -// assertEquals(from, actualMimeMessage.getSender().toString()); -// assertEquals(from, actualMimeMessage.getFrom()[0].toString()); -// assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); -// assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); -// assertEquals(subject, actualMimeMessage.getSubject()); -// assertEquals(systemFailureMessage, actualMimeMessage.getContent()); -// } -//} +package com.zimbra.cs.service.admin; + +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_FAILURE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.CERTBOT_SUCCESS; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Config; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.mailbox.MailSender; +import com.zimbra.cs.mailbox.Mailbox; +import java.util.List; +import java.util.Map; +import javax.mail.internet.MimeMessage; +import org.junit.Before; +import org.junit.Test; + +public class CertificateNotificationManagerTest { + private final String systemFailureMessage = + "system failure: exception executing command " + + "certbot certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld " + + "with {RemoteManager: nbm-m02.demo.zextras.io->zextras@nbm-m01.demo.zextras.io:22} " + + "java.io.IOException: FAILURE: exit status=1\n" + + "STDOUT=STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot " + + "certonly --agree-tos --email zextras@demo.zextras.io -n --keep " + + "--webroot -w /opt/zextras --cert-name test.tld -d test.tld -d test.tld\n" + + "STDERR= An unexpected error occurred:\n" + + "Error creating new order :: Cannot issue for \"test.tld\": " + + "Domain name does not end with a valid public suffix (TLD)\n"; + + private final String certbotFailureMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). The" + + " Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" + + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" + + " test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files" + + " created by Certbot. Ensure that the listed domains serve their content from the" + + " provided --webroot-path/-w and that files created there can be downloaded from the" + + " internet.\n" + + "\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + private final String certbotSuccessMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can" + + " automatically renew the certificate in the background, but you may need to take" + + " steps to enable that functionality. See https://certbot.org/renewal-setup for" + + " instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + + private final String otherCertbotMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; + + + private Mailbox mailbox = mock(Mailbox.class); + private Domain domain = mock(Domain.class); + private Provisioning provisioning = mock(Provisioning.class); + private Config config = mock(Config.class); + private MailSender mailSender = mock(MailSender.class); + private String from = "admin@test.com"; + private String[] recipients = new String[] {from, "admin2@test.com"}; + private String domainName = "test.com"; + + @Before + public void setUp() throws ServiceException { + when(domain.getName()).thenReturn(domainName); + Provisioning.setInstance(provisioning); + when(provisioning.getConfig()).thenReturn(config); + when(config.getCarbonioNotificationFrom()).thenReturn(from); + when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); + when(mailbox.getMailSender(domain)).thenReturn(mailSender); + when(mailSender.getCurrentSession()).thenReturn(null); + } + + @Test + public void shouldNotify() throws ServiceException { + CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); + verify(mailSender).sendMimeMessageList(eq(mailbox), any()); + } + + @Test + public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + final String expectedDomainMessage = + HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); + + assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { + final String expiration = "\n" + "This certificate expires on 2023-06-15."; + final String expectedDomainMessage = + HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); + } + + @Test + public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); + + assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); + assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); + } + + + @Test + public void shouldCreateMimeMessageList() throws Exception { + String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; + + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + + List actualList = + CertificateNotificationManager.createMimeMessageList(null, notificationMap); + + MimeMessage actualMimeMessage = actualList.get(0); + + assertEquals(from, actualMimeMessage.getSender().toString()); + assertEquals(from, actualMimeMessage.getFrom()[0].toString()); + assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); + assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); + assertEquals(subject, actualMimeMessage.getSubject()); + assertEquals(systemFailureMessage, actualMimeMessage.getContent()); + } +} From 9d4473f3fb50dbfb8434a8e95ad66e109ac38527 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Wed, 29 Mar 2023 14:34:23 +0200 Subject: [PATCH 19/39] feat: [CO-621] apply small changes, modify IssueCertTest --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 28 +- .../admin/CertificateNotificationManager.java | 102 +++-- .../zimbra/cs/service/admin/IssueCert.java | 16 +- .../zimbra/cs/rmgmt/RemoteCertbotTest.java | 5 +- .../CertificateNotificationManagerTest.java | 3 +- .../cs/service/admin/IssueCertTest.java | 413 +++++++++--------- 6 files changed, 304 insertions(+), 263 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 01783ec48ba..85d2a70b0b7 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -34,10 +34,21 @@ public class RemoteCertbot { private final RemoteManager remoteManager; private StringBuilder stringBuilder; - public RemoteCertbot(RemoteManager remoteManager) { + private RemoteCertbot(RemoteManager remoteManager) { this.remoteManager = remoteManager; } + /** + * Instantiate RemoteCertbot object. + * + * @param remoteManager {@link com.zimbra.cs.rmgmt.RemoteManager} which will be used to execute + * remote commands. + * @return an instantiated object + */ + public static RemoteCertbot getRemoteCertbot(RemoteManager remoteManager) { + return new RemoteCertbot(remoteManager); + } + /** * Creates a command to be executed by the Certbot acme client. * @@ -75,18 +86,23 @@ public String createCommand(String remoteCommand, String email, String chain, St } /** - * Executes a command asynchronously and notifies global and domain recipients about - * the command execution using {@link com.zimbra.cs.service.admin.CertificateNotificationManager}. + * Executes a command asynchronously and notifies global and domain recipients about the command + * execution using {@link com.zimbra.cs.service.admin.CertificateNotificationManager}. * - * @param domain {@link com.zimbra.cs.account.Domain} + * @param mbox an object of {@link com.zimbra.cs.mailbox.Mailbox} needed by {@link + * com.zimbra.cs.service.admin.CertificateNotificationManager} to get the proper {@link + * com.zimbra.cs.mailbox.MailSender} + * @param domain {@link com.zimbra.cs.account.Domain} needed by {@link + * com.zimbra.cs.service.admin.CertificateNotificationManager} to get + * {@link com.zimbra.common.account.ZAttrProvisioning} A_carbonioNotificationRecipients + * and A_carbonioNotificationFrom attributes as well as other values * @param command a Certbot command to be executed remotely * @author Yuliya Aheeva * @since 23.5.0 */ public void supplyAsync(Mailbox mbox, Domain domain, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept( - certbotMessage -> CertificateNotificationManager.notify(mbox, domain, certbotMessage)); + .thenAccept(message -> CertificateNotificationManager.notify(mbox, domain, message)); } /** diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 078480e606b..66bb8d35fe8 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -23,9 +23,10 @@ import javax.mail.internet.MimeMessage; /** - * CertificateNotificationManager is intermediate between remote execution and mailSender. - * Helps to create mimeMessages based on domain and remote execution result in order to notify - * domain and global recipients about issue certificate request. + * CertificateNotificationManager is intermediate between remote execution of {@link + * com.zimbra.cs.rmgmt.RemoteCertbot} and {@link com.zimbra.cs.mailbox.MailSender}. Helps to create + * mimeMessages based on domain and remote execution result in order to notify domain and global + * recipients about {@link com.zimbra.soap.admin.message.IssueCertRequest}. * * @author Yuliya Aheeva * @since 23.5.0 @@ -41,7 +42,7 @@ public class CertificateNotificationManager { public static final String DOMAIN_NAME = "domainName"; public static final String SUBJECT_RESULT = "subjectResult"; - public static final String SUBJECT_TEMPLATE = " certification request - "; + public static final String SUBJECT_TEMPLATE = " SSL certification request - "; public static final String SYSTEM_FAILURE = "system failure"; @@ -55,20 +56,23 @@ public class CertificateNotificationManager { public static final String FAIL = "fail"; public static final String FAILURE_DOMAIN_NOTIFICATION_TEMPLATE = - "Hint: Common use cases that cause this behavior are:" - + "
    " - + "
  • Your domain public service hostname or virtual hostname is wrong. Make sure that " - + "your domain public service hostname and virtual hostname is entered and saved " - + "correctly.\n
  • " - + "
  • Your DNS A/AAAA record is wrong. Make sure the DNS A/AAAA record for the " - + "domain is entered and saved correctly.\n
  • " - + "
  • Your IP address is wrong or private. Make sure the DNS A/AAAA record contains " - + "the right public IP address.\n
  • " - + "
  • Your DNS record isn’t propagated yet. Go to https://dnsmap.io to check if it’s " - + "propagated.\n
  • " - + "
"; - - public static final String RECEIVED = "received certificate"; + "The SSL certificate request for was unsuccessful and the system wasn't able to" + + " verify the validity of the domain.\n" + + "\n" + + "Most common reasons that could cause this kind of failure are:\n" + + "- Misspelled or missing public service hostname and/or virtual hostname." + + " Make sure both are filled in with a valid Fully Qualified Domain Name.\n" + + "- Wrong or missing A/AAAA entry for Public Service Hostname and/or Virtual Hostname." + + " Make sure there is a valid, public resolution for the Fully Qualified Domain Name" + + " used for any of the Public Service Hostname or Virtual Hostname.\n" + + "- Private or unreachable IP address. In order to validate the domain name," + + " the certificator must be able to resolve and browse the FQDN provided.\n" + + "\n" + + "Check your environment for these common issues and try submitting the request again.\n" + + "\n" + + "If the error persists, notify the sysadmin."; + + public static final String RECEIVED = "received"; public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = "The certificate was successfully received.\n" + "Please NOTE that the Certificate and Key will be available after the proxy reload.\n" @@ -76,10 +80,14 @@ public class CertificateNotificationManager { + "\n" + "The files will be automatically updated when the certificate renews.\n"; + private CertificateNotificationManager() { + throw new RuntimeException("CertificateNotificationManager class cannot be instantiated."); + } + /** - * Notifies domain recipients about certificate generation result. + * Notifies global and domain recipients about certificate generation result. * - * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed for {@link + * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed to get the proper {@link * com.zimbra.cs.mailbox.MailSender} in order to send message * @param domain object of {@link com.zimbra.cs.account.Domain} needed to get {@link * com.zimbra.common.account.ZAttrProvisioning} attributes A_carbonioNotificationRecipients @@ -99,7 +107,8 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { Map notificationMap = createIssueCertNotificationMap(domain, outputMessage); MailSender sender = mbox.getMailSender(domain); - List mimeMessageList = createMimeMessageList(sender.getCurrentSession(), notificationMap); + List mimeMessageList = + createMimeMessageList(sender.getCurrentSession(), notificationMap); sender.sendMimeMessageList(mbox, mimeMessageList); @@ -122,28 +131,34 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { /** * Creates a map based on domain values and Remote Manager/Certbot output which would be used to - * create a MimeMessage. + * create {@link javax.mail.internet.MimeMessage}. * * @param outputMessage output from RemoteManager/Certbot - * @return map + * @return map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT */ - protected static Map createIssueCertNotificationMap(Domain domain, String outputMessage) - throws ServiceException { + protected static Map createIssueCertNotificationMap( + Domain domain, String outputMessage) throws ServiceException { Provisioning provisioning = Provisioning.getInstance(); Config config = provisioning.getConfig(); - String globalFrom = Optional.ofNullable(config.getCarbonioNotificationFrom()) - .orElseThrow(() -> ServiceException.FAILURE( - "Global CarbonioNotificationFrom attribute is not present.", null)); - String[] globalTo = Optional.ofNullable(config.getCarbonioNotificationRecipients()) - .orElseThrow(() -> ServiceException.FAILURE( - "Global CarbonioNotificationRecipients attribute is not present.", null)); - - String domainFrom = Optional.ofNullable(domain.getCarbonioNotificationFrom()) - .orElse(globalFrom); - String[] domainTo = Optional.ofNullable(domain.getCarbonioNotificationRecipients()) - .orElse(globalTo); + String globalFrom = + Optional.ofNullable(config.getCarbonioNotificationFrom()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationFrom attribute is not present.", null)); + String[] globalTo = + Optional.ofNullable(config.getCarbonioNotificationRecipients()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationRecipients attribute is not present.", null)); + + String domainFrom = + Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElse(globalFrom); + String[] domainTo = + Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); Map notificationMap = new HashMap<>(); @@ -175,7 +190,12 @@ protected static Map createIssueCertNotificationMap(Domain domai notificationMap.put(SUBJECT_RESULT, CERTBOT_FAILURE); String domainMessage = - String.join("", HEADER, FAILURE_RESULT, FAILURE_DOMAIN_NOTIFICATION_TEMPLATE); + String.join( + "", + HEADER, + FAILURE_RESULT, + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName())); + notificationMap.put(DOMAIN_MESSAGE, domainMessage); notificationMap.put(DOMAIN_FROM, domainFrom); notificationMap.put(DOMAIN_TO, domainTo); @@ -208,6 +228,14 @@ protected static Map createIssueCertNotificationMap(Domain domai return notificationMap; } + /** + * Creates {@link javax.mail.internet.MimeMessage} list what would be sent to recipients. + * + * @param session {@link javax.mail.Session} + * @param notificationMap map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT + * @return a list of {@link javax.mail.internet.MimeMessage} + * @throws ServiceException if unable to parse addresses or create a MimeMessage + */ protected static List createMimeMessageList( Session session, Map notificationMap) throws ServiceException { diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index 752525dce9a..b5909a69407 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -25,11 +25,14 @@ * @since 23.3.0 */ public class IssueCert extends AdminDocumentHandler { + public static final String RESPONSE = "The System is processing your certificate generation " + + "request. It will send the result to the Domain notification recipients."; /** * Handles the request. Searches a domain by id, checks admin rights (accessible to global and - * delegated admin of requested domain), searches a server with proxy node, executes remote - * certbot command on it, creates response element. + * delegated admin of requested domain), searches a server with proxy node, creates certbot + * command, asynchronously executes it, creates response element, notifies global and domain + * recipients about the result of remote execution. * * @param request {@link Element} representation of {@link * com.zimbra.soap.admin.message.IssueCertRequest} @@ -40,9 +43,6 @@ public class IssueCert extends AdminDocumentHandler { * PublicServiceHostname and at least one VirtualHostName, * server with proxy node could not be found or domain admin doesn't have rights to deal with * this domain. - * - * It won't throw an exception in case if remote execution command fails, instead will create - * a response and add a failure message to it. */ @Override public Element handle(final Element request, final Map context) @@ -87,7 +87,7 @@ public Element handle(final Element request, final Map context) ZimbraLog.rmgmt.info("Issuing LetsEncrypt cert for domain " + domainName); RemoteManager remoteManager = RemoteManager.getRemoteManager(proxyServer); - RemoteCertbot certbot = new RemoteCertbot(remoteManager); + RemoteCertbot certbot = RemoteCertbot.getRemoteCertbot(remoteManager); String command = certbot.createCommand( RemoteCommands.CERTBOT_CERTONLY, @@ -108,9 +108,7 @@ public Element handle(final Element request, final Map context) .addNonUniqueElement(AdminConstants.E_MESSAGE) .addAttribute(AdminConstants.A_DOMAIN, domainName); - responseMessageElement.setText( - "Your request for the certificate generation has been taken and will be processed. " - + "Domain notification recipients would be notified about the certification result."); + responseMessageElement.setText(RESPONSE); return response; } diff --git a/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java b/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java index 8b7244c1877..cf52398cfba 100644 --- a/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java +++ b/store/src/test/java/com/zimbra/cs/rmgmt/RemoteCertbotTest.java @@ -3,14 +3,13 @@ import static org.mockito.Mockito.mock; import com.zimbra.common.soap.AdminConstants; -import java.util.Map; import org.junit.Test; import static org.junit.Assert.assertEquals; public class RemoteCertbotTest { - RemoteManager remoteManager = mock(RemoteManager.class); - RemoteCertbot remoteCertbot = new RemoteCertbot(remoteManager); + private final RemoteManager remoteManager = mock(RemoteManager.class); + private final RemoteCertbot remoteCertbot = RemoteCertbot.getRemoteCertbot(remoteManager); private final String domainName = "example.com"; private final String publicServiceHostName = "public.example.com"; diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3bee59f73b2..3b2f952440c 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -154,7 +154,8 @@ public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { @Test public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { final String expectedDomainMessage = - HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; + HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE + .replace("", domainName); final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java index 7d2461da0d6..52328bfce8f 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java @@ -1,207 +1,206 @@ -//package com.zimbra.cs.service.admin; -// -//import static com.zimbra.common.soap.AdminConstants.A_DOMAIN; -//import static com.zimbra.common.soap.AdminConstants.E_MESSAGE; -//import static com.zimbra.common.soap.AdminConstants.ISSUE_CERT_REQUEST; -//import static org.junit.Assert.assertEquals; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.mockStatic; -//import static org.mockito.Mockito.when; -// -//import com.zimbra.common.account.ZAttrProvisioning; -//import com.zimbra.common.service.ServiceException; -//import com.zimbra.common.soap.Element; -//import com.zimbra.common.soap.Element.XMLElement; -//import com.zimbra.common.soap.SoapProtocol; -//import com.zimbra.cs.account.Account; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.account.Server; -//import com.zimbra.cs.account.accesscontrol.RightManager; -//import com.zimbra.cs.mailbox.MailboxTestUtil; -//import com.zimbra.cs.rmgmt.RemoteManager; -//import com.zimbra.cs.rmgmt.RemoteResult; -//import com.zimbra.cs.service.AuthProvider; -//import com.zimbra.soap.SoapEngine; -//import com.zimbra.soap.ZimbraSoapContext; -//import java.util.HashMap; -//import java.util.Map; -//import org.junit.After; -//import org.junit.AfterClass; -//import org.junit.Before; -//import org.junit.Rule; -//import org.junit.Test; -//import org.junit.rules.ExpectedException; -//import org.mockito.MockedStatic; -// -//public class IssueCertTest { -// -// private Provisioning provisioning; -// -// private final Map context = new HashMap<>(); -// private final Map domainAttributes = new HashMap<>(); -// -// private final String domainName = "example.com"; -// private final String publicServiceHostName = "public.example.com"; -// private final String virtualHostName = "virtual.example.com"; -// -// private final String mail = "admin@example.com"; -// -// private final String command = "certbot certonly --agree-tos --email admin@example.com" -// + " -n --keep --webroot -w /opt/zextras " -// + "--cert-name example.com " -// + "-d public.example.com -d virtual.example.com"; -// -// private final static MockedStatic mockedStatic = mockStatic(RemoteManager.class); -// private final RemoteManager remoteManager = mock(RemoteManager.class); -// private final RemoteResult remoteResult = mock(RemoteResult.class); -// -// private final IssueCert handler = new IssueCert(); -// private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); -// -// @Rule public ExpectedException expectedEx = ExpectedException.none(); -// -// @Before -// public void setUp() throws Exception { -// MailboxTestUtil.initServer(); -// -// this.provisioning = Provisioning.getInstance(); -// -// RightManager.getInstance(); -// -// String domainId = "domainId"; -// String password = "testPwd"; -// -// Account account = -// provisioning.createAccount( -// mail, -// password, -// new HashMap<>() { -// { -// put(ZAttrProvisioning.A_zimbraIsAdminAccount, "TRUE"); -// put(ZAttrProvisioning.A_zimbraIsDelegatedAdminAccount, "TRUE"); -// put(ZAttrProvisioning.A_mail, mail); -// } -// }); -// -// domainAttributes.put(ZAttrProvisioning.A_zimbraDomainName, domainName); -// domainAttributes.put(ZAttrProvisioning.A_zimbraId, domainId); -// -// this.context.put( -// SoapEngine.ZIMBRA_CONTEXT, -// new ZimbraSoapContext( -// AuthProvider.getAuthToken(account, true), -// account.getId(), -// SoapProtocol.Soap12, -// SoapProtocol.Soap12)); -// -// this.request.addNonUniqueElement(A_DOMAIN).addText(domainId); -// } -// -// @After -// public void clearData() { -// try { -// MailboxTestUtil.clearData(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// -// @AfterClass -// public static void tearDown() { -// mockedStatic.close(); -// } -// -// @Test -// public void shouldReturnSuccessMessageIfAllChecksPassed() throws Exception { -// createInfrastructure(); -// -// final String result = "SUCCESS"; -// -// when(remoteManager.execute(command)).thenReturn(remoteResult); -// when(remoteResult.getMStdout()).thenReturn(result.getBytes()); -// -// final Element response = handler.handle(request, context); -// final Element message = response.getElement(E_MESSAGE); -// assertEquals(message.getAttribute(A_DOMAIN), domainName); -// assertEquals(message.getText(), result); -// } -// -// @Test -// public void shouldReturnFailureMessageIfRemoteExecutionFailed() throws Exception { -// createInfrastructure(); -// -// final String result = "FAILURE"; -// final String expectedMessage = "system failure: FAILURE"; -// -// when(remoteManager.execute(command)).thenThrow(ServiceException.FAILURE(result)); -// -// final Element response = handler.handle(request, context); -// final Element message = response.getElement(E_MESSAGE); -// assertEquals(message.getAttribute(A_DOMAIN), domainName); -// assertEquals(message.getText(), expectedMessage); -// } -// -// @Test -// public void shouldReturnInvalidIfNoSuchDomain() throws Exception { -// expectedEx.expect(ServiceException.class); -// expectedEx.expectMessage("Domain with id domainId could not be found."); -// -// handler.handle(request, context); -// } -// -// @Test -// public void shouldReturnInvalidIfNoPublicServiceHostName() throws Exception { -// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); -// provisioning.createDomain(domainName, domainAttributes); -// -// expectedEx.expect(ServiceException.class); -// expectedEx.expectMessage("must have PublicServiceHostname"); -// -// handler.handle(request, context); -// } -// -// @Test -// public void shouldReturnInvalidIfNoVirtualHostName() throws Exception { -// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); -// -// provisioning.createDomain(domainName, domainAttributes); -// -// expectedEx.expect(ServiceException.class); -// expectedEx.expectMessage("must have at least one VirtualHostName."); -// -// handler.handle(request, context); -// } -// -// @Test -// public void shouldReturnFailureIfNoServerWithProxy() throws Exception { -// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); -// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); -// -// provisioning.createDomain(domainName, domainAttributes); -// -// expectedEx.expect(ServiceException.class); -// expectedEx.expectMessage("Issuing LetsEncrypt certificate command requires carbonio-proxy."); -// -// handler.handle(request, context); -// } -// -// private void createInfrastructure() throws ServiceException { -// domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); -// domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); -// -// provisioning.createDomain(domainName, domainAttributes); -// -// final String serverName = "serverName"; -// final Server server = -// provisioning.createServer( -// serverName, -// new HashMap<>() { -// { -// put(ZAttrProvisioning.A_cn, serverName); -// put(ZAttrProvisioning.A_zimbraServiceEnabled, Provisioning.SERVICE_PROXY); -// } -// }); -// -// mockedStatic.when(() -> RemoteManager.getRemoteManager(server)).thenReturn(remoteManager); -// } -//} +package com.zimbra.cs.service.admin; + +import static com.zimbra.common.soap.AdminConstants.A_DOMAIN; +import static com.zimbra.common.soap.AdminConstants.E_MESSAGE; +import static com.zimbra.common.soap.AdminConstants.ISSUE_CERT_REQUEST; +import static com.zimbra.soap.DocumentHandler.getRequestedMailbox; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.zimbra.common.account.ZAttrProvisioning; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.AdminConstants; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.Element.XMLElement; +import com.zimbra.common.soap.SoapProtocol; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Domain; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.account.Server; +import com.zimbra.cs.account.accesscontrol.RightManager; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.rmgmt.RemoteCertbot; +import com.zimbra.cs.rmgmt.RemoteCommands; +import com.zimbra.cs.rmgmt.RemoteManager; +import com.zimbra.cs.service.AuthProvider; +import com.zimbra.soap.SoapEngine; +import com.zimbra.soap.ZimbraSoapContext; +import java.util.HashMap; +import java.util.Map; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.MockedStatic; + +public class IssueCertTest { + + private Provisioning provisioning; + private ZimbraSoapContext zsc; + private final Map context = new HashMap<>(); + private final Map domainAttributes = new HashMap<>(); + + private final String domainName = "example.com"; + private final String publicServiceHostName = "public.example.com"; + private final String virtualHostName = "virtual.example.com"; + + private final String mail = "admin@example.com"; + + private final static MockedStatic staticRemoteManager = mockStatic(RemoteManager.class); + private final RemoteManager remoteManager = mock(RemoteManager.class); + private final static MockedStatic staticRemoteCertbot = mockStatic(RemoteCertbot.class); + private final RemoteCertbot remoteCertbot = mock(RemoteCertbot.class); + + private final IssueCert handler = new IssueCert(); + private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); + + @Rule public ExpectedException expectedEx = ExpectedException.none(); + + @Before + public void setUp() throws Exception { + MailboxTestUtil.initServer(); + + this.provisioning = Provisioning.getInstance(); + + RightManager.getInstance(); + + String domainId = "domainId"; + String password = "testPwd"; + + Account account = + provisioning.createAccount( + mail, + password, + new HashMap<>() { + { + put(ZAttrProvisioning.A_zimbraIsAdminAccount, "TRUE"); + put(ZAttrProvisioning.A_zimbraIsDelegatedAdminAccount, "TRUE"); + put(ZAttrProvisioning.A_mail, mail); + } + }); + + domainAttributes.put(ZAttrProvisioning.A_zimbraDomainName, domainName); + domainAttributes.put(ZAttrProvisioning.A_zimbraId, domainId); + + this.zsc = new ZimbraSoapContext( + AuthProvider.getAuthToken(account, true), + account.getId(), + SoapProtocol.Soap12, + SoapProtocol.Soap12); + this.context.put(SoapEngine.ZIMBRA_CONTEXT, zsc); + + this.request.addNonUniqueElement(A_DOMAIN).addText(domainId); + } + + @After + public void clearData() { + try { + MailboxTestUtil.clearData(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @AfterClass + public static void tearDown() { + staticRemoteManager.close(); + staticRemoteCertbot.close(); + } + + @Test + public void shouldSupplyAsyncAndReturnResponse() throws Exception { + domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); + domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); + + Domain expectedDomain = provisioning.createDomain(domainName, domainAttributes); + + final String serverName = "serverName"; + final Server server = + provisioning.createServer( + serverName, + new HashMap<>() { + { + put(ZAttrProvisioning.A_cn, serverName); + put(ZAttrProvisioning.A_zimbraServiceEnabled, Provisioning.SERVICE_PROXY); + } + }); + + staticRemoteManager.when(() -> RemoteManager.getRemoteManager(server)) + .thenReturn(remoteManager); + staticRemoteCertbot.when(() -> RemoteCertbot.getRemoteCertbot(remoteManager)) + .thenReturn(remoteCertbot); + + Mailbox expectMailbox = getRequestedMailbox(zsc); + + String command = "certbot certonly --agree-tos --email admin@example.com" + + " -n --keep --webroot -w /opt/zextras " + + "--cert-name example.com " + + "-d public.example.com -d virtual.example.com"; + + when(remoteCertbot.createCommand( + RemoteCommands.CERTBOT_CERTONLY, + mail, + AdminConstants.DEFAULT_CHAIN, + domainName, + publicServiceHostName, + expectedDomain.getVirtualHostname())).thenReturn(command); + + final Element response = handler.handle(request, context); + final Element message = response.getElement(E_MESSAGE); + + assertEquals(message.getAttribute(A_DOMAIN), domainName); + assertEquals(message.getText(), IssueCert.RESPONSE); + + verify(remoteCertbot).supplyAsync(expectMailbox, expectedDomain, command); + } + + @Test + public void shouldReturnInvalidIfNoSuchDomain() throws Exception { + expectedEx.expect(ServiceException.class); + expectedEx.expectMessage("Domain with id domainId could not be found."); + + handler.handle(request, context); + } + + @Test + public void shouldReturnInvalidIfNoPublicServiceHostName() throws Exception { + domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); + provisioning.createDomain(domainName, domainAttributes); + + expectedEx.expect(ServiceException.class); + expectedEx.expectMessage("must have PublicServiceHostname"); + + handler.handle(request, context); + } + + @Test + public void shouldReturnInvalidIfNoVirtualHostName() throws Exception { + domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); + + provisioning.createDomain(domainName, domainAttributes); + + expectedEx.expect(ServiceException.class); + expectedEx.expectMessage("must have at least one VirtualHostName."); + + handler.handle(request, context); + } + + @Test + public void shouldReturnFailureIfNoServerWithProxy() throws Exception { + domainAttributes.put(ZAttrProvisioning.A_zimbraPublicServiceHostname, publicServiceHostName); + domainAttributes.put(ZAttrProvisioning.A_zimbraVirtualHostname, virtualHostName); + + provisioning.createDomain(domainName, domainAttributes); + + expectedEx.expect(ServiceException.class); + expectedEx.expectMessage("Issuing LetsEncrypt certificate command requires carbonio-proxy."); + + handler.handle(request, context); + } +} From 7e044e21ba235aae37ad3de606d69bf6deecbd7f Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Wed, 29 Mar 2023 16:19:39 +0200 Subject: [PATCH 20/39] feat: [CO-621] modify java docs --- .../com/zimbra/cs/mailbox/MailSender.java | 31 ++++++++++++------- .../java/com/zimbra/cs/mailbox/Mailbox.java | 5 +-- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 8 +++-- .../cs/service/admin/IssueCertTest.java | 6 ++-- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index 5d4f9c3fa5e..e52c7638f28 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -250,10 +250,12 @@ public MailSender setSession(Account account) throws ServiceException { } /** - * Sets an alternate JavaMail Session and SMTP hosts - * that will be used to send the message based on the domain. + * Sets an alternate JavaMail {@link javax.mail.Session} and SMTP hosts + * that will be used to send the message based on the domain values. * The default behavior is to use SMTP settings from - * the Session on the {@link MimeMessage}. + * the {@link javax.mail.Session} on the {@link MimeMessage}. + * + * @param domain {@link com.zimbra.cs.account.Domain} * @throws ServiceException if not able to get SMTP session for the domain * * @author Yuliya Aheeva @@ -307,8 +309,9 @@ public MailSender setEnvelopeFrom(String address) { } /** - * Returns the current session. - * @return mSession + * Returns the current session {@link javax.mail.Session}. + * + * @return {@link #mSession} value * @author Yuliya Aheeva * @since 23.5.0 */ @@ -471,13 +474,17 @@ public void rollback() { } /** - * Sends a list of messages. - * Tries to find the account by name (if unable to find will get account from the mailbox later - * with the sendMimeMessage method) and provide the proper operational context. + * Sends a list of messages {@link javax.mail.internet.MimeMessage}. + * + * Tries to find the account by name (if unable to find will set account from the mailbox later + * with the {@link #sendMimeMessage(OperationContext, Mailbox, MimeMessage)} method) + * and provide the proper operational context. * * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} * @param mimeMessageList a list of {@link javax.mail.internet.MimeMessage} to be sent - * @throws ServiceException if sender is not set for the specific {@link javax.mail.internet.MimeMessage} + * @throws ServiceException if sender is not set for the specific + * {@link javax.mail.internet.MimeMessage} + * * @author Yuliya Aheeva * @since 23.5.0 */ @@ -1308,10 +1315,12 @@ private void sendMessageToHost(String hostname, MimeMessage mm, Address[] rcptAd } /** - * Initialize a new SMTP transport if not able to get one from the mSession. + * Initializes a new SMTP transport if not able to get one from the {@link #mSession}. + * * @return SMTP transport + * * @author Yuliya Aheeva - * @since 23.4.0 + * @since 23.5.0 */ private Transport getTransport() { try { diff --git a/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java b/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java index f68992c2281..925cd15b758 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/Mailbox.java @@ -977,11 +977,12 @@ public MailSender getMailSender() throws ServiceException { * Returns a {@link MailSender} object based on specific domain properties * that can be used to send mails. * - * @param domain a domain to get needed properties + * @param domain {@link com.zimbra.cs.account.Domain} to get needed properties * @return {@link MailSender} object * @throws ServiceException if unable to get SMTP session for the current domain + * * @author Yuliya Aheeva - * @since 23.4.0 + * @since 23.5.0 */ public MailSender getMailSender(Domain domain) throws ServiceException { MailSender sender = new MailSender(); diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 85d2a70b0b7..4164e7dff1b 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -39,11 +39,14 @@ private RemoteCertbot(RemoteManager remoteManager) { } /** - * Instantiate RemoteCertbot object. + * Instantiates a RemoteCertbot object. * * @param remoteManager {@link com.zimbra.cs.rmgmt.RemoteManager} which will be used to execute - * remote commands. + * remote commands with. * @return an instantiated object + * + * @author Yuliya Aheeva + * @since 23.5.0 */ public static RemoteCertbot getRemoteCertbot(RemoteManager remoteManager) { return new RemoteCertbot(remoteManager); @@ -97,6 +100,7 @@ public String createCommand(String remoteCommand, String email, String chain, St * {@link com.zimbra.common.account.ZAttrProvisioning} A_carbonioNotificationRecipients * and A_carbonioNotificationFrom attributes as well as other values * @param command a Certbot command to be executed remotely + * * @author Yuliya Aheeva * @since 23.5.0 */ diff --git a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java index 52328bfce8f..f7b3cbcba57 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java @@ -138,7 +138,7 @@ public void shouldSupplyAsyncAndReturnResponse() throws Exception { Mailbox expectMailbox = getRequestedMailbox(zsc); - String command = "certbot certonly --agree-tos --email admin@example.com" + String expectedCommand = "certbot certonly --agree-tos --email admin@example.com" + " -n --keep --webroot -w /opt/zextras " + "--cert-name example.com " + "-d public.example.com -d virtual.example.com"; @@ -149,7 +149,7 @@ public void shouldSupplyAsyncAndReturnResponse() throws Exception { AdminConstants.DEFAULT_CHAIN, domainName, publicServiceHostName, - expectedDomain.getVirtualHostname())).thenReturn(command); + expectedDomain.getVirtualHostname())).thenReturn(expectedCommand); final Element response = handler.handle(request, context); final Element message = response.getElement(E_MESSAGE); @@ -157,7 +157,7 @@ public void shouldSupplyAsyncAndReturnResponse() throws Exception { assertEquals(message.getAttribute(A_DOMAIN), domainName); assertEquals(message.getText(), IssueCert.RESPONSE); - verify(remoteCertbot).supplyAsync(expectMailbox, expectedDomain, command); + verify(remoteCertbot).supplyAsync(expectMailbox, expectedDomain, expectedCommand); } @Test From bbd9fba832c7faddfab22a7c591eedf3be17bc1e Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 12:13:49 +0200 Subject: [PATCH 21/39] feat: [CO-621] add checkValidity method --- .../admin/CertificateNotificationManager.java | 47 +++++- .../zimbra/cs/service/admin/IssueCert.java | 22 ++- .../CertificateNotificationManagerTest.java | 157 +++++++++--------- 3 files changed, 127 insertions(+), 99 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 66bb8d35fe8..5f0b5320d7c 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -1,5 +1,6 @@ package com.zimbra.cs.service.admin; +import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Config; @@ -244,18 +245,36 @@ protected static List createMimeMessageList( String subject = notificationMap.get(DOMAIN_NAME) + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); - Address globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); - Address[] globalTo = convert((String[]) notificationMap.get(GLOBAL_TO)); - String globalMessage = (String) notificationMap.get(GLOBAL_MESSAGE); + try { + Address globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); + Address[] globalTo = convert((String[]) notificationMap.get(GLOBAL_TO)); + String globalMessage = (String) notificationMap.get(GLOBAL_MESSAGE); - list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); + list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); - if (notificationMap.containsKey(DOMAIN_MESSAGE)) { - Address domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); - Address[] domainTo = convert((String[]) notificationMap.get(DOMAIN_TO)); - String domainMessage = (String) notificationMap.get(DOMAIN_MESSAGE); + } catch(ServiceException e) { + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation for " + + notificationMap.get(DOMAIN_NAME) + + " won't be sent for the global recipients.\n" + + e.getMessage()); + } - list.add(createMimeMessage(session, subject, domainFrom, domainTo, domainMessage)); + if (notificationMap.containsKey(DOMAIN_MESSAGE)) { + try { + Address domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); + Address[] domainTo = convert((String[]) notificationMap.get(DOMAIN_TO)); + String domainMessage = (String) notificationMap.get(DOMAIN_MESSAGE); + + list.add(createMimeMessage(session, subject, domainFrom, domainTo, domainMessage)); + + } catch (ServiceException e) { + ZimbraLog.rmgmt.info( + "Notifications about LetsEncrypt certificate generation for " + + notificationMap.get(DOMAIN_NAME) + + " won't be sent for the domain recipients.\n" + + e.getMessage()); + } } return list; @@ -282,6 +301,7 @@ private static MimeMessage createMimeMessage( } private static Address[] convert(String[] addresses) throws ServiceException { + checkAddressValidity(addresses); try { String addressList = String.join(", ", addresses); return InternetAddress.parse(addressList); @@ -291,10 +311,19 @@ private static Address[] convert(String[] addresses) throws ServiceException { } private static Address convert(String address) throws ServiceException { + checkAddressValidity(address); try { return new InternetAddress(address); } catch (AddressException e) { throw ServiceException.FAILURE("Unable to parse address", e); } } + + private static void checkAddressValidity(String... addresses) throws ServiceException { + Provisioning provisioning = Provisioning.getInstance(); + for (String address: addresses) { + Optional.ofNullable(provisioning.get(AccountBy.name, address)).orElseThrow( + () -> ServiceException.FAILURE("Unable to find account with address " + address)); + } + } } diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index b5909a69407..b933e758845 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -61,18 +61,16 @@ public Element handle(final Element request, final Map context) String chain = request.getAttribute(AdminConstants.A_CHAIN_TYPE, AdminConstants.DEFAULT_CHAIN); - String domainName = domain.getDomainName(); - String publicServiceHostname = domain.getPublicServiceHostname(); - String[] virtualHostNames = domain.getVirtualHostname(); - if (publicServiceHostname == null) { - throw ServiceException.FAILURE( - "Domain " + domainName + " must have PublicServiceHostname.", - null); - } else if (virtualHostNames.length == 0) { - throw ServiceException.FAILURE( - "Domain " + domainName + " must have at least one VirtualHostName.", - null); - } + String domainName = Optional.ofNullable(domain.getDomainName()) + .orElseThrow(() -> ServiceException.FAILURE( + "Domain with id " + domainId + " must have domain name", null)); + String publicServiceHostname = Optional.ofNullable(domain.getPublicServiceHostname()) + .orElseThrow(() -> ServiceException.FAILURE( + "Domain " + domainName + " must have PublicServiceHostname.", null)); + String[] virtualHostNames = Optional.ofNullable(domain.getVirtualHostname()) + .filter(hosts -> hosts.length > 0) + .orElseThrow(() -> ServiceException.FAILURE( + "Domain " + domainName + " must have at least one VirtualHostName.")); // First release will work only on ONE proxy even if there are multiple proxy in the infrastructure. Server proxyServer = diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3b2f952440c..46f44795f9e 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -20,7 +20,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; +import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Config; import com.zimbra.cs.account.Domain; import com.zimbra.cs.account.Provisioning; @@ -46,93 +48,27 @@ public class CertificateNotificationManagerTest { + "Error creating new order :: Cannot issue for \"test.tld\": " + "Domain name does not end with a valid public suffix (TLD)\n"; - private final String certbotFailureMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating a certificate request for test.zextras.io\n" - + "\n" - + "Certbot failed to authenticate some domains (authenticator: webroot). The" - + " Certificate Authority reported these problems:\n" - + "Domain: test.zextras.io\n" - + "Type: dns\n" - + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" - + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" - + " test.zextras.io - check that a DNS record exists for this domain\n" - + "\n" - + "Hint: The Certificate Authority failed to download the temporary challenge files" - + " created by Certbot. Ensure that the listed domains serve their content from the" - + " provided --webroot-path/-w and that files created there can be downloaded from the" - + " internet.\n" - + "\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - private final String certbotSuccessMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" - + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" - + "The dry run was successful.\n" - + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" - + "\n" - + "Successfully received certificate.\n" - + "Certificate is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" - + "Key is saved at:" - + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" - + "This certificate expires on 2023-06-15.\n" - + "These files will be updated when the certificate renews.\n" - + "NEXT STEPS:\n" - + "- The certificate will need to be renewed before it expires. Certbot can" - + " automatically renew the certificate in the background, but you may need to take" - + " steps to enable that functionality. See https://certbot.org/renewal-setup for" - + " instructions.\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "If you like Certbot, please consider supporting our work by:\n" - + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" - + "* Donating to EFF: https://eff.org/donate-le\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - - private final String otherCertbotMessage = - "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" - + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" - + "The dry run was successful.\n" - + "Certificate not yet due for renewal\n" - + "\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "Certificate not yet due for renewal; no action taken.\n" - + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" - + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" - + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" - + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - - - private Mailbox mailbox = mock(Mailbox.class); - private Domain domain = mock(Domain.class); - private Provisioning provisioning = mock(Provisioning.class); - private Config config = mock(Config.class); - private MailSender mailSender = mock(MailSender.class); - private String from = "admin@test.com"; - private String[] recipients = new String[] {from, "admin2@test.com"}; - private String domainName = "test.com"; + private final Mailbox mailbox = mock(Mailbox.class); + private final Domain domain = mock(Domain.class); + private final Provisioning provisioning = mock(Provisioning.class); + private final Config config = mock(Config.class); + private final Account account = mock(Account.class); + private final MailSender mailSender = mock(MailSender.class); + private final String from = "admin@test.com"; + private final String[] recipients = new String[] {from, "admin2@test.com"}; + private final String domainName = "test.com"; @Before public void setUp() throws ServiceException { - when(domain.getName()).thenReturn(domainName); Provisioning.setInstance(provisioning); + when(domain.getName()).thenReturn(domainName); when(provisioning.getConfig()).thenReturn(config); when(config.getCarbonioNotificationFrom()).thenReturn(from); when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); when(mailbox.getMailSender(domain)).thenReturn(mailSender); when(mailSender.getCurrentSession()).thenReturn(null); + when(provisioning.get(AccountBy.name, from)).thenReturn(account); + when(provisioning.get(AccountBy.name, recipients[1])).thenReturn(account); } @Test @@ -156,6 +92,28 @@ public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { final String expectedDomainMessage = HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE .replace("", domainName); + String certbotFailureMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating a certificate request for test.zextras.io\n" + + "\n" + + "Certbot failed to authenticate some domains (authenticator: webroot). The" + + " Certificate Authority reported these problems:\n" + + "Domain: test.zextras.io\n" + + "Type: dns\n" + + "Detail: DNS problem: NXDOMAIN looking up A for test.zextras.io - check that a DNS" + + " record exists for this domain; DNS problem: NXDOMAIN looking up AAAA for" + + " test.zextras.io - check that a DNS record exists for this domain\n" + + "\n" + + "Hint: The Certificate Authority failed to download the temporary challenge files" + + " created by Certbot. Ensure that the listed domains serve their content from the" + + " provided --webroot-path/-w and that files created there can be downloaded from the" + + " internet.\n" + + "\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); @@ -169,6 +127,35 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws Servi final String expiration = "\n" + "This certificate expires on 2023-06-15."; final String expectedDomainMessage = HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + String certbotSuccessMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io\n" + + "Simulating a certificate request for le1.zextras.io and le2.zextras.io\n" + + "The dry run was successful.\n" + + "Requesting a certificate for le1.zextras.io and le2.zextras.io\n" + + "\n" + + "Successfully received certificate.\n" + + "Certificate is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/fullchain.pem\n" + + "Key is saved at:" + + " /opt/zextras/common/certbot/etc/letsencrypt/live/le.zextras.io/privkey.pem\n" + + "This certificate expires on 2023-06-15.\n" + + "These files will be updated when the certificate renews.\n" + + "NEXT STEPS:\n" + + "- The certificate will need to be renewed before it expires. Certbot can" + + " automatically renew the certificate in the background, but you may need to take" + + " steps to enable that functionality. See https://certbot.org/renewal-setup for" + + " instructions.\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "If you like Certbot, please consider supporting our work by:\n" + + "* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate\n" + + "* Donating to EFF: https://eff.org/donate-le\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); @@ -179,6 +166,20 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws Servi @Test public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + String otherCertbotMessage = + "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io\n" + + "Simulating renewal of an existing certificate for abc.demo.zextras.io\n" + + "The dry run was successful.\n" + + "Certificate not yet due for renewal\n" + + "\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "Certificate not yet due for renewal; no action taken.\n" + + "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" + + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + + " test.zextras.io -d test.zextras.io -d test.zextras.io"; final Map notificationMap = CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); From 6825292ea7ac9a31dc35276679cad95f80b0a138 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 12:23:34 +0200 Subject: [PATCH 22/39] feat: [CO-621] make provisioning to be a field --- .../cs/service/admin/CertificateNotificationManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 5f0b5320d7c..8606bfa609e 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -81,6 +81,8 @@ public class CertificateNotificationManager { + "\n" + "The files will be automatically updated when the certificate renews.\n"; + private static final Provisioning provisioning = Provisioning.getInstance(); + private CertificateNotificationManager() { throw new RuntimeException("CertificateNotificationManager class cannot be instantiated."); } @@ -140,7 +142,6 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { protected static Map createIssueCertNotificationMap( Domain domain, String outputMessage) throws ServiceException { - Provisioning provisioning = Provisioning.getInstance(); Config config = provisioning.getConfig(); String globalFrom = @@ -320,7 +321,6 @@ private static Address convert(String address) throws ServiceException { } private static void checkAddressValidity(String... addresses) throws ServiceException { - Provisioning provisioning = Provisioning.getInstance(); for (String address: addresses) { Optional.ofNullable(provisioning.get(AccountBy.name, address)).orElseThrow( () -> ServiceException.FAILURE("Unable to find account with address " + address)); From 1e9f15e5f2416519bebcac93f4457ee7124cc4e0 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 12:50:03 +0200 Subject: [PATCH 23/39] feat: [CO-621] uncomment Contact and FileIntoCopy tests --- .../zimbra/cs/filter/FileIntoCopyTest.java | 1126 ++++++++--------- .../com/zimbra/cs/mailbox/ContactTest.java | 868 ++++++------- 2 files changed, 997 insertions(+), 997 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java index ca9bcf75202..271c59300c9 100644 --- a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java +++ b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java @@ -1,563 +1,563 @@ -//// SPDX-FileCopyrightText: 2022 Synacor, Inc. -//// SPDX-FileCopyrightText: 2022 Zextras -//// -//// SPDX-License-Identifier: GPL-2.0-only -// -//package com.zimbra.cs.filter; -// -//import static org.junit.Assert.*; -//import java.util.HashMap; -//import java.util.List; -//import org.junit.Assert; -//import org.junit.Before; -//import org.junit.BeforeClass; -//import org.junit.Test; -//import com.zimbra.common.account.Key; -//import com.zimbra.cs.account.Account; -//import com.zimbra.cs.account.MockProvisioning; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.account.Server; -//import com.zimbra.cs.mailbox.DeliveryContext; -//import com.zimbra.cs.mailbox.DeliveryOptions; -//import com.zimbra.cs.mailbox.Flag; -//import com.zimbra.cs.mailbox.Folder; -//import com.zimbra.cs.mailbox.MailItem; -//import com.zimbra.cs.mailbox.Mailbox; -//import com.zimbra.cs.mailbox.MailboxManager; -//import com.zimbra.cs.mailbox.MailboxTestUtil; -//import com.zimbra.cs.mailbox.Message; -//import com.zimbra.cs.mailbox.OperationContext; -//import com.zimbra.cs.mime.ParsedMessage; -//import com.zimbra.cs.service.util.ItemId; -//import qa.unittest.TestUtil; -// -//public class FileIntoCopyTest { -// -// @BeforeClass -// public static void init() throws Exception { -// MailboxTestUtil.initServer(); -// Provisioning prov = Provisioning.getInstance(); -// Account acct = prov.createAccount("test@zimbra.com", "secret", -// new HashMap()); -// Server server = Provisioning.getInstance().getServer(acct); -// } -// -// @Before -// public void setUp() throws Exception { -// MailboxTestUtil.clearData(); -// } -// -// @Test -// public void testCopyFileInto() { -// String filterScript = "require [\"copy\", \"fileinto\"];\n" -// + "if header :contains \"Subject\" \"test\" { fileinto :copy \"Junk\"; }"; -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(2, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals("Test", msg.getSubject()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// @Test -// public void testPlainFileInto() { -// String filterPlainFileintoScript = "require [\"fileinto\"];\n" -// + "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterPlainFileintoScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(1, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals("Test", msg.getSubject()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// @Test -// public void testPlainFileIntoNonExistingFolder() { -// String filterPlainFileintoScript = "require [\"fileinto\"];\n" -// + "if header :contains \"Subject\" \"test\" { fileinto \"HelloWorld\"; }"; -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterPlainFileintoScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(1, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals("Test", msg.getSubject()); -// com.zimbra.cs.mailbox.Folder folder = mbox.getFolderById(null, msg.getFolderId()); -// Assert.assertEquals("HelloWorld", folder.getName()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; -// * } -// * -// * if message has "Subject: Test" ==> it should be stored in "foo" and "bar" -// */ -// @Test -// public void testCopyFileIntoPattern1Test() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" -// + "fileinto \"bar\"; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawTest = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Test\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(rawTest.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should not be stored in inbox -// Assert.assertNull( -// mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); -// // message should be stored in foo -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in bar -// item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; -// * } -// * -// * if message has "Subject: real" ==> it should be stored in "foo" and INBOX -// */ -// -// @Test -// public void testCopyFileIntoPattern1Real() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" -// + "fileinto \"bar\"; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Real\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, -// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should be stored in foo -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in inbox -// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) -// .get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy -// * bar; } -// * -// * if message has "Subject: test" ==> it should be stored in "foo", "bar" -// * and INBOX -// */ -// -// @Test -// public void testCopyFileIntoPattern2Test() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" -// + "fileinto :copy \"bar\"; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Test\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, -// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should be stored in bar -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in foo -// item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in inbox -// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) -// .get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy -// * bar; } -// * -// * if message has "Subject: Real" ==> it should be stored in "foo" and INBOX -// */ -// -// @Test -// public void testCopyFileIntoPattern2Real() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" -// + "fileinto :copy \"bar\"; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Real\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, -// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should be stored in foo -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in inbox -// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) -// .get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } -// * -// * if message has "Subject: Test" ==> it should be stored in "foo" -// */ -// -// @Test -// public void testCopyFileIntoPattern3Test() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" -// + "discard; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Test\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, -// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should be stored in foo -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should not be stored in inbox -// Assert.assertNull( -// mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } -// * -// * if message has "Subject: real" ==> it should be stored in "foo" and INBOX -// */ -// -// @Test -// public void testCopyFileIntoPattern3Real() { -// try { -// String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" -// + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" -// + "discard; }"; -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScriptPattern1); -// String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" -// + "Subject: Real\n" + "\n" + "Hello World"; -// RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, -// new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// // message should be stored in foo -// Integer item = mbox -// .getItemIds(null, -// mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) -// .getIds(MailItem.Type.MESSAGE).get(0); -// Message msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// // message should be stored in inbox -// item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) -// .get(0); -// msg = mbox.getMessageById(null, item); -// Assert.assertEquals("Hello World", msg.getFragment()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// /* -// * Only one copy of message should be delivered in INBOX -// */ -// @Test -// public void testKeepAndFileInto() { -// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox\";"); -// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox\";"); -// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox/\";"); -// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox/\";"); -// doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"inbox\";"); -// doKeepAndFileInto("require \"fileinto\"; fileinto \"Inbox\"; keep;"); -// doKeepAndFileInto("require [\"fileinto\", \"copy\"]; fileinto :copy \"Inbox\"; keep;"); -// -// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent\";"); -// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent\";"); -// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent/\";"); -// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent/\";"); -// doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"sent\";"); -// doKeepAndFileIntoOutgoing("require \"fileinto\"; fileinto \"Sent\"; keep;"); -// doKeepAndFileIntoOutgoing("require [\"fileinto\", \"copy\"]; fileinto :copy \"Sent\"; keep;"); -// } -// -// private void doKeepAndFileInto(String filterScript) { -// doKeepAndFileIntoIncoming(filterScript); -// doKeepAndFileIntoExisting(filterScript); -// } -// -// private void doKeepAndFileIntoIncoming(String filterScript) { -// String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); -// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + body; -// try { -// // Incoming -// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScript); -// -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(sampleMsg.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(1, ids.size()); -// List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); -// Assert.assertEquals(1, searchedIds.size()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// private void doKeepAndFileIntoExisting(String filterScript) { -// String body = "doKeepAndFileIntoExisting" + filterScript.hashCode(); -// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + body; -// try { -// // Existing -// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// List items = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX) -// .getIds(MailItem.Type.MESSAGE); -// OperationContext octx = new OperationContext(mbox); -// Message msg = mbox.addMessage(octx, -// new ParsedMessage(sampleMsg.getBytes(), false), -// new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_PRIORITY), -// new DeliveryContext()); -// boolean filtered = RuleManager.applyRulesToExistingMessage(new OperationContext(mbox), mbox, msg.getId(), -// RuleManager.parse(filterScript)); -// Assert.assertEquals(false, filtered); -// List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); -// Assert.assertEquals(1, searchedIds.size()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// private void doKeepAndFileIntoOutgoing(String filterScript) { -// String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); -// String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + body; -// try { -// // Outgoing -// Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailOutgoingSieveScript(filterScript); -// -// List ids = RuleManager.applyRulesToOutgoingMessage( -// new OperationContext(mbox), mbox, -// new ParsedMessage(sampleMsg.getBytes(), false), -// 5, /* sent folder */ -// true, 0, null, Mailbox.ID_AUTO_INCREMENT); -// List searchedIds = TestUtil.search(mbox, "in:sent " + body, MailItem.Type.MESSAGE); -// Assert.assertEquals(1, searchedIds.size()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// @Test -// public void testNoCapability1() { -// // No "fileinto" declaration -// String filterPlainFileintoScript = -// "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterPlainFileintoScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(1, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// @Test -// public void testNoCapability2() { -// // declare "fileinto" without "copy" -// String filterPlainFileintoScript = "require \"fileinto\";\n" -// + "if header :contains \"Subject\" \"test\" {\n" -// + " fileinto :copy \"copyAndJunk\";\n" -// + "}"; -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterPlainFileintoScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// -// // Capability string is mandatory ==> :copy extension will be failed -// account.setSieveRequireControlEnabled(true); -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(1, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); -// -// // Capability string is optional ==> :copy extension should be available -// account.setSieveRequireControlEnabled(false); -// ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// Assert.assertEquals(2, ids.size()); -// msg = mbox.getMessageById(null, ids.get(0).getId()); -// Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); -// msg = mbox.getMessageById(null, ids.get(1).getId()); -// Folder folder = mbox.getFolderById(null, msg.getFolderId()); -// Assert.assertEquals("copyAndJunk", folder.getName()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -// -// @Test -// public void testPlainFileIntoWithSpaces() { -// String filterScript = "require [\"fileinto\"];\n" -// + "fileinto \" abc\";" // final destination folder = " abc" -// + "fileinto \"abc \";" // final destination folder = "abc" -// + "fileinto \" abc \";"; // final destination folder = " abc" -// try { -// Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); -// RuleManager.clearCachedRules(account); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// account.setMailSieveScript(filterScript); -// String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" -// + "\n" + "Hello World."; -// List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), -// mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), -// new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); -// assertEquals(2, ids.size()); -// Message msg = mbox.getMessageById(null, ids.get(0).getId()); -// Folder folder = mbox.getFolderById(null, msg.getFolderId()); -// assertEquals(" abc", folder.getName()); -// msg = mbox.getMessageById(null, ids.get(1).getId()); -// folder = mbox.getFolderById(null, msg.getFolderId()); -// assertEquals("abc", folder.getName()); -// } catch (Exception e) { -// e.printStackTrace(); -// fail("No exception should be thrown"); -// } -// } -//} +// SPDX-FileCopyrightText: 2022 Synacor, Inc. +// SPDX-FileCopyrightText: 2022 Zextras +// +// SPDX-License-Identifier: GPL-2.0-only + +package com.zimbra.cs.filter; + +import static org.junit.Assert.*; +import java.util.HashMap; +import java.util.List; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import com.zimbra.common.account.Key; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.MockProvisioning; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.account.Server; +import com.zimbra.cs.mailbox.DeliveryContext; +import com.zimbra.cs.mailbox.DeliveryOptions; +import com.zimbra.cs.mailbox.Flag; +import com.zimbra.cs.mailbox.Folder; +import com.zimbra.cs.mailbox.MailItem; +import com.zimbra.cs.mailbox.Mailbox; +import com.zimbra.cs.mailbox.MailboxManager; +import com.zimbra.cs.mailbox.MailboxTestUtil; +import com.zimbra.cs.mailbox.Message; +import com.zimbra.cs.mailbox.OperationContext; +import com.zimbra.cs.mime.ParsedMessage; +import com.zimbra.cs.service.util.ItemId; +import qa.unittest.TestUtil; + +public class FileIntoCopyTest { + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + Provisioning prov = Provisioning.getInstance(); + Account acct = prov.createAccount("test@zimbra.com", "secret", + new HashMap()); + Server server = Provisioning.getInstance().getServer(acct); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void testCopyFileInto() { + String filterScript = "require [\"copy\", \"fileinto\"];\n" + + "if header :contains \"Subject\" \"test\" { fileinto :copy \"Junk\"; }"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(2, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals("Test", msg.getSubject()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + @Test + public void testPlainFileInto() { + String filterPlainFileintoScript = "require [\"fileinto\"];\n" + + "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterPlainFileintoScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals("Test", msg.getSubject()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + @Test + public void testPlainFileIntoNonExistingFolder() { + String filterPlainFileintoScript = "require [\"fileinto\"];\n" + + "if header :contains \"Subject\" \"test\" { fileinto \"HelloWorld\"; }"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterPlainFileintoScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals("Test", msg.getSubject()); + com.zimbra.cs.mailbox.Folder folder = mbox.getFolderById(null, msg.getFolderId()); + Assert.assertEquals("HelloWorld", folder.getName()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; + * } + * + * if message has "Subject: Test" ==> it should be stored in "foo" and "bar" + */ + @Test + public void testCopyFileIntoPattern1Test() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" + + "fileinto \"bar\"; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawTest = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Test\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(rawTest.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should not be stored in inbox + Assert.assertNull( + mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); + // message should be stored in foo + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in bar + item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "test" { fileinto bar; + * } + * + * if message has "Subject: real" ==> it should be stored in "foo" and INBOX + */ + + @Test + public void testCopyFileIntoPattern1Real() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";\n" + "if header :contains \"Subject\" \"Test\" {\n" + + "fileinto \"bar\"; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Real\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should be stored in foo + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in inbox + item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + .get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy + * bar; } + * + * if message has "Subject: test" ==> it should be stored in "foo", "bar" + * and INBOX + */ + + @Test + public void testCopyFileIntoPattern2Test() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" + + "fileinto :copy \"bar\"; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Test\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should be stored in bar + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in foo + item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in inbox + item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + .get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "Test" { fileinto :copy + * bar; } + * + * if message has "Subject: Real" ==> it should be stored in "foo" and INBOX + */ + + @Test + public void testCopyFileIntoPattern2Real() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" + + "fileinto :copy \"bar\"; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Real\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should be stored in foo + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in inbox + item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + .get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } + * + * if message has "Subject: Test" ==> it should be stored in "foo" + */ + + @Test + public void testCopyFileIntoPattern3Test() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" + + "discard; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Test\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should be stored in foo + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should not be stored in inbox + Assert.assertNull( + mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * fileinto :copy foo; if header :contains "Subject" "Test" { discard; } + * + * if message has "Subject: real" ==> it should be stored in "foo" and INBOX + */ + + @Test + public void testCopyFileIntoPattern3Real() { + try { + String filterScriptPattern1 = "require [\"copy\", \"fileinto\"];\n" + + "fileinto :copy \"foo\";" + "if header :contains \"Subject\" \"Test\" {\n" + + "discard; }"; + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScriptPattern1); + String rawReal = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + + "Subject: Real\n" + "\n" + "Hello World"; + RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), mbox, + new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + // message should be stored in foo + Integer item = mbox + .getItemIds(null, + mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) + .getIds(MailItem.Type.MESSAGE).get(0); + Message msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + // message should be stored in inbox + item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + .get(0); + msg = mbox.getMessageById(null, item); + Assert.assertEquals("Hello World", msg.getFragment()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + /* + * Only one copy of message should be delivered in INBOX + */ + @Test + public void testKeepAndFileInto() { + doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox\";"); + doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox\";"); + doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"Inbox/\";"); + doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"/Inbox/\";"); + doKeepAndFileInto("require \"fileinto\"; keep; fileinto \"inbox\";"); + doKeepAndFileInto("require \"fileinto\"; fileinto \"Inbox\"; keep;"); + doKeepAndFileInto("require [\"fileinto\", \"copy\"]; fileinto :copy \"Inbox\"; keep;"); + + doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent\";"); + doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent\";"); + doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"Sent/\";"); + doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"/Sent/\";"); + doKeepAndFileIntoOutgoing("require \"fileinto\"; keep; fileinto \"sent\";"); + doKeepAndFileIntoOutgoing("require \"fileinto\"; fileinto \"Sent\"; keep;"); + doKeepAndFileIntoOutgoing("require [\"fileinto\", \"copy\"]; fileinto :copy \"Sent\"; keep;"); + } + + private void doKeepAndFileInto(String filterScript) { + doKeepAndFileIntoIncoming(filterScript); + doKeepAndFileIntoExisting(filterScript); + } + + private void doKeepAndFileIntoIncoming(String filterScript) { + String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); + String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + body; + try { + // Incoming + Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScript); + + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(sampleMsg.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); + Assert.assertEquals(1, searchedIds.size()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + private void doKeepAndFileIntoExisting(String filterScript) { + String body = "doKeepAndFileIntoExisting" + filterScript.hashCode(); + String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + body; + try { + // Existing + Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + List items = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX) + .getIds(MailItem.Type.MESSAGE); + OperationContext octx = new OperationContext(mbox); + Message msg = mbox.addMessage(octx, + new ParsedMessage(sampleMsg.getBytes(), false), + new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX).setFlags(Flag.BITMASK_PRIORITY), + new DeliveryContext()); + boolean filtered = RuleManager.applyRulesToExistingMessage(new OperationContext(mbox), mbox, msg.getId(), + RuleManager.parse(filterScript)); + Assert.assertEquals(false, filtered); + List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); + Assert.assertEquals(1, searchedIds.size()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + private void doKeepAndFileIntoOutgoing(String filterScript) { + String body = "doKeepAndFileIntoIncoming" + filterScript.hashCode(); + String sampleMsg = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + body; + try { + // Outgoing + Account account = Provisioning.getInstance().getAccount(MockProvisioning.DEFAULT_ACCOUNT_ID); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailOutgoingSieveScript(filterScript); + + List ids = RuleManager.applyRulesToOutgoingMessage( + new OperationContext(mbox), mbox, + new ParsedMessage(sampleMsg.getBytes(), false), + 5, /* sent folder */ + true, 0, null, Mailbox.ID_AUTO_INCREMENT); + List searchedIds = TestUtil.search(mbox, "in:sent " + body, MailItem.Type.MESSAGE); + Assert.assertEquals(1, searchedIds.size()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + @Test + public void testNoCapability1() { + // No "fileinto" declaration + String filterPlainFileintoScript = + "if header :contains \"Subject\" \"test\" { fileinto \"Junk\"; }"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterPlainFileintoScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + @Test + public void testNoCapability2() { + // declare "fileinto" without "copy" + String filterPlainFileintoScript = "require \"fileinto\";\n" + + "if header :contains \"Subject\" \"test\" {\n" + + " fileinto :copy \"copyAndJunk\";\n" + + "}"; + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterPlainFileintoScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + + // Capability string is mandatory ==> :copy extension will be failed + account.setSieveRequireControlEnabled(true); + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(1, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); + + // Capability string is optional ==> :copy extension should be available + account.setSieveRequireControlEnabled(false); + ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + Assert.assertEquals(2, ids.size()); + msg = mbox.getMessageById(null, ids.get(0).getId()); + Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, msg.getFolderId()); + msg = mbox.getMessageById(null, ids.get(1).getId()); + Folder folder = mbox.getFolderById(null, msg.getFolderId()); + Assert.assertEquals("copyAndJunk", folder.getName()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } + + @Test + public void testPlainFileIntoWithSpaces() { + String filterScript = "require [\"fileinto\"];\n" + + "fileinto \" abc\";" // final destination folder = " abc" + + "fileinto \"abc \";" // final destination folder = "abc" + + "fileinto \" abc \";"; // final destination folder = " abc" + try { + Account account = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com"); + RuleManager.clearCachedRules(account); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + account.setMailSieveScript(filterScript); + String raw = "From: sender@zimbra.com\n" + "To: test1@zimbra.com\n" + "Subject: Test\n" + + "\n" + "Hello World."; + List ids = RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox), + mbox, new ParsedMessage(raw.getBytes(), false), 0, account.getName(), + new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); + assertEquals(2, ids.size()); + Message msg = mbox.getMessageById(null, ids.get(0).getId()); + Folder folder = mbox.getFolderById(null, msg.getFolderId()); + assertEquals(" abc", folder.getName()); + msg = mbox.getMessageById(null, ids.get(1).getId()); + folder = mbox.getFolderById(null, msg.getFolderId()); + assertEquals("abc", folder.getName()); + } catch (Exception e) { + e.printStackTrace(); + fail("No exception should be thrown"); + } + } +} diff --git a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java index 5be46859308..a4cf2738b84 100644 --- a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java +++ b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java @@ -1,434 +1,434 @@ -//// SPDX-FileCopyrightText: 2022 Synacor, Inc. -//// SPDX-FileCopyrightText: 2022 Zextras -//// -//// SPDX-License-Identifier: GPL-2.0-only -// -//package com.zimbra.cs.mailbox; -// -//import static org.junit.Assert.*; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.anyBoolean; -//import static org.mockito.ArgumentMatchers.anyString; -//import static org.mockito.Mockito.doReturn; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.mockStatic; -// -//import com.google.common.base.Strings; -//import com.google.common.collect.ImmutableList; -//import com.google.common.collect.Lists; -//import com.google.common.collect.Maps; -//import com.zimbra.common.account.Key; -//import com.zimbra.common.mailbox.ContactConstants; -//import com.zimbra.common.mime.InternetAddress; -//import com.zimbra.common.service.ServiceException; -//import com.zimbra.common.soap.Element; -//import com.zimbra.common.soap.MailConstants; -//import com.zimbra.cs.account.Account; -//import com.zimbra.cs.account.Provisioning; -//import com.zimbra.cs.db.DbMailItem; -//import com.zimbra.cs.db.DbPool; -//import com.zimbra.cs.db.DbPool.DbConnection; -//import com.zimbra.cs.db.DbResults; -//import com.zimbra.cs.db.DbUtil; -//import com.zimbra.cs.gal.GalGroup.GroupInfo; -//import com.zimbra.cs.gal.GalGroupInfoProvider; -//import com.zimbra.cs.mailbox.Contact.Attachment; -//import com.zimbra.cs.mime.Mime; -//import com.zimbra.cs.mime.ParsedContact; -//import com.zimbra.cs.service.formatter.ArchiveFormatter; -//import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputEntry; -//import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputStream; -//import com.zimbra.cs.service.formatter.TarArchiveInputStream; -//import com.zimbra.cs.service.formatter.VCard; -//import com.zimbra.cs.service.mail.ToXML; -//import com.zimbra.cs.service.util.ItemIdFormatter; -//import com.zimbra.cs.util.JMSession; -//import com.zimbra.cs.util.ZTestWatchman; -//import java.io.File; -//import java.io.FileInputStream; -//import java.io.IOException; -//import java.io.InputStream; -//import java.util.ArrayList; -//import java.util.Collection; -//import java.util.Collections; -//import java.util.HashMap; -//import java.util.List; -//import java.util.Map; -//import java.util.zip.GZIPInputStream; -//import javax.mail.internet.MimeMessage; -//import javax.mail.internet.MimePart; -//import org.junit.After; -//import org.junit.Before; -//import org.junit.BeforeClass; -//import org.junit.Rule; -//import org.junit.Test; -//import org.junit.rules.MethodRule; -//import org.junit.rules.TestName; -//import org.mockito.MockedStatic; -// -///** -// * Unit test for {@link Contact}. -// * -// * @author ysasaki -// */ -//public final class ContactTest { -// -// @Rule public TestName testName = new TestName(); -// @Rule public MethodRule watchman = new ZTestWatchman(); -// -// @BeforeClass -// public static void init() throws Exception { -// MailboxTestUtil.initServer(); -// } -// -// @Before -// public void setUp() throws Exception { -// System.out.println(testName.getMethodName()); -// Provisioning prov = Provisioning.getInstance(); -// prov.createAccount("testCont@zimbra.com", "secret", new HashMap()); -// prov.createAccount("test6232@zimbra.com", "secret", new HashMap()); -// } -// -// @Test -// public void reanalyze() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Map fields = new HashMap(); -// fields.put(ContactConstants.A_firstName, "First1"); -// fields.put(ContactConstants.A_lastName, "Last1"); -// Contact contact = -// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); -// -// DbConnection conn = DbPool.getConnection(mbox); -// -// assertEquals( -// "Last1, First1", -// DbUtil.executeQuery( -// conn, -// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", -// mbox.getId(), -// contact.getId()) -// .getString(1)); -// -// fields.put(ContactConstants.A_firstName, "First2"); -// fields.put(ContactConstants.A_lastName, "Last2"); -// mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); -// -// assertEquals( -// "Last2, First2", -// DbUtil.executeQuery( -// conn, -// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", -// mbox.getId(), -// contact.getId()) -// .getString(1)); -// -// conn.closeQuietly(); -// } -// -// @Test -// public void tooLongSender() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Map fields = new HashMap(); -// fields.put(ContactConstants.A_firstName, Strings.repeat("F", 129)); -// Contact contact = -// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); -// -// DbConnection conn = DbPool.getConnection(mbox); -// -// assertEquals( -// Strings.repeat("F", 128), -// DbUtil.executeQuery( -// conn, -// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", -// mbox.getId(), -// contact.getId()) -// .getString(1)); -// -// fields.put(ContactConstants.A_firstName, null); -// fields.put(ContactConstants.A_lastName, Strings.repeat("L", 129)); -// mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); -// -// assertEquals( -// Strings.repeat("L", 128), -// DbUtil.executeQuery( -// conn, -// "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", -// mbox.getId(), -// contact.getId()) -// .getString(1)); -// -// conn.closeQuietly(); -// } -// -// /** -// * Bug 77746 Test that VCARD formatting escapes ';' and ',' chars which are part of name -// * components -// */ -// @Test -// public void semiColonAndCommaInName() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Map fields = new HashMap(); -// fields.put(ContactConstants.A_lastName, "Last"); -// fields.put(ContactConstants.A_firstName, "First ; SemiColon"); -// fields.put(ContactConstants.A_middleName, "Middle , Comma"); -// fields.put(ContactConstants.A_namePrefix, "Ms."); -// Contact contact = -// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); -// -// VCard vcard = VCard.formatContact(contact); -// String vcardAsString = vcard.getFormatted(); -// String expectedPattern = "N:Last;First \\; SemiColon;Middle \\, Comma;Ms.;"; -// String assertMsg = -// String.format("Vcard\n%s\nshould contain string [%s]", vcardAsString, expectedPattern); -// assertTrue(assertMsg, vcardAsString.contains(expectedPattern)); -// } -// -// @Test -// public void existsInContacts() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// mbox.createContact( -// null, -// new ParsedContact(Collections.singletonMap(ContactConstants.A_email, "test1@zimbra.com")), -// Mailbox.ID_FOLDER_CONTACTS, -// null); -// MailboxTestUtil.index(mbox); -// Thread.sleep(500); -// assertTrue( -// mbox.index.existsInContacts( -// ImmutableList.of( -// new InternetAddress("Test "), -// new InternetAddress("Test ")))); -// assertFalse( -// mbox.index.existsInContacts( -// ImmutableList.of( -// new InternetAddress("Test "), -// new InternetAddress("Test ")))); -// } -// -// @Test -// public void createAutoContact() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// List contacts = -// mbox.createAutoContact( -// null, -// ImmutableList.of( -// new InternetAddress("Test 1", "TEST1@zimbra.com"), -// new InternetAddress("Test 2", "TEST2@zimbra.com"))); -// -// assertEquals(2, contacts.size()); -// assertEquals("1, Test", contacts.get(0).getFileAsString()); -// assertEquals("TEST1@zimbra.com", contacts.get(0).getFields().get(ContactConstants.A_email)); -// assertEquals("2, Test", contacts.get(1).getFileAsString()); -// assertEquals("TEST2@zimbra.com", contacts.get(1).getFields().get(ContactConstants.A_email)); -// -// Collection newAddrs = -// mbox.newContactAddrs( -// ImmutableList.of( -// (javax.mail.Address) -// new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), -// (javax.mail.Address) -// new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), -// "aaa"); -// -// assertEquals(0, newAddrs.size()); -// } -// -// /** Confirms that locator is not set for contacts. */ -// @Test -// public void locator() throws Exception { -// // Create contact. -// Map attrs = Maps.newHashMap(); -// attrs.put(ContactConstants.A_fullName, "Volume Id"); -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// mbox.createContact(null, new ParsedContact(attrs), Mailbox.ID_FOLDER_CONTACTS, null); -// -// // Check volume id in database. -// String sql = -// String.format( -// "SELECT COUNT(*) FROM %s WHERE type = %d AND blob_digest IS NULL AND locator IS NOT" -// + " NULL", -// DbMailItem.getMailItemTableName(mbox), MailItem.Type.CONTACT.toByte()); -// DbResults results = DbUtil.executeQuery(sql); -// assertEquals("Found non-null locator values for contacts", 0, results.getInt(1)); -// } -// -// /** Tests {@link Attachment#getContent()} (bug 36974). */ -// @Test -// public void getAttachmentContent() throws Exception { -// // Create a contact with an attachment. -// Map attrs = new HashMap(); -// attrs.put("fullName", "Get Attachment Content"); -// byte[] attachData = "attachment 1".getBytes(); -// Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "text.txt"); -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// -// mbox.createContact( -// null, -// new ParsedContact(attrs, Lists.newArrayList(textAttachment)), -// Mailbox.ID_FOLDER_CONTACTS, -// null); -// -// // Call getContent() on all attachments. -// for (Contact contact : mbox.getContactList(null, Mailbox.ID_FOLDER_CONTACTS)) { -// List attachments = contact.getAttachments(); -// for (Attachment attach : attachments) { -// attach.getContent(); -// } -// } -// } -// -// /** Modify Contact having an attachment (bug 70488). */ -// @Test -// public void modifyContactHavingAttachment() throws Exception { -// // Create a contact with an attachment. -// Map attrs = new HashMap(); -// attrs.put("fullName", "Contact Initial Content"); -// byte[] attachData = "attachment 1".getBytes(); -// Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "file.txt"); -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Contact contact = -// mbox.createContact( -// null, -// new ParsedContact(attrs, Lists.newArrayList(textAttachment)), -// Mailbox.ID_FOLDER_CONTACTS, -// null); -// -// ParsedContact pc = -// new ParsedContact(contact) -// .modify(new ParsedContact.FieldDeltaList(), new ArrayList(), "ownerId"); -// MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), pc.getContentStream()); -// MimePart mp = Mime.getMimePart(mm, "1"); -// assertEquals("text/plain", mp.getContentType()); -// assertEquals("attachment 1", mp.getContent()); -// } -// -// /** Tests Invalid image attachment (bug 71868). */ -// @Test -// public void createInvalidImageAttachment() throws Exception { -// // Create a contact with an attachment. -// Map attrs = new HashMap(); -// attrs.put("fullName", "Get Attachment Content"); -// byte[] attachData = "attachment 1".getBytes(); -// Attachment attachment = new Attachment(attachData, "image/png", "image", "file1.png"); -// try { -// ParsedContact pc = new ParsedContact(attrs, Lists.newArrayList(attachment)); -// fail("Expected INVALID_IMAGE exception"); -// } catch (ServiceException se) { -// assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); -// } -// } -// -// /** Tests Invalid image attachment (bug 71868). */ -// @Test -// public void modifyInvalidImageAttachment() throws Exception { -// // Create a contact with an attachment. -// Map attrs = new HashMap(); -// attrs.put("fullName", "Contact Initial Content"); -// byte[] attachData = "attachment 1".getBytes(); -// Attachment attachment1 = new Attachment(attachData, "image/png", "customField", "image.png"); -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Contact contact = -// mbox.createContact( -// null, -// new ParsedContact(attrs, Lists.newArrayList(attachment1)), -// Mailbox.ID_FOLDER_CONTACTS, -// null); -// Attachment attachment2 = new Attachment(attachData, "image/png", "image", "image2.png"); -// try { -// ParsedContact pc = -// new ParsedContact(contact) -// .modify( -// new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); -// } catch (ServiceException se) { -// assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); -// } -// } -// -// @Test -// public void testEncodeContact() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); -// Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); -// Map fields = new HashMap(); -// fields.put(ContactConstants.A_userCertificate, "{\"ZMVAL\":[\"Cert1149638887753217\"]}"); -// Contact contact = -// mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); -// -// Element response = new Element.XMLElement(MailConstants.MODIFY_CONTACT_RESPONSE); -// Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "testCont@zimbra.com"); -// ToXML.encodeContact( -// response, new ItemIdFormatter(), new OperationContext(acct), contact, true, null); -// assertEquals(response.getElement("cn").getElement("a").getText(), "Cert1149638887753217"); -// } -// -// @Test -// public void testZCS6232() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); -// // mocking the group not to have view permission -// try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { -// GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); -// doReturn(GroupInfo.IS_GROUP) -// .when(galGroupInfoProvider) -// .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); -// toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); -// toXMLMockedStatic -// .when(() -> ToXML.hasDLViewRight("mydl@zimbra.com", account, account)) -// .thenCallRealMethod(); -// assertFalse(ToXML.hasDLViewRight("mydl@zimbra.com", account, account)); -// } -// } -// -// @Test -// public void testZCS6232WithNullEmail() throws Exception { -// Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); -// GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); -// // inside try logic to avoid Mockito exception when mocking static same class (Thread scope) -// try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { -// doReturn(GroupInfo.IS_GROUP) -// .when(galGroupInfoProvider) -// .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); -// toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); -// toXMLMockedStatic -// .when(() -> ToXML.hasDLViewRight(null, account, account)) -// .thenCallRealMethod(); -// assertTrue(ToXML.hasDLViewRight(null, account, account)); -// } -// } -// -// @Test -// public void testTruncatedContactsTgzImport() throws IOException { -// File file = new File(MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); -// System.out.println(file.getAbsolutePath()); -// InputStream is = new FileInputStream(file); -// ArchiveInputStream ais = new TarArchiveInputStream(new GZIPInputStream(is), "UTF-8"); -// ArchiveInputEntry aie; -// boolean errorCaught = false; -// while ((aie = ais.getNextEntry()) != null) { -// try { -// ArchiveFormatter.readArchiveEntry(ais, aie); -// } catch (IOException e) { -// e.printStackTrace(); -// errorCaught = true; -// break; -// } -// } -// assertTrue(errorCaught); -// } -// -// @After -// public void tearDown() { -// try { -// MailboxTestUtil.clearData(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -//} +// SPDX-FileCopyrightText: 2022 Synacor, Inc. +// SPDX-FileCopyrightText: 2022 Zextras +// +// SPDX-License-Identifier: GPL-2.0-only + +package com.zimbra.cs.mailbox; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.zimbra.common.account.Key; +import com.zimbra.common.mailbox.ContactConstants; +import com.zimbra.common.mime.InternetAddress; +import com.zimbra.common.service.ServiceException; +import com.zimbra.common.soap.Element; +import com.zimbra.common.soap.MailConstants; +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import com.zimbra.cs.db.DbMailItem; +import com.zimbra.cs.db.DbPool; +import com.zimbra.cs.db.DbPool.DbConnection; +import com.zimbra.cs.db.DbResults; +import com.zimbra.cs.db.DbUtil; +import com.zimbra.cs.gal.GalGroup.GroupInfo; +import com.zimbra.cs.gal.GalGroupInfoProvider; +import com.zimbra.cs.mailbox.Contact.Attachment; +import com.zimbra.cs.mime.Mime; +import com.zimbra.cs.mime.ParsedContact; +import com.zimbra.cs.service.formatter.ArchiveFormatter; +import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputEntry; +import com.zimbra.cs.service.formatter.ArchiveFormatter.ArchiveInputStream; +import com.zimbra.cs.service.formatter.TarArchiveInputStream; +import com.zimbra.cs.service.formatter.VCard; +import com.zimbra.cs.service.mail.ToXML; +import com.zimbra.cs.service.util.ItemIdFormatter; +import com.zimbra.cs.util.JMSession; +import com.zimbra.cs.util.ZTestWatchman; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimePart; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.junit.rules.TestName; +import org.mockito.MockedStatic; + +/** + * Unit test for {@link Contact}. + * + * @author ysasaki + */ +public final class ContactTest { + + @Rule public TestName testName = new TestName(); + @Rule public MethodRule watchman = new ZTestWatchman(); + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + } + + @Before + public void setUp() throws Exception { + System.out.println(testName.getMethodName()); + Provisioning prov = Provisioning.getInstance(); + prov.createAccount("testCont@zimbra.com", "secret", new HashMap()); + prov.createAccount("test6232@zimbra.com", "secret", new HashMap()); + } + + @Test + public void reanalyze() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Map fields = new HashMap(); + fields.put(ContactConstants.A_firstName, "First1"); + fields.put(ContactConstants.A_lastName, "Last1"); + Contact contact = + mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); + + DbConnection conn = DbPool.getConnection(mbox); + + assertEquals( + "Last1, First1", + DbUtil.executeQuery( + conn, + "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", + mbox.getId(), + contact.getId()) + .getString(1)); + + fields.put(ContactConstants.A_firstName, "First2"); + fields.put(ContactConstants.A_lastName, "Last2"); + mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); + + assertEquals( + "Last2, First2", + DbUtil.executeQuery( + conn, + "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", + mbox.getId(), + contact.getId()) + .getString(1)); + + conn.closeQuietly(); + } + + @Test + public void tooLongSender() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Map fields = new HashMap(); + fields.put(ContactConstants.A_firstName, Strings.repeat("F", 129)); + Contact contact = + mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); + + DbConnection conn = DbPool.getConnection(mbox); + + assertEquals( + Strings.repeat("F", 128), + DbUtil.executeQuery( + conn, + "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", + mbox.getId(), + contact.getId()) + .getString(1)); + + fields.put(ContactConstants.A_firstName, null); + fields.put(ContactConstants.A_lastName, Strings.repeat("L", 129)); + mbox.modifyContact(null, contact.getId(), new ParsedContact(fields)); + + assertEquals( + Strings.repeat("L", 128), + DbUtil.executeQuery( + conn, + "SELECT sender FROM mboxgroup1.mail_item WHERE mailbox_id = ? AND id = ?", + mbox.getId(), + contact.getId()) + .getString(1)); + + conn.closeQuietly(); + } + + /** + * Bug 77746 Test that VCARD formatting escapes ';' and ',' chars which are part of name + * components + */ + @Test + public void semiColonAndCommaInName() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Map fields = new HashMap(); + fields.put(ContactConstants.A_lastName, "Last"); + fields.put(ContactConstants.A_firstName, "First ; SemiColon"); + fields.put(ContactConstants.A_middleName, "Middle , Comma"); + fields.put(ContactConstants.A_namePrefix, "Ms."); + Contact contact = + mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); + + VCard vcard = VCard.formatContact(contact); + String vcardAsString = vcard.getFormatted(); + String expectedPattern = "N:Last;First \\; SemiColon;Middle \\, Comma;Ms.;"; + String assertMsg = + String.format("Vcard\n%s\nshould contain string [%s]", vcardAsString, expectedPattern); + assertTrue(assertMsg, vcardAsString.contains(expectedPattern)); + } + + @Test + public void existsInContacts() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + mbox.createContact( + null, + new ParsedContact(Collections.singletonMap(ContactConstants.A_email, "test1@zimbra.com")), + Mailbox.ID_FOLDER_CONTACTS, + null); + MailboxTestUtil.index(mbox); + Thread.sleep(500); + assertTrue( + mbox.index.existsInContacts( + ImmutableList.of( + new InternetAddress("Test "), + new InternetAddress("Test ")))); + assertFalse( + mbox.index.existsInContacts( + ImmutableList.of( + new InternetAddress("Test "), + new InternetAddress("Test ")))); + } + + @Test + public void createAutoContact() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + List contacts = + mbox.createAutoContact( + null, + ImmutableList.of( + new InternetAddress("Test 1", "TEST1@zimbra.com"), + new InternetAddress("Test 2", "TEST2@zimbra.com"))); + + assertEquals(2, contacts.size()); + assertEquals("1, Test", contacts.get(0).getFileAsString()); + assertEquals("TEST1@zimbra.com", contacts.get(0).getFields().get(ContactConstants.A_email)); + assertEquals("2, Test", contacts.get(1).getFileAsString()); + assertEquals("TEST2@zimbra.com", contacts.get(1).getFields().get(ContactConstants.A_email)); + + Collection newAddrs = + mbox.newContactAddrs( + ImmutableList.of( + (javax.mail.Address) + new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), + (javax.mail.Address) + new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), + "aaa"); + + assertEquals(0, newAddrs.size()); + } + + /** Confirms that locator is not set for contacts. */ + @Test + public void locator() throws Exception { + // Create contact. + Map attrs = Maps.newHashMap(); + attrs.put(ContactConstants.A_fullName, "Volume Id"); + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + mbox.createContact(null, new ParsedContact(attrs), Mailbox.ID_FOLDER_CONTACTS, null); + + // Check volume id in database. + String sql = + String.format( + "SELECT COUNT(*) FROM %s WHERE type = %d AND blob_digest IS NULL AND locator IS NOT" + + " NULL", + DbMailItem.getMailItemTableName(mbox), MailItem.Type.CONTACT.toByte()); + DbResults results = DbUtil.executeQuery(sql); + assertEquals("Found non-null locator values for contacts", 0, results.getInt(1)); + } + + /** Tests {@link Attachment#getContent()} (bug 36974). */ + @Test + public void getAttachmentContent() throws Exception { + // Create a contact with an attachment. + Map attrs = new HashMap(); + attrs.put("fullName", "Get Attachment Content"); + byte[] attachData = "attachment 1".getBytes(); + Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "text.txt"); + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + + mbox.createContact( + null, + new ParsedContact(attrs, Lists.newArrayList(textAttachment)), + Mailbox.ID_FOLDER_CONTACTS, + null); + + // Call getContent() on all attachments. + for (Contact contact : mbox.getContactList(null, Mailbox.ID_FOLDER_CONTACTS)) { + List attachments = contact.getAttachments(); + for (Attachment attach : attachments) { + attach.getContent(); + } + } + } + + /** Modify Contact having an attachment (bug 70488). */ + @Test + public void modifyContactHavingAttachment() throws Exception { + // Create a contact with an attachment. + Map attrs = new HashMap(); + attrs.put("fullName", "Contact Initial Content"); + byte[] attachData = "attachment 1".getBytes(); + Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "file.txt"); + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Contact contact = + mbox.createContact( + null, + new ParsedContact(attrs, Lists.newArrayList(textAttachment)), + Mailbox.ID_FOLDER_CONTACTS, + null); + + ParsedContact pc = + new ParsedContact(contact) + .modify(new ParsedContact.FieldDeltaList(), new ArrayList(), "ownerId"); + MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), pc.getContentStream()); + MimePart mp = Mime.getMimePart(mm, "1"); + assertEquals("text/plain", mp.getContentType()); + assertEquals("attachment 1", mp.getContent()); + } + + /** Tests Invalid image attachment (bug 71868). */ + @Test + public void createInvalidImageAttachment() throws Exception { + // Create a contact with an attachment. + Map attrs = new HashMap(); + attrs.put("fullName", "Get Attachment Content"); + byte[] attachData = "attachment 1".getBytes(); + Attachment attachment = new Attachment(attachData, "image/png", "image", "file1.png"); + try { + ParsedContact pc = new ParsedContact(attrs, Lists.newArrayList(attachment)); + fail("Expected INVALID_IMAGE exception"); + } catch (ServiceException se) { + assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); + } + } + + /** Tests Invalid image attachment (bug 71868). */ + @Test + public void modifyInvalidImageAttachment() throws Exception { + // Create a contact with an attachment. + Map attrs = new HashMap(); + attrs.put("fullName", "Contact Initial Content"); + byte[] attachData = "attachment 1".getBytes(); + Attachment attachment1 = new Attachment(attachData, "image/png", "customField", "image.png"); + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Contact contact = + mbox.createContact( + null, + new ParsedContact(attrs, Lists.newArrayList(attachment1)), + Mailbox.ID_FOLDER_CONTACTS, + null); + Attachment attachment2 = new Attachment(attachData, "image/png", "image", "image2.png"); + try { + ParsedContact pc = + new ParsedContact(contact) + .modify( + new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); + } catch (ServiceException se) { + assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); + } + } + + @Test + public void testEncodeContact() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); + Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); + Map fields = new HashMap(); + fields.put(ContactConstants.A_userCertificate, "{\"ZMVAL\":[\"Cert1149638887753217\"]}"); + Contact contact = + mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); + + Element response = new Element.XMLElement(MailConstants.MODIFY_CONTACT_RESPONSE); + Account acct = Provisioning.getInstance().get(Key.AccountBy.name, "testCont@zimbra.com"); + ToXML.encodeContact( + response, new ItemIdFormatter(), new OperationContext(acct), contact, true, null); + assertEquals(response.getElement("cn").getElement("a").getText(), "Cert1149638887753217"); + } + + @Test + public void testZCS6232() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); + // mocking the group not to have view permission + try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { + GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); + doReturn(GroupInfo.IS_GROUP) + .when(galGroupInfoProvider) + .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); + toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); + toXMLMockedStatic + .when(() -> ToXML.hasDLViewRight("mydl@zimbra.com", account, account)) + .thenCallRealMethod(); + assertFalse(ToXML.hasDLViewRight("mydl@zimbra.com", account, account)); + } + } + + @Test + public void testZCS6232WithNullEmail() throws Exception { + Account account = Provisioning.getInstance().getAccountByName("test6232@zimbra.com"); + GalGroupInfoProvider galGroupInfoProvider = mock(GalGroupInfoProvider.class); + // inside try logic to avoid Mockito exception when mocking static same class (Thread scope) + try (MockedStatic toXMLMockedStatic = mockStatic(ToXML.class)) { + doReturn(GroupInfo.IS_GROUP) + .when(galGroupInfoProvider) + .getGroupInfo(anyString(), anyBoolean(), any(Account.class), any(Account.class)); + toXMLMockedStatic.when(ToXML::getGalGroupInfoProvider).thenReturn(galGroupInfoProvider); + toXMLMockedStatic + .when(() -> ToXML.hasDLViewRight(null, account, account)) + .thenCallRealMethod(); + assertTrue(ToXML.hasDLViewRight(null, account, account)); + } + } + + @Test + public void testTruncatedContactsTgzImport() throws IOException { + File file = new File(MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); + System.out.println(file.getAbsolutePath()); + InputStream is = new FileInputStream(file); + ArchiveInputStream ais = new TarArchiveInputStream(new GZIPInputStream(is), "UTF-8"); + ArchiveInputEntry aie; + boolean errorCaught = false; + while ((aie = ais.getNextEntry()) != null) { + try { + ArchiveFormatter.readArchiveEntry(ais, aie); + } catch (IOException e) { + e.printStackTrace(); + errorCaught = true; + break; + } + } + assertTrue(errorCaught); + } + + @After + public void tearDown() { + try { + MailboxTestUtil.clearData(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} From e7c822948273f30a1af8c9be27ee6d28e8e7e510 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 13:43:07 +0200 Subject: [PATCH 24/39] feat: [CO-621] slightly modify Contact and FileIntoCopy tests --- .../zimbra/cs/filter/FileIntoCopyTest.java | 68 +++++++++------- .../com/zimbra/cs/mailbox/ContactTest.java | 78 +++++++++---------- 2 files changed, 77 insertions(+), 69 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java index 271c59300c9..fc3fb7fd697 100644 --- a/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java +++ b/store/src/test/java/com/zimbra/cs/filter/FileIntoCopyTest.java @@ -6,17 +6,19 @@ package com.zimbra.cs.filter; import static org.junit.Assert.*; + +import com.zimbra.cs.mailbox.MailItem.Type; import java.util.HashMap; import java.util.List; +import java.util.Objects; +import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import com.zimbra.common.account.Key; import com.zimbra.cs.account.Account; import com.zimbra.cs.account.MockProvisioning; import com.zimbra.cs.account.Provisioning; -import com.zimbra.cs.account.Server; import com.zimbra.cs.mailbox.DeliveryContext; import com.zimbra.cs.mailbox.DeliveryOptions; import com.zimbra.cs.mailbox.Flag; @@ -33,18 +35,20 @@ public class FileIntoCopyTest { - @BeforeClass - public static void init() throws Exception { + @Before + public void setUp() throws Exception { MailboxTestUtil.initServer(); Provisioning prov = Provisioning.getInstance(); - Account acct = prov.createAccount("test@zimbra.com", "secret", - new HashMap()); - Server server = Provisioning.getInstance().getServer(acct); + prov.createAccount("test@zimbra.com", "secret", new HashMap<>()); } - @Before - public void setUp() throws Exception { + @After + public void tearDown() { + try { MailboxTestUtil.clearData(); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -143,17 +147,17 @@ mbox, new ParsedMessage(rawTest.getBytes(), false), 0, account.getName(), Assert.assertNull( mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE)); // message should be stored in foo - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in bar - item = mbox + item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); } catch (Exception e) { @@ -185,14 +189,15 @@ public void testCopyFileIntoPattern1Real() { new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); // message should be stored in foo - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + item = Objects + .requireNonNull(mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(Type.MESSAGE)) .get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); @@ -226,21 +231,22 @@ public void testCopyFileIntoPattern2Test() { new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); // message should be stored in bar - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "bar").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in foo - item = mbox + item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + item = Objects + .requireNonNull(mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(Type.MESSAGE)) .get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); @@ -273,14 +279,15 @@ public void testCopyFileIntoPattern2Real() { new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); // message should be stored in foo - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + item = Objects + .requireNonNull(mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(Type.MESSAGE)) .get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); @@ -312,10 +319,10 @@ public void testCopyFileIntoPattern3Test() { new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); // message should be stored in foo - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should not be stored in inbox @@ -349,14 +356,15 @@ public void testCopyFileIntoPattern3Real() { new ParsedMessage(rawReal.getBytes(), false), 0, account.getName(), new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true); // message should be stored in foo - Integer item = mbox + Integer item = Objects.requireNonNull(mbox .getItemIds(null, mbox.getFolderByName(null, Mailbox.ID_FOLDER_USER_ROOT, "foo").getId()) - .getIds(MailItem.Type.MESSAGE).get(0); + .getIds(Type.MESSAGE)).get(0); Message msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); // message should be stored in inbox - item = mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE) + item = Objects + .requireNonNull(mbox.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(Type.MESSAGE)) .get(0); msg = mbox.getMessageById(null, item); Assert.assertEquals("Hello World", msg.getFragment()); @@ -434,7 +442,7 @@ private void doKeepAndFileIntoExisting(String filterScript) { new DeliveryContext()); boolean filtered = RuleManager.applyRulesToExistingMessage(new OperationContext(mbox), mbox, msg.getId(), RuleManager.parse(filterScript)); - Assert.assertEquals(false, filtered); + assertFalse(filtered); List searchedIds = TestUtil.search(mbox, "in:inbox " + body, MailItem.Type.MESSAGE); Assert.assertEquals(1, searchedIds.size()); } catch (Exception e) { diff --git a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java index a4cf2738b84..dae312984b8 100644 --- a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java +++ b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java @@ -5,7 +5,10 @@ package com.zimbra.cs.mailbox; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; @@ -59,7 +62,6 @@ import javax.mail.internet.MimePart; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.MethodRule; @@ -76,24 +78,29 @@ public final class ContactTest { @Rule public TestName testName = new TestName(); @Rule public MethodRule watchman = new ZTestWatchman(); - @BeforeClass - public static void init() throws Exception { - MailboxTestUtil.initServer(); - } - @Before public void setUp() throws Exception { + MailboxTestUtil.initServer(); System.out.println(testName.getMethodName()); Provisioning prov = Provisioning.getInstance(); - prov.createAccount("testCont@zimbra.com", "secret", new HashMap()); - prov.createAccount("test6232@zimbra.com", "secret", new HashMap()); + prov.createAccount("testCont@zimbra.com", "secret", new HashMap<>()); + prov.createAccount("test6232@zimbra.com", "secret", new HashMap<>()); + } + + @After + public void tearDown() { + try { + MailboxTestUtil.clearData(); + } catch (Exception e) { + e.printStackTrace(); + } } @Test public void reanalyze() throws Exception { Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); + Map fields = new HashMap<>(); fields.put(ContactConstants.A_firstName, "First1"); fields.put(ContactConstants.A_lastName, "Last1"); Contact contact = @@ -130,7 +137,7 @@ public void reanalyze() throws Exception { public void tooLongSender() throws Exception { Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); + Map fields = new HashMap<>(); fields.put(ContactConstants.A_firstName, Strings.repeat("F", 129)); Contact contact = mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); @@ -170,7 +177,7 @@ public void tooLongSender() throws Exception { public void semiColonAndCommaInName() throws Exception { Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); + Map fields = new HashMap<>(); fields.put(ContactConstants.A_lastName, "Last"); fields.put(ContactConstants.A_firstName, "First ; SemiColon"); fields.put(ContactConstants.A_middleName, "Middle , Comma"); @@ -229,10 +236,8 @@ public void createAutoContact() throws Exception { Collection newAddrs = mbox.newContactAddrs( ImmutableList.of( - (javax.mail.Address) - new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), - (javax.mail.Address) - new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), + new javax.mail.internet.InternetAddress("test1@zimbra.com", "Test 1"), + new javax.mail.internet.InternetAddress("test2@zimbra.com", "Test 2")), "aaa"); assertEquals(0, newAddrs.size()); @@ -262,7 +267,7 @@ public void locator() throws Exception { @Test public void getAttachmentContent() throws Exception { // Create a contact with an attachment. - Map attrs = new HashMap(); + Map attrs = new HashMap<>(); attrs.put("fullName", "Get Attachment Content"); byte[] attachData = "attachment 1".getBytes(); Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "text.txt"); @@ -288,7 +293,7 @@ public void getAttachmentContent() throws Exception { @Test public void modifyContactHavingAttachment() throws Exception { // Create a contact with an attachment. - Map attrs = new HashMap(); + Map attrs = new HashMap<>(); attrs.put("fullName", "Contact Initial Content"); byte[] attachData = "attachment 1".getBytes(); Attachment textAttachment = new Attachment(attachData, "text/plain", "customField", "file.txt"); @@ -303,7 +308,7 @@ public void modifyContactHavingAttachment() throws Exception { ParsedContact pc = new ParsedContact(contact) - .modify(new ParsedContact.FieldDeltaList(), new ArrayList(), "ownerId"); + .modify(new ParsedContact.FieldDeltaList(), new ArrayList<>(), "ownerId"); MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSession(), pc.getContentStream()); MimePart mp = Mime.getMimePart(mm, "1"); assertEquals("text/plain", mp.getContentType()); @@ -312,14 +317,14 @@ public void modifyContactHavingAttachment() throws Exception { /** Tests Invalid image attachment (bug 71868). */ @Test - public void createInvalidImageAttachment() throws Exception { + public void createInvalidImageAttachment() { // Create a contact with an attachment. - Map attrs = new HashMap(); + Map attrs = new HashMap<>(); attrs.put("fullName", "Get Attachment Content"); byte[] attachData = "attachment 1".getBytes(); Attachment attachment = new Attachment(attachData, "image/png", "image", "file1.png"); try { - ParsedContact pc = new ParsedContact(attrs, Lists.newArrayList(attachment)); + new ParsedContact(attrs, Lists.newArrayList(attachment)); fail("Expected INVALID_IMAGE exception"); } catch (ServiceException se) { assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); @@ -330,7 +335,7 @@ public void createInvalidImageAttachment() throws Exception { @Test public void modifyInvalidImageAttachment() throws Exception { // Create a contact with an attachment. - Map attrs = new HashMap(); + Map attrs = new HashMap<>(); attrs.put("fullName", "Contact Initial Content"); byte[] attachData = "attachment 1".getBytes(); Attachment attachment1 = new Attachment(attachData, "image/png", "customField", "image.png"); @@ -344,10 +349,8 @@ public void modifyInvalidImageAttachment() throws Exception { null); Attachment attachment2 = new Attachment(attachData, "image/png", "image", "image2.png"); try { - ParsedContact pc = - new ParsedContact(contact) - .modify( - new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); + new ParsedContact(contact) + .modify(new ParsedContact.FieldDeltaList(), Lists.newArrayList(attachment2), "ownerId"); } catch (ServiceException se) { assertEquals("check the INVALID_IMAGE exception", "mail.INVALID_IMAGE", se.getCode()); } @@ -357,7 +360,7 @@ public void modifyInvalidImageAttachment() throws Exception { public void testEncodeContact() throws Exception { Account account = Provisioning.getInstance().getAccountByName("testCont@zimbra.com"); Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account); - Map fields = new HashMap(); + Map fields = new HashMap<>(); fields.put(ContactConstants.A_userCertificate, "{\"ZMVAL\":[\"Cert1149638887753217\"]}"); Contact contact = mbox.createContact(null, new ParsedContact(fields), Mailbox.ID_FOLDER_CONTACTS, null); @@ -405,8 +408,10 @@ public void testZCS6232WithNullEmail() throws Exception { @Test public void testTruncatedContactsTgzImport() throws IOException { - File file = new File(MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); + File file = new File( + MailboxTestUtil.getZimbraServerDir("") + "src/test/resources/Truncated.tgz"); System.out.println(file.getAbsolutePath()); + InputStream is = new FileInputStream(file); ArchiveInputStream ais = new TarArchiveInputStream(new GZIPInputStream(is), "UTF-8"); ArchiveInputEntry aie; @@ -415,20 +420,15 @@ public void testTruncatedContactsTgzImport() throws IOException { try { ArchiveFormatter.readArchiveEntry(ais, aie); } catch (IOException e) { - e.printStackTrace(); + System.out.println("Expected exception was caught: " + e); errorCaught = true; break; } } - assertTrue(errorCaught); - } - @After - public void tearDown() { - try { - MailboxTestUtil.clearData(); - } catch (Exception e) { - e.printStackTrace(); - } + is.close(); + ais.close(); + + assertTrue(errorCaught); } } From 1ada9cb0dd0b009a72ac6d8afdab29fcfce06a87 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 14:03:42 +0200 Subject: [PATCH 25/39] feat: [CO-621] slightly modify ImapHandlerTest --- .../com/zimbra/cs/imap/ImapHandlerTest.java | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java b/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java index a4b99e65738..4bb11f20551 100644 --- a/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java +++ b/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java @@ -7,19 +7,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -import org.apache.commons.io.output.ByteArrayOutputStream; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.MethodRule; -import org.junit.rules.TestName; - import com.zimbra.common.localconfig.LC; import com.zimbra.common.mailbox.FolderStore; import com.zimbra.common.service.ServiceException; @@ -33,9 +20,18 @@ import com.zimbra.cs.mailbox.SearchFolder; import com.zimbra.cs.server.ServerThrottle; import com.zimbra.cs.util.ZTestWatchman; -import qa.unittest.TestUtil; - +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import junit.framework.Assert; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.MethodRule; +import org.junit.rules.TestName; +import qa.unittest.TestUtil; public class ImapHandlerTest { @@ -43,28 +39,28 @@ public class ImapHandlerTest { @Rule public TestName testName = new TestName(); @Rule public MethodRule watchman = new ZTestWatchman(); - - @BeforeClass - public static void init() throws Exception { - LC.imap_use_ehcache.setDefault(false); - MailboxTestUtil.initServer(); - String[] hosts = {"localhost", "127.0.0.1"}; - ServerThrottle.configureThrottle(new ImapConfig(false).getProtocol(), 100, 100, Arrays.asList(hosts), Arrays.asList(hosts)); - } @Before public void setUp() throws Exception { - System.out.println(testName.getMethodName()); - Provisioning prov = Provisioning.getInstance(); - HashMap attrs = new HashMap(); - attrs.put(Provisioning.A_zimbraId, "12aa345b-2b47-44e6-8cb8-7fdfa18c1a9f"); - attrs.put(Provisioning.A_zimbraFeatureAntispamEnabled , "true"); - prov.createAccount(LOCAL_USER, "secret", attrs); + LC.imap_use_ehcache.setDefault(false); + MailboxTestUtil.initServer(); + String[] hosts = {"localhost", "127.0.0.1"}; + ServerThrottle.configureThrottle(new ImapConfig(false).getProtocol(), 100, 100, Arrays.asList(hosts), Arrays.asList(hosts)); + System.out.println(testName.getMethodName()); + Provisioning prov = Provisioning.getInstance(); + HashMap attrs = new HashMap<>(); + attrs.put(Provisioning.A_zimbraId, "12aa345b-2b47-44e6-8cb8-7fdfa18c1a9f"); + attrs.put(Provisioning.A_zimbraFeatureAntispamEnabled , "true"); + prov.createAccount(LOCAL_USER, "secret", attrs); } @After - public void tearDown() throws Exception { + public void tearDown() { + try { MailboxTestUtil.clearData(); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -82,8 +78,10 @@ public void testDoCOPYByUID() { Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, mbox.getMessageById(null, m3.getId()).getFolderId()); ImapHandler handler = new MockImapHandler(); ImapCredentials creds = new ImapCredentials(acct, ImapCredentials.EnabledHack.NONE); - ImapPath pathSpam = new MockImapPath(null,mbox.getFolderById(null, Mailbox.ID_FOLDER_SPAM), creds); - ImapPath pathInbox = new MockImapPath(null,mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); + ImapPath pathSpam = new MockImapPath(null, mbox.getFolderById(null, Mailbox.ID_FOLDER_SPAM), + creds); + ImapPath pathInbox = new MockImapPath(null, + mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); handler.setCredentials(creds); byte params = 0; handler.setSelectedFolder(pathSpam, params); @@ -139,8 +137,10 @@ public void testDoCOPYByNumber() throws Exception { Assert.assertEquals(Mailbox.ID_FOLDER_INBOX, mbox.getMessageById(null, m3.getId()).getFolderId()); ImapHandler handler = new MockImapHandler(); ImapCredentials creds = new ImapCredentials(acct, ImapCredentials.EnabledHack.NONE); - ImapPath pathSpam = new MockImapPath(null,mbox.getFolderById(null, Mailbox.ID_FOLDER_SPAM), creds); - ImapPath pathInbox = new MockImapPath(null,mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); + ImapPath pathSpam = new MockImapPath(null, mbox.getFolderById(null, Mailbox.ID_FOLDER_SPAM), + creds); + ImapPath pathInbox = new MockImapPath(null, + mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); handler.setCredentials(creds); byte params = 0; handler.setSelectedFolder(pathSpam, params); @@ -198,7 +198,8 @@ public void testDoSearch() throws Exception { Thread.sleep(500); ImapHandler handler = new MockImapHandler(); ImapCredentials creds = new ImapCredentials(acct, ImapCredentials.EnabledHack.NONE); - ImapPath pathInbox = new MockImapPath(null,mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); + ImapPath pathInbox = new MockImapPath(null, + mbox.getFolderById(null, Mailbox.ID_FOLDER_INBOX), creds); handler.setCredentials(creds); byte params = 0; handler.setSelectedFolder(pathInbox, params); @@ -278,7 +279,7 @@ public void testLogin() throws Exception { Assert.assertFalse(handler.isAuthenticated()); } - class MockImapPath extends ImapPath { + static class MockImapPath extends ImapPath { MockImapPath(ImapPath other) { super(other); @@ -300,7 +301,7 @@ protected boolean isWritable() { } @Override - protected boolean isWritable(short rights) throws ServiceException { + protected boolean isWritable(short rights) { return true; } } From 6c30810c8beb00a3c4d643da25993f538724c7b4 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 15:01:41 +0200 Subject: [PATCH 26/39] feat: [CO-621] remove checkValidity --- .../service/admin/CertificateNotificationManager.java | 10 ---------- .../admin/CertificateNotificationManagerTest.java | 5 ----- 2 files changed, 15 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 8606bfa609e..eb97a9e2245 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -1,6 +1,5 @@ package com.zimbra.cs.service.admin; -import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; import com.zimbra.common.util.ZimbraLog; import com.zimbra.cs.account.Config; @@ -302,7 +301,6 @@ private static MimeMessage createMimeMessage( } private static Address[] convert(String[] addresses) throws ServiceException { - checkAddressValidity(addresses); try { String addressList = String.join(", ", addresses); return InternetAddress.parse(addressList); @@ -312,18 +310,10 @@ private static Address[] convert(String[] addresses) throws ServiceException { } private static Address convert(String address) throws ServiceException { - checkAddressValidity(address); try { return new InternetAddress(address); } catch (AddressException e) { throw ServiceException.FAILURE("Unable to parse address", e); } } - - private static void checkAddressValidity(String... addresses) throws ServiceException { - for (String address: addresses) { - Optional.ofNullable(provisioning.get(AccountBy.name, address)).orElseThrow( - () -> ServiceException.FAILURE("Unable to find account with address " + address)); - } - } } diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 46f44795f9e..37d60e162c0 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -20,9 +20,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.zimbra.common.account.Key.AccountBy; import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Account; import com.zimbra.cs.account.Config; import com.zimbra.cs.account.Domain; import com.zimbra.cs.account.Provisioning; @@ -52,7 +50,6 @@ public class CertificateNotificationManagerTest { private final Domain domain = mock(Domain.class); private final Provisioning provisioning = mock(Provisioning.class); private final Config config = mock(Config.class); - private final Account account = mock(Account.class); private final MailSender mailSender = mock(MailSender.class); private final String from = "admin@test.com"; private final String[] recipients = new String[] {from, "admin2@test.com"}; @@ -67,8 +64,6 @@ public void setUp() throws ServiceException { when(config.getCarbonioNotificationRecipients()).thenReturn(recipients); when(mailbox.getMailSender(domain)).thenReturn(mailSender); when(mailSender.getCurrentSession()).thenReturn(null); - when(provisioning.get(AccountBy.name, from)).thenReturn(account); - when(provisioning.get(AccountBy.name, recipients[1])).thenReturn(account); } @Test From 6ea1e959ec5a346ed0ebc30e8c3d96b93e2b65a1 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Thu, 30 Mar 2023 16:28:18 +0200 Subject: [PATCH 27/39] feat: [CO-621] modify templates --- .../admin/CertificateNotificationManager.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index eb97a9e2245..e2921c95f66 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -56,8 +56,9 @@ public class CertificateNotificationManager { public static final String FAIL = "fail"; public static final String FAILURE_DOMAIN_NOTIFICATION_TEMPLATE = - "The SSL certificate request for was unsuccessful and the system wasn't able to" - + " verify the validity of the domain.\n" + "\n" + + "The SSL certificate request for was unsuccessful and the system " + + "wasn't able to verify the validity of the domain.\n" + "\n" + "Most common reasons that could cause this kind of failure are:\n" + "- Misspelled or missing public service hostname and/or virtual hostname." @@ -74,7 +75,8 @@ public class CertificateNotificationManager { public static final String RECEIVED = "received"; public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = - "The certificate was successfully received.\n" + "\n" + + "The certificate was successfully received.\n" + "Please NOTE that the Certificate and Key will be available after the proxy reload.\n" + "You’ll be able to download them from the Certificate section in the admin interface.\n" + "\n" @@ -136,7 +138,7 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { * create {@link javax.mail.internet.MimeMessage}. * * @param outputMessage output from RemoteManager/Certbot - * @return map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT + * @return map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT */ protected static Map createIssueCertNotificationMap( Domain domain, String outputMessage) throws ServiceException { @@ -252,7 +254,7 @@ protected static List createMimeMessageList( list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); - } catch(ServiceException e) { + } catch (ServiceException e) { ZimbraLog.rmgmt.info( "Notifications about LetsEncrypt certificate generation for " + notificationMap.get(DOMAIN_NAME) From d2183f36050a9968124c51f7ddd39eba3334f28a Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Fri, 31 Mar 2023 10:17:16 +0200 Subject: [PATCH 28/39] feat: [CO-621] add domain name to success template --- .../admin/CertificateNotificationManager.java | 13 +++++++++---- .../admin/CertificateNotificationManagerTest.java | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index e2921c95f66..7e5c9331f70 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -61,7 +61,7 @@ public class CertificateNotificationManager { + "wasn't able to verify the validity of the domain.\n" + "\n" + "Most common reasons that could cause this kind of failure are:\n" - + "- Misspelled or missing public service hostname and/or virtual hostname." + + "- Misspelled or missing Public Service Hostname and/or Virtual Hostname." + " Make sure both are filled in with a valid Fully Qualified Domain Name.\n" + "- Wrong or missing A/AAAA entry for Public Service Hostname and/or Virtual Hostname." + " Make sure there is a valid, public resolution for the Fully Qualified Domain Name" @@ -76,7 +76,7 @@ public class CertificateNotificationManager { public static final String RECEIVED = "received"; public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = "\n" - + "The certificate was successfully received.\n" + + "The certificate for was successfully received.\n" + "Please NOTE that the Certificate and Key will be available after the proxy reload.\n" + "You’ll be able to download them from the Certificate section in the admin interface.\n" + "\n" @@ -214,11 +214,16 @@ protected static Map createIssueCertNotificationMap( Matcher matcher = Pattern.compile(regex).matcher(substringResult); if (matcher.find()) { String expiresTemplate = "This certificate expires on "; - expire = expire + expiresTemplate + matcher.group() + "."; + expire = String.join("",expire, expiresTemplate, matcher.group(), "."); } String domainMessage = - String.join("", HEADER, SUCCESS_RESULT, SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE, expire); + String.join( + "", + HEADER, + SUCCESS_RESULT, + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName()), + expire); notificationMap.put(DOMAIN_MESSAGE, domainMessage); notificationMap.put(DOMAIN_FROM, domainFrom); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 37d60e162c0..1e6cfeadb9b 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -120,8 +120,10 @@ public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { @Test public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { final String expiration = "\n" + "This certificate expires on 2023-06-15."; - final String expectedDomainMessage = - HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE + expiration; + final String expectedDomainMessage = HEADER + SUCCESS_RESULT + + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName) + + expiration; + String certbotSuccessMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" From 8474927818a14c79ddf5c843df8141da8e45bd99 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 12:02:16 +0200 Subject: [PATCH 29/39] feat: [CO-621] refactor to avoid casting --- .../admin/CertificateNotificationManager.java | 100 ++++++++---------- .../CertificateNotificationManagerTest.java | 22 ++-- 2 files changed, 54 insertions(+), 68 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 7e5c9331f70..8145c9c9dac 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -32,12 +32,7 @@ * @since 23.5.0 */ public class CertificateNotificationManager { - public static final String GLOBAL_FROM = "globalFrom"; - public static final String GLOBAL_TO = "globalTo"; public static final String GLOBAL_MESSAGE = "globalMessage"; - - public static final String DOMAIN_FROM = "domainFrom"; - public static final String DOMAIN_TO = "domainTo"; public static final String DOMAIN_MESSAGE = "domainMessage"; public static final String DOMAIN_NAME = "domainName"; @@ -82,8 +77,6 @@ public class CertificateNotificationManager { + "\n" + "The files will be automatically updated when the certificate renews.\n"; - private static final Provisioning provisioning = Provisioning.getInstance(); - private CertificateNotificationManager() { throw new RuntimeException("CertificateNotificationManager class cannot be instantiated."); } @@ -108,11 +101,12 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { + outputMessage); try { - Map notificationMap = createIssueCertNotificationMap(domain, outputMessage); + Map notificationMap = + createIssueCertNotificationMap(domainName, outputMessage); MailSender sender = mbox.getMailSender(domain); List mimeMessageList = - createMimeMessageList(sender.getCurrentSession(), notificationMap); + createMimeMessageList(sender, domain, notificationMap); sender.sendMimeMessageList(mbox, mimeMessageList); @@ -134,41 +128,16 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { } /** - * Creates a map based on domain values and Remote Manager/Certbot output which would be used to + * Creates a map based on Remote Manager/Certbot output which would be used to * create {@link javax.mail.internet.MimeMessage}. * * @param outputMessage output from RemoteManager/Certbot - * @return map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT + * @return map with needed values of notification SUBJECT and MESSAGE TEXT */ - protected static Map createIssueCertNotificationMap( - Domain domain, String outputMessage) throws ServiceException { - - Config config = provisioning.getConfig(); - - String globalFrom = - Optional.ofNullable(config.getCarbonioNotificationFrom()) - .orElseThrow( - () -> - ServiceException.FAILURE( - "Global CarbonioNotificationFrom attribute is not present.", null)); - String[] globalTo = - Optional.ofNullable(config.getCarbonioNotificationRecipients()) - .orElseThrow( - () -> - ServiceException.FAILURE( - "Global CarbonioNotificationRecipients attribute is not present.", null)); - - String domainFrom = - Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElse(globalFrom); - String[] domainTo = - Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); + protected static Map createIssueCertNotificationMap( + String domainName, String outputMessage) throws ServiceException { - Map notificationMap = new HashMap<>(); - - notificationMap.put(DOMAIN_NAME, domain.getName()); - - notificationMap.put(GLOBAL_FROM, globalFrom); - notificationMap.put(GLOBAL_TO, globalTo); + Map notificationMap = new HashMap<>(); // message for global admin contains all output notificationMap.put(GLOBAL_MESSAGE, outputMessage); @@ -197,11 +166,9 @@ protected static Map createIssueCertNotificationMap( "", HEADER, FAILURE_RESULT, - FAILURE_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName())); + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName)); notificationMap.put(DOMAIN_MESSAGE, domainMessage); - notificationMap.put(DOMAIN_FROM, domainFrom); - notificationMap.put(DOMAIN_TO, domainTo); return notificationMap; } @@ -222,12 +189,10 @@ protected static Map createIssueCertNotificationMap( "", HEADER, SUCCESS_RESULT, - SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName()), + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName), expire); notificationMap.put(DOMAIN_MESSAGE, domainMessage); - notificationMap.put(DOMAIN_FROM, domainFrom); - notificationMap.put(DOMAIN_TO, domainTo); } // in any other cases (like certificate is not yet due for renewal ... etc) @@ -240,24 +205,45 @@ protected static Map createIssueCertNotificationMap( * Creates {@link javax.mail.internet.MimeMessage} list what would be sent to recipients. * * @param session {@link javax.mail.Session} - * @param notificationMap map with needed values of FROM, TO, SUBJECT and MESSAGE TEXT + * @param notificationMap map with needed values MESSAGE TEXT * @return a list of {@link javax.mail.internet.MimeMessage} * @throws ServiceException if unable to parse addresses or create a MimeMessage */ protected static List createMimeMessageList( - Session session, Map notificationMap) throws ServiceException { + MailSender sender, Domain domain, Map notificationMap) throws ServiceException { + + Session session = sender.getCurrentSession(); + Provisioning provisioning = Provisioning.getInstance(); + Config config = provisioning.getConfig(); + + String globalFrom = + Optional.ofNullable(config.getCarbonioNotificationFrom()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationFrom attribute is not present.", null)); + String[] globalTo = + Optional.ofNullable(config.getCarbonioNotificationRecipients()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationRecipients attribute is not present.", null)); + + String domainFrom = + Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElse(globalFrom); + String[] domainTo = + Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); List list = new ArrayList<>(); - String subject = - notificationMap.get(DOMAIN_NAME) + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); + String subject = domain.getName() + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); try { - Address globalFrom = convert((String) notificationMap.get(GLOBAL_FROM)); - Address[] globalTo = convert((String[]) notificationMap.get(GLOBAL_TO)); - String globalMessage = (String) notificationMap.get(GLOBAL_MESSAGE); + Address globalAddressFrom = convert(globalFrom); + Address[] globalAddressTo = convert(globalTo); + String globalMessage = notificationMap.get(GLOBAL_MESSAGE); - list.add(createMimeMessage(session, subject, globalFrom, globalTo, globalMessage)); + list.add(createMimeMessage(session, subject, globalAddressFrom, globalAddressTo, globalMessage)); } catch (ServiceException e) { ZimbraLog.rmgmt.info( @@ -269,11 +255,11 @@ protected static List createMimeMessageList( if (notificationMap.containsKey(DOMAIN_MESSAGE)) { try { - Address domainFrom = convert((String) notificationMap.get(DOMAIN_FROM)); - Address[] domainTo = convert((String[]) notificationMap.get(DOMAIN_TO)); - String domainMessage = (String) notificationMap.get(DOMAIN_MESSAGE); + Address domainAddressFrom = convert(domainFrom); + Address[] domainAddressTo = convert(domainTo); + String domainMessage = notificationMap.get(DOMAIN_MESSAGE); - list.add(createMimeMessage(session, subject, domainFrom, domainTo, domainMessage)); + list.add(createMimeMessage(session, subject, domainAddressFrom, domainAddressTo, domainMessage)); } catch (ServiceException e) { ZimbraLog.rmgmt.info( diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 1e6cfeadb9b..3ed73e3790e 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -74,8 +74,8 @@ public void shouldNotify() throws ServiceException { @Test public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domainName, systemFailureMessage); assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -109,8 +109,8 @@ public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotFailureMessage); + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domainName, certbotFailureMessage); assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -153,8 +153,8 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws Servi + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, certbotSuccessMessage); + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domainName, certbotSuccessMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -177,8 +177,8 @@ public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, otherCertbotMessage); + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domainName, otherCertbotMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -190,11 +190,11 @@ public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { public void shouldCreateMimeMessageList() throws Exception { String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domain, systemFailureMessage); + final Map notificationMap = + CertificateNotificationManager.createIssueCertNotificationMap(domainName, systemFailureMessage); List actualList = - CertificateNotificationManager.createMimeMessageList(null, notificationMap); + CertificateNotificationManager.createMimeMessageList(mailSender, domain, notificationMap); MimeMessage actualMimeMessage = actualList.get(0); From 632322cb48aa5ec371ccc674f26e791cf7f75c5e Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 12:12:38 +0200 Subject: [PATCH 30/39] feat: [CO-621] delete domainName from fields --- .../cs/service/admin/CertificateNotificationManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 8145c9c9dac..815634cb217 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -35,7 +35,6 @@ public class CertificateNotificationManager { public static final String GLOBAL_MESSAGE = "globalMessage"; public static final String DOMAIN_MESSAGE = "domainMessage"; - public static final String DOMAIN_NAME = "domainName"; public static final String SUBJECT_RESULT = "subjectResult"; public static final String SUBJECT_TEMPLATE = " SSL certification request - "; @@ -248,7 +247,7 @@ protected static List createMimeMessageList( } catch (ServiceException e) { ZimbraLog.rmgmt.info( "Notifications about LetsEncrypt certificate generation for " - + notificationMap.get(DOMAIN_NAME) + + domain.getName() + " won't be sent for the global recipients.\n" + e.getMessage()); } @@ -264,7 +263,7 @@ protected static List createMimeMessageList( } catch (ServiceException e) { ZimbraLog.rmgmt.info( "Notifications about LetsEncrypt certificate generation for " - + notificationMap.get(DOMAIN_NAME) + + domain.getName() + " won't be sent for the domain recipients.\n" + e.getMessage()); } From 51c737566c8c797e64996ac51d2ca8d1c5b4f9ac Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 15:37:53 +0200 Subject: [PATCH 31/39] feat: [CO-621] apply requested changes --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 12 +-- .../admin/CertificateNotificationManager.java | 89 +++++++++++-------- .../zimbra/cs/service/admin/IssueCert.java | 4 +- .../CertificateNotificationManagerTest.java | 26 +++--- .../cs/service/admin/IssueCertTest.java | 14 ++- 5 files changed, 83 insertions(+), 62 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index 4164e7dff1b..a69e944854e 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -92,21 +92,15 @@ public String createCommand(String remoteCommand, String email, String chain, St * Executes a command asynchronously and notifies global and domain recipients about the command * execution using {@link com.zimbra.cs.service.admin.CertificateNotificationManager}. * - * @param mbox an object of {@link com.zimbra.cs.mailbox.Mailbox} needed by {@link - * com.zimbra.cs.service.admin.CertificateNotificationManager} to get the proper {@link - * com.zimbra.cs.mailbox.MailSender} - * @param domain {@link com.zimbra.cs.account.Domain} needed by {@link - * com.zimbra.cs.service.admin.CertificateNotificationManager} to get - * {@link com.zimbra.common.account.ZAttrProvisioning} A_carbonioNotificationRecipients - * and A_carbonioNotificationFrom attributes as well as other values + * @param notificationManager an object of {@link com.zimbra.cs.service.admin.CertificateNotificationManager} * @param command a Certbot command to be executed remotely * * @author Yuliya Aheeva * @since 23.5.0 */ - public void supplyAsync(Mailbox mbox, Domain domain, String command) { + public void supplyAsync(CertificateNotificationManager notificationManager, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> CertificateNotificationManager.notify(mbox, domain, message)); + .thenAccept(message -> notificationManager.notify(message)); } /** diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 815634cb217..b711a8a983c 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -61,11 +61,12 @@ public class CertificateNotificationManager { + " Make sure there is a valid, public resolution for the Fully Qualified Domain Name" + " used for any of the Public Service Hostname or Virtual Hostname.\n" + "- Private or unreachable IP address. In order to validate the domain name," - + " the certificator must be able to resolve and browse the FQDN provided.\n" + + "the Certificate Authority (CA) must be able to resolve and browse the provided Fully " + + "Qualified Domain Name (FQDN).\n" + "\n" + "Check your environment for these common issues and try submitting the request again.\n" + "\n" - + "If the error persists, notify the sysadmin."; + + "If the error persists, please contact your system administrator(s) for assistance."; public static final String RECEIVED = "received"; public static final String SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE = @@ -76,21 +77,38 @@ public class CertificateNotificationManager { + "\n" + "The files will be automatically updated when the certificate renews.\n"; - private CertificateNotificationManager() { - throw new RuntimeException("CertificateNotificationManager class cannot be instantiated."); + private final Mailbox mbox; + private final Domain domain; + + private CertificateNotificationManager(Mailbox mbox, Domain domain) { + this.mbox = mbox; + this.domain = domain; } /** - * Notifies global and domain recipients about certificate generation result. + * Instantiates a CertificateNotificationManager object. * * @param mbox object of {@link com.zimbra.cs.mailbox.Mailbox} needed to get the proper {@link * com.zimbra.cs.mailbox.MailSender} in order to send message * @param domain object of {@link com.zimbra.cs.account.Domain} needed to get {@link * com.zimbra.common.account.ZAttrProvisioning} attributes A_carbonioNotificationRecipients * and A_carbonioNotificationFrom - * @param message a message returned by Certbot acme client + * @return an instantiated object + * + * @author Yuliya Aheeva + * @since 23.5.0 + */ + public static CertificateNotificationManager getCertificateNotificationManager( + Mailbox mbox, Domain domain) { + return new CertificateNotificationManager(mbox, domain); + } + + /** + * Notifies global and domain recipients about certificate generation result. + * + * @param outputMessage a message returned by RemoteManager/Certbot acme client */ - public static void notify(Mailbox mbox, Domain domain, String outputMessage) { + public void notify(String outputMessage) { String domainName = domain.getName(); ZimbraLog.rmgmt.info( @@ -100,12 +118,14 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { + outputMessage); try { - Map notificationMap = - createIssueCertNotificationMap(domainName, outputMessage); + Map notificationMap = parseOutput( + outputMessage); MailSender sender = mbox.getMailSender(domain); + Session session = sender.getCurrentSession(); + List mimeMessageList = - createMimeMessageList(sender, domain, notificationMap); + createMimeMessageList(session, notificationMap); sender.sendMimeMessageList(mbox, mimeMessageList); @@ -127,14 +147,14 @@ public static void notify(Mailbox mbox, Domain domain, String outputMessage) { } /** - * Creates a map based on Remote Manager/Certbot output which would be used to + * Parses and creates a map based on Remote Manager/Certbot output which would be used to * create {@link javax.mail.internet.MimeMessage}. * * @param outputMessage output from RemoteManager/Certbot * @return map with needed values of notification SUBJECT and MESSAGE TEXT */ - protected static Map createIssueCertNotificationMap( - String domainName, String outputMessage) throws ServiceException { + protected Map parseOutput( + String outputMessage) throws ServiceException { Map notificationMap = new HashMap<>(); @@ -149,14 +169,7 @@ protected static Map createIssueCertNotificationMap( } // check if a certbot failure - String startParsing = "Simulating"; - String endParsing = "ENDCMD"; - int startIndex = outputMessage.indexOf(startParsing); - int endIndex = outputMessage.lastIndexOf(endParsing); - String substringResult = outputMessage.substring(startIndex, endIndex); - - boolean isFailure = substringResult.contains(FAIL); - + boolean isFailure = outputMessage.contains(FAIL); if (isFailure) { notificationMap.put(SUBJECT_RESULT, CERTBOT_FAILURE); @@ -165,19 +178,19 @@ protected static Map createIssueCertNotificationMap( "", HEADER, FAILURE_RESULT, - FAILURE_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName)); + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName())); notificationMap.put(DOMAIN_MESSAGE, domainMessage); return notificationMap; } // check if a certificate received - boolean isReceived = substringResult.contains(RECEIVED); + boolean isReceived = outputMessage.contains(RECEIVED); if (isReceived) { String expire = "\n"; String regex = "\\d{4}-\\d{2}-\\d{2}"; - Matcher matcher = Pattern.compile(regex).matcher(substringResult); + Matcher matcher = Pattern.compile(regex).matcher(outputMessage); if (matcher.find()) { String expiresTemplate = "This certificate expires on "; expire = String.join("",expire, expiresTemplate, matcher.group(), "."); @@ -188,30 +201,30 @@ protected static Map createIssueCertNotificationMap( "", HEADER, SUCCESS_RESULT, - SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName), + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domain.getName()), expire); notificationMap.put(DOMAIN_MESSAGE, domainMessage); } - // in any other cases (like certificate is not yet due for renewal ... etc) - // only global admin would be notified notificationMap.put(SUBJECT_RESULT, CERTBOT_SUCCESS); return notificationMap; } /** - * Creates {@link javax.mail.internet.MimeMessage} list what would be sent to recipients. + * Creates a {@link javax.mail.internet.MimeMessage} list representing the emails for global + * and domain recipients. + * If unable to create an email for global recipients then would proceed for only for domain ones + * or vice versa. * * @param session {@link javax.mail.Session} - * @param notificationMap map with needed values MESSAGE TEXT + * @param notificationMap map with needed values of MESSAGE TEXT * @return a list of {@link javax.mail.internet.MimeMessage} * @throws ServiceException if unable to parse addresses or create a MimeMessage */ - protected static List createMimeMessageList( - MailSender sender, Domain domain, Map notificationMap) throws ServiceException { + protected List createMimeMessageList( + Session session, Map notificationMap) throws ServiceException { - Session session = sender.getCurrentSession(); Provisioning provisioning = Provisioning.getInstance(); Config config = provisioning.getConfig(); @@ -242,7 +255,8 @@ protected static List createMimeMessageList( Address[] globalAddressTo = convert(globalTo); String globalMessage = notificationMap.get(GLOBAL_MESSAGE); - list.add(createMimeMessage(session, subject, globalAddressFrom, globalAddressTo, globalMessage)); + list.add( + createMimeMessage(session, subject, globalAddressFrom, globalAddressTo, globalMessage)); } catch (ServiceException e) { ZimbraLog.rmgmt.info( @@ -258,7 +272,8 @@ protected static List createMimeMessageList( Address[] domainAddressTo = convert(domainTo); String domainMessage = notificationMap.get(DOMAIN_MESSAGE); - list.add(createMimeMessage(session, subject, domainAddressFrom, domainAddressTo, domainMessage)); + list.add( + createMimeMessage(session, subject, domainAddressFrom, domainAddressTo, domainMessage)); } catch (ServiceException e) { ZimbraLog.rmgmt.info( @@ -272,7 +287,7 @@ protected static List createMimeMessageList( return list; } - private static MimeMessage createMimeMessage( + private MimeMessage createMimeMessage( Session session, String subject, Address from, Address[] to, String message) throws ServiceException { @@ -292,7 +307,7 @@ private static MimeMessage createMimeMessage( } } - private static Address[] convert(String[] addresses) throws ServiceException { + private Address[] convert(String[] addresses) throws ServiceException { try { String addressList = String.join(", ", addresses); return InternetAddress.parse(addressList); @@ -301,7 +316,7 @@ private static Address[] convert(String[] addresses) throws ServiceException { } } - private static Address convert(String address) throws ServiceException { + private Address convert(String address) throws ServiceException { try { return new InternetAddress(address); } catch (AddressException e) { diff --git a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java index b933e758845..2a4887a761f 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/IssueCert.java @@ -96,8 +96,10 @@ public Element handle(final Element request, final Map context) virtualHostNames); Mailbox mbox = getRequestedMailbox(zsc); + CertificateNotificationManager certificateNotificationManager = + CertificateNotificationManager.getCertificateNotificationManager(mbox, domain); - certbot.supplyAsync(mbox, domain, command); + certbot.supplyAsync(certificateNotificationManager, command); Element response = zsc.createElement(AdminConstants.ISSUE_CERT_RESPONSE); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 3ed73e3790e..cb044c12d38 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -12,6 +12,7 @@ import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.getCertificateNotificationManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; @@ -54,6 +55,8 @@ public class CertificateNotificationManagerTest { private final String from = "admin@test.com"; private final String[] recipients = new String[] {from, "admin2@test.com"}; private final String domainName = "test.com"; + private final CertificateNotificationManager notificationManager = getCertificateNotificationManager(mailbox, domain); + @Before public void setUp() throws ServiceException { @@ -68,14 +71,13 @@ public void setUp() throws ServiceException { @Test public void shouldNotify() throws ServiceException { - CertificateNotificationManager.notify(mailbox, domain, systemFailureMessage); + notificationManager.notify(systemFailureMessage); verify(mailSender).sendMimeMessageList(eq(mailbox), any()); } @Test public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domainName, systemFailureMessage); + final Map notificationMap = notificationManager.parseOutput(systemFailureMessage); assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -109,8 +111,7 @@ public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domainName, certbotFailureMessage); + final Map notificationMap = notificationManager.parseOutput(certbotFailureMessage); assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -153,8 +154,11 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws Servi + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; + + CertificateNotificationManager notificationManager = getCertificateNotificationManager(mailbox, domain); + final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domainName, certbotSuccessMessage); + notificationManager.parseOutput(certbotSuccessMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -177,8 +181,7 @@ public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domainName, otherCertbotMessage); + final Map notificationMap = notificationManager.parseOutput(otherCertbotMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -190,11 +193,10 @@ public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { public void shouldCreateMimeMessageList() throws Exception { String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - final Map notificationMap = - CertificateNotificationManager.createIssueCertNotificationMap(domainName, systemFailureMessage); + final Map notificationMap = notificationManager.parseOutput(systemFailureMessage); - List actualList = - CertificateNotificationManager.createMimeMessageList(mailSender, domain, notificationMap); + List actualList = notificationManager + .createMimeMessageList(mailSender.getCurrentSession(), notificationMap); MimeMessage actualMimeMessage = actualList.get(0); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java index f7b3cbcba57..bb2847d54e4 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java @@ -56,6 +56,10 @@ public class IssueCertTest { private final RemoteManager remoteManager = mock(RemoteManager.class); private final static MockedStatic staticRemoteCertbot = mockStatic(RemoteCertbot.class); private final RemoteCertbot remoteCertbot = mock(RemoteCertbot.class); + private final static MockedStatic staticNotificationManager + = mockStatic(CertificateNotificationManager.class); + private final CertificateNotificationManager notificationManager + = mock(CertificateNotificationManager.class); private final IssueCert handler = new IssueCert(); private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); @@ -111,6 +115,7 @@ public void clearData() { public static void tearDown() { staticRemoteManager.close(); staticRemoteCertbot.close(); + staticNotificationManager.close(); } @Test @@ -137,6 +142,9 @@ public void shouldSupplyAsyncAndReturnResponse() throws Exception { .thenReturn(remoteCertbot); Mailbox expectMailbox = getRequestedMailbox(zsc); + staticNotificationManager.when(() -> CertificateNotificationManager + .getCertificateNotificationManager(expectMailbox, expectedDomain)) + .thenReturn(notificationManager); String expectedCommand = "certbot certonly --agree-tos --email admin@example.com" + " -n --keep --webroot -w /opt/zextras " @@ -154,10 +162,10 @@ public void shouldSupplyAsyncAndReturnResponse() throws Exception { final Element response = handler.handle(request, context); final Element message = response.getElement(E_MESSAGE); - assertEquals(message.getAttribute(A_DOMAIN), domainName); - assertEquals(message.getText(), IssueCert.RESPONSE); + assertEquals(domainName, message.getAttribute(A_DOMAIN)); + assertEquals(IssueCert.RESPONSE, message.getText()); - verify(remoteCertbot).supplyAsync(expectMailbox, expectedDomain, expectedCommand); + verify(remoteCertbot).supplyAsync(notificationManager, expectedCommand); } @Test From 0c5033b04824df74dfc2d5c4bdfd53357ff7b2d6 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 15:46:25 +0200 Subject: [PATCH 32/39] feat: [CO-621] apply requested changes --- .../admin/CertificateNotificationManager.java | 5 ++-- .../CertificateNotificationManagerTest.java | 29 ++----------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index b711a8a983c..9bd20c5729d 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -153,8 +153,7 @@ public void notify(String outputMessage) { * @param outputMessage output from RemoteManager/Certbot * @return map with needed values of notification SUBJECT and MESSAGE TEXT */ - protected Map parseOutput( - String outputMessage) throws ServiceException { + public Map parseOutput(String outputMessage) { Map notificationMap = new HashMap<>(); @@ -222,7 +221,7 @@ protected Map parseOutput( * @return a list of {@link javax.mail.internet.MimeMessage} * @throws ServiceException if unable to parse addresses or create a MimeMessage */ - protected List createMimeMessageList( + private List createMimeMessageList( Session session, Map notificationMap) throws ServiceException { Provisioning provisioning = Provisioning.getInstance(); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index cb044c12d38..5c5f172b9af 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -8,7 +8,6 @@ import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; @@ -27,9 +26,7 @@ import com.zimbra.cs.account.Provisioning; import com.zimbra.cs.mailbox.MailSender; import com.zimbra.cs.mailbox.Mailbox; -import java.util.List; import java.util.Map; -import javax.mail.internet.MimeMessage; import org.junit.Before; import org.junit.Test; @@ -76,7 +73,7 @@ public void shouldNotify() throws ServiceException { } @Test - public void shouldCreateMapFromSystemFailureMessage() throws ServiceException { + public void shouldCreateMapFromSystemFailureMessage() { final Map notificationMap = notificationManager.parseOutput(systemFailureMessage); assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); @@ -119,7 +116,7 @@ public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { } @Test - public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws ServiceException { + public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() { final String expiration = "\n" + "This certificate expires on 2023-06-15."; final String expectedDomainMessage = HEADER + SUCCESS_RESULT + SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE.replace("", domainName) @@ -166,7 +163,7 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() throws Servi } @Test - public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { + public void shouldCreateMapFromOtherCertbotMessage() { String otherCertbotMessage = "STARTCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" @@ -187,24 +184,4 @@ public void shouldCreateMapFromOtherCertbotMessage() throws ServiceException { assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); } - - - @Test - public void shouldCreateMimeMessageList() throws Exception { - String subject = domainName + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - - final Map notificationMap = notificationManager.parseOutput(systemFailureMessage); - - List actualList = notificationManager - .createMimeMessageList(mailSender.getCurrentSession(), notificationMap); - - MimeMessage actualMimeMessage = actualList.get(0); - - assertEquals(from, actualMimeMessage.getSender().toString()); - assertEquals(from, actualMimeMessage.getFrom()[0].toString()); - assertEquals(recipients[0], actualMimeMessage.getAllRecipients()[0].toString()); - assertEquals(recipients[1], actualMimeMessage.getAllRecipients()[1].toString()); - assertEquals(subject, actualMimeMessage.getSubject()); - assertEquals(systemFailureMessage, actualMimeMessage.getContent()); - } } From 7d3a12e3904061776ca43b5590dcbcaac13a532c Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 15:54:04 +0200 Subject: [PATCH 33/39] feat: [CO-621] apply requested changes --- .../zimbra/cs/service/admin/IssueCertTest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java index bb2847d54e4..bbb0bb59499 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/IssueCertTest.java @@ -40,9 +40,13 @@ import org.mockito.MockedStatic; public class IssueCertTest { + private static final MockedStatic staticRemoteManager + = mockStatic(RemoteManager.class); + private static final MockedStatic staticRemoteCertbot + = mockStatic(RemoteCertbot.class); + private static final MockedStatic staticNotificationManager + = mockStatic(CertificateNotificationManager.class); - private Provisioning provisioning; - private ZimbraSoapContext zsc; private final Map context = new HashMap<>(); private final Map domainAttributes = new HashMap<>(); @@ -52,18 +56,17 @@ public class IssueCertTest { private final String mail = "admin@example.com"; - private final static MockedStatic staticRemoteManager = mockStatic(RemoteManager.class); private final RemoteManager remoteManager = mock(RemoteManager.class); - private final static MockedStatic staticRemoteCertbot = mockStatic(RemoteCertbot.class); private final RemoteCertbot remoteCertbot = mock(RemoteCertbot.class); - private final static MockedStatic staticNotificationManager - = mockStatic(CertificateNotificationManager.class); private final CertificateNotificationManager notificationManager = mock(CertificateNotificationManager.class); private final IssueCert handler = new IssueCert(); private final XMLElement request = new XMLElement(ISSUE_CERT_REQUEST); + private Provisioning provisioning; + private ZimbraSoapContext zsc; + @Rule public ExpectedException expectedEx = ExpectedException.none(); @Before From c9558a07f362bb0304b99f753f2669a4bc3c76b4 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 15:56:12 +0200 Subject: [PATCH 34/39] feat: [CO-621] apply requested changes --- .../cs/service/admin/CertificateNotificationManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 5c5f172b9af..a59d41fb9a5 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -82,7 +82,7 @@ public void shouldCreateMapFromSystemFailureMessage() { } @Test - public void shouldCreateMapFromCertbotFailureMessage() throws ServiceException { + public void shouldCreateMapFromCertbotFailureMessage() { final String expectedDomainMessage = HEADER + FAILURE_RESULT + FAILURE_DOMAIN_NOTIFICATION_TEMPLATE .replace("", domainName); From c642e082534049bb875fcf7330cd8922d10f6c2c Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 15:58:07 +0200 Subject: [PATCH 35/39] feat: [CO-621] add small changes to tests --- .../admin/CertificateNotificationManagerTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index a59d41fb9a5..7cd2940506b 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -52,7 +52,8 @@ public class CertificateNotificationManagerTest { private final String from = "admin@test.com"; private final String[] recipients = new String[] {from, "admin2@test.com"}; private final String domainName = "test.com"; - private final CertificateNotificationManager notificationManager = getCertificateNotificationManager(mailbox, domain); + private final CertificateNotificationManager notificationManager + = getCertificateNotificationManager(mailbox, domain); @Before @@ -74,7 +75,8 @@ public void shouldNotify() throws ServiceException { @Test public void shouldCreateMapFromSystemFailureMessage() { - final Map notificationMap = notificationManager.parseOutput(systemFailureMessage); + final Map notificationMap = + notificationManager.parseOutput(systemFailureMessage); assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -108,7 +110,8 @@ public void shouldCreateMapFromCertbotFailureMessage() { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = notificationManager.parseOutput(certbotFailureMessage); + final Map notificationMap = + notificationManager.parseOutput(certbotFailureMessage); assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); @@ -152,8 +155,6 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() { + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; - CertificateNotificationManager notificationManager = getCertificateNotificationManager(mailbox, domain); - final Map notificationMap = notificationManager.parseOutput(certbotSuccessMessage); @@ -178,7 +179,8 @@ public void shouldCreateMapFromOtherCertbotMessage() { + "ENDCMD: nbm-m01.demo.zextras.io /opt/zextras/libexec/certbot certonly --agree-tos" + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; - final Map notificationMap = notificationManager.parseOutput(otherCertbotMessage); + final Map notificationMap = + notificationManager.parseOutput(otherCertbotMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); From 3c7313fc62bc2aa7a7b2f466db737741d9fa3059 Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Mon, 3 Apr 2023 17:36:55 +0200 Subject: [PATCH 36/39] feat: [CO-621] refactor CertificateNotificationManager, modify tests --- .../admin/CertificateNotificationManager.java | 137 ++++++------------ .../CertificateNotificationManagerTest.java | 5 - 2 files changed, 45 insertions(+), 97 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 9bd20c5729d..3e786f8e884 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -32,9 +32,6 @@ * @since 23.5.0 */ public class CertificateNotificationManager { - public static final String GLOBAL_MESSAGE = "globalMessage"; - public static final String DOMAIN_MESSAGE = "domainMessage"; - public static final String SUBJECT_RESULT = "subjectResult"; public static final String SUBJECT_TEMPLATE = " SSL certification request - "; @@ -43,6 +40,7 @@ public class CertificateNotificationManager { public static final String CERTBOT_SUCCESS = "Certificate Authority success"; public static final String CERTBOT_FAILURE = "Certificate Authority failure"; + public static final String DOMAIN_MESSAGE = "domainMessage"; public static final String RESULT = "result"; public static final String HEADER = "The certification result is: "; public static final String SUCCESS_RESULT = "SUCCESS\n"; @@ -116,16 +114,47 @@ public void notify(String outputMessage) { + domainName + " was finished with the following result: " + outputMessage); - try { - Map notificationMap = parseOutput( - outputMessage); - + Provisioning provisioning = Provisioning.getInstance(); + Config config = provisioning.getConfig(); + + String globalFrom = + Optional.ofNullable(config.getCarbonioNotificationFrom()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationFrom attribute is not present.", null)); + String[] globalTo = + Optional.ofNullable(config.getCarbonioNotificationRecipients()) + .orElseThrow( + () -> + ServiceException.FAILURE( + "Global CarbonioNotificationRecipients attribute is not present.", null)); + + String domainFrom = + Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElse(globalFrom); + String[] domainTo = + Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); + + Map notificationMap = parseOutput(outputMessage); MailSender sender = mbox.getMailSender(domain); Session session = sender.getCurrentSession(); - List mimeMessageList = - createMimeMessageList(session, notificationMap); + String subject = domainName + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); + + + List mimeMessageList = new ArrayList<>(); + + MimeMessage globalNotification = + createMimeMessage(session, subject, globalFrom, globalTo, outputMessage); + mimeMessageList.add(globalNotification); + + if (notificationMap.get(SUBJECT_RESULT).equals(CERTBOT_FAILURE) + || notificationMap.get(SUBJECT_RESULT).equals(CERTBOT_SUCCESS)) { + MimeMessage domainNotification = createMimeMessage( + session, subject, domainFrom, domainTo, notificationMap.get(DOMAIN_MESSAGE)); + mimeMessageList.add(domainNotification); + } sender.sendMimeMessageList(mbox, mimeMessageList); @@ -157,9 +186,6 @@ public Map parseOutput(String outputMessage) { Map notificationMap = new HashMap<>(); - // message for global admin contains all output - notificationMap.put(GLOBAL_MESSAGE, outputMessage); - // check if a system failure boolean isSystemFailure = outputMessage.contains(SYSTEM_FAILURE); if (isSystemFailure) { @@ -210,91 +236,18 @@ public Map parseOutput(String outputMessage) { return notificationMap; } - /** - * Creates a {@link javax.mail.internet.MimeMessage} list representing the emails for global - * and domain recipients. - * If unable to create an email for global recipients then would proceed for only for domain ones - * or vice versa. - * - * @param session {@link javax.mail.Session} - * @param notificationMap map with needed values of MESSAGE TEXT - * @return a list of {@link javax.mail.internet.MimeMessage} - * @throws ServiceException if unable to parse addresses or create a MimeMessage - */ - private List createMimeMessageList( - Session session, Map notificationMap) throws ServiceException { - - Provisioning provisioning = Provisioning.getInstance(); - Config config = provisioning.getConfig(); - - String globalFrom = - Optional.ofNullable(config.getCarbonioNotificationFrom()) - .orElseThrow( - () -> - ServiceException.FAILURE( - "Global CarbonioNotificationFrom attribute is not present.", null)); - String[] globalTo = - Optional.ofNullable(config.getCarbonioNotificationRecipients()) - .orElseThrow( - () -> - ServiceException.FAILURE( - "Global CarbonioNotificationRecipients attribute is not present.", null)); - - String domainFrom = - Optional.ofNullable(domain.getCarbonioNotificationFrom()).orElse(globalFrom); - String[] domainTo = - Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); - - List list = new ArrayList<>(); - - String subject = domain.getName() + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); - - try { - Address globalAddressFrom = convert(globalFrom); - Address[] globalAddressTo = convert(globalTo); - String globalMessage = notificationMap.get(GLOBAL_MESSAGE); - - list.add( - createMimeMessage(session, subject, globalAddressFrom, globalAddressTo, globalMessage)); - - } catch (ServiceException e) { - ZimbraLog.rmgmt.info( - "Notifications about LetsEncrypt certificate generation for " - + domain.getName() - + " won't be sent for the global recipients.\n" - + e.getMessage()); - } - - if (notificationMap.containsKey(DOMAIN_MESSAGE)) { - try { - Address domainAddressFrom = convert(domainFrom); - Address[] domainAddressTo = convert(domainTo); - String domainMessage = notificationMap.get(DOMAIN_MESSAGE); - - list.add( - createMimeMessage(session, subject, domainAddressFrom, domainAddressTo, domainMessage)); - - } catch (ServiceException e) { - ZimbraLog.rmgmt.info( - "Notifications about LetsEncrypt certificate generation for " - + domain.getName() - + " won't be sent for the domain recipients.\n" - + e.getMessage()); - } - } - - return list; - } - private MimeMessage createMimeMessage( - Session session, String subject, Address from, Address[] to, String message) + Session session, String subject, String from, String[] to, String message) throws ServiceException { try { + Address addressFrom = convert(from); + Address[] addressTo = convert(to); + MimeMessage mm = new MimeMessage(session); - mm.setFrom(from); - mm.setSender(from); - mm.setRecipients(RecipientType.TO, to); + mm.setFrom(addressFrom); + mm.setSender(addressFrom); + mm.setRecipients(RecipientType.TO, addressTo); mm.setSubject(subject); mm.setText(message); mm.saveChanges(); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 7cd2940506b..8e163e9a5db 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -5,7 +5,6 @@ import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; @@ -79,7 +78,6 @@ public void shouldCreateMapFromSystemFailureMessage() { notificationManager.parseOutput(systemFailureMessage); assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); } @@ -114,7 +112,6 @@ public void shouldCreateMapFromCertbotFailureMessage() { notificationManager.parseOutput(certbotFailureMessage); assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); } @@ -159,7 +156,6 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() { notificationManager.parseOutput(certbotSuccessMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); } @@ -183,7 +179,6 @@ public void shouldCreateMapFromOtherCertbotMessage() { notificationManager.parseOutput(otherCertbotMessage); assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); - assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); } } From 160d086893c9024668a1b6faa0263e388af3790e Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 4 Apr 2023 10:27:28 +0200 Subject: [PATCH 37/39] feat: [CO-621] refactor CertificateNotificationManager, modify tests --- .../com/zimbra/cs/rmgmt/RemoteCertbot.java | 5 +- .../admin/CertificateNotificationManager.java | 63 +++++++++++-------- .../CertificateNotificationManagerTest.java | 36 ++++++++--- 3 files changed, 64 insertions(+), 40 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java index a69e944854e..bb5696bf4ea 100644 --- a/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java +++ b/store/src/main/java/com/zimbra/cs/rmgmt/RemoteCertbot.java @@ -1,8 +1,6 @@ package com.zimbra.cs.rmgmt; import com.zimbra.common.service.ServiceException; -import com.zimbra.cs.account.Domain; -import com.zimbra.cs.mailbox.Mailbox; import com.zimbra.cs.service.admin.CertificateNotificationManager; import java.nio.charset.StandardCharsets; import java.util.Objects; @@ -100,7 +98,8 @@ public String createCommand(String remoteCommand, String email, String chain, St */ public void supplyAsync(CertificateNotificationManager notificationManager, String command) { CompletableFuture.supplyAsync(() -> execute(command)) - .thenAccept(message -> notificationManager.notify(message)); + .thenApply(notificationManager::createIssueCertNotificationMap) + .thenAccept(notificationManager::notify); } /** diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 3e786f8e884..198c6dbf2d7 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -32,7 +32,10 @@ * @since 23.5.0 */ public class CertificateNotificationManager { - public static final String SUBJECT_RESULT = "subjectResult"; + public static final String GLOBAL_MESSAGE = "globalMessage"; + public static final String DOMAIN_MESSAGE = "domainMessage"; + + public static final String SUBJECT = "subject"; public static final String SUBJECT_TEMPLATE = " SSL certification request - "; public static final String SYSTEM_FAILURE = "system failure"; @@ -40,7 +43,6 @@ public class CertificateNotificationManager { public static final String CERTBOT_SUCCESS = "Certificate Authority success"; public static final String CERTBOT_FAILURE = "Certificate Authority failure"; - public static final String DOMAIN_MESSAGE = "domainMessage"; public static final String RESULT = "result"; public static final String HEADER = "The certification result is: "; public static final String SUCCESS_RESULT = "SUCCESS\n"; @@ -106,14 +108,9 @@ public static CertificateNotificationManager getCertificateNotificationManager( * * @param outputMessage a message returned by RemoteManager/Certbot acme client */ - public void notify(String outputMessage) { + public void notify(Map notificationMap) { String domainName = domain.getName(); - - ZimbraLog.rmgmt.info( - "Issuing LetsEncrypt cert command for domain " - + domainName - + " was finished with the following result: " - + outputMessage); + try { Provisioning provisioning = Provisioning.getInstance(); Config config = provisioning.getConfig(); @@ -136,23 +133,29 @@ public void notify(String outputMessage) { String[] domainTo = Optional.ofNullable(domain.getCarbonioNotificationRecipients()).orElse(globalTo); - Map notificationMap = parseOutput(outputMessage); MailSender sender = mbox.getMailSender(domain); Session session = sender.getCurrentSession(); - String subject = domainName + SUBJECT_TEMPLATE + notificationMap.get(SUBJECT_RESULT); - + String subject = notificationMap.get(SUBJECT); List mimeMessageList = new ArrayList<>(); MimeMessage globalNotification = - createMimeMessage(session, subject, globalFrom, globalTo, outputMessage); + createMimeMessage( + session, + subject, + convert(globalFrom), + convert(globalTo), + notificationMap.get(GLOBAL_MESSAGE)); mimeMessageList.add(globalNotification); - if (notificationMap.get(SUBJECT_RESULT).equals(CERTBOT_FAILURE) - || notificationMap.get(SUBJECT_RESULT).equals(CERTBOT_SUCCESS)) { + if (notificationMap.containsKey(DOMAIN_MESSAGE)) { MimeMessage domainNotification = createMimeMessage( - session, subject, domainFrom, domainTo, notificationMap.get(DOMAIN_MESSAGE)); + session, + subject, + convert(domainFrom), + convert(domainTo), + notificationMap.get(DOMAIN_MESSAGE)); mimeMessageList.add(domainNotification); } @@ -182,21 +185,29 @@ public void notify(String outputMessage) { * @param outputMessage output from RemoteManager/Certbot * @return map with needed values of notification SUBJECT and MESSAGE TEXT */ - public Map parseOutput(String outputMessage) { + public Map createIssueCertNotificationMap(String outputMessage) { + ZimbraLog.rmgmt.info( + "Issuing LetsEncrypt cert command for domain " + + domain.getName() + + " was finished with the following result: " + + outputMessage); Map notificationMap = new HashMap<>(); + notificationMap.put(GLOBAL_MESSAGE, outputMessage); // check if a system failure boolean isSystemFailure = outputMessage.contains(SYSTEM_FAILURE); if (isSystemFailure) { - notificationMap.put(SUBJECT_RESULT, SYSTEM_FAILURE); + String subject = domain.getName() + SUBJECT_TEMPLATE + SYSTEM_FAILURE; + notificationMap.put(SUBJECT, subject); return notificationMap; } // check if a certbot failure boolean isFailure = outputMessage.contains(FAIL); if (isFailure) { - notificationMap.put(SUBJECT_RESULT, CERTBOT_FAILURE); + String subject = domain.getName() + SUBJECT_TEMPLATE + CERTBOT_FAILURE; + notificationMap.put(SUBJECT, subject); String domainMessage = String.join( @@ -232,22 +243,20 @@ public Map parseOutput(String outputMessage) { notificationMap.put(DOMAIN_MESSAGE, domainMessage); } - notificationMap.put(SUBJECT_RESULT, CERTBOT_SUCCESS); + String subject = domain.getName() + SUBJECT_TEMPLATE + CERTBOT_SUCCESS; + notificationMap.put(SUBJECT, subject); return notificationMap; } private MimeMessage createMimeMessage( - Session session, String subject, String from, String[] to, String message) + Session session, String subject, Address from, Address[] to, String message) throws ServiceException { try { - Address addressFrom = convert(from); - Address[] addressTo = convert(to); - MimeMessage mm = new MimeMessage(session); - mm.setFrom(addressFrom); - mm.setSender(addressFrom); - mm.setRecipients(RecipientType.TO, addressTo); + mm.setFrom(from); + mm.setSender(from); + mm.setRecipients(RecipientType.TO, to); mm.setSubject(subject); mm.setText(message); mm.saveChanges(); diff --git a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java index 8e163e9a5db..22f8d0d5d65 100644 --- a/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java +++ b/store/src/test/java/com/zimbra/cs/service/admin/CertificateNotificationManagerTest.java @@ -5,8 +5,10 @@ import static com.zimbra.cs.service.admin.CertificateNotificationManager.DOMAIN_MESSAGE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_DOMAIN_NOTIFICATION_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.FAILURE_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.GLOBAL_MESSAGE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.HEADER; -import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_RESULT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT; +import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUBJECT_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_DOMAIN_NOTIFICATION_TEMPLATE; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SUCCESS_RESULT; import static com.zimbra.cs.service.admin.CertificateNotificationManager.SYSTEM_FAILURE; @@ -68,16 +70,21 @@ public void setUp() throws ServiceException { @Test public void shouldNotify() throws ServiceException { - notificationManager.notify(systemFailureMessage); + final Map notificationMap = + notificationManager.createIssueCertNotificationMap(systemFailureMessage); + notificationManager.notify(notificationMap); verify(mailSender).sendMimeMessageList(eq(mailbox), any()); } @Test public void shouldCreateMapFromSystemFailureMessage() { final Map notificationMap = - notificationManager.parseOutput(systemFailureMessage); + notificationManager.createIssueCertNotificationMap(systemFailureMessage); + + String expectedSubject = domain.getName() + SUBJECT_TEMPLATE + SYSTEM_FAILURE; - assertEquals(SYSTEM_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(expectedSubject, notificationMap.get(SUBJECT)); + assertEquals(systemFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); } @@ -109,9 +116,12 @@ public void shouldCreateMapFromCertbotFailureMessage() { + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; final Map notificationMap = - notificationManager.parseOutput(certbotFailureMessage); + notificationManager.createIssueCertNotificationMap(certbotFailureMessage); + + String expectedSubject = domain.getName() + SUBJECT_TEMPLATE + CERTBOT_FAILURE; - assertEquals(CERTBOT_FAILURE, notificationMap.get(SUBJECT_RESULT)); + assertEquals(expectedSubject, notificationMap.get(SUBJECT)); + assertEquals(certbotFailureMessage, notificationMap.get(GLOBAL_MESSAGE)); assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); } @@ -153,9 +163,12 @@ public void shouldCreateMapFromCertbotSuccessfullyReceivedMessage() { + " le.zextras.io -d le1.zextras.io -d le2.zextras.io"; final Map notificationMap = - notificationManager.parseOutput(certbotSuccessMessage); + notificationManager.createIssueCertNotificationMap(certbotSuccessMessage); - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + String expectedSubject = domain.getName() + SUBJECT_TEMPLATE + CERTBOT_SUCCESS; + + assertEquals(expectedSubject, notificationMap.get(SUBJECT)); + assertEquals(certbotSuccessMessage, notificationMap.get(GLOBAL_MESSAGE)); assertEquals(expectedDomainMessage, notificationMap.get(DOMAIN_MESSAGE)); } @@ -176,9 +189,12 @@ public void shouldCreateMapFromOtherCertbotMessage() { + " --email zextras@demo.zextras.io -n --keep --webroot -w /opt/zextras --cert-name" + " test.zextras.io -d test.zextras.io -d test.zextras.io"; final Map notificationMap = - notificationManager.parseOutput(otherCertbotMessage); + notificationManager.createIssueCertNotificationMap(otherCertbotMessage); + + String expectedSubject = domain.getName() + SUBJECT_TEMPLATE + CERTBOT_SUCCESS; - assertEquals(CERTBOT_SUCCESS, notificationMap.get(SUBJECT_RESULT)); + assertEquals(expectedSubject, notificationMap.get(SUBJECT)); + assertEquals(otherCertbotMessage, notificationMap.get(GLOBAL_MESSAGE)); assertFalse(notificationMap.containsKey(DOMAIN_MESSAGE)); } } From 17adeb33f0779d3fddb3ffb3071e2dbdce1d35af Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 4 Apr 2023 10:42:52 +0200 Subject: [PATCH 38/39] feat: [CO-621] change javadoc --- .../cs/service/admin/CertificateNotificationManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index 198c6dbf2d7..ffa4e114323 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -104,9 +104,12 @@ public static CertificateNotificationManager getCertificateNotificationManager( } /** - * Notifies global and domain recipients about certificate generation result. + * Notifies global and domain recipients with provided notifications from notificationMap. * - * @param outputMessage a message returned by RemoteManager/Certbot acme client + * Gets global and domain values for sender and recipients, creates emails, send emails with + * {@link com.zimbra.cs.mailbox.MailSender}. + * + * @param notificationMap a map with needed values of notification SUBJECT and MESSAGE TEXT */ public void notify(Map notificationMap) { String domainName = domain.getName(); From dd98b692b4f7b6f10f0ef02699f08009fad1cb8f Mon Sep 17 00:00:00 2001 From: Yuliya Aheeva Date: Tue, 4 Apr 2023 13:38:45 +0200 Subject: [PATCH 39/39] feat: [CO-621] add logger to tests --- .../cs/service/admin/CertificateNotificationManager.java | 2 +- .../src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java | 5 ++++- store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java index ffa4e114323..c702307125f 100644 --- a/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java +++ b/store/src/main/java/com/zimbra/cs/service/admin/CertificateNotificationManager.java @@ -171,7 +171,7 @@ public void notify(Map notificationMap) { + " recipients."); } catch (Exception e) { - ZimbraLog.rmgmt.info( + ZimbraLog.rmgmt.warn( "Notifications about LetsEncrypt certificate generation weren't sent " + "for the global and domain " + domainName diff --git a/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java b/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java index 4bb11f20551..5b6e762d3a3 100644 --- a/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java +++ b/store/src/test/java/com/zimbra/cs/imap/ImapHandlerTest.java @@ -31,11 +31,14 @@ import org.junit.Test; import org.junit.rules.MethodRule; import org.junit.rules.TestName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import qa.unittest.TestUtil; public class ImapHandlerTest { private static final String LOCAL_USER = "localimaptest@zimbra.com"; + private final Logger log = LoggerFactory.getLogger(this.getClass()); @Rule public TestName testName = new TestName(); @Rule public MethodRule watchman = new ZTestWatchman(); @@ -46,7 +49,7 @@ public void setUp() throws Exception { MailboxTestUtil.initServer(); String[] hosts = {"localhost", "127.0.0.1"}; ServerThrottle.configureThrottle(new ImapConfig(false).getProtocol(), 100, 100, Arrays.asList(hosts), Arrays.asList(hosts)); - System.out.println(testName.getMethodName()); + log.info(testName.getMethodName()); Provisioning prov = Provisioning.getInstance(); HashMap attrs = new HashMap<>(); attrs.put(Provisioning.A_zimbraId, "12aa345b-2b47-44e6-8cb8-7fdfa18c1a9f"); diff --git a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java index dae312984b8..ca1ea98e221 100644 --- a/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java +++ b/store/src/test/java/com/zimbra/cs/mailbox/ContactTest.java @@ -67,6 +67,8 @@ import org.junit.rules.MethodRule; import org.junit.rules.TestName; import org.mockito.MockedStatic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Unit test for {@link Contact}. @@ -74,6 +76,7 @@ * @author ysasaki */ public final class ContactTest { + private final Logger log = LoggerFactory.getLogger(this.getClass()); @Rule public TestName testName = new TestName(); @Rule public MethodRule watchman = new ZTestWatchman(); @@ -81,7 +84,7 @@ public final class ContactTest { @Before public void setUp() throws Exception { MailboxTestUtil.initServer(); - System.out.println(testName.getMethodName()); + log.info(testName.getMethodName()); Provisioning prov = Provisioning.getInstance(); prov.createAccount("testCont@zimbra.com", "secret", new HashMap<>()); prov.createAccount("test6232@zimbra.com", "secret", new HashMap<>()); @@ -420,7 +423,7 @@ public void testTruncatedContactsTgzImport() throws IOException { try { ArchiveFormatter.readArchiveEntry(ais, aie); } catch (IOException e) { - System.out.println("Expected exception was caught: " + e); + log.info("Expected exception was caught: " + e); errorCaught = true; break; }