Skip to content

Commit a9c6fd2

Browse files
committed
feat: Back office user role and auth
1 parent d4a75f3 commit a9c6fd2

File tree

8 files changed

+73
-10
lines changed

8 files changed

+73
-10
lines changed

src/main/java/fr/insee/genesis/configuration/auth/security/ApplicationRole.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public enum ApplicationRole {
66
USER_PLATINE,
77
COLLECT_PLATFORM,
88
SCHEDULER,
9-
READER
9+
READER,
10+
USER_BACK_OFFICE
1011
}
1112

src/main/java/fr/insee/genesis/configuration/auth/security/RoleConfiguration.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public class RoleConfiguration {
3131
@Value("#{'${app.role.collect-platform.claims}'.split(',')}")
3232
private List<String> collectPlatformClaims;
3333

34+
@Value("#{'${app.role.user-back-office.claims}'.split(',')}")
35+
private List<String> userBackOfficeClaims;
36+
3437
@Value("#{'${app.role.scheduler.claims}'.split(',')}")
3538
private List<String> schedulerClaims;
3639

@@ -50,10 +53,12 @@ static RoleHierarchy roleHierarchy() {
5053
return RoleHierarchyImpl.withDefaultRolePrefix()
5154
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_KRAFTWERK.toString())
5255
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_PLATINE.toString())
56+
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.USER_BACK_OFFICE.toString())
5357
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.COLLECT_PLATFORM.toString())
5458
.role(ApplicationRole.ADMIN.toString()).implies(ApplicationRole.SCHEDULER.toString())
5559
.role(ApplicationRole.USER_KRAFTWERK.toString()).implies(ApplicationRole.READER.toString())
5660
.role(ApplicationRole.USER_PLATINE.toString()).implies(ApplicationRole.READER.toString())
61+
.role(ApplicationRole.USER_BACK_OFFICE.toString()).implies(ApplicationRole.READER.toString())
5762
.build();
5863
}
5964

@@ -85,6 +90,11 @@ public void initialization() {
8590
.computeIfAbsent(claim, k -> new ArrayList<>())
8691
.add(String.valueOf(ApplicationRole.USER_PLATINE)));
8792

93+
// Ajout des claims pour le rôle USER_BACK_OFFICE
94+
userBackOfficeClaims.forEach(claim -> rolesByClaim
95+
.computeIfAbsent(claim, k -> new ArrayList<>())
96+
.add(String.valueOf(ApplicationRole.USER_BACK_OFFICE)));
97+
8898
// Add claims for the COLLECT_PLATFORM role
8999
collectPlatformClaims.forEach(claim -> rolesByClaim
90100
.computeIfAbsent(claim, k -> new ArrayList<>())
@@ -102,5 +112,4 @@ public void initialization() {
102112

103113
log.info("Roles configuration : {}", rolesByClaim);
104114
}
105-
106115
}

src/main/java/fr/insee/genesis/controller/rest/DataProcessingContextController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class DataProcessingContextController {
4646

4747
@Operation(summary = "Create or update a data processing context")
4848
@PutMapping(path = "/review")
49-
@PreAuthorize("hasRole('ADMIN')")
49+
@PreAuthorize("hasRole('USER_BACK_OFFICE')")
5050
public ResponseEntity<Object> saveContext(
5151
@Parameter(description = "Identifier of the partition", required = true) @RequestParam("partitionId") String partitionId,
5252
@Parameter(description = "Allow reviewing") @RequestParam(value = "withReview", defaultValue = "false") Boolean withReview

src/main/java/fr/insee/genesis/controller/rest/LunaticModelController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public LunaticModelController(LunaticModelApiPort lunaticModelApiPort) {
3131

3232
@Operation(summary = "Save lunatic json data from one interrogation in Genesis Database")
3333
@PutMapping(path = "/save")
34-
@PreAuthorize("hasRole('ADMIN')")
34+
@PreAuthorize("hasRole('USER_BACK_OFFICE')")
3535
public ResponseEntity<String> saveRawResponsesFromJsonBody(
3636
@RequestParam("questionnaireId") String questionnaireId,
3737
@RequestBody Map<String, Object> dataJson

src/main/java/fr/insee/genesis/controller/rest/responses/EditedResponseController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public ResponseEntity<Object> getEditedResponses(
5050

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

7878
@Operation(summary = "Add edited external json file")
7979
@PostMapping(path = "/external/json")
80-
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER')")
80+
@PreAuthorize("hasAnyRole('USER_PLATINE','SCHEDULER','USER_BACK_OFFICE')")
8181
public ResponseEntity<Object> readEditedExternalJson(
8282
@RequestParam("questionnaireId") String questionnaireId,
8383
@RequestParam("mode") Mode mode,

src/main/resources/application-test-cucumber.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ fr.insee.genesis.sourcefolder.specifications = /data/genesis
55
app.role.admin.claims=administrateur_traiter
66
app.role.user-kraftwerk.claims=utilisateur_Kraftwerk
77
app.role.user-platine.claims=utilisateur_Platine
8+
app.role.user-back-office.claims=utilisateur_Back_Office
89
app.role.reader.claims=lecteur_traiter
910
app.role.collect-platform.claims=protools
1011
app.role.scheduler.claims=scheduler_traiter

src/main/resources/application-test.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ fr.insee.genesis.sourcefolder.specifications = /data/genesis
55
app.role.admin.claims=administrateur_traiter
66
app.role.user-kraftwerk.claims=utilisateur_Kraftwerk
77
app.role.user-platine.claims=utilisateur_Platine
8+
app.role.user-back-office.claims=utilisateur_Back_Office
89
app.role.reader.claims=lecteur_traiter
910
app.role.collect-platform.claims=protools
1011
app.role.scheduler.claims=scheduler_traiter

src/test/java/fr/insee/genesis/controller/rest/ControllerAccessTest.java

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
3434

3535
import java.util.Date;
36+
import java.util.HashMap;
3637
import java.util.List;
3738
import java.util.Map;
3839
import java.util.stream.Stream;
@@ -43,6 +44,7 @@
4344
import static org.mockito.Mockito.when;
4445
import static org.springframework.http.HttpMethod.GET;
4546
import static org.springframework.http.HttpMethod.POST;
47+
import static org.springframework.http.HttpMethod.PUT;
4648
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
4749
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
4850
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -58,6 +60,7 @@ class ControllerAccessTest {
5860
// Constants for user roles
5961
private static final String USER_KRAFTWERK = "USER_KRAFTWERK";
6062
private static final String USER_PLATINE = "USER_PLATINE";
63+
private static final String USER_BACK_OFFICE = "USER_BACK_OFFICE";
6164
private static final String ADMIN = "ADMIN";
6265
private static final String READER = "READER";
6366
// JWT claim properties loaded from application properties
@@ -115,9 +118,18 @@ private static Stream<Arguments> endpointsReader() {
115118
private static Stream<Arguments> responseEndpoint() {
116119
return Stream.of(
117120
Arguments.of(GET,"/response/lunatic-json/get/unprocessed"),
118-
Arguments.of(GET,"/response//lunatic-json/get/by-interrogation-mode-and-campaign"),
119-
Arguments.of(POST,"/response//lunatic-json/process"),
120-
Arguments.of(GET,"/response//lunatic-json/campaignId=TOTO")
121+
Arguments.of(GET,"/response/lunatic-json/get/by-interrogation-mode-and-campaign"),
122+
Arguments.of(POST,"/response/lunatic-json/process"),
123+
Arguments.of(GET,"/response/lunatic-json/campaignId=TOTO")
124+
);
125+
}
126+
127+
private static Stream<Arguments> backOfficeEndpointProd() {
128+
return Stream.of(
129+
Arguments.of(PUT,"/lunatic-model/save?questionnaireId=TEST", new HashMap<>()),
130+
Arguments.of(POST,"/edited/previous/json?questionnaireId=TEST&mode=WEB&jsonFileName=truc.json"),
131+
Arguments.of(POST,"/edited/external/json?questionnaireId=TEST&mode=WEB&jsonFileName=truc.json"),
132+
Arguments.of(PUT,"/context/review?partitionId=TEST")
121133
);
122134
}
123135

@@ -160,6 +172,45 @@ void platine_users_should_access_reader_allowed_services(String endpointURI) thr
160172
.andExpect(status().is(oneOf(200, 404)));
161173
}
162174

175+
/**
176+
* Tests that users with the "USER_BACK_OFFICE" role can access read-only endpoints.
177+
*/
178+
@ParameterizedTest
179+
@MethodSource("backOfficeEndpointProd")
180+
@DisplayName("Back office users should access prod services")
181+
void back_office_users_should_access_prod_services(HttpMethod method, String endpointURI) throws Exception {
182+
Jwt jwt = generateJwt(List.of("utilisateur_Back_Office"), USER_BACK_OFFICE);
183+
when(jwtDecoder.decode(anyString())).thenReturn(jwt);
184+
MockHttpServletRequestBuilder requestBuilder;
185+
if (method == HttpMethod.GET) {
186+
requestBuilder = get(endpointURI);
187+
} else if (method == HttpMethod.POST) {
188+
requestBuilder = post(endpointURI);
189+
} else if (method == PUT) {
190+
requestBuilder = put(endpointURI);
191+
} else if (method == HttpMethod.DELETE) {
192+
requestBuilder = delete(endpointURI);
193+
} else {
194+
throw new IllegalArgumentException("Unsupported HTTP method: " + method);
195+
}
196+
197+
mockMvc.perform(requestBuilder.header("Authorization", "bearer token_blabla"))
198+
.andExpect(status().is(oneOf(200, 400, 404)));
199+
}
200+
201+
/**
202+
* Tests that users with the "USER_BACK_OFFICE" role can access read-only endpoints.
203+
*/
204+
@ParameterizedTest
205+
@MethodSource("endpointsReader")
206+
@DisplayName("Back office users should access reader-allowed services")
207+
void back_office_users_should_access_reader_allowed_services(String endpointURI) throws Exception {
208+
Jwt jwt = generateJwt(List.of("utilisateur_Back_Office"), USER_BACK_OFFICE);
209+
when(jwtDecoder.decode(anyString())).thenReturn(jwt);
210+
mockMvc.perform(get(endpointURI).header("Authorization", "bearer token_blabla"))
211+
.andExpect(status().is(oneOf(200, 404)));
212+
}
213+
163214
/**
164215
* Tests that users with the "READER" role can access read-only endpoints.
165216
*/
@@ -226,7 +277,7 @@ void reader_should_not_access_response_services(HttpMethod method,String endpoin
226277
requestBuilder = get(endpointURI);
227278
} else if (method == HttpMethod.POST) {
228279
requestBuilder = post(endpointURI);
229-
} else if (method == HttpMethod.PUT) {
280+
} else if (method == PUT) {
230281
requestBuilder = put(endpointURI);
231282
} else if (method == HttpMethod.DELETE) {
232283
requestBuilder = delete(endpointURI);

0 commit comments

Comments
 (0)