Skip to content
Open
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 @@ -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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GetMapping(value = "/elements/accessible", produces = MediaType.APPLICATION_JSON_VALUE)

@Operation(summary = "Get, among the given elements, the ones the user can access with the given permission")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filter the given elements to the ones the user has the given permission on

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "The uuids of the accessible elements"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The uuids of the given elements the user has the permission on

})
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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userGroupIdsSupplier

//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()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userGroupIdsSupplier.get()

.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