Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3574ad9e0c | |||
| 49eb8fbe85 | |||
| 253716f4b2 | |||
| 02e282c7ba | |||
| 180ea8cac1 | |||
| 2c21c691df | |||
| 0da31a8de2 | |||
| 46d88d77f2 | |||
| 51967284ba | |||
| a218291748 |
@@ -142,6 +142,7 @@ dependencies {
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.15'
|
||||
testImplementation 'junit:junit:4.4'
|
||||
testImplementation files('libs/damo-manager.jar', 'libs/kjb-safedb.jar')
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.adapter.http.client.impl.kjb;
|
||||
package com.eactive.eai.adapter.http.client.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
@@ -43,7 +43,6 @@ import com.eactive.eai.adapter.http.HttpMethodType;
|
||||
import com.eactive.eai.adapter.http.client.HttpClient5AdapterServiceSupport;
|
||||
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.client.HttpClientAdapterVO;
|
||||
import com.eactive.eai.adapter.http.client.impl.HttpClientAdapterServiceRest;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.impl.HttpAdapterServiceBypass;
|
||||
import com.eactive.eai.common.TransactionContextKeys;
|
||||
@@ -70,13 +70,13 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H
|
||||
throw e;
|
||||
} catch (JwtAuthException e) { // filter error
|
||||
logger.error(LOG_PREFIX + transactionId + "-" + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
|
||||
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
|
||||
"RECEAIIRP202", e);
|
||||
// UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
|
||||
// "RECEAIIRP202", e);
|
||||
throw e;
|
||||
} catch (Exception e) { // filter error
|
||||
logger.error(LOG_PREFIX + transactionId + "-" + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
|
||||
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
|
||||
"RECEAIIRP201", e);
|
||||
// UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
|
||||
// "RECEAIIRP201", e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.nimbusds.jose.JWSVerifier;
|
||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||
import com.nimbusds.jose.util.IOUtils;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -141,26 +143,32 @@ public class ApiAuthFilter implements HttpAdapterFilter {
|
||||
|
||||
OAuth2Manager manager = OAuth2Manager.getInstance();
|
||||
HashSet<String> scopeSet = manager.getApiScopeMap().get(apiId);
|
||||
|
||||
String[] scopeArr = signedJWT.getJWTClaimsSet().getStringArrayClaim(PAYLOAD_PARAM_NAME_SCOPE);
|
||||
if (scopeArr == null || scopeArr.length == 0) {
|
||||
throw new JwtAuthException(ERROR_AUTHORIZATION_FAIL,
|
||||
String.format("Insufficient [Scope](Allowed Scope=%s)", scopeSet.toString()));
|
||||
}
|
||||
|
||||
for (String scope : scopeArr) {
|
||||
if (StringUtils.equals(scope, "oob") || StringUtils.equals(scope, "public")) {
|
||||
isPassScope = true;
|
||||
}
|
||||
}
|
||||
// API에 scope 설정이 안되어 있는 경우, scope 체크를 pass하고 나중에 client API 맵을 체크한다.
|
||||
if(CollectionUtils.isEmpty(scopeSet))
|
||||
isPassScope = true;
|
||||
|
||||
if (!isPassScope) {
|
||||
if (!verifyScope(scopeSet, signedJWT)) {
|
||||
if(!isPassScope) {
|
||||
String[] scopeArr = signedJWT.getJWTClaimsSet().getStringArrayClaim(PAYLOAD_PARAM_NAME_SCOPE);
|
||||
if (scopeArr == null || scopeArr.length == 0) {
|
||||
throw new JwtAuthException(ERROR_AUTHORIZATION_FAIL,
|
||||
String.format("Insufficient [Scope](Allowed Scope=%s)", scopeSet.toString()));
|
||||
}
|
||||
|
||||
for (String scope : scopeArr) {
|
||||
if (StringUtils.equals(scope, "oob") || StringUtils.equals(scope, "public")) {
|
||||
isPassScope = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPassScope) {
|
||||
if (!verifyScope(scopeSet, signedJWT)) {
|
||||
throw new JwtAuthException(ERROR_AUTHORIZATION_FAIL,
|
||||
String.format("Insufficient [Scope](Allowed Scope=%s)", scopeSet.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// header 값으로 전송된 clientId와 토큰 소유 clientId check
|
||||
if (!verifyClientId(prop, signedJWT)) {
|
||||
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "client_id not matched(header/token)");
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
|
||||
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
|
||||
@@ -48,7 +49,7 @@ public class ApiKeyExtractFilter implements HttpAdapterFilter {
|
||||
// PathVariable 지원 추가
|
||||
String ruledPath = getMatchedKey(requestPath);
|
||||
if(ruledPath == null)
|
||||
throw new IllegalAccessException("path not found - " + requestPath);
|
||||
throw new FilterException("path not found - " + requestPath, ERROR_PRE_FAIL, HttpStatus.FORBIDDEN.value());
|
||||
prop.setProperty(FINAL_STD_MESSAGE_KEY, ruledPath);// StandardMessageUtil.getMatchedKey(), url
|
||||
// pathvariable도 처리
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface HttpAdapterFilter {
|
||||
|
||||
public static final String ERROR_PRE_FAIL = "E.PREFILTER_FAIL";
|
||||
public static final String ERROR_POST_FAIL = "E.POSTFILTER_FAIL";
|
||||
|
||||
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
|
||||
HttpServletRequest request, HttpServletResponse response) throws Exception;
|
||||
|
||||
|
||||
+47
-42
@@ -1,5 +1,27 @@
|
||||
package com.eactive.eai.adapter.http.dynamic.impl;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.apache.mina.common.ByteBuffer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
import com.eactive.eai.adapter.AdapterGroupVO;
|
||||
import com.eactive.eai.adapter.AdapterManager;
|
||||
import com.eactive.eai.adapter.AdapterPropManager;
|
||||
@@ -8,8 +30,8 @@ import com.eactive.eai.adapter.Keys;
|
||||
import com.eactive.eai.adapter.http.HttpMemoryLogger;
|
||||
import com.eactive.eai.adapter.http.HttpStatusException;
|
||||
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
|
||||
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
|
||||
import com.eactive.eai.adapter.http.dynamic.UnkownMessageLogUtils;
|
||||
import com.eactive.eai.common.TransactionContextKeys;
|
||||
import com.eactive.eai.common.exception.ExceptionUtil;
|
||||
import com.eactive.eai.common.util.CommonLib;
|
||||
@@ -19,30 +41,6 @@ import com.eactive.eai.common.util.MessageUtil;
|
||||
import com.eactive.eai.env.ElinkConfig;
|
||||
import com.eactive.eai.inbound.processor.Processor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.mina.common.ByteBuffer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.springframework.jms.support.converter.MessageType;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
{
|
||||
public static final String PROPERTIES_NAME_HTTP_REQUEST_METHOD = "httpRequestMethod";
|
||||
@@ -66,7 +64,8 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
|
||||
AdapterGroupVO adapterGroupVo = null;
|
||||
Properties prop = null;
|
||||
|
||||
byte[] requestBytes = null;
|
||||
String encode = "MS949";
|
||||
try {
|
||||
AdapterManager adapterManager = AdapterManager.getInstance();
|
||||
AdapterVO adptVO = adapterManager.getAdapterVO(adptGrpName,adptName);
|
||||
@@ -78,9 +77,9 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
}
|
||||
|
||||
Properties httpProp = manager.getProperties(adptVO.getPropGroupName());
|
||||
encode = StringUtils.defaultIfBlank(adapterManager.getAdapterGroupVO(adptGrpName).getMessageEncode(), "MS949");
|
||||
String responseType = httpProp.getProperty(RESPONSE_TYPE,"SYNC");
|
||||
String urlDecodeYn = httpProp.getProperty(URL_DECODE_YN,"N");
|
||||
String encode = StringUtils.defaultIfBlank(adapterManager.getAdapterGroupVO(adptGrpName).getMessageEncode(), "MS949");
|
||||
String messageType = adapterManager.getAdapterGroupVO(adptGrpName).getMessageType();
|
||||
String requestBodyYn = httpProp.getProperty(REQUEST_BODY_YN,"N");
|
||||
String parameterName = httpProp.getProperty(PARAMETER_NAME,PARAMETER_MESSAGE);
|
||||
@@ -107,7 +106,6 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
|
||||
logger.info("시작 >> encode = [" + encode + "]");
|
||||
|
||||
byte[] requestBytes = null;
|
||||
|
||||
if ("Y".equals(requestBodyYn)){
|
||||
ServletInputStream sis = request.getInputStream();
|
||||
@@ -191,19 +189,19 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
prop.put(PROPERTIES_NAME_HTTP_REQUEST_METHOD, request.getMethod());
|
||||
prop.put(ALLOW_IP, httpProp.getProperty(ALLOW_IP, ""));
|
||||
|
||||
String body = new String ( requestBytes,encode);
|
||||
|
||||
try {
|
||||
Object root = JSONValue.parse(body);
|
||||
if( root instanceof JSONArray ) {
|
||||
JSONObject wrappedObject = new JSONObject();
|
||||
wrappedObject.put("DJB_ROOTLESS_ARRAY", root);
|
||||
requestBytes = wrappedObject.toJSONString().getBytes(encode);
|
||||
}
|
||||
|
||||
}catch (Exception e) {
|
||||
// ignore json이 아니기에 해줄것이 없음.
|
||||
}
|
||||
// String body = new String ( requestBytes,encode);
|
||||
//
|
||||
// try {
|
||||
// Object root = JSONValue.parse(body);
|
||||
// if( root instanceof JSONArray ) {
|
||||
// JSONObject wrappedObject = new JSONObject();
|
||||
// wrappedObject.put("DJB_ROOTLESS_ARRAY", root);
|
||||
// requestBytes = wrappedObject.toJSONString().getBytes(encode);
|
||||
// }
|
||||
//
|
||||
// }catch (Exception e) {
|
||||
// // ignore json이 아니기에 해줄것이 없음.
|
||||
// }
|
||||
|
||||
// 로컬 서비스 호출
|
||||
Object result = null;
|
||||
@@ -338,7 +336,14 @@ public class HttpAdapterServiceStandard extends HttpAdapterServiceSupport
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (traceLevel >= 3){
|
||||
try {
|
||||
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes, encode) : null, prop, request, response,
|
||||
"RECEAIIRP202", e);
|
||||
} catch (UnsupportedEncodingException e1) {
|
||||
UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, requestBytes != null ? new String(requestBytes) : null, prop, request, response,
|
||||
"RECEAIIRP202", e);
|
||||
}
|
||||
if (traceLevel >= 3){
|
||||
HttpMemoryLogger.error(adptGrpName+adptName, e.toString(),e);
|
||||
}
|
||||
logger.error("HttpAdapter] "+adptGrpName+"-"+adptName, e);
|
||||
|
||||
@@ -12,8 +12,8 @@ import com.eactive.eai.common.property.PropManager;
|
||||
import com.eactive.eai.common.server.Keys;
|
||||
import com.eactive.eai.common.util.ApplicationContextProvider;
|
||||
import com.eactive.eai.common.util.Logger;
|
||||
import com.eactive.ext.djb.DamoManager;
|
||||
import com.eactive.ext.kjb.safedb.KjbSafedbWrapper;
|
||||
import com.eactive.ext.kjb.safedb.Utils;
|
||||
|
||||
@Component
|
||||
public class EncryptionManager implements Lifecycle {
|
||||
@@ -130,7 +130,7 @@ public class EncryptionManager implements Lifecycle {
|
||||
if (StringUtils.isNotEmpty(plainText)) {
|
||||
KjbSafedbWrapper wrapper = KjbSafedbWrapper.getInstance();
|
||||
plainText = wrapper.encryptNotRnnoString(plainText);
|
||||
|
||||
|
||||
if (logger.isInfo()) {
|
||||
// originalAttribute 홀수 글자 마스킹
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -161,14 +161,19 @@ public class EncryptionManager implements Lifecycle {
|
||||
public String decryptDBData(String dbData) {
|
||||
if (StringUtils.isNotEmpty(dbData)) {
|
||||
if (this.isEncrypted(dbData)) {
|
||||
KjbSafedbWrapper safeDBWrapper = KjbSafedbWrapper.getInstance();
|
||||
try {
|
||||
dbData = safeDBWrapper.decryptNotRnno(dbData);
|
||||
} catch (Exception e) {
|
||||
// 복호화 실패시 원본 반환
|
||||
String logData = dbData.length() <= 3 ? dbData : dbData.substring(0, 3) + "...";
|
||||
logger.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length());
|
||||
return dbData;
|
||||
if ("DAMO".equals(dbEncryptSolutionName)) {
|
||||
com.eactive.ext.djb.DamoManager damoManager = new com.eactive.ext.djb.DamoManager();
|
||||
return damoManager.decrypt(dbData);
|
||||
} else if ("SAFEDB".equals(dbEncryptSolutionName)) {
|
||||
KjbSafedbWrapper safeDBWrapper = KjbSafedbWrapper.getInstance();
|
||||
try {
|
||||
dbData = safeDBWrapper.decryptNotRnno(dbData);
|
||||
} catch (Exception e) {
|
||||
// 복호화 실패시 원본 반환
|
||||
String logData = dbData.length() <= 3 ? dbData : dbData.substring(0, 3) + "...";
|
||||
logger.warn("DB 복호화 실패: 복호화하지 않고 원본 반환. dbData={} (Length : {})", logData, dbData.length());
|
||||
return dbData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("DB 복호화 경고: Base64 형식이 아님. 복호화하지 않고 원본 반환. dbData={}", dbData);
|
||||
@@ -197,7 +202,7 @@ public class EncryptionManager implements Lifecycle {
|
||||
data = data.trim();
|
||||
|
||||
// Base64 형식 체크
|
||||
if (!Utils.isBase64(data)) {
|
||||
if (!isBase64(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -208,4 +213,13 @@ public class EncryptionManager implements Lifecycle {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isBase64(String str) {
|
||||
if (str == null || str.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String base64Pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$";
|
||||
return str.matches(base64Pattern);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import javax.crypto.SecretKey;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.eactive.eai.agent.encryption.EncryptionManager;
|
||||
import com.eactive.eai.common.exception.ExceptionUtil;
|
||||
import com.eactive.eai.common.lifecycle.Lifecycle;
|
||||
import com.eactive.eai.common.lifecycle.LifecycleException;
|
||||
@@ -81,8 +82,10 @@ public class HsmManager implements Lifecycle {
|
||||
}
|
||||
|
||||
private void init() throws Exception {
|
||||
String configContent = PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG);
|
||||
String pin = PropManager.getInstance().getProperty(GROUP_NAME, PROP_PIN);
|
||||
EncryptionManager encManager = EncryptionManager.getInstance();
|
||||
|
||||
String configContent = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_CONFIG));
|
||||
String pin = encManager.decryptDBData(PropManager.getInstance().getProperty(GROUP_NAME, PROP_PIN));
|
||||
|
||||
if (configContent == null || configContent.trim().isEmpty()) {
|
||||
logger.warn("HsmManager] PKCS11_CONFIG 가 설정되지 않았습니다. HSM 초기화를 건너뜁니다.");
|
||||
|
||||
@@ -1007,7 +1007,14 @@ public class RequestProcessor extends RequestProcessorSupport {
|
||||
if (logger.isError()) logger.error(guidLogPrefix + " : 거래통제 Log 실패 - " + vo.getRspErrorMsg());
|
||||
}
|
||||
|
||||
return restrictResponse;
|
||||
AdapterGroupVO adptGrpVO = AdapterManager.getInstance().getAdapterGroupVO(vo.getAdapterGroupName());
|
||||
if (!Keys.IF_STANDARD.equals(vo.getStdMsgTypeCode()) && StringUtils.equalsAny(adptGrpVO.getType(),
|
||||
Keys.TYPE_REST, Keys.TYPE_HTTP, Keys.TYPE_HTTP_CUSTOM)) {
|
||||
throw new HttpStatusException(eaiMsg.getRspErrMsg(), eaiMsg.getRspErrCd(),
|
||||
HttpStatus.SERVICE_UNAVAILABLE.value());
|
||||
} else {
|
||||
return restrictResponse;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// ExceptionHandler에 의해 에러 응답송신
|
||||
|
||||
@@ -694,35 +694,37 @@ public class RESTProcess extends HTTPProcess {
|
||||
public void setOutboundErrorMessage() throws Exception {
|
||||
this.logPssSno = TranLogUtil.getResLogSeq(this.svcPssTp, this.svcPssSeq, this.isComp);
|
||||
|
||||
boolean setResObject = false;
|
||||
// 에러에 대한 응답메시지
|
||||
if(this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP) instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) this.tempProp.get(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP);
|
||||
this.callProp.put(HttpAdapterServiceKey.OUTBOUND_PROPERTY_MAP, map);
|
||||
}
|
||||
|
||||
boolean setResObject = false;
|
||||
AdapterGroupVO outboundAdapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
|
||||
if (outboundAdapterGroupVO != null) {
|
||||
AdapterVO outboundAdapterVo = null;
|
||||
if(adapterName != null)
|
||||
outboundAdapterVo = outboundAdapterGroupVO.getAdapterVO(adapterName);
|
||||
else
|
||||
outboundAdapterVo = outboundAdapterGroupVO.nextAdapterVO();
|
||||
|
||||
if (outboundAdapterVo != null) {
|
||||
String errorHandlerClass = AdapterPropManager.getInstance().getProperty(
|
||||
outboundAdapterVo.getPropGroupName(), "ERR_MSG_HANDLER");
|
||||
if (StringUtils.isNotBlank(errorHandlerClass)) {
|
||||
if (logger.isInfo())
|
||||
logger.info("ExceptionHandler] errorSyncSend ERR_MSG_HANDLER=" + errorHandlerClass);
|
||||
AdapterErrorMessageHandler handler = AdapterErrorMessageHandlerFactory.createHandler(errorHandlerClass);
|
||||
this.resObject = handler.generateOutboundErrorResponseMessage(adapterGroupName, adapterGroupName,
|
||||
callProp, this.reqObject, this.resEaiMsg);
|
||||
setResObject = true;
|
||||
// OUTBOUND_PROPERTY_MAP 이 있는 경우, 즉 타겟서버와 통신은 정상적으로 이루진 경우 처리한다.
|
||||
AdapterGroupVO outboundAdapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
|
||||
if (outboundAdapterGroupVO != null) {
|
||||
AdapterVO outboundAdapterVo = null;
|
||||
if(adapterName != null)
|
||||
outboundAdapterVo = outboundAdapterGroupVO.getAdapterVO(adapterName);
|
||||
else
|
||||
outboundAdapterVo = outboundAdapterGroupVO.nextAdapterVO();
|
||||
|
||||
if (outboundAdapterVo != null) {
|
||||
String errorHandlerClass = AdapterPropManager.getInstance().getProperty(
|
||||
outboundAdapterVo.getPropGroupName(), "ERR_MSG_HANDLER");
|
||||
if (StringUtils.isNotBlank(errorHandlerClass)) {
|
||||
if (logger.isInfo())
|
||||
logger.info("ExceptionHandler] errorSyncSend ERR_MSG_HANDLER=" + errorHandlerClass);
|
||||
AdapterErrorMessageHandler handler = AdapterErrorMessageHandlerFactory.createHandler(errorHandlerClass);
|
||||
this.resObject = handler.generateOutboundErrorResponseMessage(adapterGroupName, adapterGroupName,
|
||||
callProp, this.reqObject, this.resEaiMsg);
|
||||
setResObject = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!setResObject) {
|
||||
this.resObject = "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.eactive.eai.agent.encryption;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* EncryptionManager 단위 테스트 — DAMO 솔루션 모드.
|
||||
*
|
||||
* damo-manager.jar 가 DAMO 라이브러리(com.penta.scpdb.ScpDbAgent) 없이 로드되면
|
||||
* 자동으로 FAKE MODE 로 동작한다:
|
||||
* encrypt(plain) → Base64 인코딩
|
||||
* decrypt(b64) → Base64 디코딩
|
||||
* 따라서 encrypt → decrypt 라운드트립이 완전히 검증 가능하다.
|
||||
*
|
||||
* EncryptionManager 생성자가 private 이므로 리플렉션으로 인스턴스를 생성하고
|
||||
* 필드를 직접 주입한다.
|
||||
*/
|
||||
class EncryptionManagerTest {
|
||||
|
||||
private EncryptionManager manager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
Constructor<EncryptionManager> ctor = EncryptionManager.class.getDeclaredConstructor();
|
||||
ctor.setAccessible(true);
|
||||
manager = ctor.newInstance();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 헬퍼
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private void setField(String name, Object value) throws Exception {
|
||||
Field f = EncryptionManager.class.getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
f.set(manager, value);
|
||||
}
|
||||
|
||||
private void enableDamo() throws Exception {
|
||||
setField("encryptYN", "Y");
|
||||
setField("dbEncryptSolutionName", "DAMO");
|
||||
}
|
||||
|
||||
private void disableEncrypt() throws Exception {
|
||||
setField("encryptYN", "N");
|
||||
setField("dbEncryptSolutionName", "DAMO");
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 1. DAMO 모드 — encrypt + decrypt 라운드트립
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
@DisplayName("1-1. DAMO 암호화 후 복호화 시 원문 복원 — 한글")
|
||||
void testRoundTrip_korean() throws Exception {
|
||||
enableDamo();
|
||||
String plain = "홍길동";
|
||||
String encrypted = manager.encryptDBData(plain);
|
||||
assertNotEquals(plain, encrypted, "암호화 결과가 원문과 달라야 한다");
|
||||
assertEquals(plain, manager.decryptDBData(encrypted));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("1-2. DAMO 암호화 후 복호화 시 원문 복원 — 영문/숫자 혼합")
|
||||
void testRoundTrip_alphanumeric() throws Exception {
|
||||
enableDamo();
|
||||
String plain = "test@example.com";
|
||||
String encrypted = manager.encryptDBData(plain);
|
||||
assertNotEquals(plain, encrypted);
|
||||
assertEquals(plain, manager.decryptDBData(encrypted));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("1-3. DAMO 암호화 후 복호화 시 원문 복원 — 주민등록번호 형식")
|
||||
void testRoundTrip_idNumber() throws Exception {
|
||||
enableDamo();
|
||||
String plain = "900101-1234567";
|
||||
String encrypted = manager.encryptDBData(plain);
|
||||
// 숫자와 '-' 만으로 이루어진 원문은 암호화되어 Base64 형식으로 변환된다
|
||||
assertNotEquals(plain, encrypted);
|
||||
assertEquals(plain, manager.decryptDBData(encrypted));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("1-4. DAMO 암호화 후 복호화 시 원문 복원 — 다양한 입력 일괄 검증")
|
||||
void testRoundTrip_multipleValues() throws Exception {
|
||||
enableDamo();
|
||||
String[] inputs = {
|
||||
"홍길동",
|
||||
"test@example.com",
|
||||
"900101-1234567",
|
||||
"ABC테스트123",
|
||||
"special chars: !@#$%",
|
||||
"긴문자열긴문자열긴문자열긴문자열긴문자열긴문자열긴문자열긴문자열긴문자열긴문자열"
|
||||
};
|
||||
for (String input : inputs) {
|
||||
String encrypted = manager.encryptDBData(input);
|
||||
String decrypted = manager.decryptDBData(encrypted);
|
||||
assertEquals(input, decrypted, "라운드트립 불일치: [" + input + "]");
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 2. 암호화 비활성(encryptYN=N)
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
@DisplayName("2-1. encryptYN=N 이면 encryptDBData 가 원문 그대로 반환")
|
||||
void testEncrypt_disabled_returnsPlain() throws Exception {
|
||||
disableEncrypt();
|
||||
String plain = "홍길동";
|
||||
assertEquals(plain, manager.encryptDBData(plain));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("2-2. encryptYN=N 상태의 원문은 isEncrypted=false 이므로 decryptDBData 도 원문 반환")
|
||||
void testDecrypt_plainTextNotBase64_returnsOriginal() throws Exception {
|
||||
disableEncrypt();
|
||||
String plain = "홍길동";
|
||||
assertEquals(plain, manager.decryptDBData(plain));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 3. 특수 입력 처리
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
@DisplayName("3-1. decryptDBData — null 입력 시 null 반환")
|
||||
void testDecrypt_null() throws Exception {
|
||||
enableDamo();
|
||||
assertNull(manager.decryptDBData(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("3-2. decryptDBData — 빈 문자열 입력 시 빈 문자열 반환")
|
||||
void testDecrypt_empty() throws Exception {
|
||||
enableDamo();
|
||||
assertEquals("", manager.decryptDBData(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("3-3. decryptDBData — 숫자로만 구성된 값은 복호화하지 않고 원문 반환 (연락처)")
|
||||
void testDecrypt_numericOnly_returnsOriginal() throws Exception {
|
||||
enableDamo();
|
||||
assertEquals("01012345678", manager.decryptDBData("01012345678"));
|
||||
assertEquals("0101234-5678", manager.decryptDBData("0101234-5678"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("3-4. decryptDBData — Base64 형식이 아닌 문자열은 원문 반환")
|
||||
void testDecrypt_nonBase64_returnsOriginal() throws Exception {
|
||||
enableDamo();
|
||||
String plain = "이름: 홍길동"; // 공백 포함, Base64 문자셋 아님
|
||||
assertEquals(plain, manager.decryptDBData(plain));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 4. isEncrypt() / getEncryptYN() 상태 확인
|
||||
// =========================================================================
|
||||
|
||||
@Test
|
||||
@DisplayName("4-1. encryptYN=Y 이면 isEncrypt()=true")
|
||||
void testIsEncrypt_true() throws Exception {
|
||||
setField("encryptYN", "Y");
|
||||
assertTrue(manager.isEncrypt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("4-2. encryptYN=N 이면 isEncrypt()=false")
|
||||
void testIsEncrypt_false() throws Exception {
|
||||
setField("encryptYN", "N");
|
||||
assertFalse(manager.isEncrypt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("4-3. getDBEncryptSolutionName() 반환값 확인")
|
||||
void testGetDBEncryptSolutionName() throws Exception {
|
||||
setField("dbEncryptSolutionName", "DAMO");
|
||||
assertEquals("DAMO", manager.getDBEncryptSolutionName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.eactive.eai.common.hsm;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class HsmManagerSingleTest {
|
||||
|
||||
/**
|
||||
* JDK 버전에 따라 SunPKCS11 Provider 를 생성한다.
|
||||
*
|
||||
* JDK 8 : SunPKCS11(InputStream) 생성자를 리플렉션으로 호출
|
||||
* JDK 9+: Provider.configure(configFilePath) 를 리플렉션으로 호출
|
||||
*
|
||||
* 두 경로 모두 리플렉션을 사용하므로 컴파일 타임에 JDK 버전 의존성이 없다.
|
||||
*/
|
||||
static Provider createProvider(String cfgContent) throws Exception {
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
if (javaVersion.startsWith("1.")) {
|
||||
// JDK 8: new SunPKCS11(InputStream)
|
||||
InputStream is = new ByteArrayInputStream(cfgContent.getBytes("UTF-8"));
|
||||
return (Provider) Class.forName("sun.security.pkcs11.SunPKCS11")
|
||||
.getConstructor(InputStream.class)
|
||||
.newInstance(is);
|
||||
} else {
|
||||
// JDK 9+: Security.getProvider("SunPKCS11").configure(configFilePath)
|
||||
// configure() 는 JDK 9 에서 추가된 메서드이므로 리플렉션으로 호출
|
||||
File tmp = File.createTempFile("pkcs11-hsm-", ".cfg");
|
||||
tmp.deleteOnExit();
|
||||
Files.write(tmp.toPath(), cfgContent.getBytes("UTF-8"));
|
||||
Provider base = Security.getProvider("SunPKCS11");
|
||||
Method configure = Provider.class.getMethod("configure", String.class);
|
||||
return (Provider) configure.invoke(base, tmp.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// String config = "name = ProtectServer\r\n"
|
||||
// + "library = /usr/safenet/protecttoolkit5/ptk/lib/libcryptoki.so\r\n"
|
||||
// + "slot = 0";
|
||||
|
||||
String config = "name = SoftHSM\r\nlibrary = C:/SoftHSM2/lib/softhsm2-x64.dll\r\nslotListIndex = 0\r\n";
|
||||
|
||||
KeyStore keyStore;
|
||||
// Provider pkcs11Provider = HsmManagerSingleTest.createProvider(config);
|
||||
InputStream is = new ByteArrayInputStream(config.getBytes("UTF-8"));
|
||||
Provider pkcs11Provider = (Provider) Class.forName("sun.security.pkcs11.SunPKCS11")
|
||||
.getConstructor(InputStream.class)
|
||||
.newInstance(is);
|
||||
Provider existing = Security.getProvider(pkcs11Provider.getName());
|
||||
Security.addProvider(pkcs11Provider);
|
||||
String pin = "1234";
|
||||
keyStore = KeyStore.getInstance("PKCS11", pkcs11Provider);
|
||||
char[] pinChars = (pin != null) ? pin.toCharArray() : null;
|
||||
keyStore.load(null, pinChars);
|
||||
|
||||
System.out.println("HsmManager] 초기화 완료. Provider=" + pkcs11Provider.getName());
|
||||
|
||||
java.util.Enumeration<String> aliases = keyStore.aliases();
|
||||
StringBuilder aliasList = new StringBuilder();
|
||||
while (aliases.hasMoreElements()) {
|
||||
if (aliasList.length() > 0) aliasList.append(", ");
|
||||
|
||||
String alias = aliases.nextElement();
|
||||
aliasList.append(alias);
|
||||
|
||||
java.security.Key key = keyStore.getKey(alias, null);
|
||||
if (key instanceof SecretKey) {
|
||||
SecretKey secretKey = (SecretKey) key;
|
||||
if(secretKey.getEncoded() != null) {
|
||||
String encBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded());
|
||||
System.out.println("HsmManager] HSM - alias:" + alias +", base64:"+ encBase64);
|
||||
} else {
|
||||
System.out.println("HsmManager] HSM - secretKey null - alias:" + alias + ", secretKey:" + secretKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("HsmManager] HSM 키 목록: [" + aliasList + "]");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user