刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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));
    }
 
}