Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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 @@ -236,6 +236,17 @@ public ResponseEntity<Void> areElementsAccessible(@RequestParam("ids") List<UUID
return ResponseEntity.ok().build();
}

@GetMapping(value = "/elements/permission", produces = MediaType.APPLICATION_JSON_VALUE)
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
@Operation(summary = "Get, among the given elements, the ones the user can access with the given permission")
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "The uuids of the accessible elements"),
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
})
public ResponseEntity<List<UUID>> getAccessibleElements(@RequestParam("ids") List<UUID> elementUuids,
@RequestParam(value = "accessType") PermissionType permissionType,
@RequestHeader("userId") String userId) {
return ResponseEntity.ok().body(permissionService.filterAccessibleElements(userId, elementUuids, permissionType));
}

@GetMapping(value = "/directories/{directoryUuid}/permissions", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Get permissions for the directory")
@ApiResponses(value = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.gridsuite.directory.server.repository.PermissionRepository;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static org.gridsuite.directory.server.DirectoryService.DIRECTORY;
import static org.gridsuite.directory.server.dto.PermissionType.MANAGE;
Expand Down Expand Up @@ -70,6 +71,29 @@ public void checkDirectoriesPermission(String userId, List<UUID> elementUuids, U
}
}

/**
* Tells which of the given elements the user may access.
*
* @param userId User ID checking permissions for
* @param elementUuids List of element UUIDs to check permissions on
* @param permissionType Type of permission to check (READ, WRITE, MANAGE)
* @return the uuids of the accessible elements, in no particular order
*/
public List<UUID> filterAccessibleElements(String userId, List<UUID> elementUuids, PermissionType permissionType) {
boolean isExploreAdmin = roleService.isUserExploreAdmin();
//Resolved once for the whole batch: hasElementPermission would otherwise query user-admin-server for
//every single element.
List<UUID> userGroupIds = isExploreAdmin ? List.of() : getUserGroupIds(userId);
return directoryElementRepository.findAllByIdIn(elementUuids).stream()
//If it's a directory we check its own permission else we check the permission on its parent directory
.filter(element -> isExploreAdmin || hasElementPermission(userId,
element.getType().equals(DIRECTORY) ? element.getId() : element.getParentId(),
permissionType,
() -> userGroupIds))
.map(DirectoryElementEntity::getId)
.toList();
}

public boolean hasReadPermissions(String userId, List<UUID> elementUuids) {
return roleService.isUserExploreAdmin() || directoryElementRepository.findAllByIdIn(elementUuids).stream().allMatch(element ->
//If it's a directory we check its own write permission else we check the permission on the element parent directory
Expand Down Expand Up @@ -204,6 +228,10 @@ private boolean checkPermission(String userId, List<UUID> elementUuids, Permissi
}

private boolean hasElementPermission(String userId, UUID uuid, PermissionType permissionType) {
return hasElementPermission(userId, uuid, permissionType, () -> getUserGroupIds(userId));
}

private boolean hasElementPermission(String userId, UUID uuid, PermissionType permissionType, Supplier<List<UUID>> userGroupIds) {
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
//Check global permission first
boolean globalPermission = checkPermission(permissionRepository.findById(new PermissionId(uuid, ALL_USERS, "")), permissionType);
if (globalPermission) {
Expand All @@ -217,14 +245,17 @@ private boolean hasElementPermission(String userId, UUID uuid, PermissionType pe
}

//Finally check group permission
return userAdminService.getUserGroups(userId)
return userGroupIds.get()
Comment thread
ghazwarhili marked this conversation as resolved.
Outdated
.stream()
.map(UserGroupDTO::id)
.anyMatch(groupId ->
checkPermission(permissionRepository.findById(new PermissionId(uuid, "", groupId.toString())), permissionType)
);
}

private List<UUID> getUserGroupIds(String userId) {
return userAdminService.getUserGroups(userId).stream().map(UserGroupDTO::id).toList();
}

private boolean checkPermission(Optional<PermissionEntity> permissionEntity, PermissionType permissionType) {
return permissionEntity
.map(p -> switch (permissionType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.gridsuite.directory.server.DirectoryService.DIRECTORY;
import static org.gridsuite.directory.server.dto.PermissionType.READ;
import static org.gridsuite.directory.server.dto.PermissionType.WRITE;
Expand Down Expand Up @@ -504,6 +505,56 @@ private void grantGroupPermission(UUID directoryUuid, UUID groupId, PermissionTy
permissionRepository.save(permission);
}

@Test
void testFilterAccessibleElements() throws Exception {
UUID openDir = insertRootDirectory(ADMIN_USER, "openDir");
UUID restrictedDir = insertRootDirectory(ADMIN_USER, "restrictedDir");

UUID openElement = insertSubElement(openDir, toElementAttributes(null, "openElement", TYPE_01, ADMIN_USER));
UUID restrictedElement = insertSubElement(restrictedDir, toElementAttributes(null, "restrictedElement", TYPE_01, ADMIN_USER));
UUID unknownElement = UUID.randomUUID();

// Only GROUP_TWO may write into restrictedDir, while USER_ONE belongs to GROUP_ONE
updateDirectoryPermissions(ADMIN_USER, restrictedDir, List.of(
new PermissionDTO(true, List.of(), READ),
new PermissionDTO(false, List.of(GROUP_TWO_ID), WRITE)
)).andExpect(status().isOk());

// USER_ONE can't write in restrictedDir
assertThat(getAccessibleElements(USER_ONE, List.of(openElement, restrictedElement), WRITE))
.containsExactlyInAnyOrder(openElement);

// USER_TWO belongs to GROUP_TWO, so it may write into both
assertThat(getAccessibleElements(USER_TWO, List.of(openElement, restrictedElement), WRITE))
.containsExactlyInAnyOrder(openElement, restrictedElement);

// READ is left open to everyone on both directories
assertThat(getAccessibleElements(USER_ONE, List.of(openElement, restrictedElement), READ))
.containsExactlyInAnyOrder(openElement, restrictedElement);

// An unknown element is never accessible, not even to an explore admin
assertThat(getAccessibleElements(USER_ONE, List.of(unknownElement), WRITE)).isEmpty();
assertThat(getAccessibleElements(ADMIN_USER, List.of(openElement, restrictedElement, unknownElement), WRITE))
.containsExactlyInAnyOrder(openElement, restrictedElement);
}

/**
* Helper method asking which of the given elements the user may access
*/
private List<UUID> getAccessibleElements(String userId, List<UUID> elementUuids, PermissionType permissionType) throws Exception {
String ids = elementUuids.stream().map(UUID::toString).collect(Collectors.joining(","));

MvcResult result = mockMvc.perform(get("/v1/elements/permission")
.param("ids", ids)
.param("accessType", permissionType.name())
.header(USER_ID_HEADER, userId)
.header(USER_ROLES_HEADER, userId.equals(ADMIN_USER) ? ADMIN_ROLE : USER_ROLE))
.andExpect(status().isOk())
.andReturn();

return objectMapper.readValue(result.getResponse().getContentAsString(), new TypeReference<>() { });
}

@Test
void testRecursiveChecks() throws Exception {
// Setup test users and directories
Expand Down
Loading