diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java index 320fc650e..0bd75f712 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java @@ -177,7 +177,7 @@ public class ManualRedactionController implements ManualRedactionResource { .userId(KeycloakSecurity.getUserId()) .objectId(fileId) .category(AuditCategory.DOCUMENT.name()) - .message("Manual redaction was added.") + .message("Manual annotation was added.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId())) .build())); @@ -211,7 +211,7 @@ public class ManualRedactionController implements ManualRedactionResource { .userId(KeycloakSecurity.getUserId()) .objectId(fileId) .category(AuditCategory.DOCUMENT.name()) - .message("Redaction was manually removed") + .message("Annotation was manually removed") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId())) .build())); @@ -234,7 +234,7 @@ public class ManualRedactionController implements ManualRedactionResource { .userId(KeycloakSecurity.getUserId()) .objectId(fileId) .category(AuditCategory.DOCUMENT.name()) - .message("Skipped redaction was forced to be redacted") + .message("Skipped annotation was forced to be redacted") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId())) .build())); @@ -310,7 +310,7 @@ public class ManualRedactionController implements ManualRedactionResource { .userId(KeycloakSecurity.getUserId()) .objectId(fileId) .category(AuditCategory.DOCUMENT.name()) - .message("Skipped redaction was resized to be redacted") + .message("Skipped annotation was resized to be redacted") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId())) .build())); diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java index 3f3e12953..eed33943b 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java @@ -22,6 +22,7 @@ import com.iqser.red.service.persistence.service.v2.api.external.model.Component import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents; import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList; import com.iqser.red.service.persistence.service.v2.api.external.resource.ComponentResource; +import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AccessLevel; @@ -48,6 +49,7 @@ public class ComponentControllerV2 implements ComponentResource { @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) { dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId); + componentLogService.validateUserRoles(KeycloakSecurity.getUserId()); var componentLog = componentLogService.getComponentLog(dossierId, fileId, true); return componentMapper.toFileComponents(componentLog, dossierTemplateId, dossierId, fileId, fileStatusService.getFileName(fileId), includeDetails); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/roles/ApplicationRoles.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/roles/ApplicationRoles.java index f53538221..8c966f94f 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/roles/ApplicationRoles.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/roles/ApplicationRoles.java @@ -112,15 +112,11 @@ public final class ApplicationRoles { public static final String RED_ADMIN_ROLE = "RED_ADMIN"; public static final String RED_USER_ADMIN_ROLE = "RED_USER_ADMIN"; + public static final Set VALID_MEMBER_ROLES = Set.of(ApplicationRoles.RED_USER_ROLE, ApplicationRoles.RED_MANAGER_ROLE); + public static final Set UNMAPPED_ACTION_ROLES = Sets.newHashSet(UNARCHIVE_DOSSIER, UPDATE_LICENSE, GET_RSS, USE_SUPPORT_CONTROLLER); - public static final Set KNECON_ADMIN_ACTION_ROLES = Sets.newHashSet(READ_LICENSE, - UPDATE_LICENSE, - GET_TENANTS, - CREATE_TENANT, - READ_USERS, - READ_ALL_USERS, - WRITE_USERS, + public static final Set KNECON_ADMIN_ACTION_ROLES = Sets.newHashSet(READ_LICENSE, UPDATE_LICENSE, GET_TENANTS, CREATE_TENANT, READ_USERS, READ_ALL_USERS, WRITE_USERS, READ_SMTP_CONFIGURATION, WRITE_SMTP_CONFIGURATION, UNARCHIVE_DOSSIER, diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java index 6e4800d01..696caab9d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java @@ -4,14 +4,19 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ComponentDefinitionEntity; +import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException; +import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ComponentDefinitionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; +import com.iqser.red.service.persistence.management.v1.processor.service.users.model.User; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry; @@ -32,6 +37,7 @@ public class ComponentLogService { private final ComponentLogMongoService componentLogMongoService; private final AuditPersistenceService auditPersistenceService; private final ComponentDefinitionPersistenceService componentDefinitionPersistenceService; + private final UserService userService; public ComponentLog getComponentLog(String dossierId, String fileId, boolean includeOverrides) { @@ -58,6 +64,19 @@ public class ComponentLogService { } + public void validateUserRoles(String userId) { + + Optional userOptional = userService.getUserById(userId); + if (userOptional.isPresent()) { + if (userOptional.get().getRoles() + .stream() + .noneMatch(ApplicationRoles.VALID_MEMBER_ROLES::contains)) { + throw new NotAllowedException("User doesn't have appropriate roles"); + } + } + } + + private ComponentLog sortComponentLogEntries(ComponentLog componentLog, List orderedNames) { List componentLogEntries = componentLog.getComponentLogEntries(); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index 31559e21e..1ef9ec401 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -49,6 +49,7 @@ import com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUti import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.MessageType; import com.iqser.red.service.persistence.service.v1.api.shared.model.RequestEntryPair; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; @@ -69,6 +70,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; @@ -213,6 +215,13 @@ public class ManualRedactionService { log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); IdRemovalEntity idRemoval = removeRedactionPersistenceService.insert(fileId, removeRedactionRequest); + if ((entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) + && (entityLogEntry.getEngines().contains(Engine.DICTIONARY) + || entityLogEntry.getEngines().contains(Engine.DOSSIER_DICTIONARY)) + && entityLogEntry.getEngines().contains(Engine.MANUAL)) { + insertLocalRemove(fileId, removeRedactionRequest); + } + Long commentId = commentService.addCommentAndGetId(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), @@ -240,6 +249,24 @@ public class ManualRedactionService { } + private void insertLocalRemove(String fileId, RemoveRedactionRequest removeRedactionRequest) { + + removeRedactionPersistenceService.insert(fileId, + RemoveRedactionRequest.builder() + .annotationId(removeRedactionRequest.getAnnotationId()) + .value(removeRedactionRequest.getValue()) + .dictionaryEntryType(removeRedactionRequest.getDictionaryEntryType()) + .user(removeRedactionRequest.getUser()) + .dossierId(removeRedactionRequest.getDossierId()) + .dossierTemplateId(removeRedactionRequest.getDossierTemplateId()) + .typeToRemove(removeRedactionRequest.getTypeToRemove()) + .removeFromDictionary(false) + .removeFromAllDossiers(false) + .page(removeRedactionRequest.getPage()) + .build()); + } + + @Transactional public List addForceRedaction(String dossierId, String fileId, Set forceRedactionRequests) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentTest.java new file mode 100644 index 000000000..df533d391 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ComponentTest.java @@ -0,0 +1,57 @@ +package com.iqser.red.service.peristence.v1.server.integration.tests; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.peristence.v1.server.integration.client.ComponentClient; +import com.iqser.red.service.peristence.v1.server.integration.client.ComponentLogClient; +import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.peristence.v1.server.integration.utils.TokenService; + +import feign.FeignException; + +public class ComponentTest extends AbstractPersistenceServerServiceTest { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private DossierTesterAndProvider dossierTesterAndProvider; + + @Autowired + private FileTesterAndProvider fileTesterAndProvider; + + @Autowired + private ComponentClient componentClient; + + @Autowired + private ComponentLogClient componentLogClient; + + @Autowired + private DossierTemplateClient dossierTemplateClient; + + @Autowired + protected TokenService tokenService; + + + @Test + public void testGetComponentLogWithoutAppropriateRoles() { + + var dossier = dossierTesterAndProvider.provideTestDossier(); + var dossierTemplate = dossierTemplateClient.getDossierTemplate(dossier.getDossierTemplateId()); + var file = fileTesterAndProvider.testAndProvideFile(dossier, "filename"); + + Assertions.assertThrows(FeignException.NotFound.class, () -> componentClient.getComponents(dossierTemplate.getId(), dossier.getId(), file.getFileId(), true)); + + tokenService.setUser("manageradmin4@test.com", "secret"); + + Assertions.assertThrows(FeignException.Forbidden.class, () -> componentClient.getComponents(dossierTemplate.getId(), dossier.getId(), file.getFileId(), true)); + + } + +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 15d7a4948..34346604f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -6,6 +6,7 @@ import static com.iqser.red.service.peristence.v1.server.integration.utils.Mongo import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; @@ -330,6 +331,16 @@ public abstract class AbstractPersistenceServerServiceTest { .isActive(true) .roles(Set.of(getAllRoles())) .build()); + Set allRolesWithoutValid = Arrays.stream(getAllRoles()) + .collect(Collectors.toSet()); + allRolesWithoutValid.remove("RED_USER"); + allRolesWithoutValid.remove("RED_MANAGER"); + allUsers.add(com.iqser.red.service.persistence.management.v1.processor.service.users.model.User.builder() + .userId("manageradmin4@test.com") + .email("manageradmin4@test.com") + .isActive(true) + .roles(allRolesWithoutValid) + .build()); when(usersClient.getAllUsers(false)).thenReturn(allUsers); when(usersClient.getAllUsers(true)).thenReturn(allUsers); // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); @@ -618,8 +629,17 @@ public abstract class AbstractPersistenceServerServiceTest { @Bean public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) { - UserDetails user = User.withUsername("manageradmin1@test.com").password(passwordEncoder.encode("secret")).roles(getAllRoles()).authorities(getAllRoles()).build(); - return new InMemoryUserDetailsManager(user); + var allRoles = getAllRoles(); + UserDetails user = User.withUsername("manageradmin1@test.com").password(passwordEncoder.encode("secret")).roles(allRoles).authorities(getAllRoles()).build(); + var allRolesWithoutRedUserOrRedManager = Arrays.stream(allRoles) + .filter(s -> !(s.equalsIgnoreCase(ApplicationRoles.RED_USER_ROLE) || s.equalsIgnoreCase(ApplicationRoles.RED_MANAGER_ROLE))) + .collect(Collectors.toList()); + UserDetails userWithoutRedUserOrRedManager = User.withUsername("manageradmin4@test.com") + .password(passwordEncoder.encode("secret")) + .roles(allRolesWithoutRedUserOrRedManager.toArray(new String[0])) + .authorities(getAllRoles()) + .build(); + return new InMemoryUserDetailsManager(user, userWithoutRedUserOrRedManager); }