云
11 小时以前 95ae0c83d2aa58d86b4039e3f7f16ee93afb8f00
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
117
118
119
120
121
122
123
124
125
126
127
package cn.iocoder.yudao.module.system.framework.agent;
 
import cn.iocoder.yudao.framework.common.biz.system.permission.PermissionCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.permission.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import static org.junit.jupiter.api.Assertions.*;
 
class SystemAgentDelegationServiceTest {
 
    private final Map<String, AgentDelegation> records = new HashMap<>();
    private boolean permissionGranted = true;
    private SystemAgentDelegationService service;
 
    @BeforeEach
    void setUp() {
        AgentDelegationStore store = new AgentDelegationStore() {
            @Override
            public void save(AgentDelegation delegation, long ttlSeconds) {
                records.put(delegation.getId(), delegation);
            }
 
            @Override
            public AgentDelegation get(String delegationId) {
                return records.get(delegationId);
            }
 
            @Override
            public void delete(String delegationId) {
                records.remove(delegationId);
            }
        };
        PermissionCommonApi permissions = new PermissionCommonApi() {
            @Override
            public boolean hasAnyPermissions(Long userId, String... permission) {
                return permissionGranted;
            }
 
            @Override
            public boolean hasAnyRoles(Long userId, String... roles) {
                return false;
            }
 
            @Override
            public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
                return null;
            }
        };
        service = new SystemAgentDelegationService(store, permissions);
        ReflectionTestUtils.setField(service, "delegationTtlSeconds", 1800L);
        login(7L);
    }
 
    @AfterEach
    void clearContext() {
        SecurityContextHolder.clearContext();
        RequestContextHolder.resetRequestAttributes();
    }
 
    @Test
    void issuedTokenStoresOnlySecretHash() {
        AgentDelegationToken result = issue("task-1");
        AgentDelegation stored = records.get(result.delegationId());
        assertNotNull(stored);
        assertFalse(stored.getSecretHash().contains(result.token().substring(result.token().indexOf('.') + 1)));
        assertEquals("task-1", stored.getTaskId());
        assertNotNull(result.expiresAt());
    }
 
    @Test
    void rejectsDifferentTaskAndTamperedSecret() {
        AgentDelegationToken result = issue("task-1");
        AgentBridgeException mismatch = assertThrows(AgentBridgeException.class,
                () -> service.require(result.token(), "task-2", "attachment.read",
                        "mdm:item:import", "mdm.item", 21L));
        assertEquals("DELEGATION_SCOPE_MISMATCH", mismatch.getErrorCode());
 
        String tampered = result.token().substring(0, result.token().indexOf('.') + 1) + "tampered";
        AgentBridgeException invalid = assertThrows(AgentBridgeException.class,
                () -> service.require(tampered, "task-1", "attachment.read",
                        "mdm:item:import", "mdm.item", 21L));
        assertEquals("DELEGATION_INVALID", invalid.getErrorCode());
    }
 
    @Test
    void permissionRevocationInvalidatesExistingToken() {
        AgentDelegationToken result = issue("task-1");
        permissionGranted = false;
        AgentBridgeException revoked = assertThrows(AgentBridgeException.class,
                () -> service.require(result.token(), "task-1", "attachment.read",
                        "mdm:item:import", "mdm.item", 21L));
        assertEquals("DELEGATION_PERMISSION_REVOKED", revoked.getErrorCode());
    }
 
    @Test
    void ownerCanRevokeToken() {
        AgentDelegationToken result = issue("task-1");
        service.revoke(result.delegationId(), 7L);
        assertFalse(records.containsKey(result.delegationId()));
    }
 
    private AgentDelegationToken issue(String taskId) {
        return service.issue(taskId, "mdm.item", 21L, Set.of("attachment.read"), "mdm:item:import");
    }
 
    private static void login(Long userId) {
        LoginUser loginUser = new LoginUser().setId(userId).setUserType(UserTypeEnum.ADMIN.getValue());
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken(loginUser, null, List.of()));
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
    }
}