Skip to content

Commit

Permalink
feat: [CO-1430] emit user delete event on message broker when user is…
Browse files Browse the repository at this point in the history
… deleted (#571)

- Publish UserDeleted event when user is deleted
- Adapt delete user IT

Refs: CO-1430
  • Loading branch information
galvagnimatteo authored Sep 13, 2024
1 parent 75b9b53 commit 9d8d919
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 79 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -812,13 +812,13 @@
<log4j.version>2.20.0</log4j.version>
<dom4j.version>2.1.4</dom4j.version>
<hsqldb.version>2.2.9</hsqldb.version>
<mockito.version>4.4.0</mockito.version>
<mockito.version>5.2.0</mockito.version>
<unboundid-ldapsdk.version>2.3.5</unboundid-ldapsdk.version>
<jsr305.version>3.0.2</jsr305.version>
<error_prone_annotations.version>2.3.2</error_prone_annotations.version>
<jersey.version>1.11</jersey.version>
<system-lambda.version>1.2.1</system-lambda.version>
<carbonio-message-broker-sdk.version>0.0.3</carbonio-message-broker-sdk.version>
<carbonio-message-broker-sdk.version>0.0.4-SNAPSHOT</carbonio-message-broker-sdk.version>
<!-- Maven revision: https://maven.apache.org/maven-ci-friendly.html -->
<changelist>-SNAPSHOT</changelist>
<revision>24.12.0</revision>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@

package com.zimbra.cs.account.callback;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Set;

import com.zextras.carbonio.message_broker.MessageBrokerClient;
import com.zextras.carbonio.message_broker.config.enums.Service;
import com.zextras.carbonio.message_broker.events.services.mailbox.UserStatusChanged;
import com.zextras.mailbox.client.ServiceDiscoverHttpClient;
import com.zimbra.common.account.Key;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.util.ZimbraLog;
Expand All @@ -25,6 +19,7 @@
import com.zimbra.cs.account.DistributionList;
import com.zimbra.cs.account.Entry;
import com.zimbra.cs.account.Provisioning;
import com.zimbra.cs.service.admin.AdminService;

public class AccountStatus extends AttributeCallback {

Expand Down Expand Up @@ -84,27 +79,8 @@ private void publishStatusChangedEvent(Account account) {
String status = account.getAccountStatus(prov);
String userId = account.getId();

Path filePath = Paths.get("/etc/carbonio/mailbox/service-discover/token");
String token;
try {
token = Files.readString(filePath);
} catch (IOException e) {
throw new RuntimeException("Can't read consul token from file", e);
}

ServiceDiscoverHttpClient serviceDiscoverHttpClient =
ServiceDiscoverHttpClient.defaultURL("carbonio-message-broker")
.withToken(token);

try {
MessageBrokerClient messageBrokerClient = MessageBrokerClient.fromConfig(
"127.78.0.7",
20005,
serviceDiscoverHttpClient.getConfig("default/username").get(),
serviceDiscoverHttpClient.getConfig("default/password").get()
)
.withCurrentService(Service.MAILBOX);

MessageBrokerClient messageBrokerClient = AdminService.getMessageBrokerClientInstance();
boolean result = messageBrokerClient.publish(new UserStatusChanged(userId, status.toUpperCase()));
if (result) {
ZimbraLog.account.info("Published status changed event for user: " + userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@

package com.zimbra.cs.service.admin;

import com.zextras.carbonio.message_broker.MessageBrokerClient;
import com.zextras.carbonio.message_broker.config.enums.Service;
import com.zextras.carbonio.message_broker.events.services.mailbox.UserDeleted;
import com.zextras.mailbox.account.usecase.DeleteUserUseCase;
import com.zextras.mailbox.acl.AclService;
import com.zextras.mailbox.client.ServiceDiscoverHttpClient;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.soap.AdminConstants;
import com.zimbra.common.soap.Element;
Expand All @@ -16,6 +20,11 @@
import com.zimbra.cs.mailbox.MailboxManager;
import com.zimbra.soap.DocumentDispatcher;
import com.zimbra.soap.DocumentService;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -54,7 +63,8 @@ public void registerHandlers(DocumentDispatcher dispatcher) throws ServiceExcept
Provisioning.getInstance(),
MailboxManager.getInstance(),
new AclService(MailboxManager.getInstance(), Provisioning.getInstance()),
ZimbraLog.security)));
ZimbraLog.security),
getMessageBrokerClientInstance()));
dispatcher.registerHandler(AdminConstants.SET_PASSWORD_REQUEST, new SetPassword());
dispatcher.registerHandler(
AdminConstants.CHECK_PASSWORD_STRENGTH_REQUEST, new CheckPasswordStrength());
Expand Down Expand Up @@ -390,4 +400,26 @@ public static Map<String, Object> getAttrs(Element request, boolean ignoreEmptyV
}
return result;
}

public static MessageBrokerClient getMessageBrokerClientInstance() {
Path filePath = Paths.get("/etc/carbonio/mailbox/service-discover/token");
String token;
try {
token = Files.readString(filePath);
} catch (IOException e) {
throw new RuntimeException("Can't read consul token from file", e);
}

ServiceDiscoverHttpClient serviceDiscoverHttpClient =
ServiceDiscoverHttpClient.defaultURL("carbonio-message-broker")
.withToken(token);

return MessageBrokerClient.fromConfig(
"127.78.0.7",
20005,
serviceDiscoverHttpClient.getConfig("default/username").get(),
serviceDiscoverHttpClient.getConfig("default/password").get()
)
.withCurrentService(Service.MAILBOX);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
*/
package com.zimbra.cs.service.admin;

import com.zextras.carbonio.message_broker.MessageBrokerClient;
import com.zextras.carbonio.message_broker.config.enums.Service;
import com.zextras.carbonio.message_broker.events.services.mailbox.UserDeleted;
import com.zextras.mailbox.account.usecase.DeleteUserUseCase;
import com.zextras.mailbox.client.ServiceDiscoverHttpClient;
import com.zimbra.common.account.Key.AccountBy;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.soap.AdminConstants;
Expand All @@ -21,6 +25,11 @@
import com.zimbra.soap.ZimbraSoapContext;
import com.zimbra.soap.admin.message.DeleteAccountRequest;
import com.zimbra.soap.admin.message.DeleteAccountResponse;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

Expand All @@ -32,9 +41,11 @@ public class DeleteAccount extends AdminDocumentHandler {
private static final String[] TARGET_ACCOUNT_PATH = new String[] {AdminConstants.E_ID};

private final DeleteUserUseCase deleteUserUseCase;
private final MessageBrokerClient messageBrokerClient;

public DeleteAccount(DeleteUserUseCase deleteUserUseCase) {
public DeleteAccount(DeleteUserUseCase deleteUserUseCase, MessageBrokerClient messageBrokerClient) {
this.deleteUserUseCase = deleteUserUseCase;
this.messageBrokerClient = messageBrokerClient;
}

@Override
Expand Down Expand Up @@ -86,6 +97,7 @@ public Element handle(Element request, Map<String, Object> context) throws Servi
* so mail delivery and any user action is blocked.
*/
deleteUserUseCase.delete(account.getId());
publishAccountDeletedEvent(account);

ZimbraLog.security.info(
ZimbraLog.encodeAttrs(
Expand All @@ -100,4 +112,18 @@ public Element handle(Element request, Map<String, Object> context) throws Servi
public void docRights(List<AdminRight> relatedRights, List<String> notes) {
relatedRights.add(Admin.R_deleteAccount);
}

private void publishAccountDeletedEvent(Account account) {
String userId = account.getId();
try {
boolean result = messageBrokerClient.publish(new UserDeleted(userId));
if (result) {
ZimbraLog.account.info("Published deleted account event for user: " + userId);
} else {
ZimbraLog.account.error("Failed to publish deleted account event for user: " + userId);
}
} catch (Exception e){
ZimbraLog.account.error("Exception while publishing deleted account event for user: " + userId, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,17 @@
package com.zextras.mailbox.callbacks;

import com.zextras.carbonio.message_broker.MessageBrokerClient;
import com.zextras.carbonio.message_broker.config.enums.Service;
import com.zextras.carbonio.message_broker.events.services.mailbox.UserStatusChanged;
import com.zextras.mailbox.client.ServiceDiscoverHttpClient;
import com.zextras.mailbox.util.MailboxTestUtil;
import com.zimbra.cs.account.Account;
import com.zimbra.cs.account.Provisioning;
import com.zimbra.cs.account.callback.AccountStatus;
import com.zimbra.cs.account.callback.CallbackContext;
import io.vavr.control.Try;
import com.zimbra.cs.service.admin.AdminService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;

Expand All @@ -36,51 +30,24 @@ void setUp() throws Exception {
}

/**
* A lot of calls are mocked since they are external calls to service discover or message broker, this
* just tests that if calls are successful no other exceptions are thrown.
* This just tests that if calls are successful no other exceptions are thrown.
*/
@Test
void shouldNotFailWhenExecutingUserStatusChangedCallback(){
CallbackContext context = Mockito.mock(CallbackContext.class);
String attrName = "fake";
Account entry = Mockito.mock(Account.class);

ServiceDiscoverHttpClient serviceDiscoverHttpClient = Mockito.mock(ServiceDiscoverHttpClient.class);
MessageBrokerClient messageBrokerClient = Mockito.mock(MessageBrokerClient.class);

Mockito.when(context.isDoneAndSetIfNot(AccountStatus.class)).thenReturn(false);
Mockito.when(context.isCreate()).thenReturn(false);
Mockito.when(entry.getAccountStatus(any(Provisioning.class))).thenReturn("active");
Mockito.when(entry.getId()).thenReturn("fake-account-id");

try(MockedStatic<Files> mockedFiles = Mockito.mockStatic(Files.class);
MockedStatic<ServiceDiscoverHttpClient> mockedServiceDiscoverStatic = Mockito.mockStatic(ServiceDiscoverHttpClient.class);
MockedStatic<MessageBrokerClient> mockedMessageBrokerClientStatic = Mockito.mockStatic(MessageBrokerClient.class)) {

mockedFiles.when(() -> Files.readString(any(Path.class))).thenReturn("fake-token");
mockedServiceDiscoverStatic.when(() -> ServiceDiscoverHttpClient.defaultURL("carbonio-message-broker"))
.thenReturn(serviceDiscoverHttpClient);
Mockito.when(serviceDiscoverHttpClient.withToken("fake-token")).thenReturn(serviceDiscoverHttpClient);

Mockito.when(serviceDiscoverHttpClient.getConfig("default/username")).thenReturn(Try.success("fake-username"));
Mockito.when(serviceDiscoverHttpClient.getConfig("default/password")).thenReturn(Try.success("fake-password"));

mockedMessageBrokerClientStatic.when(() -> MessageBrokerClient.fromConfig(
"127.78.0.7",
20005,
"fake-username",
"fake-password"
)).thenReturn(messageBrokerClient);

Mockito.when(messageBrokerClient.withCurrentService(Service.MAILBOX)).thenReturn(messageBrokerClient);
Mockito.when(messageBrokerClient.publish(any(UserStatusChanged.class))).thenReturn(true);
MessageBrokerClient mockedMessageBrokerClient = AdminService.getMessageBrokerClientInstance();
Mockito.when(mockedMessageBrokerClient.publish(any(UserStatusChanged.class))).thenReturn(true);

accountStatus.postModify(context, attrName, entry);
accountStatus.postModify(context, attrName, entry);

assertTrue(true);
}catch(Exception e) {
e.printStackTrace();
fail();
}
assertTrue(true);
}
}
18 changes: 18 additions & 0 deletions store/src/test/java/com/zextras/mailbox/util/MailboxTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static com.zimbra.cs.account.Provisioning.SERVICE_MAILCLIENT;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.zextras.carbonio.message_broker.MessageBrokerClient;
import com.zextras.carbonio.message_broker.config.enums.Service;
import com.zextras.mailbox.util.InMemoryLdapServer.Builder;
import com.zimbra.common.account.ZAttrProvisioning;
import com.zimbra.common.localconfig.LC;
Expand All @@ -20,7 +22,11 @@
import com.zimbra.cs.mailbox.*;
import com.zimbra.cs.mime.ParsedMessage;
import com.zimbra.cs.redolog.RedoLogProvider;
import com.zimbra.cs.service.admin.AdminService;
import com.zimbra.cs.store.StoreManager;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -46,6 +52,8 @@ public static InMemoryLdapServer getInMemoryLdapServer() {

private static InMemoryLdapServer inMemoryLdapServer;

private static MessageBrokerClient mockedMessageBrokerClient;

private MailboxTestUtil() {}

/**
Expand Down Expand Up @@ -108,6 +116,16 @@ public static void initData() throws Exception {
SERVER_NAME,
new HashMap<>(Map.of(ZAttrProvisioning.A_zimbraServiceEnabled, SERVICE_MAILCLIENT)));
provisioning.createDomain(DEFAULT_DOMAIN, new HashMap<>());
mockMessageBrokerClient();
}

private static void mockMessageBrokerClient() {
if(mockedMessageBrokerClient == null) {
MessageBrokerClient messageBrokerClient = Mockito.mock(MessageBrokerClient.class);
MockedStatic<AdminService> mockedAdminServiceStatic = Mockito.mockStatic(AdminService.class, Mockito.CALLS_REAL_METHODS);
mockedAdminServiceStatic.when(AdminService::getMessageBrokerClientInstance).thenReturn(messageBrokerClient);
mockedMessageBrokerClient = messageBrokerClient;
}
}

/** Performs actions on an account. Start with {@link #shareWith(Account)} */
Expand Down
Loading

0 comments on commit 9d8d919

Please sign in to comment.