Skip to content
Snippets Groups Projects
Commit 51173e35 authored by Lukasz Lopatowski's avatar Lukasz Lopatowski
Browse files

Merge branch '276_user_domain_webhook' into 'develop'

276 user domain webhook

See merge request !224
parents 198073eb 87aa22be
No related branches found
No related tags found
2 merge requests!273Release 1.8.0 update,!224276 user domain webhook
Pipeline #94708 failed
......@@ -45,9 +45,7 @@ public class DomainCreationJob extends WebhookJob {
}
Domain domain = domainService.findDomain(domainId).orElseThrow(() -> new MissingElementException(String.format("Domain with id: %d cannot be found", domainId)));
DomainView view = modelMapper.map(domain, DomainView.class);
callWebhook(webhook, view);
callWebhook(webhook, modelMapper.map(domain, DomainView.class));
} catch (GeneralSecurityException e) {
log.error("Failed to decrypt webhook with id {}", webhookId);
throw new JobExecutionException("Failed webhook decryption");
......
package net.geant.nmaas.orchestration.jobs;
import lombok.extern.slf4j.Slf4j;
import net.geant.nmaas.orchestration.exceptions.WebServiceCommunicationException;
import net.geant.nmaas.portal.api.domain.DomainView;
import net.geant.nmaas.portal.api.domain.UserDomainAssignmentWebhookDto;
import net.geant.nmaas.portal.api.domain.UserView;
import net.geant.nmaas.portal.api.domain.WebhookEventDto;
import net.geant.nmaas.portal.api.exceptions.MissingElementException;
import net.geant.nmaas.portal.persistent.entity.Domain;
import net.geant.nmaas.portal.persistent.entity.Role;
import net.geant.nmaas.portal.persistent.entity.User;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.service.DomainService;
import net.geant.nmaas.portal.service.UserService;
import net.geant.nmaas.portal.service.WebhookEventService;
import org.modelmapper.ModelMapper;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import java.security.GeneralSecurityException;
@Slf4j
@Component
public class UserDomainAssignmentJob extends WebhookJob {
private final DomainService domainService;
private final UserService userService;
@Autowired
public UserDomainAssignmentJob(RestClient restClient, WebhookEventService webhookEventService, ModelMapper modelMapper, DomainService domainService, UserService userService) {
super(restClient, webhookEventService, modelMapper);
this.domainService = domainService;
this.userService = userService;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
Long webhookId = dataMap.getLong("webhookId");
Long domainId = dataMap.getLong("domainId");
Long userId = dataMap.getLong("userId");
Role role = Role.valueOf(dataMap.getString("role"));
String action = dataMap.getString("action");
try {
WebhookEventDto webhook = webhookEventService.getById(webhookId);
if (!WebhookEventType.USER_ASSIGNMENT.equals(webhook.getEventType())) {
log.warn("Webhook's event type with id {} has been updated. UserDomainAssignmentJob is abandoned", webhookId);
return;
}
Domain domain = domainService.findDomain(domainId).orElseThrow(() -> new MissingElementException(String.format("Domain with id: %d cannot be found", domainId)));
User user = userService.findById(userId).orElseThrow(() -> new MissingElementException(String.format("User with id: %d cannot be found", userId)));
UserDomainAssignmentWebhookDto dto = new UserDomainAssignmentWebhookDto(modelMapper.map(user, UserView.class), modelMapper.map(domain, DomainView.class), role, action);
callWebhook(webhook, dto);
} catch (GeneralSecurityException e) {
log.error("Failed to decrypt webhook with id {}", webhookId);
throw new JobExecutionException("Failed webhook decryption");
} catch (MissingElementException e) {
log.warn(e.getMessage() + " UserDomainAssignmentJob is abandoned");
} catch (WebServiceCommunicationException e) {
log.error("Failed to communicate with external system for the webhoook of assignment of the user with id {} in the domain with id {}", userId, domainId);
throw new JobExecutionException("Failed communication with external system");
}
}
}
package net.geant.nmaas.portal.api.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.geant.nmaas.portal.persistent.entity.Role;
@AllArgsConstructor
@Getter
@Setter
public class UserDomainAssignmentWebhookDto {
private UserView user;
private DomainView domain;
private Role role;
private String action;
}
......@@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
import net.geant.nmaas.notifications.MailAttributes;
import net.geant.nmaas.notifications.NotificationEvent;
import net.geant.nmaas.notifications.templates.MailType;
import net.geant.nmaas.orchestration.jobs.UserDomainAssignmentJob;
import net.geant.nmaas.portal.api.domain.PasswordChange;
import net.geant.nmaas.portal.api.domain.PasswordReset;
import net.geant.nmaas.portal.api.domain.UserBase;
......@@ -22,11 +23,14 @@ import net.geant.nmaas.portal.persistent.entity.Domain;
import net.geant.nmaas.portal.persistent.entity.Role;
import net.geant.nmaas.portal.persistent.entity.User;
import net.geant.nmaas.portal.persistent.entity.UserRole;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.persistent.repositories.WebhookEventRepository;
import net.geant.nmaas.portal.persistent.results.UserLoginDate;
import net.geant.nmaas.portal.service.ApplicationInstanceService;
import net.geant.nmaas.portal.service.DomainService;
import net.geant.nmaas.portal.service.UserLoginRegisterService;
import net.geant.nmaas.portal.service.UserService;
import net.geant.nmaas.scheduling.ScheduleManager;
import net.geant.nmaas.utils.captcha.ValidateCaptcha;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
......@@ -52,6 +56,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
import java.time.LocalDateTime;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -100,6 +105,8 @@ public class UsersController {
private final UserLoginRegisterService userLoginService;
private final ApplicationInstanceService instanceService;
private final WebhookEventRepository webhookEventRepository;
private final ScheduleManager scheduleManager;
@Autowired
public UsersController(UserService userService,
......@@ -109,7 +116,9 @@ public class UsersController {
JWTTokenService jwtTokenService,
ApplicationEventPublisher eventPublisher,
UserLoginRegisterService userLoginService,
ApplicationInstanceService instanceService) {
ApplicationInstanceService instanceService,
WebhookEventRepository webhookEventRepository,
ScheduleManager scheduleManager) {
this.userService = userService;
this.domainService = domainService;
this.modelMapper = modelMapper;
......@@ -118,6 +127,8 @@ public class UsersController {
this.eventPublisher = eventPublisher;
this.userLoginService = userLoginService;
this.instanceService = instanceService;
this.webhookEventRepository = webhookEventRepository;
this.scheduleManager = scheduleManager;
}
@GetMapping("/users")
......@@ -508,6 +519,9 @@ public class UsersController {
try {
domainService.addMemberRole(domain.getId(), user.getId(), role);
if (!domain.equals(globalDomain)){
webhookEventRepository.findIdByEventType(WebhookEventType.USER_ASSIGNMENT).forEach(id -> scheduleManager.createOneTimeJob(UserDomainAssignmentJob.class, "UserDomainAssignmentJobCreate_" + id + "_user" + user.getId()+ "_domain" + domain.getId()+"_" + LocalDateTime.now(), Map.of("webhookId", id, "domainId", domain.getId(), "userId", user.getId(), "role", role.name(), "action", "create")));
}
final User adminUser = userService.findByUsername(principal.getName()).orElseThrow(() -> new ObjectNotFoundException(USER_NOT_FOUND_ERROR_MESSAGE));
final String adminRoles = getRoleAsString(adminUser.getRoles());
......@@ -541,6 +555,10 @@ public class UsersController {
domainService.removeMemberRole(domain.getId(), user.getId(), role);
final User adminUser = userService.findByUsername(principal.getName()).orElseThrow(() -> new ObjectNotFoundException(USER_NOT_FOUND_ERROR_MESSAGE));
final String adminRoles = getRoleAsString(adminUser.getRoles());
final Domain globalDomain = domainService.getGlobalDomain().orElse(null);
if (!domain.equals(globalDomain)){
webhookEventRepository.findIdByEventType(WebhookEventType.USER_ASSIGNMENT).forEach(id -> scheduleManager.createOneTimeJob(UserDomainAssignmentJob.class, "UserDomainAssignmentJobDelete_" + id + "_user" + user.getId()+ "_domain" + domain.getId()+"_" + LocalDateTime.now(), Map.of("webhookId", id, "domainId", domain.getId(), "userId", user.getId(), "role", role.name(), "action", "delete")));
}
log.info(String.format("User [%s] with role [%s] removed role [%s] of user name [%s] in domain [%d].",
principal.getName(),
......
package net.geant.nmaas.portal.api.market;
import com.google.common.collect.ImmutableSet;
import net.geant.nmaas.orchestration.jobs.DomainCreationJob;
import net.geant.nmaas.orchestration.jobs.UserDomainAssignmentJob;
import net.geant.nmaas.portal.api.domain.PasswordChange;
import net.geant.nmaas.portal.api.domain.UserRequest;
import net.geant.nmaas.portal.api.domain.UserRoleView;
......@@ -14,13 +16,23 @@ import net.geant.nmaas.portal.exceptions.ObjectNotFoundException;
import net.geant.nmaas.portal.persistent.entity.Domain;
import net.geant.nmaas.portal.persistent.entity.Role;
import net.geant.nmaas.portal.persistent.entity.User;
import net.geant.nmaas.portal.persistent.entity.WebhookEvent;
import net.geant.nmaas.portal.persistent.entity.WebhookEventType;
import net.geant.nmaas.portal.persistent.repositories.WebhookEventRepository;
import net.geant.nmaas.portal.service.ApplicationInstanceService;
import net.geant.nmaas.portal.service.DomainService;
import net.geant.nmaas.portal.service.UserLoginRegisterService;
import net.geant.nmaas.portal.service.UserService;
import net.geant.nmaas.scheduling.ScheduleManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.internal.verification.VerificationModeFactory;
import org.modelmapper.ModelMapper;
import org.quartz.JobListener;
import org.quartz.ListenerManager;
import org.quartz.Matcher;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.crypto.password.PasswordEncoder;
......@@ -30,15 +42,19 @@ import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
public class UsersControllerTest {
......@@ -69,9 +85,15 @@ public class UsersControllerTest {
private final ApplicationInstanceService instanceService = mock(ApplicationInstanceService.class);
WebhookEventRepository webhookEventRepository = mock(WebhookEventRepository.class);
Scheduler scheduler = mock(Scheduler.class);
ListenerManager listenerManager = mock(ListenerManager.class);
ScheduleManager scheduleManager;
@BeforeEach
public void setup(){
usersController = new UsersController(userService, domainService, modelMapper, passwordEncoder, jwtTokenService, eventPublisher, userLoginService, instanceService);
scheduleManager = new ScheduleManager(scheduler);
usersController = new UsersController(userService, domainService, modelMapper, passwordEncoder, jwtTokenService, eventPublisher, userLoginService, instanceService, webhookEventRepository, scheduleManager);
User tester = new User("tester", true, "test123", DOMAIN, Role.ROLE_USER);
tester.setId(1L);
User admin = new User("testadmin", true, "testadmin123", DOMAIN, Role.ROLE_SYSTEM_ADMIN);
......@@ -329,12 +351,31 @@ public class UsersControllerTest {
}
@Test
public void shouldAddUserRoleToCustomDomain(){
public void shouldAddUserRoleToCustomDomain() throws SchedulerException {
UserRoleView userRole = new UserRoleView();
userRole.setDomainId(DOMAIN.getId());
userRole.setRole(Role.ROLE_USER);
// Setup webhook event
WebhookEvent webhookEvent = new WebhookEvent(1L, "webhook", "https://example.com/webhook", WebhookEventType.USER_ASSIGNMENT, null, null);
when(webhookEventRepository.findIdByEventType(WebhookEventType.USER_ASSIGNMENT))
.thenReturn(Stream.of(1L));
when(webhookEventRepository.findById(1L))
.thenReturn(Optional.of(webhookEvent));
when(scheduler.getListenerManager()).thenReturn(listenerManager);
doNothing().when(listenerManager).addJobListener(any(JobListener.class), any(Matcher.class));
usersController.addUserRole(DOMAIN.getId(), userList.get(0).getId(), userRole, principal);
verify(domainService, times(1)).addMemberRole(DOMAIN.getId(), userList.get(0).getId(), userRole.getRole());
// Verify webhook job was scheduled
verify(scheduler, VerificationModeFactory.times(1)).scheduleJob(
argThat(jobDetail ->
jobDetail.getKey().getName().startsWith("UserDomainAssignmentJobCreate_1_user"+userList.get(0).getId()+"_domain2") &&
jobDetail.getJobClass().equals(UserDomainAssignmentJob.class)
),
argThat(trigger ->
trigger.getKey().getName().startsWith("UserDomainAssignmentJobCreate_1_user"+userList.get(0).getId()+"_domain2")
)
);
}
@Test
......@@ -345,6 +386,8 @@ public class UsersControllerTest {
when(domainService.findDomain(GLOBAL_DOMAIN.getId())).thenReturn(Optional.of(GLOBAL_DOMAIN));
usersController.addUserRole(GLOBAL_DOMAIN.getId(), userList.get(0).getId(), userRole, principal);
verify(domainService, times(1)).addMemberRole(GLOBAL_DOMAIN.getId(), userList.get(0).getId(), userRole.getRole());
verifyNoInteractions(scheduler);
}
@Test
......@@ -396,10 +439,29 @@ public class UsersControllerTest {
}
@Test
public void shouldRemoveUserRole(){
public void shouldRemoveUserRole() throws SchedulerException {
String userRole = "ROLE_SYSTEM_ADMIN";
// Setup webhook event
WebhookEvent webhookEvent = new WebhookEvent(1L, "webhook", "https://example.com/webhook", WebhookEventType.USER_ASSIGNMENT, null, null);
when(webhookEventRepository.findIdByEventType(WebhookEventType.USER_ASSIGNMENT))
.thenReturn(Stream.of(1L));
when(webhookEventRepository.findById(1L))
.thenReturn(Optional.of(webhookEvent));
when(scheduler.getListenerManager()).thenReturn(listenerManager);
doNothing().when(listenerManager).addJobListener(any(JobListener.class), any(Matcher.class));
usersController.removeUserRole(DOMAIN.getId(), userList.get(0).getId(), userRole, principal);
verify(domainService, times(1)).removeMemberRole(DOMAIN.getId(), userList.get(0).getId(), Role.ROLE_SYSTEM_ADMIN);
// Verify webhook job was scheduled
verify(scheduler, VerificationModeFactory.times(1)).scheduleJob(
argThat(jobDetail ->
jobDetail.getKey().getName().startsWith("UserDomainAssignmentJobDelete_1_user"+userList.get(0).getId()+"_domain2") &&
jobDetail.getJobClass().equals(UserDomainAssignmentJob.class)
),
argThat(trigger ->
trigger.getKey().getName().startsWith("UserDomainAssignmentJobDelete_1_user"+userList.get(0).getId()+"_domain2")
)
);
}
@Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment