Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public enum ApplicationRole {
COLLECT_PLATFORM,
SCHEDULER,
READER,
USER_BACK_OFFICE,
USER_BATCH_GENERIC
}

Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public class RoleConfiguration {
@Value("#{'${app.role.collect-platform.claims}'.split(',')}")
private List<String> collectPlatformClaims;

@Value("#{'${app.role.user-back-office.claims}'.split(',')}")
private List<String> userBackOfficeClaims;

@Value("#{'${app.role.scheduler.claims}'.split(',')}")
private List<String> schedulerClaims;

Expand All @@ -54,11 +57,13 @@ static RoleHierarchy roleHierarchy() {
return RoleHierarchyImpl.withDefaultRolePrefix()
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_KRAFTWERK.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_PLATINE.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_BACK_OFFICE.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.COLLECT_PLATFORM.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.SCHEDULER.toString())
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_BATCH_GENERIC.toString())
.role(ApplicationRole.USER_KRAFTWERK.toString()).implies(ApplicationRole.READER.toString())
.role(ApplicationRole.USER_PLATINE.toString()).implies(ApplicationRole.READER.toString())
.role(ApplicationRole.USER_BACK_OFFICE.toString()).implies(ApplicationRole.READER.toString())
.build();
}

Expand Down Expand Up @@ -90,6 +95,11 @@ public void initialization() {
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.USER_PLATINE)));

// Ajout des claims pour le rôle USER_BACK_OFFICE
userBackOfficeClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
.add(String.valueOf(ApplicationRole.USER_BACK_OFFICE)));

// Add claims for the COLLECT_PLATFORM role
collectPlatformClaims.forEach(claim -> rolesByClaim
.computeIfAbsent(claim, k -> new ArrayList<>())
Expand All @@ -112,5 +122,4 @@ public void initialization() {

log.info("Roles configuration : {}", rolesByClaim);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class DataProcessingContextController {

@Operation(summary = "Create or update a data processing context")
@PutMapping(path = "/review")
@PreAuthorize("hasRole('ADMIN')")
@PreAuthorize("hasRole('USER_BACK_OFFICE')")
public ResponseEntity<Object> saveContext(
@Parameter(description = "Identifier of the partition", required = true) @RequestParam("partitionId") String partitionId,
@Parameter(description = "Allow reviewing") @RequestParam(value = "withReview", defaultValue = "false") Boolean withReview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public LunaticModelController(LunaticModelApiPort lunaticModelApiPort) {

@Operation(summary = "Save lunatic json data from one interrogation in Genesis Database")
@PutMapping(path = "/save")
@PreAuthorize("hasRole('ADMIN')")
@PreAuthorize("hasRole('USER_BACK_OFFICE')")
public ResponseEntity<String> saveRawResponsesFromJsonBody(
@RequestParam("questionnaireId") String questionnaireId,
@RequestBody Map<String, Object> dataJson
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public ResponseEntity<Object> getEditedResponses(

@Operation(summary = "Add edited previous json file")
@PostMapping(path = "previous/json")
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER')")
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER','USER_BACK_OFFICE')")
public ResponseEntity<Object> readEditedPreviousJson(
@RequestParam("questionnaireId") String questionnaireId,
@RequestParam("mode") Mode mode,
Expand All @@ -77,7 +77,7 @@ public ResponseEntity<Object> readEditedPreviousJson(

@Operation(summary = "Add edited external json file")
@PostMapping(path = "/external/json")
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER')")
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER','USER_BACK_OFFICE')")
public ResponseEntity<Object> readEditedExternalJson(
@RequestParam("questionnaireId") String questionnaireId,
@RequestParam("mode") Mode mode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import fr.insee.bpm.metadata.reader.lunatic.LunaticReader;
import fr.insee.genesis.Constants;
import fr.insee.genesis.controller.adapter.LunaticXmlAdapter;
import fr.insee.genesis.domain.model.surveyunit.InterrogationId;
import fr.insee.genesis.controller.dto.SurveyUnitDto;
import fr.insee.genesis.controller.dto.SurveyUnitInputDto;
import fr.insee.genesis.controller.dto.SurveyUnitQualityToolDto;
Expand All @@ -21,6 +20,7 @@
import fr.insee.genesis.controller.utils.ControllerUtils;
import fr.insee.genesis.controller.utils.DataTransformer;
import fr.insee.genesis.domain.model.context.DataProcessingContextModel;
import fr.insee.genesis.domain.model.surveyunit.InterrogationId;
import fr.insee.genesis.domain.model.surveyunit.Mode;
import fr.insee.genesis.domain.model.surveyunit.SurveyUnitModel;
import fr.insee.genesis.domain.model.surveyunit.VariableModel;
Expand Down Expand Up @@ -57,11 +57,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

@RequestMapping(path = "/responses" )
@Controller
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-test-cucumber.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fr.insee.genesis.sourcefolder.specifications = /data/genesis
app.role.admin.claims=administrateur_traiter
app.role.user-kraftwerk.claims=utilisateur_Kraftwerk
app.role.user-platine.claims=utilisateur_Platine
app.role.user-back-office.claims=utilisateur_Back_Office
app.role.reader.claims=lecteur_traiter
app.role.collect-platform.claims=protools
app.role.scheduler.claims=scheduler_traiter
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-test.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fr.insee.genesis.sourcefolder.specifications = /data/genesis
app.role.admin.claims=administrateur_traiter
app.role.user-kraftwerk.claims=utilisateur_Kraftwerk
app.role.user-platine.claims=utilisateur_Platine
app.role.user-back-office.claims=utilisateur_Back_Office
app.role.reader.claims=lecteur_traiter
app.role.collect-platform.claims=protools
app.role.scheduler.claims=scheduler_traiter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import fr.insee.genesis.infrastructure.repository.RundeckExecutionDBRepository;
import fr.insee.genesis.infrastructure.repository.SurveyUnitMongoDBRepository;
import fr.insee.genesis.infrastructure.repository.VariableTypeMongoDBRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
Expand All @@ -30,13 +32,15 @@
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

import java.util.HashMap;
import java.util.stream.Stream;

import static org.hamcrest.Matchers.oneOf;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
Expand All @@ -51,6 +55,12 @@
@EnableAutoConfiguration(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
class ControllerAccessTest {

// Constants for user roles
// JWT claim properties loaded from application properties
@Value("${fr.insee.genesis.security.token.oidc-claim-role}")
private String claimRoleDotRoles;
@Value("${fr.insee.genesis.security.token.oidc-claim-username}")
private String claimName;
@Autowired
private MockMvc mockMvc; // Simulates HTTP requests to the REST endpoints

Expand Down Expand Up @@ -108,6 +118,15 @@ private static Stream<Arguments> responseEndpoint() {
);
}

private static Stream<Arguments> backOfficeEndpointProd() {
return Stream.of(
Arguments.of(PUT,"/lunatic-model/save?questionnaireId=TEST", new HashMap<>()),
Arguments.of(POST,"/edited/previous/json?questionnaireId=TEST&mode=WEB&jsonFileName=truc.json"),
Arguments.of(POST,"/edited/external/json?questionnaireId=TEST&mode=WEB&jsonFileName=truc.json"),
Arguments.of(PUT,"/context/review?partitionId=TEST")
);
}

/**
* Tests that users with the "ADMIN" role can access read-only endpoints.
*/
Expand Down Expand Up @@ -150,6 +169,42 @@ void platine_users_should_access_reader_allowed_services(String endpointURI) thr
.andExpect(status().is(oneOf(200,404)));
}

/**
* Tests that users with the "USER_BACK_OFFICE" role can access read-only endpoints.
*/
@ParameterizedTest
@MethodSource("backOfficeEndpointProd")
@DisplayName("Back office users should access prod services")
void back_office_users_should_access_prod_services(HttpMethod method, String endpointURI) throws Exception {
switch (method.name()){
case "PUT" -> mockMvc.perform(
put(endpointURI).with(
jwt().authorities(new SimpleGrantedAuthority("ROLE_USER_BACK_OFFICE")))
)
.andExpect(status().is(oneOf(200,400,404)));
case "POST" -> mockMvc.perform(
post(endpointURI).with(
jwt().authorities(new SimpleGrantedAuthority("ROLE_USER_BACK_OFFICE")))
)
.andExpect(status().is(oneOf(200,400,404)));
default -> Assertions.fail("Method %s not supported".formatted(method.name()));
}
}

/**
* Tests that users with the "USER_BACK_OFFICE" role can access read-only endpoints.
*/
@ParameterizedTest
@MethodSource("endpointsReader")
@DisplayName("Back office users should access reader-allowed services")
void back_office_users_should_access_reader_allowed_services(String endpointURI) throws Exception {
mockMvc.perform(
get(endpointURI).with(
jwt().authorities(new SimpleGrantedAuthority("ROLE_USER_BACK_OFFICE")))
)
.andExpect(status().is(oneOf(200,400,404)));
}

/**
* Tests that users with the "READER" role can access read-only endpoints.
*/
Expand Down Expand Up @@ -269,6 +324,4 @@ void invalid_roles_should_access_schedules_services() throws Exception {
jwt().authorities(new SimpleGrantedAuthority("ROLE_invalid"))))
.andExpect(status().isForbidden());
}


}
Loading