Untitled

 avatar
unknown
plain_text
16 days ago
24 kB
3
Indexable
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