package jnpf.dmsService;
|
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.permission.form.UserFolderPermissionTreeForm;
|
import jnpf.dmsEntity.permission.model.DmsSubjectSet;
|
import jnpf.dmsEntity.permission.model.DmsUserFolderPermissionTreeRow;
|
import jnpf.dmsEntity.permission.vo.DmsCursorPageVO;
|
import jnpf.dmsEntity.permission.vo.DmsUserFolderPermissionTreeNodeVO;
|
import jnpf.dmsMapper.DmsUserFolderPermissionTreeMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsPermission.DmsFileCenterCursorCodec;
|
import jnpf.dmsPermission.DmsPermissionError;
|
import jnpf.dmsPermission.DmsPermissionException;
|
import jnpf.dmsPermission.DmsPermissionGroupMembershipResolver;
|
import jnpf.dmsPermission.DmsPermissionProperties;
|
import jnpf.dmsPermission.DmsUserFolderPermissionPrincipal;
|
import jnpf.dmsPermission.DmsUserFolderPermissionTreeQuery;
|
import jnpf.dmsPermission.DmsUserSubjectBatchResolver;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.ArgumentCaptor;
|
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.UUID;
|
import java.util.stream.Collectors;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
|
class DmsUserFolderPermissionTreeServiceTest {
|
private final UUID parentId = UUID.fromString("018f0000-0000-7000-8000-000000000301");
|
private final UUID firstId = UUID.fromString("018f0000-0000-7000-8000-000000000302");
|
private final UUID secondId = UUID.fromString("018f0000-0000-7000-8000-000000000303");
|
private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class);
|
private final DmsPermissionProperties properties = properties();
|
private final DmsFileCenterCursorCodec cursorCodec = new DmsFileCenterCursorCodec(properties);
|
private final DmsUserSubjectBatchResolver subjectResolver = mock(DmsUserSubjectBatchResolver.class);
|
private final DmsPermissionGroupMembershipResolver groupResolver =
|
mock(DmsPermissionGroupMembershipResolver.class);
|
private final DmsUserFolderPermissionTreeMapper mapper = mock(DmsUserFolderPermissionTreeMapper.class);
|
private final DmsUserFolderPermissionTreeService service = new DmsUserFolderPermissionTreeService(
|
currentIdentity, properties, cursorCodec, subjectResolver, groupResolver, mapper);
|
private final UserInfo actor = new UserInfo();
|
|
@Test
|
void currentUserPrintScopeUsesAllPrincipalsWithoutAdministratorCheckOrTreePagination() {
|
DmsSubjectSet subject = subject("admin-1");
|
subject.getDirectOrgIds().add("org");
|
subject.getAncestorOrgIds().add("parent-org");
|
subject.getPositionIds().add("position");
|
subject.getRoleIds().add("role");
|
subject.getPermissionGroupIds().add("group");
|
when(subjectResolver.resolve("tenant-1", Collections.singletonList("admin-1")))
|
.thenReturn(Collections.singletonList(subject));
|
when(mapper.selectPrintFolders(any())).thenReturn(Arrays.asList(
|
row(firstId, "A", 1L, null, null, false), row(secondId, "B", 2L, null, null, false)));
|
assertEquals(Arrays.asList(firstId, secondId), service.currentUserPrintFolderIds());
|
verify(currentIdentity, never()).requirePermissionAdministrator();
|
verify(mapper, never()).selectTree(any());
|
verify(groupResolver).resolveAll(Collections.singletonList(subject), 1000);
|
ArgumentCaptor<DmsUserFolderPermissionTreeQuery> q = ArgumentCaptor.forClass(DmsUserFolderPermissionTreeQuery.class);
|
verify(mapper).selectPrintFolders(q.capture());
|
assertEquals("tenant-1", q.getValue().getTenantId());
|
assertEquals(6, q.getValue().getPrincipals().size());
|
}
|
|
@Test
|
void personalWorkflowVersionsUseOnlyAuthenticatedUserAndIndependentQuery() {
|
when(mapper.selectWorkflowPrintVersions("tenant-1", "admin-1")).thenReturn(
|
Collections.singletonList(row(firstId, null, 0L, null, null, false)));
|
assertEquals(Collections.singletonList(firstId), service.currentUserWorkflowPrintVersionIds());
|
verify(mapper).selectWorkflowPrintVersions("tenant-1", "admin-1");
|
verify(mapper, never()).selectPrintFolders(any());
|
verify(currentIdentity, never()).requirePermissionAdministrator();
|
verify(subjectResolver, never()).resolve(any(), any());
|
verify(groupResolver, never()).resolveAll(any(List.class), anyInt());
|
}
|
|
@Test
|
void currentUserScopeRejectsAnotherUsersResolvedSubjects() {
|
when(subjectResolver.resolve("tenant-1", Collections.singletonList("admin-1")))
|
.thenReturn(Collections.singletonList(subject("other-user")));
|
assertThrows(DmsPermissionException.class, () -> service.currentUserPrintFolderIds());
|
verify(mapper, never()).selectPrintFolders(any());
|
}
|
|
@BeforeEach
|
void setUp() {
|
actor.setUserId("admin-1");
|
actor.setTenantId("tenant-1");
|
when(currentIdentity.requireUser()).thenReturn(actor);
|
when(currentIdentity.tenantId(actor)).thenReturn("tenant-1");
|
}
|
|
@Test
|
void returnsPermissionAnnotatedUnionTreeAndPaginatesByFolder() {
|
DmsSubjectSet user2 = subject("user-2");
|
user2.getDirectOrgIds().add("org-direct");
|
user2.getAncestorOrgIds().addAll(Arrays.asList("org-direct", "org-parent"));
|
user2.getPositionIds().add("position-1");
|
user2.getRoleIds().add("role-1");
|
user2.getPermissionGroupIds().add("permission-group-1");
|
DmsSubjectSet user1 = subject("user-1");
|
when(subjectResolver.resolve("tenant-1", Arrays.asList("user-2", "user-1")))
|
.thenReturn(Arrays.asList(user2, user1));
|
when(mapper.selectTree(any())).thenReturn(Arrays.asList(
|
row(firstId, "A", 1024L, "user-1", "PRINT", true),
|
row(firstId, "A", 1024L, "user-2", "READ", true),
|
row(firstId, "A", 1024L, "user-1", "READ", true),
|
row(secondId, "B", 2048L, null, null, false)));
|
|
UserFolderPermissionTreeForm form = new UserFolderPermissionTreeForm();
|
form.setUserIds(Arrays.asList("user-2", " user-1 ", "user-2"));
|
form.setParentId(parentId);
|
form.setPageSize(1);
|
|
DmsCursorPageVO<DmsUserFolderPermissionTreeNodeVO> result = service.tree(form);
|
|
assertEquals(1, result.getList().size());
|
assertTrue(result.isHasMore());
|
assertNotNull(result.getNextCursor());
|
DmsUserFolderPermissionTreeNodeVO node = result.getList().get(0);
|
assertEquals(firstId, node.getId());
|
assertTrue(node.isHasChildren());
|
assertEquals(Arrays.asList("user-2", "user-1"), node.getUserPermissions().stream()
|
.map(value -> value.getUserId()).collect(Collectors.toList()));
|
assertEquals(Collections.singletonList("READ"), node.getUserPermissions().get(0).getActions());
|
assertEquals(Arrays.asList("READ", "PRINT"), node.getUserPermissions().get(1).getActions());
|
|
String fingerprint = cursorCodec.fingerprint("user-2\nuser-1");
|
DmsFileCenterCursorCodec.Cursor cursor = cursorCodec.decode(result.getNextCursor(),
|
"USER_FOLDER_PERMISSION_TREE", "tenant-1", "admin-1", parentId, fingerprint);
|
assertEquals(1024L, cursor.getSortCode());
|
assertEquals(firstId, cursor.getId());
|
|
verify(groupResolver).resolveAll(Arrays.asList(user2, user1), 1000);
|
ArgumentCaptor<DmsUserFolderPermissionTreeQuery> queryCaptor =
|
ArgumentCaptor.forClass(DmsUserFolderPermissionTreeQuery.class);
|
verify(mapper).selectTree(queryCaptor.capture());
|
DmsUserFolderPermissionTreeQuery query = queryCaptor.getValue();
|
assertEquals(2, query.getLimit());
|
assertEquals(parentId, query.getParentId());
|
assertEquals("tenant-1", query.getTenantId());
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "USER", "user-2"));
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "ORG_DIRECT", "org-direct"));
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "ORG_ANCESTOR", "org-parent"));
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "POSITION", "position-1"));
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "ROLE", "role-1"));
|
assertTrue(hasPrincipal(query.getPrincipals(), "user-2", "GROUP", "permission-group-1"));
|
}
|
|
@Test
|
void keepsNavigationAncestorsWithoutClaimingPermissions() {
|
DmsSubjectSet subject = subject("user-1");
|
when(subjectResolver.resolve("tenant-1", Collections.singletonList("user-1")))
|
.thenReturn(Collections.singletonList(subject));
|
when(mapper.selectTree(any())).thenReturn(Collections.singletonList(
|
row(firstId, "Navigation", 1024L, null, null, true)));
|
UserFolderPermissionTreeForm form = new UserFolderPermissionTreeForm();
|
form.setUserIds(Collections.singletonList("user-1"));
|
|
DmsCursorPageVO<DmsUserFolderPermissionTreeNodeVO> result = service.tree(form);
|
|
assertEquals(1, result.getList().size());
|
assertTrue(result.getList().get(0).getUserPermissions().isEmpty());
|
assertFalse(result.isHasMore());
|
}
|
|
@Test
|
void rejectsInvalidInputBeforeResolvingSubjects() {
|
UserFolderPermissionTreeForm empty = new UserFolderPermissionTreeForm();
|
empty.setUserIds(Collections.<String>emptyList());
|
assertThrows(DmsPermissionException.class, () -> service.tree(empty));
|
|
UserFolderPermissionTreeForm invalidPage = new UserFolderPermissionTreeForm();
|
invalidPage.setUserIds(Collections.singletonList("user-1"));
|
invalidPage.setPageSize(101);
|
assertThrows(DmsPermissionException.class, () -> service.tree(invalidPage));
|
|
verify(subjectResolver, never()).resolve(any(), any());
|
verify(groupResolver, never()).resolveAll(any(List.class), anyInt());
|
verify(mapper, never()).selectTree(any());
|
}
|
|
@Test
|
void rejectsNonAdministratorsBeforeReadingRequestContextOrCallingDownstreamServices() {
|
doThrow(DmsPermissionException.of(DmsPermissionError.ADMIN_REQUIRED, "admin required"))
|
.when(currentIdentity).requirePermissionAdministrator();
|
UserFolderPermissionTreeForm form = new UserFolderPermissionTreeForm();
|
form.setUserIds(Collections.singletonList("user-1"));
|
|
DmsPermissionException error = assertThrows(DmsPermissionException.class,
|
() -> service.tree(form));
|
|
assertEquals(DmsPermissionError.ADMIN_REQUIRED, error.getError());
|
verify(currentIdentity, never()).requireUser();
|
verify(subjectResolver, never()).resolve(any(), any());
|
verify(groupResolver, never()).resolveAll(any(List.class), anyInt());
|
verify(mapper, never()).selectTree(any());
|
}
|
|
private DmsSubjectSet subject(String userId) {
|
DmsSubjectSet value = new DmsSubjectSet();
|
value.setUserId(userId);
|
return value;
|
}
|
|
private DmsUserFolderPermissionTreeRow row(UUID id, String name, long sortCode,
|
String userId, String action, boolean hasChildren) {
|
DmsUserFolderPermissionTreeRow value = new DmsUserFolderPermissionTreeRow();
|
value.setId(id);
|
value.setParentId(parentId);
|
value.setName(name);
|
value.setSortCode(sortCode);
|
value.setHasChildren(hasChildren);
|
value.setUserId(userId);
|
value.setActionCode(action);
|
return value;
|
}
|
|
private boolean hasPrincipal(List<DmsUserFolderPermissionPrincipal> values,
|
String userId, String kind, String principalId) {
|
return values.stream().anyMatch(value -> userId.equals(value.getUserId())
|
&& kind.equals(value.getPrincipalKind()) && principalId.equals(value.getPrincipalId()));
|
}
|
|
private static DmsPermissionProperties properties() {
|
DmsPermissionProperties value = new DmsPermissionProperties();
|
value.setDefaultPageSize(20);
|
value.setMaxPageSize(100);
|
value.setMaxUserFolderTreeUsers(50);
|
value.setMaxPermissionGroupScan(1000);
|
value.setCursorSigningSecret("0123456789abcdef0123456789abcdef");
|
return value;
|
}
|
}
|