union-ark-web 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/PROJECT_OVERVIEW.md +405 -0
  2. package/README.md +177 -0
  3. package/ark-control/pom.xml +142 -0
  4. package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SecurityResult.java +14 -0
  5. package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SymmetricalSecurityService.java +11 -0
  6. package/ark-control/src/local-mock/java/com/epcc/dubbo/result/Result.java +29 -0
  7. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptField.java +16 -0
  8. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldLong.java +17 -0
  9. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldWithTag.java +16 -0
  10. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/BaseDataErrorCode.java +26 -0
  11. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/CheckException.java +33 -0
  12. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/ErrorCode.java +9 -0
  13. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/redis/RedisCacheService.java +131 -0
  14. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/Constant.java +24 -0
  15. package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/ResultUtil.java +9 -0
  16. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalMockSensitiveProxy.java +40 -0
  17. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalRedisCacheService.java +45 -0
  18. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveHostConfiguration.java +27 -0
  19. package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveProxyConfiguration.java +16 -0
  20. package/ark-control/src/main/java/com/union/control/ArkControlApplication.java +17 -0
  21. package/ark-control/src/main/java/com/union/control/dubbo/ProviderAccessLogFilter.java +45 -0
  22. package/ark-control/src/main/java/com/union/control/mapper/AgentExecutionMapper.java +35 -0
  23. package/ark-control/src/main/java/com/union/control/mapper/ConversationMapper.java +44 -0
  24. package/ark-control/src/main/java/com/union/control/mapper/MemoryStoreMapper.java +41 -0
  25. package/ark-control/src/main/java/com/union/control/mapper/ScheduledTaskMapper.java +96 -0
  26. package/ark-control/src/main/java/com/union/control/mapper/SensitiveAddressBookDemo.java +31 -0
  27. package/ark-control/src/main/java/com/union/control/mapper/SensitiveDataDemoMapper.java +24 -0
  28. package/ark-control/src/main/java/com/union/control/mapper/interceptor/AESInterceptor.java +265 -0
  29. package/ark-control/src/main/java/com/union/control/mapper/interceptor/AddressBookHandler.java +105 -0
  30. package/ark-control/src/main/java/com/union/control/schedule/ScheduledExecutionToken.java +55 -0
  31. package/ark-control/src/main/java/com/union/control/schedule/ScheduledTaskScheduler.java +206 -0
  32. package/ark-control/src/main/java/com/union/control/service/impl/AgentExecutionServiceImpl.java +212 -0
  33. package/ark-control/src/main/java/com/union/control/service/impl/AgentProxyServiceImpl.java +143 -0
  34. package/ark-control/src/main/java/com/union/control/service/impl/ConversationServiceImpl.java +245 -0
  35. package/ark-control/src/main/java/com/union/control/service/impl/MemoryStoreServiceImpl.java +252 -0
  36. package/ark-control/src/main/java/com/union/control/service/impl/RunningAnalysisMockServiceImpl.java +301 -0
  37. package/ark-control/src/main/java/com/union/control/service/impl/ScheduledTaskServiceImpl.java +576 -0
  38. package/ark-control/src/main/java/com/union/control/service/impl/SensitiveDataDemoServiceImpl.java +144 -0
  39. package/ark-control/src/main/java/com/union/control/service/sensitive/RedisRevealTokenStore.java +90 -0
  40. package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealProcessor.java +319 -0
  41. package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealServiceImpl.java +72 -0
  42. package/ark-control/src/main/java/com/union/control/utils/AgentSupport.java +103 -0
  43. package/ark-control/src/main/java/com/union/control/utils/security/SymmetricalSecurityUtils.java +160 -0
  44. package/ark-control/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +1 -0
  45. package/ark-control/src/main/resources/application.properties +4 -0
  46. package/ark-control/src/main/resources/application.yml +32 -0
  47. package/ark-control/src/main/resources/dubbo-provider.xml +20 -0
  48. package/ark-control/src/main/resources/mapper/AgentExecutionMapper.xml +75 -0
  49. package/ark-control/src/main/resources/mapper/ConversationMapper.xml +110 -0
  50. package/ark-control/src/main/resources/mapper/MemoryStoreMapper.xml +74 -0
  51. package/ark-control/src/main/resources/mapper/ScheduledTaskMapper.xml +286 -0
  52. package/ark-control/src/main/resources/mapper/SensitiveDataDemoMapper.xml +55 -0
  53. package/ark-control/src/main/resources/schema.sql +146 -0
  54. package/ark-control/src/test/java/com/union/control/AgentExecutionServiceTest.java +170 -0
  55. package/ark-control/src/test/java/com/union/control/ArkControlStructureContractTest.java +107 -0
  56. package/ark-control/src/test/java/com/union/control/ConversationServiceTest.java +89 -0
  57. package/ark-control/src/test/java/com/union/control/MemoryStoreServiceTest.java +26 -0
  58. package/ark-control/src/test/java/com/union/control/PydanticAiControlContractTest.java +52 -0
  59. package/ark-control/src/test/java/com/union/control/TestJson.java +45 -0
  60. package/ark-control/src/test/java/com/union/control/dubbo/ProviderAccessLogFilterTest.java +53 -0
  61. package/ark-control/src/test/java/com/union/control/local/sensitive/LocalSensitiveProxyConfigurationTest.java +23 -0
  62. package/ark-control/src/test/java/com/union/control/mapper/interceptor/AESInterceptorCompatibilityTest.java +505 -0
  63. package/ark-control/src/test/java/com/union/control/schedule/ScheduledExecutionTokenTest.java +27 -0
  64. package/ark-control/src/test/java/com/union/control/schedule/ScheduledTaskSchedulerTest.java +51 -0
  65. package/ark-control/src/test/java/com/union/control/service/AgentProxyServiceTest.java +111 -0
  66. package/ark-control/src/test/java/com/union/control/service/ScheduledTaskServiceTest.java +483 -0
  67. package/ark-control/src/test/java/com/union/control/service/impl/SensitiveDataDemoServiceImplTest.java +104 -0
  68. package/ark-control/src/test/java/com/union/control/service/sensitive/RedisRevealTokenStoreTest.java +65 -0
  69. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealBoundaryTest.java +99 -0
  70. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorCodecTest.java +111 -0
  71. package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorTest.java +111 -0
  72. package/ark-control/src/test/java/com/union/control/utils/security/SymmetricalSecurityUtilsCompatibilityTest.java +87 -0
  73. package/ark-control-facade/pom.xml +16 -0
  74. package/ark-control-facade/src/main/java/com/union/control/service/AgentExecutionService.java +8 -0
  75. package/ark-control-facade/src/main/java/com/union/control/service/AgentProxyService.java +7 -0
  76. package/ark-control-facade/src/main/java/com/union/control/service/AgentResponse.java +22 -0
  77. package/ark-control-facade/src/main/java/com/union/control/service/ConversationService.java +12 -0
  78. package/ark-control-facade/src/main/java/com/union/control/service/MemoryStoreService.java +12 -0
  79. package/ark-control-facade/src/main/java/com/union/control/service/RunningAnalysisMockService.java +10 -0
  80. package/ark-control-facade/src/main/java/com/union/control/service/ScheduledTaskService.java +40 -0
  81. package/ark-control-facade/src/main/java/com/union/control/service/SensitiveDataDemoService.java +13 -0
  82. package/ark-control-facade/src/main/java/com/union/control/service/sensitive/SensitiveRevealService.java +18 -0
  83. package/ark-web/README.md +80 -0
  84. package/ark-web/pom.xml +105 -0
  85. package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/ArkAuthServiceMock.java +105 -0
  86. package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/LocalKaptchaConfiguration.java +26 -0
  87. package/ark-web/src/main/java/com/epcc/arkweb/Application.java +13 -0
  88. package/ark-web/src/main/java/com/epcc/arkweb/config/InterceptorConfig.java +20 -0
  89. package/ark-web/src/main/java/com/epcc/arkweb/config/Realm.java +64 -0
  90. package/ark-web/src/main/java/com/epcc/arkweb/config/ShiroConfig.java +129 -0
  91. package/ark-web/src/main/java/com/epcc/arkweb/filter/LoginFormFilter.java +43 -0
  92. package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthContextHolder.java +39 -0
  93. package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthenticatedRequest.java +91 -0
  94. package/ark-web/src/main/java/com/epcc/arkweb/model/ShiroUser.java +21 -0
  95. package/ark-web/src/main/java/com/epcc/arkweb/utils/ResultMsg.java +19 -0
  96. package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskCommandVO.java +30 -0
  97. package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskQueryVO.java +20 -0
  98. package/ark-web/src/main/java/com/epcc/arkweb/web/CommonController.java +25 -0
  99. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptor.java +229 -0
  100. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentController.java +165 -0
  101. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentPermission.java +13 -0
  102. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/LlmController.java +209 -0
  103. package/ark-web/src/main/java/com/epcc/arkweb/web/llm/ScheduledTaskController.java +160 -0
  104. package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveCaptchaService.java +146 -0
  105. package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealController.java +163 -0
  106. package/ark-web/src/main/resources/application.properties +1 -0
  107. package/ark-web/src/main/resources/application.yml +23 -0
  108. package/ark-web/src/main/resources/dubbo-consumer.xml +19 -0
  109. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/CasShiroConfig.java +229 -0
  110. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/InterceptorConfig.java +35 -0
  111. package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/ShiroConfig.java +161 -0
  112. package/ark-web/src/test/java/com/epcc/arkweb/ArkWebStructureContractTest.java +290 -0
  113. package/ark-web/src/test/java/com/epcc/arkweb/ShiroTestSupport.java +32 -0
  114. package/ark-web/src/test/java/com/epcc/arkweb/config/LocalShiroIntegrationTest.java +121 -0
  115. package/ark-web/src/test/java/com/epcc/arkweb/helper/AuthenticatedRequestTest.java +131 -0
  116. package/ark-web/src/test/java/com/epcc/arkweb/local/LocalArkAuthServiceMockTest.java +17 -0
  117. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptorTest.java +134 -0
  118. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentControllerAuthorizationTest.java +97 -0
  119. package/ark-web/src/test/java/com/epcc/arkweb/web/llm/LlmControllerTest.java +113 -0
  120. package/ark-web/src/test/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealControllerTest.java +273 -0
  121. package/package.json +18 -0
  122. package/pom.xml +16 -0
@@ -0,0 +1,40 @@
1
+ package com.union.control.service;
2
+
3
+ import java.util.List;
4
+ import java.util.Map;
5
+
6
+ public interface ScheduledTaskService {
7
+ Map<String, Object> create(String input);
8
+ Map<String, Object> update(String input);
9
+ Map<String, Object> list(String input);
10
+ Map<String, Object> detail(String input);
11
+ Map<String, Object> runs(String input);
12
+ Map<String, Object> runDetail(String input);
13
+ Map<String, Object> unread(String input);
14
+ Map<String, Object> start(String input);
15
+ Map<String, Object> pause(String input);
16
+ Map<String, Object> discard(String input);
17
+ Map<String, Object> open(String input);
18
+ Long claimDueRun();
19
+ List<Long> pendingRunIds(int limit);
20
+ boolean beginRun(long runId, String tokenHash, String expiresAt);
21
+ void completeFromProxy(long runId, Map<String, Object> result);
22
+ void failRun(long runId, String errorCode, String errorMessage);
23
+ int failStaleRuns(int maxRunSeconds);
24
+ /** Resolves an active run from the raw one-time token; the provider hashes it internally. */
25
+ Map<String, Object> resolveScheduledToken(String rawToken);
26
+
27
+ class NotFoundException extends RuntimeException {
28
+ private static final long serialVersionUID = 1L;
29
+ public NotFoundException() {}
30
+ public NotFoundException(String message) { super(message); }
31
+ }
32
+ class ConflictException extends RuntimeException {
33
+ private static final long serialVersionUID = 1L;
34
+ public ConflictException() {}
35
+ public ConflictException(String message) { super(message); }
36
+ }
37
+ class DataCorruptionException extends RuntimeException {
38
+ private static final long serialVersionUID = 1L;
39
+ }
40
+ }
@@ -0,0 +1,13 @@
1
+ package com.union.control.service;
2
+
3
+ import java.util.List;
4
+ import java.util.Map;
5
+
6
+ public interface SensitiveDataDemoService {
7
+ int insert(String input);
8
+ Map<String, Object> save(String input);
9
+ Map<String, Object> saveAddressBook(String input);
10
+ List<Map<String, Object>> query(String input);
11
+ int insertAddressBook(String input);
12
+ List<Map<String, Object>> queryAddressBook(String input);
13
+ }
@@ -0,0 +1,18 @@
1
+ package com.union.control.service.sensitive;
2
+
3
+ public interface SensitiveRevealService {
4
+ String reveal(String input);
5
+
6
+ class InvalidTokenException extends RuntimeException {
7
+ private static final long serialVersionUID = 1L;
8
+ }
9
+ class ExpiredTokenException extends RuntimeException {
10
+ private static final long serialVersionUID = 1L;
11
+ }
12
+ class RevealDecryptionException extends RuntimeException {
13
+ private static final long serialVersionUID = 1L;
14
+ }
15
+ class StoreUnavailableException extends RuntimeException {
16
+ private static final long serialVersionUID = 1L;
17
+ }
18
+ }
@@ -0,0 +1,80 @@
1
+ # ark-web
2
+
3
+ This is the browser-facing module merged into the existing production Web
4
+ application. It owns the new HTTP controllers and final SSE response while
5
+ reusing the production Shiro Realm and Filter implementations.
6
+ Its standalone startup uses the production class and bean names
7
+ `ShiroConfig`, `Realm`, `LoginFormFilter`, and `InterceptorConfig`, and follows
8
+ the same Shiro Filter -> Realm -> Subject -> permission path. Production uses
9
+ the host application's existing implementations.
10
+ Business and persistence services are consumed from
11
+ `ark-control` through `ark-control-facade` Dubbo references.
12
+
13
+ The production Web application remains Shiro authenticated. Task persistence,
14
+ due-run claiming, execution tokens, workers and model calls stay in the control
15
+ provider. There is no Web-only scheduled facade or local scheduled-service
16
+ adapter:
17
+
18
+ ```text
19
+ ark-web/src/main/java/com/epcc/arkweb/
20
+ vo/llm/ScheduledTaskCommandVO.java
21
+ vo/llm/ScheduledTaskQueryVO.java
22
+ web/llm/ScheduledTaskController.java
23
+ ```
24
+
25
+ `ScheduledTaskController` uses
26
+ `com.union.control.service.ScheduledTaskService` from the shared facade. Its
27
+ implementation is published by `ark-control`.
28
+
29
+ `AgentController` keeps the production CAS path for interactive py calls. Its
30
+ scheduled authorization endpoint validates a Control-issued token and performs
31
+ the real-time role-resource check. Agent tools use a non-Shiro
32
+ `@AgentPermission` guard and a Control-backed trusted context; only the
33
+ `X-Agent-Trusted-Context` value returned by that endpoint is accepted for tool
34
+ calls. No scheduled Realm or synthetic Subject is created.
35
+ The controller lives under `/agent/**`; it must not use production's anonymous
36
+ `/api/**` namespace. Both production filter-chain maps place `/agent/** -> anon`
37
+ before `/** -> authc`, delegating this exact namespace to the fail-closed Agent
38
+ guard. No scheduled Shiro Filter or Realm is introduced.
39
+
40
+ The copy-ready production files live under `src/production-overlay/java` and
41
+ are not part of the standalone module's compilation source set. The two Shiro
42
+ files differ from production only by the `/agent/**` whitelist line; the
43
+ `InterceptorConfig` copy registers the Agent guard first and excludes
44
+ `/agent/**` from the production browser-only interceptors. During production
45
+ merge, copy these over the three matching files rather than adding parallel
46
+ configuration classes.
47
+
48
+ For local authentication testing, activate `local-auth-mock`. It establishes a
49
+ normal Shiro Subject automatically, so no login page or manual cookie is needed.
50
+ Scheduled headers skip auto-login and continue through the non-Shiro Agent
51
+ guard. The only local replacement is the external `arkAuthService` bean at
52
+ `src/local-mock/java/com/epcc/arkweb/mock/ArkAuthServiceMock.java`; configure it
53
+ with `LOCAL_USER_ID`, `LOCAL_PASSWORD`, `LOCAL_ORG_CODE`, and
54
+ `LOCAL_AUTHORIZED_ROLE_ID`.
55
+
56
+ `ShiroUser`, `AuthContextHolder` and `ResultMsg` remain Web-owned types and do
57
+ not cross the Dubbo boundary.
58
+
59
+ The controller deliberately:
60
+
61
+ - follows the existing `web/llm`, `vo` and `service` package layout;
62
+ - exposes both `/llm/**` and `/union-op/llm/**` like the current production
63
+ `LLMController`;
64
+ - uses the existing `/assistantManager/page` Shiro permission;
65
+ - gets `loginName`, `orgCode`, and the selected `roleId` only from the
66
+ production Shiro identity exposed by `AuthContextHolder`;
67
+ - browser-facing methods never accept user identity, permissions or an
68
+ execution token from the browser. The internal scheduled authorization method
69
+ accepts only the Control-issued token from py-app.
70
+
71
+ Before enabling scheduling, verify the production `arkAuthService` bean is
72
+ available and fails closed when its backing service cannot be reached. The local
73
+ build has no proprietary auth-facade dependency, so the Agent-only guard invokes the unchanged production
74
+ `queryResource(roleId, userName, traceNo)` contract reflectively.
75
+
76
+ `LlmController#chatMessage` posts directly to py-app and writes and flushes each
77
+ upstream chunk to `HttpServletResponse`. The streaming path does not use Dubbo.
78
+
79
+ Production HTTP and Dubbo filters must not log Agent cookies, request payloads,
80
+ responses, or SSE chunks.
@@ -0,0 +1,105 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5
+ <modelVersion>4.0.0</modelVersion>
6
+ <parent>
7
+ <groupId>org.springframework.boot</groupId>
8
+ <artifactId>spring-boot-starter-parent</artifactId>
9
+ <version>1.5.22.RELEASE</version>
10
+ <relativePath/>
11
+ </parent>
12
+ <groupId>com.nucc.channel.ark</groupId>
13
+ <artifactId>ark-web</artifactId>
14
+ <version>1.1-local</version>
15
+ <packaging>jar</packaging>
16
+
17
+ <properties>
18
+ <java.version>1.8</java.version>
19
+ <shiro.version>1.12.0</shiro.version>
20
+ </properties>
21
+
22
+ <dependencies>
23
+ <dependency>
24
+ <groupId>com.union</groupId>
25
+ <artifactId>ark-control-facade</artifactId>
26
+ <version>1.0.0</version>
27
+ </dependency>
28
+ <dependency>
29
+ <groupId>com.alibaba</groupId>
30
+ <artifactId>dubbo</artifactId>
31
+ <version>2.6.9</version>
32
+ <exclusions>
33
+ <exclusion><groupId>org.jboss.netty</groupId><artifactId>netty</artifactId></exclusion>
34
+ <exclusion><groupId>org.springframework</groupId><artifactId>spring</artifactId></exclusion>
35
+ <exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion>
36
+ </exclusions>
37
+ </dependency>
38
+ <dependency>
39
+ <groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.25.Final</version>
40
+ </dependency>
41
+ <dependency>
42
+ <groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>2.12.0</version>
43
+ </dependency>
44
+ <dependency>
45
+ <groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.13</version>
46
+ <exclusions>
47
+ <exclusion><groupId>io.netty</groupId><artifactId>netty</artifactId></exclusion>
48
+ <exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion>
49
+ <exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion>
50
+ </exclusions>
51
+ </dependency>
52
+ <dependency>
53
+ <groupId>org.springframework.boot</groupId>
54
+ <artifactId>spring-boot-starter-web</artifactId>
55
+ </dependency>
56
+ <dependency>
57
+ <groupId>org.apache.shiro</groupId>
58
+ <artifactId>shiro-spring</artifactId>
59
+ <version>${shiro.version}</version>
60
+ </dependency>
61
+ <dependency>
62
+ <groupId>org.apache.commons</groupId>
63
+ <artifactId>commons-lang3</artifactId>
64
+ <version>3.3</version>
65
+ </dependency>
66
+ <!-- Already supplied by the production Web parent. -->
67
+ <dependency>
68
+ <groupId>com.github.penggle</groupId>
69
+ <artifactId>kaptcha</artifactId>
70
+ <version>2.3.2</version>
71
+ </dependency>
72
+ <dependency>
73
+ <groupId>org.springframework.boot</groupId>
74
+ <artifactId>spring-boot-starter-test</artifactId>
75
+ <scope>test</scope>
76
+ </dependency>
77
+ </dependencies>
78
+
79
+ <build>
80
+ <plugins>
81
+ <plugin>
82
+ <groupId>org.codehaus.mojo</groupId>
83
+ <artifactId>build-helper-maven-plugin</artifactId>
84
+ <version>3.2.0</version>
85
+ <executions>
86
+ <execution>
87
+ <id>add-local-mock-source</id>
88
+ <phase>generate-sources</phase>
89
+ <goals><goal>add-source</goal></goals>
90
+ <configuration>
91
+ <sources><source>src/local-mock/java</source></sources>
92
+ </configuration>
93
+ </execution>
94
+ </executions>
95
+ </plugin>
96
+ <plugin>
97
+ <groupId>org.springframework.boot</groupId>
98
+ <artifactId>spring-boot-maven-plugin</artifactId>
99
+ <configuration>
100
+ <mainClass>com.epcc.arkweb.Application</mainClass>
101
+ </configuration>
102
+ </plugin>
103
+ </plugins>
104
+ </build>
105
+ </project>
@@ -0,0 +1,105 @@
1
+ package com.epcc.arkweb.mock;
2
+
3
+ import com.epcc.arkweb.model.ShiroUser;
4
+ import org.apache.shiro.SecurityUtils;
5
+ import org.apache.shiro.authc.UsernamePasswordToken;
6
+ import org.apache.shiro.web.servlet.AdviceFilter;
7
+ import org.springframework.beans.factory.annotation.Value;
8
+ import org.springframework.boot.web.servlet.FilterRegistrationBean;
9
+ import org.springframework.context.annotation.Bean;
10
+ import org.springframework.context.annotation.Profile;
11
+ import org.springframework.stereotype.Component;
12
+
13
+ import java.util.Arrays;
14
+ import java.util.Collections;
15
+ import java.util.LinkedHashSet;
16
+ import java.util.List;
17
+ import java.util.Set;
18
+ import javax.servlet.ServletRequest;
19
+ import javax.servlet.ServletResponse;
20
+ import javax.servlet.http.HttpServletRequest;
21
+
22
+ /** Local replacement for the external arkAuthService bean. */
23
+ @Component("arkAuthService")
24
+ @Profile("local-auth-mock")
25
+ public final class ArkAuthServiceMock {
26
+ private final String userId;
27
+ private final String password;
28
+ private final String orgCode;
29
+ private final String authorizedRoleId;
30
+
31
+ public ArkAuthServiceMock(
32
+ @Value("${agent.local-user-id:user-1}") String userId,
33
+ @Value("${agent.local-password:local-only}") String password,
34
+ @Value("${agent.local-org-code:104100000004}") String orgCode,
35
+ @Value("${agent.local-authorized-role-id:role-1}") String authorizedRoleId) {
36
+ this.userId = userId;
37
+ this.password = password;
38
+ this.orgCode = orgCode;
39
+ this.authorizedRoleId = authorizedRoleId;
40
+ }
41
+
42
+ public ShiroUser authenticate(String userName, char[] suppliedPassword) {
43
+ if (!userId.equals(userName)
44
+ || !Arrays.equals(password.toCharArray(), suppliedPassword)) return null;
45
+ ShiroUser user = new ShiroUser();
46
+ user.setLoginName(userId);
47
+ user.setOrgCode(orgCode);
48
+ user.setRoleId(authorizedRoleId);
49
+ return user;
50
+ }
51
+
52
+ public Set<String> queryPermissions(String roleId, String userName) {
53
+ if (!authorizedRoleId.equals(roleId) || !userId.equals(userName))
54
+ return Collections.emptySet();
55
+ return Collections.unmodifiableSet(new LinkedHashSet<>(
56
+ Collections.singletonList("/assistantManager/page")));
57
+ }
58
+
59
+ /** Local requests get a normal Shiro Subject without a login page. */
60
+ @Bean("localAuthFilter")
61
+ public AdviceFilter localAuthFilter() {
62
+ return new AdviceFilter() {
63
+ @Override
64
+ protected boolean preHandle(ServletRequest request, ServletResponse response) {
65
+ HttpServletRequest http = (HttpServletRequest) request;
66
+ String authorization = http.getHeader("Authorization");
67
+ if ((authorization != null && authorization.startsWith("Scheduled "))
68
+ || http.getHeader("X-Agent-Trusted-Context") != null)
69
+ return true;
70
+ if (!SecurityUtils.getSubject().isAuthenticated())
71
+ SecurityUtils.getSubject().login(
72
+ new UsernamePasswordToken(userId, password));
73
+ return true;
74
+ }
75
+ };
76
+ }
77
+
78
+ /** The filter belongs only to Shiro's chain, not the servlet container's global chain. */
79
+ @Bean
80
+ public FilterRegistrationBean localAuthFilterRegistration(AdviceFilter localAuthFilter) {
81
+ FilterRegistrationBean registration = new FilterRegistrationBean(localAuthFilter);
82
+ registration.setEnabled(false);
83
+ return registration;
84
+ }
85
+
86
+ public Result queryResource(String roleId, String userName, String traceNo) {
87
+ List<Resource> resources = authorizedRoleId.equals(roleId) && userId.equals(userName)
88
+ ? Collections.singletonList(new Resource("/assistantManager/page"))
89
+ : Collections.<Resource>emptyList();
90
+ return new Result(resources);
91
+ }
92
+
93
+ public static final class Result {
94
+ private final List<Resource> result;
95
+ Result(List<Resource> result) { this.result = result; }
96
+ public boolean isSuccess() { return true; }
97
+ public List<Resource> getResult() { return result; }
98
+ }
99
+
100
+ public static final class Resource {
101
+ private final String resourceUrl;
102
+ Resource(String resourceUrl) { this.resourceUrl = resourceUrl; }
103
+ public String getResourceUrl() { return resourceUrl; }
104
+ }
105
+ }
@@ -0,0 +1,26 @@
1
+ package com.epcc.arkweb.mock;
2
+
3
+ import com.google.code.kaptcha.Producer;
4
+ import com.google.code.kaptcha.impl.DefaultKaptcha;
5
+ import com.google.code.kaptcha.util.Config;
6
+ import org.springframework.context.annotation.Bean;
7
+ import org.springframework.context.annotation.Configuration;
8
+
9
+ import java.util.Properties;
10
+
11
+ /** Local wiring only. Production supplies its existing KaptchaConfig / Producer bean. */
12
+ @Configuration
13
+ public class LocalKaptchaConfiguration {
14
+ @Bean
15
+ public Producer captchaProducer() {
16
+ Properties properties = new Properties();
17
+ properties.setProperty("kaptcha.image.width", "110");
18
+ properties.setProperty("kaptcha.image.height", "40");
19
+ properties.setProperty("kaptcha.textproducer.char.length", "4");
20
+ properties.setProperty("kaptcha.textproducer.font.size", "30");
21
+ properties.setProperty("kaptcha.textproducer.font.names", "SansSerif");
22
+ DefaultKaptcha producer = new DefaultKaptcha();
23
+ producer.setConfig(new Config(properties));
24
+ return producer;
25
+ }
26
+ }
@@ -0,0 +1,13 @@
1
+ package com.epcc.arkweb;
2
+
3
+ import org.springframework.boot.SpringApplication;
4
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+ import org.springframework.context.annotation.ImportResource;
6
+
7
+ @SpringBootApplication
8
+ @ImportResource("classpath:dubbo-consumer.xml")
9
+ public class Application {
10
+ public static void main(String[] args) {
11
+ SpringApplication.run(Application.class, args);
12
+ }
13
+ }
@@ -0,0 +1,20 @@
1
+ package com.epcc.arkweb.config;
2
+
3
+ import com.epcc.arkweb.web.llm.AgentAuthorizationInterceptor;
4
+ import org.springframework.beans.factory.annotation.Autowired;
5
+ import org.springframework.context.annotation.Configuration;
6
+ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
7
+ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
8
+
9
+ /** Uses the production configuration entry point for the Agent-only guard. */
10
+ @Configuration
11
+ public class InterceptorConfig extends WebMvcConfigurerAdapter {
12
+ @Autowired
13
+ private AgentAuthorizationInterceptor agentAuthorizationInterceptor;
14
+
15
+ @Override
16
+ public void addInterceptors(InterceptorRegistry registry) {
17
+ registry.addInterceptor(agentAuthorizationInterceptor)
18
+ .addPathPatterns("/agent/**");
19
+ }
20
+ }
@@ -0,0 +1,64 @@
1
+ package com.epcc.arkweb.config;
2
+
3
+ import com.epcc.arkweb.model.ShiroUser;
4
+ import org.apache.shiro.SecurityUtils;
5
+ import org.apache.shiro.authc.AuthenticationException;
6
+ import org.apache.shiro.authc.AuthenticationInfo;
7
+ import org.apache.shiro.authc.AuthenticationToken;
8
+ import org.apache.shiro.authc.SimpleAuthenticationInfo;
9
+ import org.apache.shiro.authc.UsernamePasswordToken;
10
+ import org.apache.shiro.authz.AuthorizationInfo;
11
+ import org.apache.shiro.authz.SimpleAuthorizationInfo;
12
+ import org.apache.shiro.realm.AuthorizingRealm;
13
+ import org.apache.shiro.subject.PrincipalCollection;
14
+ import org.springframework.beans.factory.annotation.Autowired;
15
+ import org.springframework.beans.factory.annotation.Qualifier;
16
+
17
+ import java.lang.reflect.InvocationTargetException;
18
+ import java.lang.reflect.Method;
19
+ import java.util.Set;
20
+
21
+ /** Local build of the production-named Realm; only its auth-service call is mocked. */
22
+ public class Realm extends AuthorizingRealm {
23
+ private Object arkAuthService;
24
+
25
+ @Autowired
26
+ public void setArkAuthService(@Qualifier("arkAuthService") Object arkAuthService) {
27
+ this.arkAuthService = arkAuthService;
28
+ }
29
+
30
+ @Override
31
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
32
+ UsernamePasswordToken login = (UsernamePasswordToken) token;
33
+ ShiroUser user = invoke("authenticate",
34
+ new Class<?>[]{String.class, char[].class},
35
+ new Object[]{login.getUsername(), login.getPassword()}, ShiroUser.class);
36
+ if (user == null) throw new AuthenticationException("用户名或密码错误");
37
+ SecurityUtils.getSubject().getSession().setAttribute("wl_session_user_key", user);
38
+ return new SimpleAuthenticationInfo(user, login.getCredentials(), getName());
39
+ }
40
+
41
+ @Override
42
+ @SuppressWarnings("unchecked")
43
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
44
+ ShiroUser user = principals.oneByType(ShiroUser.class);
45
+ if (user == null) return null;
46
+ Set<String> permissions = invoke("queryPermissions",
47
+ new Class<?>[]{String.class, String.class},
48
+ new Object[]{user.getRoleId(), user.getLoginName()}, Set.class);
49
+ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
50
+ info.setStringPermissions(permissions);
51
+ return info;
52
+ }
53
+
54
+ private <T> T invoke(String name, Class<?>[] types, Object[] args, Class<T> resultType) {
55
+ try {
56
+ Method method = arkAuthService.getClass().getMethod(name, types);
57
+ return resultType.cast(method.invoke(arkAuthService, args));
58
+ } catch (InvocationTargetException error) {
59
+ throw new AuthenticationException("鉴权服务调用失败", error.getCause());
60
+ } catch (Exception error) {
61
+ throw new AuthenticationException("鉴权服务调用失败", error);
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,129 @@
1
+ package com.epcc.arkweb.config;
2
+
3
+ import com.epcc.arkweb.filter.LoginFormFilter;
4
+ import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
5
+ import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
6
+ import org.apache.shiro.mgt.SecurityManager;
7
+ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
8
+ import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
9
+ import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
10
+ import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
11
+ import org.apache.shiro.web.servlet.SimpleCookie;
12
+ import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
13
+ import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
14
+ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
15
+ import org.springframework.beans.factory.annotation.Autowired;
16
+ import org.springframework.beans.factory.annotation.Qualifier;
17
+ import org.springframework.context.annotation.Bean;
18
+ import org.springframework.context.annotation.Configuration;
19
+ import org.springframework.context.annotation.DependsOn;
20
+
21
+ import javax.servlet.Filter;
22
+ import java.util.HashMap;
23
+ import java.util.LinkedHashMap;
24
+ import java.util.Map;
25
+
26
+ /** Standalone wiring with the same class, bean and filter names as production. */
27
+ @Configuration
28
+ @ConditionalOnProperty(prefix = "arkshiro", name = "sso", havingValue = "false")
29
+ public class ShiroConfig {
30
+ @Autowired(required = false)
31
+ @Qualifier("localAuthFilter")
32
+ private Filter localAuthFilter;
33
+
34
+ @Bean
35
+ public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
36
+ ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
37
+ factory.setSecurityManager(securityManager);
38
+ factory.setLoginUrl("/login.html");
39
+ factory.setUnauthorizedUrl("/403.html");
40
+ factory.setSuccessUrl("/index.html");
41
+
42
+ Map<String, String> filterMap = new LinkedHashMap<>();
43
+ filterMap.put("/error", "anon");
44
+ filterMap.put("/css/**", "anon");
45
+ filterMap.put("/images/**", "anon");
46
+ filterMap.put("/script/**", "anon");
47
+ filterMap.put("/static/**", "anon");
48
+ filterMap.put("/plugins/**", "anon");
49
+ filterMap.put("/.ico", "anon");
50
+ filterMap.put("/healthcheck.html", "anon");
51
+ filterMap.put("/SSL/healthcheck.html", "anon");
52
+ filterMap.put("/agent/**", localAuthFilter == null ? "anon" : "localAuth,anon");
53
+ filterMap.put("/**", localAuthFilter == null ? "authc" : "localAuth,authc");
54
+ filterMap.put("/union-op/**", "authc");
55
+ factory.setFilterChainDefinitionMap(filterMap);
56
+
57
+ Map<String, Filter> filters = new HashMap<>();
58
+ filters.put("authc", new LoginFormFilter("LOCAL"));
59
+ if (localAuthFilter != null) filters.put("localAuth", localAuthFilter);
60
+ factory.setFilters(filters);
61
+ return factory;
62
+ }
63
+
64
+ @Bean
65
+ public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
66
+ DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
67
+ creator.setUsePrefix(true);
68
+ return creator;
69
+ }
70
+
71
+ @Bean
72
+ public ModularRealmAuthenticator modularRealmAuthenticator() {
73
+ ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
74
+ authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
75
+ return authenticator;
76
+ }
77
+
78
+ @Bean
79
+ public DefaultWebSessionManager defaultWebSessionManager() {
80
+ DefaultWebSessionManager sessions = new DefaultWebSessionManager();
81
+ sessions.setGlobalSessionTimeout(1800000);
82
+ sessions.setDeleteInvalidSessions(true);
83
+ sessions.setSessionValidationSchedulerEnabled(true);
84
+ sessions.setSessionValidationInterval(900000);
85
+ SimpleCookie cookie = new SimpleCookie("SHRIOSESSIONID");
86
+ cookie.setHttpOnly(true);
87
+ sessions.setSessionIdCookie(new SimpleCookie(cookie));
88
+ sessions.setSessionIdUrlRewritingEnabled(false);
89
+ return sessions;
90
+ }
91
+
92
+ @Bean
93
+ public DefaultWebSecurityManager defaultWebSecurityManager(
94
+ DefaultWebSessionManager sessions,
95
+ ModularRealmAuthenticator authenticator,
96
+ Realm realm) {
97
+ DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
98
+ manager.setAuthenticator(authenticator);
99
+ manager.setRealm(realm);
100
+ manager.setSessionManager(sessions);
101
+ return manager;
102
+ }
103
+
104
+ @Bean
105
+ public Realm arkRealm() {
106
+ return new Realm();
107
+ }
108
+
109
+ @Bean
110
+ public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
111
+ return new LifecycleBeanPostProcessor();
112
+ }
113
+
114
+ @Bean
115
+ @DependsOn("lifecycleBeanPostProcessor")
116
+ public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
117
+ DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
118
+ creator.setProxyTargetClass(true);
119
+ return creator;
120
+ }
121
+
122
+ @Bean
123
+ public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
124
+ SecurityManager securityManager) {
125
+ AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
126
+ advisor.setSecurityManager(securityManager);
127
+ return advisor;
128
+ }
129
+ }
@@ -0,0 +1,43 @@
1
+ package com.epcc.arkweb.filter;
2
+
3
+ import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
4
+ import org.apache.shiro.web.util.WebUtils;
5
+
6
+ import javax.servlet.ServletRequest;
7
+ import javax.servlet.ServletResponse;
8
+ import javax.servlet.http.HttpServletRequest;
9
+ import javax.servlet.http.HttpServletResponse;
10
+ import java.util.Map;
11
+
12
+ /** Production-named form filter; proprietary session telemetry is outside the local build. */
13
+ public class LoginFormFilter extends FormAuthenticationFilter {
14
+ private final String propFlag;
15
+
16
+ public LoginFormFilter(String propFlag) {
17
+ this.propFlag = propFlag;
18
+ }
19
+
20
+ @Override
21
+ protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
22
+ throws Exception {
23
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
24
+ if (isLoginRequest(request, response)) {
25
+ return !isLoginSubmission(request, response) || executeLogin(request, response);
26
+ }
27
+ httpResponse.setStatus(401);
28
+ if (!isAjax((HttpServletRequest) request))
29
+ WebUtils.issueRedirect(request, response,
30
+ wrapperUrl((HttpServletRequest) request), (Map) null, true, false);
31
+ return false;
32
+ }
33
+
34
+ private boolean isAjax(HttpServletRequest request) {
35
+ return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
36
+ }
37
+
38
+ private String wrapperUrl(HttpServletRequest request) {
39
+ if (propFlag.contains("DMZ")) return "/union-op/login.html";
40
+ return request.getServletPath().contains("/union-op")
41
+ ? "/union-op/login.html" : "/login.html";
42
+ }
43
+ }