Skip to content

Commit 4b1df68

Browse files
committed
feat: AC OIDC IdP issues tokens, allowing customization of username parameters other than the sub parameter from the userinfo API; when logging into AC OIDC IdP, the code_verifier value of cookies cannot be retrieved, displaying "Login time too long, exceeding 5 minutes, please log in again"; if the user does not have dashboard permissions, the keeper status card will not be displayed; the webhook has been changed to an AI Proxy; the maximum capacity of the adaptive cache has been increased from 1MB to 10MB.
1 parent bf4f228 commit 4b1df68

1,474 files changed

Lines changed: 67528 additions & 73444 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ licenseReport {
2222

2323
allprojects {
2424
group = 'tpi.dgrv4'
25-
version = 'release-v4.7.3'
25+
version = 'release-rc-v4.7.10.0-14-g81f406576'
2626
apply plugin: 'io.spring.dependency-management'
2727

2828
repositories {
@@ -59,22 +59,32 @@ subprojects {
5959
}
6060

6161
dependencies {
62-
implementation files("${rootDir}/libsext/dgrv4_CodecUtil-v4.7.3.5-lib.jar")
63-
implementation files("${rootDir}/libsext/dgrv4_HttpUtil-v4.7.3.5-lib.jar")
62+
implementation files("${rootDir}/libsext/dgrv4_CodecUtil-v4.7.10.0-14-g81f406576-lib.jar")
63+
implementation files("${rootDir}/libsext/dgrv4_HttpUtil-v4.7.10.0-14-g81f406576-lib.jar")
6464

6565
implementation ('org.springframework.boot:spring-boot-starter-data-jpa'){
6666
//CVE-2025-41249
6767
exclude group:'org.springframework', module:'spring-core'
68-
//CVE-2025-11226
68+
//CVE-2026-1225
6969
exclude group:'ch.qos.logback', module:'logback-core'
70+
//CVE-2026-1225
71+
exclude group:'ch.qos.logback', module:'logback-classic'
7072
}
7173

7274
// Correct the above exclusions, CVE-2025-41249
7375
implementation 'org.springframework:spring-core:6.2.11'
74-
// Correct the above exclusions, CVE-2025-11226
75-
implementation 'ch.qos.logback:logback-core:1.5.19'
76+
// Correct the above exclusions, CVE-2026-1225
77+
implementation 'ch.qos.logback:logback-core:1.5.25'
78+
// Correct the above exclusions, CVE-2026-1225
79+
implementation 'ch.qos.logback:logback-classic:1.5.25'
7680

77-
implementation 'org.springframework.boot:spring-boot-starter-web'
81+
implementation ('org.springframework.boot:spring-boot-starter-web'){
82+
//CVE-2025-66614, CVE-2026-24733
83+
exclude group:'org.apache.tomcat.embed', module:'tomcat-embed-core'
84+
}
85+
86+
// Correct the above exclusions, CVE-2025-66614, CVE-2026-24733
87+
implementation 'org.apache.tomcat.embed:tomcat-embed-core:10.1.49'
7888

7989
implementation 'org.jboss.xnio:xnio-nio:3.8.16.Final'
8090
implementation 'jakarta.servlet:jakarta.servlet-api:6.1.0'
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
connection.project.dir=..
1+
connection.project.dir=../dgrv4_Gateway_serv
22
eclipse.preferences.version=1

dgrv4_Common_lib/bin/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

dgrv4_Common_lib/src/main/java/tpi/dgrv4/common/utils/CheckmarxCommUtils.java

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@
88
import java.nio.file.Files;
99
import java.nio.file.Path;
1010
import java.nio.file.Paths;
11-
import java.util.Map;
1211
import java.util.Optional;
13-
import java.util.regex.Matcher;
1412
import java.util.regex.Pattern;
1513

16-
import org.springframework.util.StringUtils;
1714
import org.springframework.web.multipart.MultipartFile;
1815

19-
import jakarta.servlet.http.HttpServletResponse;
2016
import tpi.dgrv4.common.keeper.ITPILogger;
2117

2218
public class CheckmarxCommUtils {
@@ -132,131 +128,7 @@ public static boolean sanitizeForCheckmarxMatches(String resourceUrl, String pat
132128
public static void sanitizeForCheckmarx(MultipartFile file, Path savedFilePath) throws IllegalStateException, IOException {
133129
file.transferTo(savedFilePath.toFile());
134130
}
135-
136-
public static String sanitizeForCheckmarx(Map<String, String> maskInfo, String mbody) {
137-
if (maskInfo != null) {
138-
139-
String bodyMaskPolicy = maskInfo.get("bodyMaskPolicy");
140-
String bodyMaskPolicySymbol = maskInfo.get("bodyMaskPolicySymbol");
141-
String bodyMaskKeyword = maskInfo.get("bodyMaskKeyword");
142-
if (StringUtils.hasLength(bodyMaskKeyword)) {
143-
String[] bodyMaskKeywordArr = bodyMaskKeyword.split(",");
144-
int bodyMaskPolicyNum = Integer.parseInt(maskInfo.get("bodyMaskPolicyNum"));
145-
if (mbody.length() > (bodyMaskPolicyNum * 2)) {
146-
147-
if ("1".equals(bodyMaskPolicy)) {
148-
for (String key : bodyMaskKeywordArr) {
149-
int startIndex = 0;
150-
//checkmarx, Unchecked Input for Loop Condition
151-
while (mbody.indexOf(key, startIndex) >= 0) {
152-
int matchIndex = mbody.indexOf(key, startIndex);
153-
154-
int startindex = matchIndex - bodyMaskPolicyNum;
155-
if (startindex < 0) {
156-
startindex = 0;
157-
}
158-
int endindex = matchIndex + key.length() + bodyMaskPolicyNum;
159-
if (endindex > mbody.length() - 1) {
160-
endindex = mbody.length();
161-
}
162-
163-
mbody = mbody.substring(0, startindex) + bodyMaskPolicySymbol
164-
+ mbody.substring(matchIndex, matchIndex + key.length()) + bodyMaskPolicySymbol
165-
+ mbody.substring(endindex);
166-
167-
startIndex = matchIndex + key.length() + 1;
168-
}
169-
}
170-
return mbody;
171-
}
172-
if ("2".equals(bodyMaskPolicy)) {
173-
for (String key : bodyMaskKeywordArr) {
174-
int startIndex = 0;
175-
//checkmarx, Unchecked Input for Loop Condition
176-
while (mbody.indexOf(key, startIndex) >= 0) {
177-
int matchIndex = mbody.indexOf(key, startIndex);
178-
179-
int startindex = matchIndex - bodyMaskPolicyNum;
180-
if (startindex < 0) {
181-
startindex = 0;
182-
}
183-
184-
mbody = mbody.substring(0, startindex) + bodyMaskPolicySymbol
185-
+ mbody.substring(matchIndex);
186-
187-
startIndex = matchIndex + key.length() + 1;
188-
}
189-
}
190-
return mbody;
191-
192-
}
193-
if ("3".equals(bodyMaskPolicy)) {
194-
for (String key : bodyMaskKeywordArr) {
195-
int startIndex = 0;
196-
//checkmarx, Unchecked Input for Loop Condition
197-
while (mbody.indexOf(key, startIndex) >= 0) {
198-
int matchIndex = mbody.indexOf(key, startIndex);
199-
200-
int endindex = matchIndex + key.length() + bodyMaskPolicyNum;
201-
if (endindex > mbody.length() - 1) {
202-
endindex = mbody.length();
203-
}
204-
mbody = mbody.substring(0, matchIndex + key.length()) + bodyMaskPolicySymbol
205-
+ mbody.substring(endindex);
206-
207-
startIndex = matchIndex + key.length() + 1;
208-
}
209-
}
210-
return mbody;
211-
}
212-
if ("4".equals(bodyMaskPolicy)) {
213-
String regex = "(?<jsonField>\\\"(" + bodyMaskKeyword
214-
+ ")\\\"\\s*?:)\\s*?(?<jsonvalue>(true|false|\\d+|\\\"\\{.*?\\}\\\")|\\\".*?\\\"|\\[.*?\\])|(?<xmlField><(?<fieldname>"
215-
+ bodyMaskKeyword + ")>)\\s*?(?<xmlvalue>.*?)\\s*?(?<xmlEnd><\\/\\k<fieldname>>)";
216-
217-
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
218131

219-
Matcher matcher = pattern.matcher(mbody);// 不接受 null
220-
221-
// 遍歷所有匹配的字段,進行替換
222-
StringBuffer result = new StringBuffer();
223-
//checkmarx, Unchecked Input for Loop Condition
224-
while (matcher.find()) {
225-
String field = matcher.group("jsonField");
226-
227-
if (!StringUtils.hasLength(field)) {
228-
field = matcher.group("xmlField");
229-
}
230-
String fieldValue = matcher.group("jsonvalue");
231-
232-
if (!StringUtils.hasLength(fieldValue))
233-
fieldValue = matcher.group("xmlvalue");
234-
235-
if (StringUtils.hasLength(fieldValue)) {
236-
String maskedField = maskField(fieldValue, bodyMaskPolicyNum, bodyMaskPolicySymbol);
237-
String xmlEnd = StringUtils.hasLength(matcher.group("xmlEnd")) ? matcher.group("xmlEnd")
238-
: new String();
239-
240-
matcher.appendReplacement(result, (field + maskedField + xmlEnd));
241-
}
242-
}
243-
matcher.appendTail(result);
244-
mbody = result.toString();
245-
}
246-
}
247-
}
248-
}
249-
return mbody;
250-
}
251-
252-
private static String maskField(String fieldValue, int bodyMaskPolicyNum, String bodyMaskPolicySymbol) {
253-
254-
if (fieldValue.length() > bodyMaskPolicyNum) {
255-
return fieldValue.substring(0, bodyMaskPolicyNum) + bodyMaskPolicySymbol + fieldValue.charAt(fieldValue.length() - 1);
256-
}
257-
return fieldValue;
258-
}
259-
260132
public static void sanitizeForCheckmarxConn(String targetHostName, int targetPort, int connectTimeout) throws IOException {
261133
try (Socket socket = new Socket()) {
262134
socket.connect(new InetSocketAddress(targetHostName, targetPort), connectTimeout);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package tpi.dgrv4.common.utils;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
5+
public class ClientIpUtil {
6+
public static String getClientIp(HttpServletRequest request) {
7+
if (request == null) {
8+
return null;
9+
}
10+
String xff = request.getHeader("X-Forwarded-For");
11+
12+
if (xff == null || xff.isEmpty() || "unknown".equalsIgnoreCase(xff)) {
13+
return request.getRemoteAddr();
14+
}
15+
16+
// 處理多重代理,只取第一個非 unknown 的 IP
17+
String[] ips = xff.split(",");
18+
String clientIp = ips[0].trim();
19+
20+
return clientIp;
21+
}
22+
23+
}

dgrv4_Common_lib/src/main/java/tpi/dgrv4/common/utils/autoInitSQL/Initializer/TsmpFuncTableInitializer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,10 @@ public List<TsmpFuncVo> insertTsmpFunc(LicenseEditionTypeVo licenseEdition, bool
354354
createTsmpFunc("AI0005","User AI Prompt Template","User AI Prompt Template","userAiPromptTemplateSetting","","en-US","manager",DateTimeUtil.now());
355355
createTsmpFunc("AI0005","使用者 AI 提示詞樣板設定","使用者預設 AI 提示詞樣板設定","userAiPromptTemplateSetting","","zh-TW","manager",DateTimeUtil.now());
356356

357-
createTsmpFunc("LB0011","Webhook","Webhook","Real time event notification mechanism","","en-US","manager",DateTimeUtil.now());
358-
createTsmpFunc("LB0011","Webhook","Webhook","即時事件通知推送機制","","zh-TW","manager",DateTimeUtil.now());
359-
createTsmpFunc("LB0012","Webhook Logs","Webhook Logs","Real time event notification logs","","en-US","manager",DateTimeUtil.now());
360-
createTsmpFunc("LB0012","Webhook Logs","Webhook Logs","即時事件通知推送紀錄","","zh-TW","manager",DateTimeUtil.now());
357+
createTsmpFunc("LB0011","AI Proxy","AI Proxy","Real time event notification mechanism","","en-US","manager",DateTimeUtil.now());
358+
createTsmpFunc("LB0011","AI Proxy","AI Proxy","即時事件通知推送機制","","zh-TW","manager",DateTimeUtil.now());
359+
createTsmpFunc("LB0012","AI Proxy Logs","AI Proxy Logs","Real time event notification logs","","en-US","manager",DateTimeUtil.now());
360+
createTsmpFunc("LB0012","AI Proxy Logs","AI Proxy Logs","即時事件通知推送紀錄","","zh-TW","manager",DateTimeUtil.now());
361361

362362
createTsmpFunc("AC0322","API List Export","API List Export","apiListExport","","en-US","manager",DateTimeUtil.now());
363363
createTsmpFunc("AC0322","API列表匯出","API List Export","apiListExport","","zh-TW","manager",DateTimeUtil.now());

dgrv4_Common_lib/src/main/java/tpi/dgrv4/common/utils/autoInitSQL/Initializer/TsmpSettingTableInitializer.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,8 @@ public List<TsmpSettingVo> insertTsmpSetting() {
7272
createTsmpSetting("LDAP_DN","uid={{0}},dc=tstpi,dc=com","ldap login user DN");
7373
createTsmpSetting("LDAP_TIMEOUT","3000","Connection timeout for ldap login, in milliseconds(ms)");
7474
createTsmpSetting("LDAP_CHECK_ACCT_ENABLE","false","LDAP check account function enablement - true/false");
75-
7675
createTsmpSetting("TSMP_AC_CLIENT_ID","YWRtaW5Db25zb2xl","Login AC account (do not modify)");
7776
createTsmpSetting("TSMP_AC_CLIENT_PW","dHNtcDEyMw==","AC login password (do not modify)");
78-
7977
createTsmpSetting("TSMP_FAIL_THRESHOLD","6","Allowed \"User password\" fail THRESHOLD");
8078
createTsmpSetting("SSO_PKCE","true","PKCE Level AuthCode verification enablement - true/false");
8179
createTsmpSetting("SSO_DOUBLE_CHECK","true","Enablement of Double-check verification - true/false");
@@ -126,12 +124,12 @@ public List<TsmpSettingVo> insertTsmpSetting() {
126124
createTsmpSetting((id = "ES_URL"), (value = "https://es.example.com:19200/"), (memo = "The URL of ES, there must be a / line at the end, multiple groups are separated by commas (,), EX: https://es.example.com:19200/, https://es.example.com:29200/"));
127125
createTsmpSetting((id = "ES_ID_PWD"), (value = "ENC(cGxlYXNlIHNldCB5b3VyIGVzIGlkIGFuZCBwYXNzd29yZCwgU2V0dGluZyBpcyBFU19JRF9QV0Q=)"), (memo = "ES's ID:PWD is combined and encrypted with Base64; you can press the button\"ENC\" to encrypt with ENC. If you want to set for multiple URLs - Separated by commas before ENC encryption, EX:ENC(id1:pwd1,id2:pwd2)"));
128126
createTsmpSetting((id = "ES_TEST_TIMEOUT"), (value = "3000"), (memo = "ES connection timeout setting for testing"));
129-
createTsmpSetting((id = "ES_MBODY_MASK_FLAG"), (value = "false"), (memo = "Mask all mbody, true is masking, false is not masking"));
127+
createTsmpSetting((id = "ES_MBODY_MASK_FLAG"), (value = "false"), (memo = "ES log and log, mask all mbody, true is masking, false is not masking"));
130128
createTsmpSetting((id = "ES_IGNORE_API"), (value = ""), (memo = "Ignore the assigned API transation recording in the ES, API list can be list and separated by commas (,), and the value is moduleName/apiId"));
131-
createTsmpSetting((id = "ES_MBODY_MASK_API"), (value = ""), (memo = "Do mbody mask for the API of tsmpc, API list can be separated by commas (,), and the value is moduleName/apiId"));
129+
//createTsmpSetting((id = "ES_MBODY_MASK_API"), (value = ""), (memo = "Do mbody mask for the API of tsmpc, API list can be separated by commas (,), and the value is moduleName/apiId"));
132130
createTsmpSetting((id = "ES_TOKEN_MASK_FLAG"), (value = "true"), (memo = "Mask token, true is masking, false is not masking"));
133-
createTsmpSetting((id = "ES_MAX_SIZE_MBODY_MASK"), (value = "0"), (memo = "Auto mbody mask when the length exceeding the mbody content value byte, the unit is byte, and the value below 10 (inclusive) will not be masked"));
134-
createTsmpSetting((id = "ES_DGRC_MBODY_MASK_URI"), (value = ""), (memo = "Make an mbody mask on the URI of dgrc (value contains /dgrc), URL lists are separate by commas, Value format / dgrc/aa/bb/cc"));
131+
createTsmpSetting((id = "ES_MAX_SIZE_MBODY_MASK"), (value = "0"), (memo = "ES log and log, auto mbody mask when the length exceeding the mbody content value byte, the unit is byte, and the value below 10 (inclusive) will not be masked"));
132+
//createTsmpSetting((id = "ES_DGRC_MBODY_MASK_URI"), (value = ""), (memo = "Make an mbody mask on the URI of dgrc (value contains /dgrc), URL lists are separate by commas, Value format / dgrc/aa/bb/cc"));
135133
createTsmpSetting((id = "ES_DGRC_IGNORE_URI"), (value = ""), (memo = "ES does not record URIs for dgrc(Value contains /dgrc), URL lists are separate by commas (,),Value is /dgrc/aa/bb/cc"));
136134
createTsmpSetting((id = "ES_LOG_DISABLE"), (value = "true"), (memo = "Whether to prohibit the recording of ES LOG, true means yes, false means no"));
137135
createTsmpSetting((id = "DGR_PATHS_COMPATIBILITY"), (value = "2"), (memo = "URL Path compatibility, 0: tsmpc only, 1 : dgrc only, 2 : tsmpc dgrc Compatible"));
@@ -199,6 +197,7 @@ public List<TsmpSettingVo> insertTsmpSetting() {
199197
//對外公開的Port
200198
createTsmpSetting((id = "DGR_PUBLIC_PORT"), (value = "18080"), (memo = "Public port, ex: 80"));
201199

200+
202201
// -- 20230421, v4 GTW IdP 的設定, Mini Lee
203202
// 前端 GTW IdP errMsg 顯示訊息的URL
204203
createTsmpSetting((id = "GTW_IDP_MSG_URL"), (value = "https://localhost:8080/dgrv4/ac4/gtwidp/errMsg"), (memo = "URL of frontend GTW IdP error message display message"));
@@ -340,7 +339,22 @@ public List<TsmpSettingVo> insertTsmpSetting() {
340339
// -- 2025/12/01, Mini Lee, AC_IDP 登入時, username 是否做 base64 編碼 (true/false)(default: false)
341340
createTsmpSetting((id = "AC_IDP_USERNAME_B64_ENCODE"), (value = "false"), (memo = "When logging into AC_IDP, does the username use base64 encoding (true/false) (default: false)"));
342341

343-
} catch (Exception e) {
342+
// --2025/12/15, Session Cookie token, Tom
343+
createTsmpSetting((id = "DGR_SESSION_COOKIE_TOKEN_ENABLE"),(value = "false"),(memo="Specifies whether the session cookie token is enabled. The default value is false (true/false)."));
344+
345+
// -- 2025/12/22, Zoe Lee 對外公開的 scheme
346+
createTsmpSetting("DGR_PUBLIC_SCHEME", "https", "Public scheme ex: http https");
347+
348+
// --2026/1/13, Global masking preserves characters, Tom
349+
createTsmpSetting((id = "ES_MBODY_MASK_RESERVED_CHAR"),(value = "5"),(memo="ES log and log, global mask reserved characters, minimum value is 5."));
350+
351+
// -- 2026/01/15 , Zoe Lee kibana cookie bypass path
352+
createTsmpSetting("KIBANA_COOKIE_BYPASS_PATHS", "/api/monitoring/", "A list of Kibana's internal API paths that should bypass the one-minute cookie expiration check. Used for background polling APIs.");
353+
354+
// -- 2026/01/15, token的設定, Mini Lee, 核發 client_credentials token 是否使用 cache? (true/false) (預設為false)
355+
createTsmpSetting("DGR_TOKEN_CLIENT_CREDENTIALS_CACHE_ENABLE", "false", "Does the client_credentials token use a cache? (true/false) (default: false)");
356+
357+
} catch (Exception e) {
344358
StackTraceUtil.logStackTrace(e);
345359
throw e;
346360
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
connection.project.dir=..
1+
connection.project.dir=../dgrv4_Gateway_serv
22
eclipse.preferences.version=1

dgrv4_Entity_lib/src/main/java/tpi/dgrv4/entity/entity/DpUser.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ public class DpUser implements Serializable, DgrSequenced {
5656
@Column(name = "dp_user_name")
5757
private String dpUserName;
5858

59+
@Column(name = "status")
60+
private String status;
61+
5962
public Long getDpUserId() {
6063
return dpUserId;
6164
}
@@ -152,13 +155,21 @@ public void setDpUserName(String dpUserName) {
152155
this.dpUserName = dpUserName;
153156
}
154157

158+
public String getStatus() {
159+
return status;
160+
}
161+
162+
public void setStatus(String status) {
163+
this.status = status;
164+
}
165+
155166
@Override
156167
public String toString() {
157-
return "DpUser [dpUserId=" + dpUserId + ", userAlias=" + userAlias
158-
+ ", idTokenJwtstr=" + idTokenJwtstr + ", userIdentity=" + userIdentity + ", createDateTime="
159-
+ createDateTime + ", createUser=" + createUser + ", updateDateTime=" + updateDateTime + ", updateUser="
160-
+ updateUser + ", version=" + version + ", keywordSearch=" + keywordSearch + ", iss=" + iss
161-
+ ", dpUserName=" + dpUserName + "]";
168+
return "DpUser [dpUserId=" + dpUserId + ", userAlias=" + userAlias + ", idTokenJwtstr=" + idTokenJwtstr
169+
+ ", userIdentity=" + userIdentity + ", createDateTime=" + createDateTime + ", createUser=" + createUser
170+
+ ", updateDateTime=" + updateDateTime + ", updateUser=" + updateUser + ", version=" + version
171+
+ ", keywordSearch=" + keywordSearch + ", iss=" + iss + ", dpUserName=" + dpUserName + ", status="
172+
+ status + "]";
162173
}
163174

164175
@Override

dgrv4_Entity_lib/src/main/java/tpi/dgrv4/entity/repository/TsmpGroupApiDaoImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public List<TsmpGroupApiTopN> findReferApiBindDpApp(String apiKey, String module
162162

163163
sb.append(
164164
" SELECT new tpi.dgrv4.entity.entity.TsmpGroupApiTopN(tga.moduleName, tga.apiKey, COUNT(DISTINCT da.dpApplicationId)) ");
165-
sb.append(" FROM TsmpGroupApi tga, TsmpClientGroup tcg, TsmpClient tc, DpApp da , TsmpApi ta");
165+
sb.append(" FROM TsmpGroupApi tga, TsmpClientGroup tcg, TsmpClient tc, DpApp da");
166166
sb.append(" WHERE 3 = 3 ");
167167

168168
if (StringUtils.hasText(apiKey) && StringUtils.hasText(moduleNmae)) {

0 commit comments

Comments
 (0)