From 1275e85803902b27c184e69f1bb7fdecae2356a7 Mon Sep 17 00:00:00 2001 From: muilpp Date: Fri, 10 Nov 2023 22:50:09 +0100 Subject: [PATCH] fix: Skip validations if user is superuser [TECH-1589][2.38] --- .../TrackedEntityInstanceServiceTest.java | 62 +++++++++++++++++++ .../security/EnrollmentSecurityTest.java | 22 ++++++- .../mapper/EnrollmentCriteriaMapper.java | 9 +++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/trackedentity/TrackedEntityInstanceServiceTest.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/trackedentity/TrackedEntityInstanceServiceTest.java index ab0d7d5775bf..55c232fbb6f1 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/trackedentity/TrackedEntityInstanceServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/trackedentity/TrackedEntityInstanceServiceTest.java @@ -27,8 +27,12 @@ */ package org.hisp.dhis.trackedentity; +import static org.hisp.dhis.common.AccessLevel.CLOSED; +import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; import static org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams.OrderColumn.ENROLLED_AT; +import static org.hisp.dhis.utils.Assertions.assertContains; import static org.hisp.dhis.utils.Assertions.assertIsEmpty; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -43,6 +47,7 @@ import java.util.stream.Collectors; import org.hisp.dhis.IntegrationTestBase; import org.hisp.dhis.common.Grid; +import org.hisp.dhis.common.IllegalQueryException; import org.hisp.dhis.common.QueryFilter; import org.hisp.dhis.common.QueryItem; import org.hisp.dhis.common.QueryOperator; @@ -57,6 +62,7 @@ import org.hisp.dhis.program.ProgramStageInstance; import org.hisp.dhis.program.ProgramStageInstanceService; import org.hisp.dhis.program.ProgramStageService; +import org.hisp.dhis.program.ProgramType; import org.hisp.dhis.security.acl.AccessStringHelper; import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue; import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValueService; @@ -124,6 +130,10 @@ class TrackedEntityInstanceServiceTest extends IntegrationTestBase { private static final String ATTRIBUTE_VALUE = "Value"; + private User userWithSearchInAllAuthority; + + private Program disabledAccessProgram; + @Override public boolean emptyDatabaseAfterTest() { return true; @@ -173,7 +183,18 @@ public void setUpTest() { attributeService.addTrackedEntityAttribute(attrE); attributeService.addTrackedEntityAttribute(filtF); attributeService.addTrackedEntityAttribute(filtG); + + disabledAccessProgram = createProgram('C', new HashSet<>(), null); + disabledAccessProgram.setProgramType(ProgramType.WITH_REGISTRATION); + disabledAccessProgram.setAccessLevel(CLOSED); + disabledAccessProgram.getSharing().setPublicAccess(AccessStringHelper.disableDataSharing(null)); + programService.addProgram(disabledAccessProgram); + super.userService = this.userService; + + userWithSearchInAllAuthority = + createUser("userSearchInAll", "F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS"); + User user = createUser("testUser"); user.setTeiSearchOrganisationUnits(Sets.newHashSet(organisationUnit)); CurrentUserService currentUserService = new MockCurrentUserService(user); @@ -917,6 +938,47 @@ void shouldReturnEmptyIfTEWasUpdatedBeforePassedDateAndTime() { assertIsEmpty(trackedEntities); } + @Test + void shouldFailWhenModeAllUserCanSearchEverywhereButNotSuperuserAndNoAccessToProgram() { + injectSecurityContext(userWithSearchInAllAuthority); + + TrackedEntityInstanceQueryParams params = new TrackedEntityInstanceQueryParams(); + params.setOrganisationUnitMode(ALL); + params.setProgram(disabledAccessProgram); + params.setUser(userWithSearchInAllAuthority); + + IllegalQueryException ex = + assertThrows( + IllegalQueryException.class, + () -> entityInstanceService.getTrackedEntityInstanceIds(params, false, false)); + + assertContains( + String.format( + "Current user is not authorized to read data from selected program: %s", + disabledAccessProgram.getUid()), + ex.getMessage()); + } + + @Test + void shouldReturnAllEntitiesWhenSuperuserAndModeAll() { + injectSecurityContext(createAndInjectAdminUser(ALL.name())); + addEntityInstances(); + + TrackedEntityInstanceQueryParams params = new TrackedEntityInstanceQueryParams(); + params.setOrganisationUnitMode(ALL); + params.setOrganisationUnits(Set.of(organisationUnit)); + + List trackedEntities = + entityInstanceService.getTrackedEntityInstanceIds(params, true, true); + + assertEquals(4, trackedEntities.size()); + assertAll( + () -> trackedEntities.contains(entityInstanceA1.getId()), + () -> trackedEntities.contains(entityInstanceB1.getId()), + () -> trackedEntities.contains(entityInstanceC1.getId()), + () -> trackedEntities.contains(entityInstanceD1.getId())); + } + private void initializeEntityInstance(TrackedEntityInstance entityInstance) { entityInstance.setTrackedEntityType(trackedEntityType); entityInstanceService.addTrackedEntityInstance(entityInstance); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/events/security/EnrollmentSecurityTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/events/security/EnrollmentSecurityTest.java index ee1216aea31a..e56016add482 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/events/security/EnrollmentSecurityTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/events/security/EnrollmentSecurityTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.dxf2.events.security; +import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -103,6 +104,8 @@ class EnrollmentSecurityTest extends TransactionalIntegrationTest { private ProgramStage programStageB; + private User admin; + @Override public boolean emptyDatabaseAfterTest() { return true; @@ -111,7 +114,7 @@ public boolean emptyDatabaseAfterTest() { @Override protected void setUpTest() { userService = _userService; - User admin = createAndInjectAdminUser(); + admin = createAndInjectAdminUser(); organisationUnitA = createOrganisationUnit('A'); organisationUnitB = createOrganisationUnit('B'); manager.save(organisationUnitA); @@ -435,6 +438,23 @@ void testAddEnrollmentWithOrgUnitIdSchemeToOrgUnitWithoutProgramAccess() { assertEquals(ImportStatus.SUCCESS, importSummary.getStatus()); } + @Test + void shouldReturnAllEnrollmentsWhenOrgUnitModeAllAndUserAuthorized() { + ImportSummary importSummary = + enrollmentService.addEnrollment( + createEnrollment(programA.getUid(), maleA.getUid()), + ImportOptions.getDefaultImportOptions()); + assertEquals(ImportStatus.SUCCESS, importSummary.getStatus()); + + injectSecurityContext(admin); + ProgramInstanceQueryParams params = new ProgramInstanceQueryParams(); + params.setOrganisationUnitMode(ALL); + params.setUser(admin); + + Enrollments enrollments = enrollmentService.getEnrollments(params); + assertNotNull(enrollments); + } + private Enrollment createEnrollment(String program, String person) { Enrollment enrollment = new Enrollment(); enrollment.setEnrollment(CodeGenerator.generateUid()); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/mapper/EnrollmentCriteriaMapper.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/mapper/EnrollmentCriteriaMapper.java index 85827a46a2ed..96b36924f1e6 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/mapper/EnrollmentCriteriaMapper.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/mapper/EnrollmentCriteriaMapper.java @@ -28,6 +28,7 @@ package org.hisp.dhis.webapi.controller.event.mapper; import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull; +import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; import static org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper.toOrderParams; import java.util.Date; @@ -45,6 +46,7 @@ import org.hisp.dhis.program.ProgramInstanceQueryParams; import org.hisp.dhis.program.ProgramService; import org.hisp.dhis.program.ProgramStatus; +import org.hisp.dhis.security.Authorities; import org.hisp.dhis.trackedentity.TrackedEntityInstance; import org.hisp.dhis.trackedentity.TrackedEntityInstanceService; import org.hisp.dhis.trackedentity.TrackedEntityType; @@ -144,6 +146,13 @@ public ProgramInstanceQueryParams getFromUrl( throw new IllegalQueryException("Program does not exist: " + program); } + if (params.isOrganisationUnitMode(ALL) + && !currentUserService.currentUserIsAuthorized( + Authorities.F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS.name())) { + throw new IllegalQueryException( + "Current user is not authorized to query across all organisation units"); + } + TrackedEntityType te = trackedEntityType != null ? trackedEntityTypeService.getTrackedEntityType(trackedEntityType)