This commit is contained in:
Mauve
2026-09-29 21:55:52 +08:00
parent 3b6f0495a3
commit 32945d7469
31 changed files with 1473 additions and 268 deletions
@@ -16,6 +16,7 @@ import com.mgm.mcrm.common.utils.NetworkUtil;
import com.mgm.mcrm.logging.models.SysLogLogin;
import com.mgm.mcrm.logging.models.SysLogOperation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.springframework.boot.system.ApplicationHome;
@@ -24,8 +25,12 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.lang.reflect.Field;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -50,7 +55,9 @@ public class SysCommon {
private static Map<String,String> notifyTemplateMap = new HashMap<String,String>();
private static final Map<String,AppServerState> appServerStates = new HashMap<String,AppServerState>();
private static final List<String> allowOriginSource = new ArrayList<String>();
@Getter
private static final List<String> soapServers = new ArrayList<String>();
@Getter
private static final List<String> httpApiServers = new ArrayList<String>();
private static final List<String> allowIPSource = new ArrayList<String>();
// @Autowired
@@ -635,4 +642,20 @@ public class SysCommon {
}
return isAllow;
}
public static X509TrustManager getDefaultTrustManager() {
try {
// 获取 JVM 默认的 TrustManager 作为核心校验逻辑
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // 使用系统的默认信任库
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
return (X509TrustManager) tm;
}
}
}catch(Exception err){
LogUtil.error(SysCommon.class,"Default X509TrustManager not found["+err.getMessage()+"]");
}
return null;
}
}
@@ -1,5 +1,9 @@
package com.mgm.mcrm.common.httpclient;
import com.mgm.mcrm.common.constants.SysCommon;
import com.mgm.mcrm.common.services.ConfigurableTrustHandler;
import lombok.Getter;
import lombok.Setter;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts;
@@ -26,7 +30,11 @@ import java.security.cert.CertificateException;
* @version 2.0 (client5)
*/
public class HttpSslSupport {
private static final SSLHandler SIMPLE_VERIFIER = new SSLHandler();
@Getter
@Setter
private static boolean skipValidation=true;
private static ConfigurableTrustHandler trustHandler=null;
private static SSLSocketFactory sslFactory;
// 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated,
@@ -46,42 +54,13 @@ public class HttpSslSupport {
return new HttpSslSupport();
}
/**
* 重写 X509TrustManager 和 HostnameVerifier,信任所有证书与主机名。
* 仅推荐在内部环境或调试场景使用。
*/
private static class SSLHandler implements X509TrustManager, HostnameVerifier {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有服务器证书
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws CertificateException {
// 信任所有客户端证书
}
@Override
public boolean verify(String paramString, SSLSession paramSSLSession) {
// 信任所有主机名
return true;
public static ConfigurableTrustHandler getTrustHandler(){
if(trustHandler==null){
trustHandler =new ConfigurableTrustHandler(skipValidation, SysCommon.getDefaultTrustManager(), SysCommon.getHttpApiServers());
}
return trustHandler;
}
/**
* 获取默认 HostnameVerifier(信任所有主机名)
*/
public static HostnameVerifier getVerifier() {
return SIMPLE_VERIFIER;
}
/**
* 获取信任所有证书的 {@link SSLSocketFactory}
@@ -92,7 +71,9 @@ public class HttpSslSupport {
}
try {
SSLContext context = getSSLContext(sslpv);
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, null);
context.init(null, new TrustManager[]{
getTrustHandler()
}, null);
sslFactory = context.getSocketFactory();
return sslFactory;
} catch (KeyManagementException e) {
@@ -113,8 +94,11 @@ public class HttpSslSupport {
}
try {
SSLContext context = getSSLContext(sslpv);
context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, new java.security.SecureRandom());
sslConnFactory = new SSLConnectionSocketFactory(context, SIMPLE_VERIFIER);
ConfigurableTrustHandler trustHandler = getTrustHandler();
context.init(null, new TrustManager[]{
trustHandler
}, new java.security.SecureRandom());
sslConnFactory = new SSLConnectionSocketFactory(context, trustHandler);
return sslConnFactory;
} catch (KeyManagementException e) {
throw new RuntimeException("初始化 SSLConnectionSocketFactory 失败", e);
@@ -4,9 +4,12 @@ import com.mgm.mcrm.appsetting.models.SysSetting;
import com.mgm.mcrm.appsetting.services.SysSettingService;
import com.mgm.mcrm.common.constants.SysCommon;
import com.mgm.mcrm.common.dtos.system.AppServerState;
import com.mgm.mcrm.common.httpclient.HttpSslSupport;
import com.mgm.mcrm.common.jms.AppControlMsgSender;
import com.mgm.mcrm.common.utils.ExcelUtils;
import com.mgm.mcrm.common.utils.HttpUtil;
import com.mgm.mcrm.common.utils.NetworkUtil;
import com.mgm.mcrm.common.utils.SOAPUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -29,6 +32,14 @@ public class ConfigListener implements ApplicationListener<ApplicationStartedEve
private String httpApiServers;
@Value("${allow_ip}")
private String allowIP;
@Value("${trust-store.http-support.skip-validation}")
private boolean skipHttpSupportValidation;
@Value("${trust-store.http-util.skip-validation}")
private boolean skipHttpUtilValidation;
@Value("${trust-store.soap-util.skip-validation}")
private boolean skipSoapUtilValidation;
@Resource
private SysSettingService sysSettingService;
@Autowired
@@ -49,6 +60,12 @@ public class ConfigListener implements ApplicationListener<ApplicationStartedEve
SysCommon.loadApiServerConfig(httpApiServers);
SysCommon.loadAllowIPConfig(allowIP);
ExcelUtils.loadExcelDefines();
//-- Set Trust Manager validation
HttpSslSupport.setSkipValidation(skipHttpSupportValidation);
HttpUtil.setSkipValidation(skipHttpUtilValidation);
SOAPUtil.setSkipValidation(skipSoapUtilValidation);
if(ctrlMsgSender!=null) {
AppServerState serverState = SysCommon.refreshAppServerState();
SysCommon.jmsRunning = ctrlMsgSender.sendMessage("REQ_SYNC_SERVER_STATE",serverState);
@@ -0,0 +1,63 @@
package com.mgm.mcrm.common.services;
import com.mgm.mcrm.common.utils.LogUtil;
import org.apache.commons.lang3.Strings;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import java.util.List;
public class ConfigurableTrustHandler implements X509TrustManager, HostnameVerifier {
private final boolean skipValidation;
private final X509TrustManager defaultTrustManager;
private final List<String> allowedServers;
public ConfigurableTrustHandler(boolean skipValidation, X509TrustManager defaultTrustManager, List<String> allowedServers ) {
this.skipValidation = skipValidation;
this.defaultTrustManager = defaultTrustManager;
this.allowedServers = allowedServers;
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
if (skipValidation) {
return new java.security.cert.X509Certificate[0];
}else{
return defaultTrustManager != null ? defaultTrustManager.getAcceptedIssuers() : new java.security.cert.X509Certificate[0];
}
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
if (!skipValidation && defaultTrustManager != null) {
defaultTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
String authType) throws java.security.cert.CertificateException {
if (!skipValidation && defaultTrustManager != null) {
defaultTrustManager.checkClientTrusted(chain, authType);
}
}
@Override
public boolean verify(String hostname, SSLSession paramSSLSession) {
boolean isAllow = skipValidation;
if(!skipValidation && allowedServers!=null && !allowedServers.isEmpty()){
for(String allowItem:allowedServers) {
if(Strings.CI.startsWith(hostname, allowItem)) {
isAllow=true;
break;
}
}
}
if(!skipValidation && !isAllow) {
LogUtil.warn(ConfigurableTrustHandler.class, "API Server of ["+hostname+"] is not allowed");
}
return isAllow;
}
}
@@ -38,13 +38,15 @@ public class MGMEsbLimoApiService {
public HttpResponseResult invokeLimoOverrider(
String overriderIdOrName
String overriderIdOrName,
String employeeId
) throws Exception {
JSONObject requestObj = new JSONObject();
Map<String, String> requestHeader = new HashMap<>();
requestObj.put("OverriderIdOrName", "%");
// requestObj.put("EmployeeId", employeeId);
return mgmEsbApiService.invokeESBAPI(ESB_LIMO_API_TYPE, API_GET_LIMO_OVERRIDER, requestObj, "POST", requestHeader);
}
@@ -1,9 +1,16 @@
package com.mgm.mcrm.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.mgm.mcrm.common.constants.SysCommon;
import com.mgm.mcrm.common.dtos.config.ApiGatewaySetting;
import com.mgm.mcrm.common.dtos.http_util.HttpRequestDefine;
import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult;
import com.mgm.mcrm.common.services.ConfigurableTrustHandler;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.classic.methods.HttpGet;
@@ -35,19 +42,30 @@ import org.springframework.web.multipart.MultipartFile;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class HttpUtil {
@Getter
@Setter
private static boolean skipValidation=true;
private static ConfigurableTrustHandler trustHandler=null;
public static ConfigurableTrustHandler getTrustHandler(){
if(trustHandler==null){
trustHandler =new ConfigurableTrustHandler(skipValidation, SysCommon.getDefaultTrustManager(), SysCommon.getHttpApiServers());
}
return trustHandler;
}
//-----------
public static HttpResponseResult processHttpRequest(HttpRequestDefine request) {
HttpResponseResult responseResult = new HttpResponseResult();
@@ -200,33 +218,7 @@ public class HttpUtil {
// 这里可以填两种值 TLS和LLS , 具体差别可以自行搜索
SSLContext sc = SSLContext.getInstance("TLS");
// 构建新对象
X509TrustManager manager = new X509TrustManager() {
@Override
public void checkServerTrusted(X509Certificate[] chain, String arg1) throws CertificateException {
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException("No server certificates provided");
}
for (X509Certificate cert : chain) {
cert.checkValidity();
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String arg1) throws CertificateException {
if (chain == null || chain.length == 0) {
throw new CertificateException("No client certificates provided");
}
for (X509Certificate cert : chain) {
cert.checkValidity(); // 检查证书是否在有效期内
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
};
ConfigurableTrustHandler manager = getTrustHandler();
sc.init(null, new TrustManager[]{manager}, null);
return sc;
} catch (Exception e) {
@@ -259,4 +251,48 @@ public class HttpUtil {
}
return sb.toString();
}
public static HttpResponseResult invokeGatewayEmailAPI(JSONObject requestContent, String requestMethod,
MultipartFile[] files, ApiGatewaySetting apiGatewaySetting) throws Exception {
String serverUrl = apiGatewaySetting.getNotificationProxyUrl();
int timeoutTime = apiGatewaySetting.getRequestTimeout();
HttpRequestDefine requestDef = new HttpRequestDefine();
String apiLink="/send_email";
String requestUrl = serverUrl + apiLink;
Map<String, String> requestHeader = new HashMap<String,String>();
requestHeader.put("Origin", "MGM_CRM_CMS");
requestHeader.put("application-id", apiGatewaySetting.getNotificationAppId());
requestHeader.put("authorization", apiGatewaySetting.getNotificationAppSecret());
requestHeader.put("Content-type", "application/json;charset=utf-8");
requestDef.setRequestUrl(requestUrl);
requestDef.setRequestMethod(requestMethod);
requestDef.setTimeout(timeoutTime);
requestDef.setHeaders(requestHeader);
if(files!=null) {
requestDef.setUpload(true);
requestDef.setUploadFile(files[0]);
requestDef.setFileParaName(files[0].getName());
}
if(requestContent!=null) {
requestDef.setEntityContent(requestContent.toString());
}else {
requestDef.setEntityContent("");
}
// --
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API] start request:" + requestDef.getRequestUrl());
HttpResponseResult httpResult =HttpUtil.processHttpRequest(requestDef);
httpResult.setRequestContent(requestDef.getEntityContent());
Gson gson = new Gson();
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getRequestUrl:"+gson.toJson(requestDef.getRequestUrl()));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getHeaders:"+gson.toJson(requestDef.getHeaders()));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getRequestMethod:"+gson.toJson(requestDef.getRequestMethod()));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getEntityContent:"+gson.toJson(requestContent));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getStatusCode:"+gson.toJson(httpResult.getStatusCode()));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getErrorMessage:"+gson.toJson(httpResult.getErrorMessage()));
LogUtil.info(HttpUtil.class, "[invoke Proxy Email API]getResponseContent:"+gson.toJson(httpResult.getResponseContent()));
return httpResult;
}
}
@@ -2,13 +2,15 @@ package com.mgm.mcrm.common.utils;
import com.mgm.mcrm.common.constants.SysCommon;
import com.mgm.mcrm.common.dtos.config.ApiGatewaySetting;
import com.mgm.mcrm.common.services.ConfigurableTrustHandler;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.soap.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.core5.http.message.BasicHeader;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
@@ -17,9 +19,6 @@ import javax.xml.namespace.QName;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;
@@ -40,6 +39,19 @@ public class SOAPUtil {
* 参考---》http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?op=getWeatherbyCityName
*/
@Getter
@Setter
private static boolean skipValidation=true;
private static ConfigurableTrustHandler trustHandler=null;
public static ConfigurableTrustHandler getTrustHandler(){
if(trustHandler==null){
trustHandler =new ConfigurableTrustHandler(skipValidation, SysCommon.getDefaultTrustManager(), SysCommon.getSoapServers());
}
return trustHandler;
}
public static String getWebServiceSOAP(String url, String action, StringBuffer sendSoapString, ApiGatewaySetting apiGatewaySetting){
String soap = sendSoapString.toString();
if (soap == null) {
@@ -52,8 +64,9 @@ public class SOAPUtil {
HttpURLConnection conn = (HttpURLConnection) soapUrl.openConnection();
if(isHttps) {
HttpsURLConnection https = (HttpsURLConnection) conn;
trustAllHosts(https);
https.setHostnameVerifier(checkSoapServer);
ConfigurableTrustHandler manager = getTrustHandler();
trustAllHosts(https,manager);
https.setHostnameVerifier(manager);
}
conn.setUseCaches(false);
conn.setDoInput(true);
@@ -107,8 +120,9 @@ public class SOAPUtil {
HttpURLConnection conn = (HttpURLConnection) soapUrl.openConnection();
if(isHttps) {
HttpsURLConnection https = (HttpsURLConnection) conn;
trustAllHosts(https);
https.setHostnameVerifier(checkSoapServer);
ConfigurableTrustHandler manager = getTrustHandler();
trustAllHosts(https,manager);
https.setHostnameVerifier(manager);
}
conn.setUseCaches(false);
conn.setDoInput(true);
@@ -162,63 +176,14 @@ public class SOAPUtil {
}
return soapMessage;
}
private static final TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
private X509TrustManager defaultTrustManager=null;
{
try {
// 获取 JVM 默认的 TrustManager 作为核心校验逻辑
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // 使用系统的默认信任库
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) tm;
}
}
}catch(Exception err){
LogUtil.error(SOAPUtil.class,"Default X509TrustManager not found["+err.getMessage()+"]");
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return defaultTrustManager.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkServerTrusted(chain,authType);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain,authType);
}
}};
private static final HostnameVerifier checkSoapServer = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
boolean isServerAllow = SysCommon.isAllowSoapServer(hostname);
if(isServerAllow==false) {
LogUtil.warn(SOAPUtil.class, "SOAP Server of ["+hostname+"] is not allowed");
}
return SysCommon.isAllowSoapServer(hostname);
}
};
/**
* 信任所有
* @param connection
* @return
*/
private static SSLSocketFactory trustAllHosts(HttpsURLConnection conn) {
private static SSLSocketFactory trustAllHosts(HttpsURLConnection conn,ConfigurableTrustHandler manager) {
SSLSocketFactory oldFactory = conn.getSSLSocketFactory();
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
sc.init(null, new TrustManager[]{manager}, new java.security.SecureRandom());
SSLSocketFactory newFactory = sc.getSocketFactory();
conn.setSSLSocketFactory(newFactory);
} catch (Exception e) {
@@ -278,7 +278,7 @@ public class SendEmail {
}else {
mail_to = SysCommon.apiConfig.getSend_to_SMTP();
}
sender.setHost(mail_smtp_host);
sender.setPort(mail_port); // 默认就是25
sender.setUsername(mail_sender);
@@ -486,7 +486,7 @@ public class SendEmail {
+format.format(bookView.getCheckoutDate())+
"</td> " +
"<td>"
+(bookView.getBookerTeam()!=null?bookView.getBookerTeam():"")+
+(bookView.getSectionName()!=null?bookView.getSectionName():"")+
"</td> " +
"<td>"
+bookView.getCreatedBy()+
@@ -651,7 +651,7 @@ public class SendEmail {
+format.format(bookView.getCheckoutDate())+
"</td> " +
"<td>"
+(bookView.getBookerTeam()!=null?bookView.getBookerTeam():"")+
+(bookView.getSectionName()!=null?bookView.getSectionName():"")+
"</td> " +
"<td>"
+bookView.getCreatedBy()+
@@ -835,7 +835,7 @@ public class SendEmail {
+format.format(book.getCheckoutDate())+
"</td> " +
"<td>"
+(viewBook.getBookerTeam()!=null?viewBook.getBookerTeam():"")+
+(viewBook.getSectionName()!=null?viewBook.getSectionName():"")+
"</td> " +
"<td>"
+originBook.getCreatedBy()+
@@ -916,7 +916,6 @@ public class SendEmail {
public static Email sendCancelEmail(Bookings book,BookingsView bookingsView,Email emailObj,String userId,String userName,String emailTo) {
String content1 = cancelEmailTemp;
try {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
if(StringUtils.isEmpty(mail_smtp_host)) {