diff --git a/src/main/java/org/gridsuite/explore/server/controller/ExploreController.java b/src/main/java/org/gridsuite/explore/server/controller/ExploreController.java index 3c4d47e6..73ff1df9 100644 --- a/src/main/java/org/gridsuite/explore/server/controller/ExploreController.java +++ b/src/main/java/org/gridsuite/explore/server/controller/ExploreController.java @@ -653,17 +653,17 @@ public ResponseEntity searchElements( .body(directoryService.searchElements(userInput, directoryUuid, userId)); } - @GetMapping(value = "/explore/elements/{elementUuid}") - @Operation(summary = "Check if user has a given right on a directory, or a single element by checking its parent") + @GetMapping(value = "/explore/elements/accessible", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Filter the given elements to the ones the user has the given permission on, " + + "a directory being checked on itself and any other element on its parent directory") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The user has the right on the element"), - @ApiResponse(responseCode = "204", description = "The user has not the right on the element"), + @ApiResponse(responseCode = "200", description = "The uuids of the given elements the user has that permission on"), }) - public ResponseEntity hasRight(@PathVariable("elementUuid") UUID elementUuid, - @RequestParam(name = "permission") PermissionType permission, - @RequestHeader(QUERY_PARAM_USER_ID) String userId) { - directoryService.checkPermission(List.of(elementUuid), null, userId, permission); - return ResponseEntity.ok().build(); + public ResponseEntity> getAccessibleElements(@RequestParam("ids") List elementUuids, + @RequestParam(name = "accessType") PermissionType permissionType, + @RequestHeader(QUERY_PARAM_USER_ID) String userId) { + return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON) + .body(directoryService.getAccessibleElements(elementUuids, userId, permissionType)); } @GetMapping(value = "/explore/elements/{elementUuid}/referencing-element-infos", produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/src/main/java/org/gridsuite/explore/server/services/DirectoryService.java b/src/main/java/org/gridsuite/explore/server/services/DirectoryService.java index a436a2a9..1819ec89 100644 --- a/src/main/java/org/gridsuite/explore/server/services/DirectoryService.java +++ b/src/main/java/org/gridsuite/explore/server/services/DirectoryService.java @@ -468,6 +468,26 @@ public void checkPermission(List elementUuids, UUID targetDirectoryUuid, S restTemplate.exchange(directoryServerBaseUri + path, HttpMethod.GET, new HttpEntity<>(headers), Void.class); } + /** Tells which of the given elements the user may access. */ + public List getAccessibleElements(List elementUuids, String userId, PermissionType permissionType) { + String ids = elementUuids.stream().map(UUID::toString).collect(Collectors.joining(",")); + HttpHeaders headers = new HttpHeaders(); + headers.add(HEADER_USER_ID, userId); + + String path = UriComponentsBuilder.fromPath(ELEMENTS_SERVER_ROOT_PATH + "/accessible") + .queryParam(PARAM_ACCESS_TYPE, permissionType) + .queryParam(PARAM_IDS, ids) + .buildAndExpand() + .toUriString(); + + List accessibleUuids = restTemplate + .exchange(directoryServerBaseUri + path, HttpMethod.GET, new HttpEntity<>(headers), + new ParameterizedTypeReference>() { + }) + .getBody(); + return Objects.requireNonNullElse(accessibleUuids, Collections.emptyList()); + } + public List getDirectoryPermissions(UUID directoryUuid, String userId) { String path = UriComponentsBuilder .fromPath(DIRECTORIES_SERVER_DIRECTORIES_ROOT_PATH + "/{directoryUuid}/permissions") diff --git a/src/test/java/org/gridsuite/explore/server/ExploreTest.java b/src/test/java/org/gridsuite/explore/server/ExploreTest.java index 7c1c9abe..b1534973 100644 --- a/src/test/java/org/gridsuite/explore/server/ExploreTest.java +++ b/src/test/java/org/gridsuite/explore/server/ExploreTest.java @@ -467,14 +467,6 @@ public MockResponse dispatch(RecordedRequest request) { return new MockResponse(409); } else if (path.matches("/v1/elements/authorized\\?forDeletion=true&ids=.*") || path.matches("/v1/elements\\?forUpdate=true&ids=.*")) { return new MockResponse(200); - } else if (path.matches("/v1/elements/authorized\\?accessType=READ&ids=" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "&targetDirectoryUuid&recursiveCheck=.*")) { - return new MockResponse(200); - } else if (path.matches("/v1/elements/authorized\\?accessType=READ&ids=" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "&targetDirectoryUuid&recursiveCheck=.*")) { - return new MockResponse(403); - } else if (path.matches("/v1/elements/authorized\\?accessType=WRITE&ids=" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "&targetDirectoryUuid&recursiveCheck=.*")) { - return new MockResponse(200); - } else if (path.matches("/v1/elements/authorized\\?accessType=WRITE&ids=" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "&targetDirectoryUuid&recursiveCheck=.*")) { - return new MockResponse(403); } else if (path.matches("/v1/elements/authorized\\?accessType=.*&ids=.*&targetDirectoryUuid.*&recursiveCheck=.*")) { return new MockResponse(200); } @@ -1440,38 +1432,39 @@ void testSearchElement(final MockWebServer server) throws Exception { } @Test - void testHasRights(final MockWebServer server) throws Exception { - // test read access allowed - mockMvc.perform(head("/v1/explore/elements/" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "?permission=READ") - .header("userId", NOT_ADMIN_USER) - ).andExpect(status().isOk()); - - var requests = TestUtils.getRequestsWithBodyDone(1, server); - assertTrue(requests.stream().anyMatch(r -> r.getPath().contains("v1/elements/authorized?accessType=READ&ids=" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "&targetDirectoryUuid"))); - - // test read access forbidden - mockMvc.perform(head("/v1/explore/elements/" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "?permission=READ") - .header("userId", NOT_ADMIN_USER) - ).andExpect(status().isForbidden()); - - requests = TestUtils.getRequestsWithBodyDone(1, server); - assertTrue(requests.stream().anyMatch(r -> r.getPath().contains("v1/elements/authorized?accessType=READ&ids=" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "&targetDirectoryUuid"))); - - // test write access forbidden - mockMvc.perform(head("/v1/explore/elements/" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "?permission=WRITE") - .header("userId", NOT_ADMIN_USER) - ).andExpect(status().isForbidden()); + @UsesWireMock + void testGetAccessibleElements() throws Exception { + wireMockServer.stubFor(WireMock.get(WireMock.urlPathEqualTo("/v1/elements/accessible")) + .withQueryParam("accessType", WireMock.equalTo("WRITE")) + .withQueryParam("ids", WireMock.equalTo(TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "," + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN)) + .willReturn(WireMock.ok() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(mapper.writeValueAsString(List.of(TEST_ACCESS_DIRECTORY_UUID_ALLOWED))))); + wireMockServer.stubFor(WireMock.get(WireMock.urlPathEqualTo("/v1/elements/accessible")) + .withQueryParam("accessType", WireMock.equalTo("READ")) + .withQueryParam("ids", WireMock.equalTo(TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN.toString())) + .willReturn(WireMock.ok() + .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .withBody(mapper.writeValueAsString(List.of())))); - requests = TestUtils.getRequestsWithBodyDone(1, server); - assertTrue(requests.stream().anyMatch(r -> r.getPath().contains("v1/elements/authorized?accessType=WRITE&ids=" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "&targetDirectoryUuid"))); + // only the allowed one comes back + MvcResult result = mockMvc.perform(get("/v1/explore/elements/accessible" + + "?ids=" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "," + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + + "&accessType=WRITE") + .header("userId", NOT_ADMIN_USER) + ).andExpect(status().isOk()) + .andReturn(); + assertEquals("[\"" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "\"]", result.getResponse().getContentAsString()); - // test write access allowed (admin) - mockMvc.perform(get("/v1/explore/elements/" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "?permission=WRITE") - .header("userId", USER1) - ).andExpect(status().isOk()); + // a forbidden element alone answers an empty list + result = mockMvc.perform(get("/v1/explore/elements/accessible" + + "?ids=" + TEST_ACCESS_DIRECTORY_UUID_FORBIDDEN + "&accessType=READ") + .header("userId", NOT_ADMIN_USER) + ).andExpect(status().isOk()) + .andReturn(); + assertEquals("[]", result.getResponse().getContentAsString()); - requests = TestUtils.getRequestsWithBodyDone(1, server); - assertTrue(requests.stream().anyMatch(r -> r.getPath().contains("v1/elements/authorized?accessType=WRITE&ids=" + TEST_ACCESS_DIRECTORY_UUID_ALLOWED + "&targetDirectoryUuid"))); + wireMockServer.verify(2, WireMock.getRequestedFor(WireMock.urlPathEqualTo("/v1/elements/accessible"))); } @Test