Untitled
package com.trendmicro.serapis.admin.apiservice.api.emailnotification; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.forescout.soarcore.model.EmailNotificationResponse; import com.forescout.soarcore.model.SoarEmailRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import com.trendmicro.serapis.apiservice.api.exceptions.EntityNotFoundException; import com.trendmicro.serapis.apiservice.security.AdminSecureApi; import com.trendmicro.serapis.apiservice.security.IdParam; import io.swagger.annotations.ApiParam; import org.springframework.web.bind.annotation.RequestBody; @Path("/admin/accounts/{accountId}/emailnotifications") @Produces({MediaType.TEXT_PLAIN}) @io.swagger.annotations.Api() @Component public class SoarEmailNotificationAdminApi { private final SoarEmailNotificationAdminApiService delegate; public SoarEmailNotificationAdminApi(SoarEmailNotificationAdminApiService delegate) { this.delegate = delegate; } @POST @Path("/send") @Produces({MediaType.APPLICATION_JSON}) @AdminSecureApi(hasAccountIdParameter = true) public Response publishNotification(@ApiParam(value = "Id of the account", required = true) @PathParam("accountId") @IdParam String accountId, @RequestBody SoarEmailRequest soarEmailRequest) throws EntityNotFoundException { try { delegate.validateRecipients(soarEmailRequest.recipients()); EmailNotificationResponse emailNotificationResponse = delegate.sendEmailNotification(accountId,soarEmailRequest); return Response.status(Response.Status.OK).entity(emailNotificationResponse).build(); } catch (Exception e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Error sending email: " + e.getMessage()).build(); } } } package com.trendmicro.serapis.admin.apiservice.api.emailnotification; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import com.forescout.soarcore.model.EmailNotificationData; import com.forescout.soarcore.model.EmailNotificationDetails; import com.forescout.soarcore.model.EmailNotificationRecipients; import com.forescout.soarcore.model.EmailNotificationResponse; import com.forescout.soarcore.model.SoarEmailRequest; import com.trendmicro.serapis.admin.apiservice.api.accounts.AccountsAdminApiService; import com.trendmicro.serapis.apiservice.api.inappnotifications.model.NotificationAttributes; import com.trendmicro.serapis.apiservice.database.UserRepositoryService; import com.trendmicro.serapis.apiservice.database.entities.UserDao; import com.trendmicro.serapis.apiservice.util.NotificationPublisher; import com.trendmicro.serapis.apiservice.util.UuidUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.trendmicro.serapis.apiservice.api.accounts.model.Account; import com.trendmicro.serapis.apiservice.api.exceptions.EntityNotFoundException; import com.trendmicro.serapis.apiservice.database.AccountRepositoryService; import com.trendmicro.serapis.apiservice.database.InAppNotificationRepositoryService; @Service public class SoarEmailNotificationAdminApiService { private static final Logger log = LoggerFactory.getLogger(SoarEmailNotificationAdminApiService.class); private final InAppNotificationRepositoryService inAppNotificationRepositoryService; @Autowired private final AccountsAdminApiService accountRepositoryService; private final NotificationPublisher notificationPublisher; private final UserRepositoryService userRepositoryService; public SoarEmailNotificationAdminApiService(InAppNotificationRepositoryService inAppNotificationRepositoryService, AccountsAdminApiService accountRepositoryService, NotificationPublisher notificationPublisher, UserRepositoryService userRepositoryService) throws EntityNotFoundException { this.inAppNotificationRepositoryService = inAppNotificationRepositoryService; this.accountRepositoryService = accountRepositoryService; this.notificationPublisher = notificationPublisher; this.userRepositoryService = userRepositoryService; } public EmailNotificationResponse sendEmailNotification(String accountId, SoarEmailRequest soarEmailRequest) throws EntityNotFoundException { List<Account> accounts = getAccountDetails(soarEmailRequest.recipients()); Account account = accountRepositoryService.getAccount(accountId); return sendEmailNotificationPrivileged(accountId, soarEmailRequest, accounts, account); } private EmailNotificationResponse sendEmailNotificationPrivileged(String accountId, SoarEmailRequest soarEmailRequest, List<Account> accounts, Account account) throws EntityNotFoundException { Set<UserDao> setOfUsers = getUserDaosPrivileged(accounts); Set<EmailNotificationRecipients> recipients = getRecipients(setOfUsers); EmailNotificationDetails emailNotificationDetails = new EmailNotificationDetails(soarEmailRequest.emailSubject(), soarEmailRequest.emailBody()); notifyEmailNotificationsToRecipients(recipients,emailNotificationDetails,account.getName()); EmailNotificationResponse response = new EmailNotificationResponse(); response.setAccountId(accountId); response.setSubject(emailNotificationDetails.subject()); response.setBody(emailNotificationDetails.body()); log.info("Email notification sent successfully to {} recipients for account {}", recipients.size(), account.getId()); return response; } public List<Account> getAccountDetails(List<String> accountIds) throws EntityNotFoundException { List<Account> accounts = new ArrayList<>(); for (String accountId : accountIds) { Account account = accountRepositoryService.getAccount(accountId); accounts.add(account); } return accounts; } public void validateRecipients(List<String> accountIds) throws EntityNotFoundException { for (String accountId : accountIds) { Account account = accountRepositoryService.getAccount(accountId); if (account == null) { throw new EntityNotFoundException("Account ID not found: " + accountId); } } } private Set<UserDao> getUserDaosPrivileged(List<Account> accounts) { Set<Set<String>> userIds = accounts.stream().map(acc -> acc.getUserIds()).collect(Collectors.toSet()); Set<List<UserDao>> users = userIds.stream().map(u -> { try { return userRepositoryService.readUserDaosByIds(u); } catch (EntityNotFoundException e) { throw new RuntimeException(e); } }).collect(Collectors.toSet()); Set<UserDao> setOfUsers = new HashSet<>(); for (List<UserDao> userList : users) { setOfUsers.addAll(userList); } return setOfUsers; } private Set<EmailNotificationRecipients> getRecipients(Set<UserDao> setOfUsers) { return setOfUsers.stream().map(usr -> new EmailNotificationRecipients(UuidUtils.toStringNoDashes(usr.getId()), usr.getEmail())).collect(Collectors.toSet()); } private void notifyEmailNotificationsToRecipients(Set<EmailNotificationRecipients> recipients, EmailNotificationDetails notificationDetails, String accountName) { EmailNotificationData notificationData = new EmailNotificationData(notificationDetails, recipients); NotificationAttributes attributes = new NotificationAttributes(false, true); if (!recipients.isEmpty()) { notificationPublisher .notifyEmailNotificationsToRecipients(notificationData, attributes); } else { log.warn( "There are no users to notify while attempting to notify the email notifications to the users. Account Name- {}", accountName); } } } import java.util.regex.Pattern; import java.util.stream.Collectors; import com.forescout.soarcore.model.EmailNotificationData; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.util.Strings; @@ -251,6 +252,19 @@ public void notifyUserGroupUnassignedFromAccount(Set<String> emailsToNotify, publishNotification(NotificationType.USER_GROUP_REMOVED_FROM_ACCOUNT, data); } public void notifyEmailNotificationsToRecipients(EmailNotificationData messageData, NotificationAttributes attributes) { log.debug("NotificationPublisher: notifyEmailNotificationsToRecipients"); final String data = getDataForEmailNotification(messageData); publishNotification(NotificationType.SOAR_ACTION_EXECUTION_NOTIFICATION, data, attributes.isEmail(), attributes.isInApp()); } private String getDataForEmailNotification(EmailNotificationData data) { // Use a LinkedHashMap to maintain order of the properties. // The properties are displayed in the email in the order they are added to the map. final Map<String, Object> notificationProperties = new LinkedHashMap<>(); notificationProperties.put(NotificationAttribute.RECIPIENTS.getDisplayName(), data.recipients()); notificationProperties.put(NotificationAttribute.NOTIFICATION_DETAILS.getDisplayName(), data.notification()); return convertNotificationPropertiesToJsonString(notificationProperties); } public void notifyUserAddedToAccount(Set<String> emailsToNotify, String userEmail, String roleName, package com.trendmicro.serapis.admin.apiservice.emailnotification; import com.trendmicro.serapis.admin.apiservice.api.accounts.AccountsAdminApiService; import com.trendmicro.serapis.admin.apiservice.api.emailnotification.SoarEmailNotificationAdminApiService; import com.trendmicro.serapis.apiservice.ApiServiceApplication; import com.trendmicro.serapis.apiservice.api.exceptions.AccountManagerException; import com.trendmicro.serapis.apiservice.api.exceptions.ElasticsearchException; import com.trendmicro.serapis.apiservice.api.exceptions.GroupApiException; import com.trendmicro.serapis.apiservice.api.exceptions.InvalidParameterException; import com.trendmicro.serapis.apiservice.api.users.model.User; import com.trendmicro.serapis.apiservice.database.AccountRepositoryService; import com.trendmicro.serapis.apiservice.security.SecurityUtil; import com.trendmicro.serapis.apiservice.testutils.RandomStringUtils; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import com.forescout.soarcore.model.*; import com.trendmicro.serapis.apiservice.api.accounts.model.Account; import com.trendmicro.serapis.apiservice.api.exceptions.EntityNotFoundException; import com.trendmicro.serapis.apiservice.database.AccountRepositoryService; import com.trendmicro.serapis.apiservice.database.InAppNotificationRepositoryService; import com.trendmicro.serapis.apiservice.database.UserRepositoryService; import com.trendmicro.serapis.apiservice.database.entities.UserDao; import com.trendmicro.serapis.apiservice.util.NotificationPublisher; import com.trendmicro.serapis.apiservice.util.UuidUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; import java.io.IOException; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @SpringBootTest(classes = ApiServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles(value = "h2test") public class SoarEmailNotificationAdminApiServiceTest { @Mock private AccountsAdminApiService accountRepositoryService; @Mock private NotificationPublisher notificationPublisher; @Mock private UserRepositoryService userRepositoryService; @InjectMocks private SoarEmailNotificationAdminApiService soarEmailNotificationAdminApiService; @Autowired private SecurityUtil securityUtil; private String accountId; private SoarEmailRequest soarEmailRequest; private static final String TEST_ACCOUNT_ID = UuidUtils.toStringNoDashes(UUID.randomUUID()); private List<Account> mockAccounts; private Set<UserDao> mockUserDaos; private List<String> mockAccountIds; private Set<EmailNotificationRecipients> mockRecipients; private Account account; private User administratorUser; private User editorUser; @BeforeEach void setUp() throws EntityNotFoundException, InvalidParameterException, AccountManagerException, GroupApiException, IOException, ElasticsearchException { MockitoAnnotations.openMocks(this); // Common test data accountId = "test-account-id"; Pair<Account, User> jUnitUser = securityUtil.createAuthenticationAndAccount("junit@test.com", "JUnit_User", RandomStringUtils.randomAlphanumeric(20), "fake-es-address-1", RandomStringUtils.generateDomainListFromEmails(Arrays.asList("junit@test.com"))); account = jUnitUser.getLeft(); accountId = account.getId(); editorUser = jUnitUser.getRight(); mockAccounts = Arrays.asList(account); mockAccountIds = Arrays.asList(accountId); soarEmailRequest = new SoarEmailRequest( "Test Subject", "Test Body", List.of(accountId) ); // Mocking dependencies when(accountRepositoryService.getAccount(accountId)).thenReturn(account); // when(accountRepositoryService.read("recipient-account-id")).thenReturn(mockAccount); // when(userRepositoryService.readUserDaosByIds(Set.of("user-1"))).thenReturn(List.of(new UserDao("user-1", "user1@example.com"))); } @Test void testSendEmailNotification_Success() throws EntityNotFoundException { // when(soarEmailNotificationAdminApiService.getAccountDetails(mockAccountIds)).thenReturn(mockAccounts); EmailNotificationResponse response = soarEmailNotificationAdminApiService.sendEmailNotification(accountId, soarEmailRequest); assertEquals(accountId, response.getAccountId()); assertEquals("Test Subject", response.getSubject()); assertEquals("Test Body", response.getBody()); verify(notificationPublisher, times(1)) .notifyEmailNotificationsToRecipients(any(EmailNotificationData.class), any()); } @Test void testSendEmailNotification_EntityNotFoundException() throws EntityNotFoundException { when(accountRepositoryService.getAccount(accountId)).thenThrow(new EntityNotFoundException("Account ID not found")); SoarEmailRequest invalidRequest = new SoarEmailRequest( "Subject", "Body", List.of(accountId) ); assertThrows(EntityNotFoundException.class, () -> soarEmailNotificationAdminApiService.sendEmailNotification(accountId, invalidRequest)); } @Test void testValidateRecipients_ValidRecipients() throws EntityNotFoundException { soarEmailNotificationAdminApiService.validateRecipients(mockAccountIds); verify(accountRepositoryService, times(1)).getAccount("recipient-account-id"); } @Test void testValidateRecipients_InvalidRecipient() throws EntityNotFoundException { when(accountRepositoryService.getAccount("invalid-account-id")).thenThrow(new EntityNotFoundException("Account ID not found")); List<String> invalidAccountIds = List.of("invalid-account-id"); assertThrows(EntityNotFoundException.class, () -> soarEmailNotificationAdminApiService.validateRecipients(invalidAccountIds)); } // @Test // void testNotifyEmailNotificationsToRecipients_NoRecipients() { // Set<EmailNotificationRecipients> emptyRecipients = Collections.emptySet(); // soarEmailNotificationAdminApiService.notifyEmailNotificationsToRecipients(emptyRecipients, new EmailNotificationDetails("Test", "Body"), "Test Account"); // // verify(notificationPublisher, never()).notifyEmailNotificationsToRecipients(any(), any()); // } } package com.trendmicro.serapis.admin.apiservice.emailnotification; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.doNothing; import java.io.IOException; import java.time.Instant; import java.util.List; import java.util.UUID; import com.forescout.soarcore.model.EmailNotificationResponse; import com.forescout.soarcore.model.SoarEmailRequest; import com.trendmicro.serapis.admin.apiservice.api.emailnotification.SoarEmailNotificationAdminApiService; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import com.trendmicro.serapis.apiclient.TaskSchedulerApiClient; import com.trendmicro.serapis.apiservice.ApiServiceApplication; import com.trendmicro.serapis.apiservice.api.accounts.model.Account; import com.trendmicro.serapis.apiservice.api.exceptions.AccountManagerException; import com.trendmicro.serapis.apiservice.api.exceptions.ElasticsearchException; import com.trendmicro.serapis.apiservice.api.exceptions.EntityNotFoundException; import com.trendmicro.serapis.apiservice.api.exceptions.GroupApiException; import com.trendmicro.serapis.apiservice.api.exceptions.InvalidParameterException; import com.trendmicro.serapis.apiservice.api.users.model.User; import com.trendmicro.serapis.apiservice.security.SecurityUtil; import com.trendmicro.serapis.apiservice.util.UuidUtils; @ExtendWith(SpringExtension.class) @SpringBootTest(classes = ApiServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles(value = "h2test") public class SoarEmailNotificationAdminApiTests { @Autowired private TestRestTemplate restClient; private static final String TEST_ACCOUNT_ID = UuidUtils.toStringNoDashes(UUID.randomUUID()); private HttpHeaders headers; @Autowired private SecurityUtil securityUtil; private Account account; @MockBean private SoarEmailNotificationAdminApiService delegate; private SoarEmailRequest testEmailRequest; @BeforeEach void setup() throws InvalidParameterException, EntityNotFoundException, IOException, AccountManagerException, ElasticsearchException, GroupApiException { Pair<Account, User> result = securityUtil.createAuthenticationAndAccount(); User user = result.getRight(); account = result.getLeft(); headers = securityUtil.createAuthorizedHttpHeaders(user.getUsername()); testEmailRequest = new SoarEmailRequest( "Test Subject", "Test Body", List.of(TEST_ACCOUNT_ID) ); } @Test void testPublishNotificationSuccess() throws EntityNotFoundException { // Arrange doNothing().when(delegate).validateRecipients(testEmailRequest.recipients()); EmailNotificationResponse responseMock = new EmailNotificationResponse(TEST_ACCOUNT_ID,"success", "Done", Instant.now()); Mockito.when(delegate.sendEmailNotification(Mockito.eq(TEST_ACCOUNT_ID), Mockito.any())) .thenReturn(responseMock); HttpEntity<SoarEmailRequest> requestEntity = new HttpEntity<>(testEmailRequest, headers); // Act ResponseEntity<EmailNotificationResponse> response = restClient.exchange( String.format("/api/admin/accounts/%s/emailnotifications/send", TEST_ACCOUNT_ID), HttpMethod.POST, requestEntity, EmailNotificationResponse.class ); // Assert assertEquals(HttpStatus.OK, response.getStatusCode()); } @Test void testPublishNotificationValidationFailure() throws EntityNotFoundException { // Arrange Mockito.doThrow(new IllegalArgumentException()) .when(delegate) .validateRecipients(Mockito.any()); HttpEntity<SoarEmailRequest> requestEntity = new HttpEntity<>(testEmailRequest, headers); // Act ResponseEntity<String> response = restClient.exchange( String.format("/api/admin/accounts/%s/emailnotifications/send", TEST_ACCOUNT_ID), HttpMethod.POST, requestEntity, String.class ); // Assert assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); } @Test void testPublishNotificationEntityNotFound() throws EntityNotFoundException { // Arrange Mockito.doNothing().when(delegate).validateRecipients(Mockito.any()); Mockito.doThrow(new RuntimeException()) .when(delegate) .sendEmailNotification(Mockito.eq(TEST_ACCOUNT_ID), Mockito.any()); HttpEntity<SoarEmailRequest> requestEntity = new HttpEntity<>(testEmailRequest, headers); // Act ResponseEntity<String> response = restClient.exchange( String.format("/api/admin/accounts/%s/emailnotifications/send", TEST_ACCOUNT_ID), HttpMethod.POST, requestEntity, String.class ); // Assert assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); } @Test void testPublishNotificationMissingAccountId() { // Act ResponseEntity<String> response = restClient.exchange( "/api/admin/accounts//emailnotifications/send", HttpMethod.POST, new HttpEntity<>(testEmailRequest, headers), String.class ); // Assert assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); } }
Leave a Comment