package jnpf.dmsService;
|
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
|
import jnpf.dmsEntity.permission.enums.DmsPermissionAction;
|
import jnpf.dmsEntity.permission.enums.DmsResourceType;
|
import jnpf.dmsEntity.permission.form.PermissionDecisionForm;
|
import jnpf.dmsEntity.permission.model.DmsResourcePath;
|
import jnpf.dmsEntity.permission.model.DmsSubjectSet;
|
import jnpf.dmsEntity.permission.vo.DmsPermissionDecisionVO;
|
import jnpf.dmsIntegration.audit.DmsAuditAdapter;
|
import jnpf.dmsMapper.DmsFilePermissionMapper;
|
import jnpf.dmsPermission.DmsAccessExclusionResolver;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsPermission.DmsPermissionGroupMembershipResolver;
|
import jnpf.dmsPermission.DmsPermissionMatcher;
|
import jnpf.dmsPermission.DmsPermissionProperties;
|
import jnpf.dmsPermission.DmsResourceResolver;
|
import jnpf.dmsPermission.DmsSubjectResolver;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.UUID;
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.anyList;
|
import static org.mockito.ArgumentMatchers.anySet;
|
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
|
class DmsPermissionDecisionServiceTest {
|
private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class);
|
private final DmsSubjectResolver subjectResolver = mock(DmsSubjectResolver.class);
|
private final DmsResourceResolver resourceResolver = mock(DmsResourceResolver.class);
|
private final DmsFilePermissionMapper permissionMapper = mock(DmsFilePermissionMapper.class);
|
private final DmsPermissionGroupMembershipResolver groupResolver =
|
mock(DmsPermissionGroupMembershipResolver.class);
|
private final DmsPermissionMatcher matcher = mock(DmsPermissionMatcher.class);
|
private final DmsPermissionProperties properties = new DmsPermissionProperties();
|
private final DmsAuditAdapter auditAdapter = mock(DmsAuditAdapter.class);
|
private final DmsAccessExclusionResolver exclusionResolver = mock(DmsAccessExclusionResolver.class);
|
private final DmsPermissionDecisionService service = new DmsPermissionDecisionService(
|
currentIdentity, subjectResolver, resourceResolver, permissionMapper, groupResolver,
|
matcher, properties, auditAdapter, exclusionResolver);
|
private final UserInfo user = new UserInfo();
|
|
@BeforeEach
|
void setUp() {
|
user.setTenantId("tenant-1");
|
user.setUserId("user-1");
|
when(currentIdentity.requireUser()).thenReturn(user);
|
when(currentIdentity.tenantId(user)).thenReturn("tenant-1");
|
when(subjectResolver.resolve(user)).thenReturn(mock(DmsSubjectSet.class));
|
}
|
|
@Test
|
void exclusionWinsWithoutLoadingAllowCandidates() {
|
UUID documentId = UUID.randomUUID();
|
PermissionDecisionForm request = request(DmsResourceType.DOCUMENT, documentId);
|
DmsResourcePath path = document(documentId);
|
when(resourceResolver.resolveAll("tenant-1", Collections.singletonList(request)))
|
.thenReturn(Collections.singletonMap(documentId, path));
|
when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
|
.thenReturn(new DmsAccessExclusionResolver.Snapshot(
|
new HashSet<>(Collections.singletonList(documentId)), Collections.emptySet()));
|
|
DmsPermissionDecisionVO result = service.evaluate(request);
|
|
assertFalse(result.isAllowed());
|
assertEquals("USER_READ_EXCLUDED", result.getReasonCode());
|
verify(permissionMapper, never()).selectCandidates(any(), any(), anyList());
|
verify(subjectResolver, never()).resolve(user);
|
}
|
|
@Test
|
void fileVersionExclusionOnlyDeniesSpecifiedVersionInBatch() {
|
UUID documentId = UUID.randomUUID();
|
UUID excludedVersionId = UUID.randomUUID();
|
UUID visibleVersionId = UUID.randomUUID();
|
PermissionDecisionForm excludedRequest = request(DmsResourceType.FILE_VERSION, excludedVersionId);
|
PermissionDecisionForm visibleRequest = request(DmsResourceType.FILE_VERSION, visibleVersionId);
|
DmsResourcePath excludedPath = version(documentId, excludedVersionId);
|
DmsResourcePath visiblePath = version(documentId, visibleVersionId);
|
Map<UUID, DmsResourcePath> paths = new HashMap<>();
|
paths.put(excludedVersionId, excludedPath);
|
paths.put(visibleVersionId, visiblePath);
|
when(resourceResolver.resolveAll("tenant-1", Arrays.asList(excludedRequest, visibleRequest)))
|
.thenReturn(paths);
|
when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
|
.thenReturn(new DmsAccessExclusionResolver.Snapshot(Collections.emptySet(),
|
new HashSet<>(Collections.singletonList(excludedVersionId))));
|
when(resourceResolver.candidateResourceIds(visiblePath))
|
.thenReturn(Arrays.asList(visibleVersionId, documentId));
|
DmsFilePermissionEntity allow = new DmsFilePermissionEntity();
|
allow.setId(UUID.randomUUID());
|
when(permissionMapper.selectCandidates("tenant-1", Collections.singletonList("READ"),
|
Arrays.asList(visibleVersionId, documentId))).thenReturn(Collections.singletonList(allow));
|
allow.setActionCode("READ");
|
when(matcher.matches(eq(allow), eq(visiblePath), any(DmsSubjectSet.class))).thenReturn(true);
|
|
List<DmsPermissionDecisionVO> result = service.evaluate(Arrays.asList(excludedRequest, visibleRequest));
|
|
assertFalse(result.get(0).isAllowed());
|
assertEquals("USER_READ_EXCLUDED", result.get(0).getReasonCode());
|
assertTrue(result.get(1).isAllowed());
|
assertEquals(allow.getId(), result.get(1).getMatchedPermissionId());
|
verify(permissionMapper).selectCandidates("tenant-1", Collections.singletonList("READ"),
|
Arrays.asList(visibleVersionId, documentId));
|
verify(groupResolver).resolve(anySet(), any(DmsSubjectSet.class));
|
}
|
|
@Test
|
void twoHundredMixedDecisionsUseOneBulkLoadPerDependency() {
|
List<PermissionDecisionForm> requests = new java.util.ArrayList<>();
|
Map<UUID, DmsResourcePath> paths = new HashMap<>();
|
for (int index = 0; index < properties.getMaxDecisionBatchSize(); index++) {
|
UUID resourceId = UUID.randomUUID();
|
DmsPermissionAction action = index % 2 == 0
|
? DmsPermissionAction.READ : DmsPermissionAction.UPDATE;
|
PermissionDecisionForm request = request(DmsResourceType.DOCUMENT, resourceId, action);
|
DmsResourcePath path = document(resourceId);
|
requests.add(request);
|
paths.put(resourceId, path);
|
when(resourceResolver.candidateResourceIds(path)).thenReturn(Collections.singletonList(resourceId));
|
}
|
when(resourceResolver.resolveAll("tenant-1", requests)).thenReturn(paths);
|
when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
|
.thenReturn(DmsAccessExclusionResolver.Snapshot.empty());
|
when(permissionMapper.selectCandidates(eq("tenant-1"), anyList(), anyList()))
|
.thenReturn(Collections.emptyList());
|
|
List<DmsPermissionDecisionVO> result = service.evaluate(requests);
|
|
assertEquals(properties.getMaxDecisionBatchSize(), result.size());
|
assertTrue(result.stream().noneMatch(DmsPermissionDecisionVO::isAllowed));
|
org.mockito.ArgumentCaptor<List<String>> actions = org.mockito.ArgumentCaptor.forClass(List.class);
|
org.mockito.ArgumentCaptor<List<UUID>> resourceIds = org.mockito.ArgumentCaptor.forClass(List.class);
|
verify(resourceResolver, times(1)).resolveAll("tenant-1", requests);
|
verify(subjectResolver, times(1)).resolve(user);
|
verify(exclusionResolver, times(1)).resolve(eq("tenant-1"), eq("user-1"), any());
|
verify(permissionMapper, times(1)).selectCandidates(eq("tenant-1"), actions.capture(),
|
resourceIds.capture());
|
verify(groupResolver, times(1)).resolve(anySet(), any(DmsSubjectSet.class));
|
assertEquals(Arrays.asList("READ", "UPDATE"), actions.getValue());
|
assertEquals(properties.getMaxDecisionBatchSize(), new HashSet<>(resourceIds.getValue()).size());
|
}
|
|
private PermissionDecisionForm request(DmsResourceType type, UUID id) {
|
return request(type, id, DmsPermissionAction.READ);
|
}
|
|
private PermissionDecisionForm request(DmsResourceType type, UUID id, DmsPermissionAction action) {
|
PermissionDecisionForm result = new PermissionDecisionForm();
|
result.setResourceType(type);
|
result.setResourceId(id);
|
result.setActionCode(action);
|
return result;
|
}
|
|
private DmsResourcePath document(UUID documentId) {
|
DmsResourcePath path = new DmsResourcePath();
|
path.setActualResourceType("DOCUMENT");
|
path.setActualResourceId(documentId);
|
path.setDocumentId(documentId);
|
return path;
|
}
|
|
private DmsResourcePath version(UUID documentId, UUID versionId) {
|
DmsResourcePath path = new DmsResourcePath();
|
path.setActualResourceType("FILE_VERSION");
|
path.setActualResourceId(versionId);
|
path.setDocumentId(documentId);
|
return path;
|
}
|
}
|