package jnpf.fileStorage;
|
|
import jnpf.base.ActionResult;
|
import jnpf.base.UserInfo;
|
import jnpf.exception.DataException;
|
import jnpf.file.WorkflowFileAccessApi;
|
import jnpf.model.fileaccess.WorkflowFileGrant;
|
import jnpf.model.fileaccess.WorkflowFileRequest;
|
import jnpf.util.UserProvider;
|
import org.junit.*;
|
import org.mockito.MockedStatic;
|
import java.util.*;
|
import static org.junit.Assert.*;
|
import static org.mockito.Mockito.*;
|
|
public class WorkflowFileTicketServiceTest {
|
private WorkflowFileTicketService service;
|
private WorkflowFileAccessApi access;
|
private WorkflowFileRequest request;
|
private MockedStatic<UserProvider> users;
|
private Map<String, String> cache;
|
@Before public void setup() {
|
jnpf.util.context.SpringContext.setApplicationContext(mock(org.springframework.context.ApplicationContext.class));
|
UserInfo user = new UserInfo(); user.setUserId("owner"); user.setTenantId("tenant");
|
users = mockStatic(UserProvider.class, withSettings().mockMaker(org.mockito.MockMakers.INLINE)); users.when(UserProvider::getUser).thenReturn(user); users.when(UserProvider::getLoginUserId).thenReturn("owner");
|
access = mock(WorkflowFileAccessApi.class); cache = new HashMap<>();
|
service = new WorkflowFileTicketService(access, cache::get, value -> { String id = UUID.randomUUID().toString(); cache.put(id, value); return id; });
|
request = new WorkflowFileRequest(); request.setModelId("model"); request.setRecordId("record"); request.setTaskId("task"); request.setField("files"); request.setFileId("A");
|
when(access.authorize(any())).thenAnswer(call -> {
|
WorkflowFileRequest source = call.getArgument(0); if (source == null) return null; WorkflowFileGrant grant = new WorkflowFileGrant(); grant.setContext(source);
|
grant.setFile(Collections.singletonMap("fileId", source.getFileId())); return ActionResult.success(grant);
|
});
|
}
|
@After public void close() { if (users != null) users.close(); }
|
private void denied(Runnable call) { try { call.run(); fail("expected denial"); } catch (DataException expected) { } }
|
@Test public void ignoresClientActorAndAction() {
|
request.setOwnerId("admin"); request.setTenantId("other"); request.setAction("VIEW");
|
WorkflowFileRequest bound = service.authorizeDownloads(Collections.singletonList(request)).get(0).getContext();
|
assertEquals("owner", bound.getOwnerId()); assertEquals("tenant", bound.getTenantId()); assertEquals("DOWNLOAD", bound.getAction());
|
assertEquals("admin", request.getOwnerId());
|
}
|
private String previewTicket() { return service.previewTicket(service.authorizePreview(request)); }
|
@Test public void configRechecksCurrentAccess() {
|
String ticket = previewTicket(); service.previewAccess(ticket);
|
when(access.authorize(any())).thenReturn(ActionResult.fail("denied")); denied(() -> service.previewAccess(ticket));
|
verify(access, times(3)).authorize(any());
|
}
|
@Test public void expiredTicketDenied() { String ticket = previewTicket(); cache.clear(); denied(() -> service.previewAccess(ticket)); }
|
@Test public void malformedTicketDenied() { cache.put("bad", "1"); denied(() -> service.previewAccess("bad")); }
|
@Test public void anotherUserCannotUseConfigTicket() {
|
String ticket = previewTicket(); clearInvocations(access);
|
users.when(UserProvider::getLoginUserId).thenReturn("other");
|
denied(() -> service.previewAccess(ticket)); verifyNoInteractions(access);
|
}
|
@Test public void anotherTenantCannotUseConfigTicket() {
|
String ticket = previewTicket(); clearInvocations(access);
|
UserInfo other = new UserInfo(); other.setTenantId("other"); users.when(UserProvider::getUser).thenReturn(other);
|
denied(() -> service.previewAccess(ticket)); verifyNoInteractions(access);
|
}
|
@Test public void legacySourceTicketCannotBeUsedAsConfig() {
|
cache.put("old", "{\"purpose\":\"workflow-file-office-source-v1\"}");
|
denied(() -> service.previewAccess("old")); verifyNoInteractions(access);
|
}
|
@Test public void batchChecksEverySourceBeforeReturning() {
|
WorkflowFileRequest second = new WorkflowFileRequest(); second.setFileId("B"); second.setField("child"); second.setModelId("model");
|
when(access.authorize(argThat(r -> "B".equals(r.getFileId())))).thenReturn(ActionResult.fail("revoked"));
|
denied(() -> service.authorizeDownloads(Arrays.asList(request, second)));
|
verify(access, times(2)).authorize(any()); assertTrue(cache.isEmpty());
|
}
|
@Test public void batchIssuesNothingOnPartialFailure() {
|
when(access.authorize(any())).thenReturn(ActionResult.fail("denied")); denied(() -> service.authorizeDownloads(Collections.singletonList(request))); assertTrue(cache.isEmpty());
|
}
|
@Test public void missingUpstreamResponseDenied() { when(access.authorize(any())).thenReturn(null); denied(() -> service.authorizePreview(request)); }
|
@Test public void emptyAndOversizedBatchesDenied() { denied(() -> service.authorizeDownloads(Collections.emptyList())); denied(() -> service.authorizeDownloads(Collections.nCopies(101, request))); }
|
@Test public void fileMismatchInUpstreamResponseDenied() {
|
WorkflowFileGrant grant = new WorkflowFileGrant(); grant.setContext(request); grant.setFile(Collections.singletonMap("fileId", "other"));
|
when(access.authorize(any())).thenReturn(ActionResult.success(grant)); denied(() -> service.authorizePreview(request));
|
}
|
@Test public void ticketCannotMoveToAnotherRecordOnConsumption() {
|
String ticket = previewTicket();
|
doAnswer(call -> {
|
WorkflowFileRequest changed = jnpf.util.JsonUtil.getJsonToBean(jnpf.util.JsonUtil.getObjectToString(call.getArgument(0)), WorkflowFileRequest.class);
|
changed.setRecordId("other-record");
|
WorkflowFileGrant grant = new WorkflowFileGrant(); grant.setContext(changed); grant.setFile(Collections.singletonMap("fileId", "A"));
|
return ActionResult.success(grant);
|
}).when(access).authorize(any());
|
denied(() -> service.previewAccess(ticket));
|
}
|
@Test public void samePhysicalFileInAnotherInstanceHasIndependentPermission() {
|
String first = previewTicket();
|
request.setTaskId("other-task"); request.setRecordId("other-record");
|
String second = previewTicket();
|
doAnswer(call -> {
|
WorkflowFileRequest source = call.getArgument(0);
|
if ("task".equals(source.getTaskId())) return ActionResult.fail("revoked");
|
WorkflowFileGrant grant = new WorkflowFileGrant(); grant.setContext(source); grant.setFile(Collections.singletonMap("fileId", "A"));
|
return ActionResult.success(grant);
|
}).when(access).authorize(any());
|
denied(() -> service.previewAccess(first));
|
assertEquals("other-task", service.previewAccess(second).getContext().getTaskId());
|
}
|
|
@Test public void editLeaseBindingCannotBeStrippedByAuthorizationResponse() {
|
request.setDraftId("draft"); request.setLeaseId("lease");
|
String ticket = previewTicket();
|
assertEquals("lease", service.previewAccess(ticket).getContext().getLeaseId());
|
doAnswer(call -> {
|
WorkflowFileRequest changed = jnpf.util.JsonUtil.getJsonToBean(jnpf.util.JsonUtil.getObjectToString(call.getArgument(0)), WorkflowFileRequest.class);
|
changed.setLeaseId(null);
|
WorkflowFileGrant grant = new WorkflowFileGrant(); grant.setContext(changed); grant.setFile(Collections.singletonMap("fileId", "A"));
|
return ActionResult.success(grant);
|
}).when(access).authorize(any());
|
denied(() -> service.previewAccess(ticket));
|
}
|
|
}
|