Merge branch 'jenkins_with_weblogic' of ssh://git@192.168.240.178:18081/eapim/elink-online-common.git into jenkins_with_weblogic

This commit is contained in:
pksup
2025-12-18 16:08:31 +09:00
13 changed files with 696 additions and 78 deletions
@@ -91,7 +91,7 @@ import com.kjbank.encrypt.exchange.crypto.AES256GCMCipher;
import com.kjbank.encrypt.exchange.crypto.ECDHESA256Cipher;
import com.eactive.eai.authserver.service.OAuth2Manager;
import java.util.Set;
import java.util.HashSet;
/**
* 1. 기능 : EAI HTTP OutBound 용 어댑터로 수동 시스템의 HTTP 웹 컴포넌트를 GET/POST 방식으로 호출할 수 있는
@@ -306,7 +306,8 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
accessToken = (OAuth2AccessTokenVO) tokenManager.getAccessTokenVO(vo.getAdapterGroupName());
// 토큰이 없거나 만료 됐으면 재발급
if (accessToken == null || accessToken.isExpired()) {
//if (accessToken == null || accessToken.isExpired()) {
if (accessToken == null || accessToken.isExpired() || accessToken.getAccessToken() == null ) { // jwhong
String oldToken = accessToken == null ? null : accessToken.getAccessToken();
accessToken = (OAuth2AccessTokenVO) tokenManager.retryAccessTokenVO(vo.getAdapterGroupName(), prop,
oldToken);
@@ -321,9 +322,13 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
String encryptAlgorithm = properties.getProperty("ENCRYPT_ALGORITHM"); // jwhong
if (useAdapterToken && "AES256-NICEON".equals(encryptAlgorithm)) {
String niceToken = accessToken.getAccessToken();
String clientId = JwtClientIdExtractor(niceToken);
if ( niceToken == null || niceToken == "") {
throw new Exception("NiceOn Token is empty, TOKEN failed to be issued, TOKEN = [" + niceToken + "]");
}
String clientId = accessToken.getClientId(); // HttpClientAccessTokenServiceWithBase64NiceOn 서 넣어줌
long currentTime = System.currentTimeMillis();
auth = niceToken + ":" + currentTime + ":" + clientId ;
logger.debug("HttpClientAdapterServiceRest] NiceOn auth = [" + auth + "]");
auth = Base64.getEncoder().encodeToString(auth.getBytes("UTF-8"));
setNiceOnAuthHeaders(method, auth);
@@ -827,46 +832,96 @@ public class HttpClient5AdapterServiceRest extends HttpClient5AdapterServiceSupp
// map에 담기
Map<String, String> map = new HashMap<>();
for (String entry : entries) {
String[] kv = entry.split("=", 2);
if (kv.length == 2) {
map.put(kv[0].trim(), kv[1].trim());
}
String[] kv = entry.split("=", 2);
if (kv.length == 2) {
map.put(kv[0].trim(), kv[1].trim());
}
}
for (String k : map.keySet()) {
if (k.equalsIgnoreCase("authorization")) {
authorization = map.get(k);
break;
}
if (k.equalsIgnoreCase("authorization")) {
authorization = map.get(k);
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
e.printStackTrace();
}
String jwtToken = "";
if (authorization != null && authorization.startsWith("Bearer ")) {
jwtToken = authorization.substring(7); // "Bearer " 이후의 JWT만 추출
jwtToken = authorization.substring(7); // "Bearer " 이후의 JWT만 추출
}
String headerRelay = PropManager.getInstance().getProperty("HEADER_RELAY_ADAPTER","adapter.name");
Set<String> values = new HashSet<>(Arrays.asList(headerRelay.split(",")));
String inputAdapter = tempProp.getProperty(HttpAdapterServiceKey.OUT_ADAPTER_GROUP_NAME, "");
String[] parts = inputAdapter.split("_");
String target = parts[1]; // adapter name의 앞의 3자리
String adapterName = target.substring(0, 3);
if (values.contains(adapterName)) {
/* 업체정보 */
String clientId = JwtClientIdExtractor(jwtToken);
method.setHeader("clientId", clientId);
/* APIM 거래추적자 */
String uuid = tempProp.getProperty(TransactionContextKeys.TRANSACTION_UUID, "");
method.setHeader("traceId", uuid);
/* GUID */
String guid = tempProp.getProperty(TransactionContextKeys.GUID, "");
method.setHeader("guid", guid);
/* 최초요청시간 */
String receivedTimestamp = tempProp.getProperty(HttpAdapterServiceKey.INBOUND_REQUESTED_TIME, "");
method.setHeader("receivedTimestamp", receivedTimestamp);
}
/* 업체정보 */
String clientId = JwtClientIdExtractor(jwtToken);
method.setHeader("clientId", clientId);
/* APIM 거래추적자 */
String uuid = tempProp.getProperty(TransactionContextKeys.TRANSACTION_UUID, "");
method.setHeader("traceId", uuid);
/* GUID */
String guid = tempProp.getProperty(TransactionContextKeys.GUID, "");
method.setHeader("guid", guid);
/* 최초요청시간 */
String receivedTimestamp = tempProp.getProperty(HttpAdapterServiceKey.INBOUND_REQUESTED_TIME, "");
method.setHeader("receivedTimestamp", receivedTimestamp);
return jwtToken;
//String clientId = JwtClientIdExtractor(jwtToken);
//method.setHeader("clientId", clientId);
/* APIM 거래추적자 */
//String uuid = tempProp.getProperty(TransactionContextKeys.TRANSACTION_UUID, "");
//method.setHeader("traceId", uuid);
/* GUID */
//String guid = tempProp.getProperty(TransactionContextKeys.GUID, "");
//method.setHeader("guid", guid);
/* 최초요청시간 */
//String receivedTimestamp = tempProp.getProperty(HttpAdapterServiceKey.INBOUND_REQUESTED_TIME, "");
//method.setHeader("receivedTimestamp", receivedTimestamp);
return jwtToken;
}
private static Map<String, String> parseInboundHeader(String str) {
java.util.HashMap<String, String> map = new java.util.HashMap<>();
if (str == null || str.isEmpty()) return map;
// 중괄호 제거
str = str.trim();
if (str.startsWith("{") && str.endsWith("}")) {
str = str.substring(1, str.length() - 1);
}
// key=value 쌍 분리
String[] pairs = str.split(",");
for (String pair : pairs) {
String[] kv = pair.split("=", 2);
if (kv.length == 2) {
map.put(kv[0].trim(), kv[1].trim());
}
}
return map;
}
@SuppressWarnings("deprecation")
private void assignPostBody(Object eaiBody, String contentType, String charset, HttpUriRequestBase method, String adapterName, String niceAuth, String inboundToken) {
@@ -80,6 +80,7 @@ public interface HttpAdapterServiceKey {
static final String INBOUND_REQUESTED_TIME = "INBOUND_REQUESTED_TIME"; // jwhong
static final String GUID = "GUID"; // jwhong
static final String API_SERVICE_CODE = "API_SERVICE_CODE"; // jwhong
static final String OUT_ADAPTER_GROUP_NAME = "OUT_ADAPTER_GROUP_NAME"; // jwhong
//응답 처리 용 표준 전문 오브젝트
static final String STANDARD_MESSAGE_OBJECT = "STANDARD_MESSAGE_OBJECT";
@@ -9,14 +9,11 @@ import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.RequestDispatcher;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterFactory;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterFactoryKjb;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterType;
import com.eactive.eai.data.entity.onl.adapter.AdapterProp;
public abstract class HttpAdapterServiceSupport implements HttpAdapterService, HttpAdapterServiceKey {
protected long slowTranTime = 2000L;
@@ -65,7 +62,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H
if (!"HTC".equals(group.getType())) {
String allowIp = prop.getProperty(ALLOW_IP,"");
if (StringUtils.isNotBlank(allowIp)) {
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(HttpAdapterFilterType.ADAPTERALLOWIPLISTFILTER.toString());
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(HttpAdapterFilterType.ADAPTERALLOWIPLISTFILTER.toString());
if (adapterFilter != null) {
message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response);
}
@@ -83,7 +80,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H
continue;
}
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim());
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(filterName.trim());
if (adapterFilter != null) {
message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response);
} else {
@@ -106,7 +103,7 @@ public abstract class HttpAdapterServiceSupport implements HttpAdapterService, H
continue;
}
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim());
HttpAdapterFilter adapterFilter = HttpAdapterFilterFactoryKjb.createFilter(filterName.trim());
if (adapterFilter != null) {
resultMessage = adapterFilter.doPostFilter(adptGrpName, adptName, resultMessage, prop, request,
response);
@@ -109,6 +109,7 @@ public class ApiAuthFilter implements HttpAdapterFilter {
return message;
}
boolean isPassScope = false;
switch (eaiMessage.getAuthType()){
case "oauth":
try {
@@ -127,10 +128,25 @@ public class ApiAuthFilter implements HttpAdapterFilter {
OAuth2Manager manager = OAuth2Manager.getInstance();
HashSet<String> scopeSet = manager.getApiScopeMap().get(apiId);
if (!verifyScope(scopeSet, signedJWT)) {
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)) {
@@ -144,26 +160,6 @@ public class ApiAuthFilter implements HttpAdapterFilter {
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid");
}
break;
// case "bearer":
// try {
// String token = ApiAuthFilter.extractJWTToken(request);
// BearerTokenInfo CATokenInfo = CATokenStore.get(token);
//
// if (CATokenInfo == null) {
// throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid");
// }
//
// if (CATokenInfo.isExpired()) {
// throw new JwtAuthException(ERROR_TOKEN_EXPIRED, "Access token expired");
// }
// } catch (JwtAuthException e) {
// logger.debug(e.getMessage());
// throw e;
// } catch (Exception e) {
// logger.error(e.getMessage());
// throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Token invalid");
// }
// break;
case "api_key":
String apiKeyName = PropManager.getInstance().getProperty("ApiConfig", "api.key.name", "x-api-key");
String apiKey = request.getHeader(apiKeyName);
@@ -171,19 +167,22 @@ public class ApiAuthFilter implements HttpAdapterFilter {
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Invalid or missing API key \""+apiKeyName+"\" in Http Header");
}
prop.setProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID, apiKey);
isPassScope = true;
break;
case "none":
return message;
}
String clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID);
ClientVO clientVO = OAuth2Manager.getInstance().getClientVO(clientId);
if(clientVO == null){
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered APP");
}
if (isPassScope) {
String clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID);
ClientVO clientVO = OAuth2Manager.getInstance().getClientVO(clientId);
if(clientVO == null){
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered APP");
}
if(clientVO.getApiMap().containsKey(eaiSvcCd) == false){
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered API ["+eaiSvcCd+"] in ["+clientVO.getClientName()+"] APP");
if(clientVO.getApiMap().containsKey(eaiSvcCd) == false){
throw new JwtAuthException(ERROR_AUTHENTICATION_FAIL, "Unregistered API ["+eaiSvcCd+"] in ["+clientVO.getClientName()+"] APP");
}
}
return message;
@@ -0,0 +1,152 @@
package com.eactive.eai.adapter.http.dynamic.filter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Properties;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//import org.apache.commons.net.util.Base64;
import org.springframework.http.HttpStatus;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.HttpAdapterServiceSupport;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.util.Logger;
public class HmacSha256VerifyFilterKjb implements HttpAdapterFilter {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
public HmacSha256VerifyFilterKjb() {
super();
}
@Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String inboundMethod = prop.getProperty(HttpAdapterServiceKey.INBOUND_METHOD);
String inboundUri = prop.getProperty(HttpAdapterServiceKey.INBOUND_URI);
String inboundBody = prop.getProperty(HttpAdapterServiceKey.INBOUND_REQUEST_MESSAGE);
try {
String xObpPartnercode = request.getHeader("x-obp-partnercode");
String xObpSignatureUrl = request.getHeader("x-obp-signature-url");
String xObpSignatureBody = request.getHeader("x-obp-signature-body");
if (StringUtils.isBlank(xObpPartnercode)
|| StringUtils.isBlank(xObpSignatureUrl)
|| StringUtils.isBlank(xObpSignatureBody)) {
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Can not find mandatory Http Header");
}
if (StringUtils.isNotBlank(prop.getProperty(HttpAdapterServiceKey.INBOUND_QUERY_STRING))) {
inboundUri = inboundUri + "?" + prop.getProperty(HttpAdapterServiceKey.INBOUND_QUERY_STRING);
inboundBody = "";
}
String chkUrl = inboundMethod + "&" + inboundUri;
String chkBody = inboundBody;
String clientSecret = assignClientSecret(prop, request);
String macUrl = calculateHMAC(chkUrl, clientSecret);
String macBody = calculateHMAC(chkBody, clientSecret);
if (!StringUtils.equals(xObpSignatureUrl, macUrl)) {
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Signature verifying failed : x-obp-signature-url");
}
if (!StringUtils.equals(xObpSignatureBody, macBody)) {
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Signature verifying failed : x-obp-signature-body");
}
} catch (JwtAuthException e) {
logger.debug(e.getMessage());
throw e;
} catch (Exception e) {
logger.error(e.getMessage());
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Signature verifying failed(unkown)");
}
return message;
}
public static String calculateHMAC(String data, String key)
throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA256"));
return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));
}
private String assignClientSecret(Properties prop, HttpServletRequest request) throws Exception {
String clientId = assignClientId(prop, request);
if (StringUtils.isBlank(clientId)) {
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Can not find clientId info");
}
ClientVO client = (ClientVO) OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
if (client == null) {
throw new JwtAuthException(
String.valueOf(HttpStatus.UNAUTHORIZED.value()),
"Can not find client info");
}
return client.getClientSecret();
}
private String assignClientId(Properties prop, HttpServletRequest request) {
String clientId = null;
try {
// 이전 filter에서 셋팅한 clientId 확보
clientId = prop.getProperty(HttpAdapterServiceSupport.PROPERTIES_NAME_CLIENT_ID);
// 이전 filter에서 셋팅한 값이 없다면 header 정보에서 확보
if (StringUtils.isBlank(clientId)) {
clientId = request.getHeader(HttpAdapterServiceSupport.HEADER_NAME_CLIENT_ID);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return clientId;
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
String outboundBody = (String) resultMessage;
try {
String clientSecret = assignClientSecret(prop, request);
String macBody = calculateHMAC(outboundBody, clientSecret);
response.addHeader("x-obp-signature-body", macBody);
response.addHeader("x-obp-partnercode", request.getHeader("x-obp-partnercode"));
response.addHeader("x-obp-txid", prop.getProperty(TransactionContextKeys.TRANSACTION_UUID,""));
} catch (Exception e) {
logger.error(e.getMessage());
}
return resultMessage;
}
}
@@ -0,0 +1,64 @@
package com.eactive.eai.adapter.http.dynamic.filter;
import java.util.concurrent.ConcurrentHashMap;
import com.eactive.eai.common.util.Logger;
public class HttpAdapterFilterFactoryKjb extends HttpAdapterFilterFactory {
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
static String basePackage = "com.eactive.eai.custom.adapter.http.dynamic.filter";
static private ConcurrentHashMap<String, HttpAdapterFilter> h = new ConcurrentHashMap<String, HttpAdapterFilter>();
public HttpAdapterFilterFactoryKjb() {
super();
}
@SuppressWarnings("rawtypes")
public static HttpAdapterFilter createFilter(String type) {
if (h.containsKey(type)) {
return (HttpAdapterFilter) h.get(type);
}
HttpAdapterFilter filter = null;
switch (HttpAdapterFilterType.getValue(type)) {
case APIAUTHFILTER:
filter = new ApiAuthFilter();
break;
case JWTAUTHFILTER:
filter = new JwtAuthFilter();
break;
case IPWHITELISTFILTER:
filter = new IpWhiteListFilter();
break;
case ADAPTERALLOWIPLISTFILTER:
filter = new AdapterAllowIPListFilter();
break;
case HMAC_SHA256:
filter = new HmacSha256VerifyFilterKjb();
break;
default:
filter = classForName(type);
if (filter == null) {
filter = classForName(basePackage + "." + type);
}
break;
}
if (filter != null) {
h.put(type, filter);
return filter;
} else {
return null;
}
}
private static HttpAdapterFilter classForName(String type) {
try {
Class<?> cl = Class.forName(type);
return (HttpAdapterFilter) cl.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
logger.error("Cannot create a HttpAdapterFilter. - {}", type);
return null;
}
}
}
@@ -5,6 +5,7 @@ public enum HttpAdapterFilterType {
JWTAUTHFILTER,
IPWHITELISTFILTER,
ADAPTERALLOWIPLISTFILTER,
HMAC_SHA256,
UNKNOWN;
public static HttpAdapterFilterType getValue(String type) {
@@ -96,8 +96,7 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA
if (!UrlUtils.isAbsoluteUrl(uri)) {
uri = appendPath(adapterUrl, uri);
}
//String contentType = "application/json;"; // comment by jwhong
String contentType = "application/x-www-form-urlencoded"; // 광주은행 나이스지키미
String contentType = "application/json;";
Charset charset;
if (StringUtils.isNotBlank(encode)) {
@@ -114,9 +113,7 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA
"uri:{}, charset:{}, transactionTimeout:{}, connectionTimeout:{}, useForwardProxy:{}, forwardProxyUrl:{}",
uri, encode, timeout, connectionTimeout, useForwardProxy, forwardProxyUrl);
// mTLS config with default connection parameters
boolean useMtls = StringUtils.equalsIgnoreCase(adapterProp.getProperty(HttpClientAdapterServiceKey.USE_MTLS),
"Y");
@@ -237,17 +234,19 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA
logger.debug("contentType = [" + contentType + "]");
logger.debug("encode = [" + encode + "]");
OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO();
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
if (response.getCode() != 200) {
throw new Exception("OAuth token receive status fail value= " + response.getCode());
}
logger.info("HttpClientAccessTokenServiceWithBase64Header==>" + response.getCode());
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity, encode);
logger.debug("oauthToken RECV = [" + responseString + "]");
logger.debug("Base64Header oauthToken RECV = [" + responseString + "]");
if (StringUtils.isNotBlank(responseString)) {
OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode responseJSON = objectMapper.readTree(responseString);
@@ -272,6 +271,10 @@ public class HttpClientAccessTokenServiceWithBase64Header implements HttpClientA
} else {
throw new Exception("oauth token return null");
}
} catch (Exception e) {
e.printStackTrace();
logger.error("[HttpClientAccessTokenServiceWithBase64Header] retrieve accessToken exception :" + e.getMessage());
return accessToken;
}
}
}
@@ -0,0 +1,308 @@
package com.eactive.eai.authoutbound.client.impl;
import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.secure.HttpClient5SSLContextFactory;
import com.eactive.eai.authoutbound.OutboundOAuthCredentialVo;
import com.eactive.eai.authoutbound.client.HttpClientAccessTokenServiceByDB;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoManager;
import com.eactive.eai.httpouttlsinfo.HttpOutTlsInfoVO;
import com.eactive.eai.util.TestModeChecker;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openbanking.eai.common.token.AccessTokenVO;
import com.openbanking.eai.common.token.OAuth2AccessTokenVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.apache.hc.core5.util.Timeout;
import org.springframework.security.web.util.UrlUtils;
import tcseed.base64;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.*;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
/**
* 1. 기능 : HTTP 웹 컴포넌트를 POST 방식으로 호출할 수 있는 기능을 제공한다. 2. 처리 개요 : * - 2009.11.24
* retry 로직 제거 : 요청 3. 주의사항
*
* @author :
* @version : v 1.0.0
* @see : WLIAdapterFactory.java, WLIAdapter.java, WLIDefaultAdapter.java
* @since :
*
*/
public class HttpClientAccessTokenServiceWithBase64NiceOn implements HttpClientAccessTokenServiceByDB {
public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
private static boolean testMode = TestModeChecker.isTestMode();
/**
* 1. 기능 : 법인검증 토큰 발급에 사용 2. 처리 개요 : - 속성 정보를 설정 하고 토큰 발급 URL 호출 한다. 3. 주의사항
* - JSON 방식
* - ( Header Authorization Basic <base64_Encode(client_id:client_secret)> ) 으로 구성
* @param adapterProp Http Adapter 속성 정보
* @return 반환 된 AccessTokenVO
* @exception Exception 수동 시스템 간 통신 중 발생
**/
public AccessTokenVO execute(String name, Properties adapterProp, OutboundOAuthCredentialVo oAuthCredentialVo)
throws Exception {
AdapterGroupVO gvo = AdapterManager.getInstance().getAdapterGroupVO(name);
String adapterUrl = adapterProp.getProperty("URL");
String encode = gvo.getMessageEncode();
String timeoutTemp = adapterProp.getProperty("HTTP_TIME_OUT");
if (StringUtils.isBlank(timeoutTemp)) {
timeoutTemp = "30000";
}
String connectionTimeoutTemp = adapterProp.getProperty("CONNECTION_TIMEOUT");
if (StringUtils.isBlank(connectionTimeoutTemp)) {
connectionTimeoutTemp = "30000";
}
int timeout = Integer.parseInt(timeoutTemp);
int connectionTimeout = Integer.parseInt(connectionTimeoutTemp);
long currentTime = System.currentTimeMillis();
String uri = oAuthCredentialVo.getUrl();
if (!UrlUtils.isAbsoluteUrl(uri)) {
uri = appendPath(adapterUrl, uri);
}
String contentType = "application/x-www-form-urlencoded"; // 광주은행 나이스지키미
Charset charset;
if (StringUtils.isNotBlank(encode)) {
charset = Charset.forName(encode);
} else {
charset = Charset.defaultCharset();
encode = charset.toString();
}
boolean useForwardProxy = StringUtils.equalsIgnoreCase(adapterProp.getProperty("FORWARD_PROXY_USE_YN"), "Y");
String forwardProxyUrl = adapterProp.getProperty("FORWARD_PROXY_URL");
logger.debug(
"uri:{}, charset:{}, transactionTimeout:{}, connectionTimeout:{}, useForwardProxy:{}, forwardProxyUrl:{}",
uri, encode, timeout, connectionTimeout, useForwardProxy, forwardProxyUrl);
List<NameValuePair> formParams = new ArrayList<>();
//formParams.add(new BasicNameValuePair("client_id", oAuthCredentialVo.getClientId()));
//formParams.add(new BasicNameValuePair("client_secret", oAuthCredentialVo.getClientSecret()));
formParams.add(new BasicNameValuePair("grant_type", oAuthCredentialVo.getGrantType()));
formParams.add(new BasicNameValuePair("scope", oAuthCredentialVo.getScope()));
//String postParameters = "grant_type=" + oAuthCredentialVo.getGrantType() + "&scope=" + oAuthCredentialVo.getScope();
// mTLS config with default connection parameters
boolean useMtls = StringUtils.equalsIgnoreCase(adapterProp.getProperty(HttpClientAdapterServiceKey.USE_MTLS),
"Y");
AdapterGroupVO adapterGroup = AdapterManager.getInstance().getAdapterGroup(name);
String clientId = adapterGroup.getClientId();
if (logger.isInfo()) {
logger.info("MTLS adapterGroupName. : {}, useMtls. : {}, clientId : {}", name, useMtls, clientId);
}
int maxTotalConnections = HttpClientAdapterServiceKey.DEFAULT_MAX_TOTAL_CONNECTIONS;
int maxHostConnections = HttpClientAdapterServiceKey.DEFAULT_MAX_CONNECTION_PER_HOST;
HttpOutTlsInfoVO mtlsInfo = null;
SSLContext sslContext = null;
PoolingHttpClientConnectionManagerBuilder cmBuilder = PoolingHttpClientConnectionManagerBuilder.create();
PoolingHttpClientConnectionManager connectionManager = null;
try {
if (useMtls) {
HttpOutTlsInfoManager tlsManager = HttpOutTlsInfoManager.getInstance();
if (StringUtils.isNotEmpty(clientId)) {
mtlsInfo = tlsManager.getHttpOutTlsInfo(clientId);
}
}
if (useMtls && mtlsInfo != null) {
String storeType = mtlsInfo.getStoreType();
String keyStoreInfo = mtlsInfo.getKeystoreInfo();
String keyStorePassword = mtlsInfo.getKeystorePassword();
String trustStoreInfo = mtlsInfo.getTruststoreInfo();
String trustStorePassword = mtlsInfo.getTruststorePassword();
String[] tlsVersions = null;
String[] cipherSuites = null;
if (StringUtils.isAnyEmpty(keyStoreInfo, keyStorePassword)) {
throw new Exception("mTLS keyStore config error");
}
boolean skipTrust = false;
if (StringUtils.isAnyEmpty(trustStoreInfo, trustStorePassword)) {
if (logger.isWarn())
logger.warn("Skip trustStore validation adapterGroupName : " + name);
skipTrust = true;
}
sslContext = HttpClient5SSLContextFactory.createMTLSContextFromContent(storeType, keyStoreInfo,
keyStorePassword, trustStoreInfo, trustStorePassword, skipTrust, tlsVersions, cipherSuites);
SSLConnectionSocketFactory sslSocketFactory = null;
if (testMode) {
sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
} else {
sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
}
cmBuilder.setSSLSocketFactory(sslSocketFactory);
} else {
sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustAllStrategy()).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
cmBuilder.setSSLSocketFactory(csf);
}
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | CertificateException
| IOException | UnrecoverableKeyException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
connectionManager = cmBuilder.build();
connectionManager.setMaxTotal(maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(maxHostConnections);
try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();) {
HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(new UrlEncodedFormEntity(formParams, charset));
//httpPost.setEntity(new StringEntity(postParameters, StandardCharsets.UTF_8));
httpPost.setHeader("Content-Type", contentType+";charset=" + encode); // 중간에 ; 주어야 함
//HTTP HEADER에 client id, client secret를 base64Encode 한 후 추가
String cId = oAuthCredentialVo.getClientId();
String cSecret = oAuthCredentialVo.getClientSecret();
String authValue = cId + ":" + cSecret;
String encodedAuth = Base64.getEncoder().encodeToString(authValue.getBytes(StandardCharsets.UTF_8));
httpPost.setHeader("Authorization","Basic "+ encodedAuth);
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
if (useForwardProxy) {
java.net.URL url = new java.net.URL(forwardProxyUrl);
// 프로토콜, 호스트, 포트 추출
String protocol = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
HttpHost proxy = new HttpHost(protocol, host, port);
requestConfigBuilder.setProxy(proxy);
}
RequestConfig requestConfig = requestConfigBuilder
.setConnectTimeout(Timeout.ofMilliseconds(connectionTimeout))
.setResponseTimeout(Timeout.ofMilliseconds(timeout)).build();
httpPost.setConfig(requestConfig);
logger.debug("uri = [" + uri + "]");
logger.debug("oauthClientId = [" + oAuthCredentialVo.getClientId() + "]");
logger.debug("oauthClientSecret = [" + oAuthCredentialVo.getClientSecret() + "]");
logger.debug("oauthScope = [" + oAuthCredentialVo.getScope() + "]");
logger.debug("oauthGrantType = [" + oAuthCredentialVo.getGrantType() + "]");
logger.debug("oauthauthValue = [" + authValue + "]");
logger.debug("oauthauthEncodedAuth = [" + encodedAuth + "]");
logger.debug("contentType = [" + contentType + "]");
logger.debug("encode = [" + encode + "]");
OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO();
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
if (response.getCode() != 200) {
throw new Exception("NiceOn token receive status fail value== " + response.getCode());
}
logger.info("HttpClientAccessTokenServiceWithBase64NiceOn==>" + response.getCode());
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity, encode);
logger.debug("Base64NiceOn oauthToken RECV == [" + responseString + "]");
if (StringUtils.isNotBlank(responseString)) {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode responseJSONRtn = objectMapper.readTree(responseString);
JsonNode responseJSON = null;
String gwRsltCd = responseJSONRtn.get("dataHeader").get("GW_RSLT_CD").asText();
if ("1200".equals(gwRsltCd)) {
responseJSON = responseJSONRtn.get("dataBody");
}
if (responseJSON.has("access_token") && responseJSON.has("token_type")
&& responseJSON.has("expires_in") && responseJSON.has("scope")) {
accessToken.setAccessToken(responseJSON.get("access_token").asText());
accessToken.setTokenType(responseJSON.get("token_type").asText());
long expiresIn = responseJSON.get("expires_in").asLong();
accessToken.setExpiration(new Date(currentTime + expiresIn * 1000L));
accessToken.setScope(responseJSON.get("scope").asText());
accessToken.setClientId(cId);
}
if (responseJSON.has("client_use_code")) {
accessToken.setClientUseCode(responseJSON.get("client_use_code").asText());
}
logger.debug("NiceOn oauthToken =" + accessToken.toString());
return accessToken;
} else {
throw new Exception("oauth token return null");
}
} catch (Exception e) {
e.printStackTrace();
logger.error("[HttpClientAccessTokenServiceWithBase64NiceOn] retrieve accessToken exception :" + e.getMessage());
return accessToken;
}
}
}
/**
* URL에 경로를 추가합니다. 중복되는 슬래시를 방지합니다.
*
* @param baseUrl 기본 URL
* @param pathToAdd 추가할 경로
* @return 완성된 URL 문자열
*/
public static String appendPath(String baseUrl, String pathToAdd) {
if (!baseUrl.endsWith("/") && !pathToAdd.startsWith("/")) {
return baseUrl + "/" + pathToAdd;
} else if (baseUrl.endsWith("/") && pathToAdd.startsWith("/")) {
return baseUrl + pathToAdd.substring(1);
} else {
return baseUrl + pathToAdd;
}
}
}
@@ -31,9 +31,15 @@ public class ScopeDAO extends BaseDAO {
Map<String, HashSet<String>> clientEntitymap = new HashMap<>();
scopeEntities.forEach(scopeEntity -> {
HashSet<String> set = new HashSet<>();
String scopeId = scopeEntity.getId().getBzwksvckeyname() + scopeEntity.getId().getScopeid();
clientEntitymap.put(scopeId, set);
String apiId = scopeEntity.getId().getBzwksvckeyname();
HashSet<String> scopeSet = clientEntitymap.get(apiId);
if (scopeSet == null) {
scopeSet = new HashSet<String>();
clientEntitymap.put(apiId, scopeSet);
}
String scopeId = scopeEntity.getId().getScopeid();
clientEntitymap.get(apiId).add(scopeId);
// clientEntitymap.put(scopeId, set);
});
return clientEntitymap;
@@ -48,7 +54,7 @@ public class ScopeDAO extends BaseDAO {
ScopeEntity scopeEntity = scopeLoader.findByIdBzwksvckeyname(apiId);
scopeSet.add(scopeEntity.getId().getBzwksvckeyname());
scopeSet.add(scopeEntity.getId().getScopeid());
return scopeSet;
} catch (Exception e) {
throw new DAOException(ExceptionUtil.getErrorCode(e, "RECEAIAUC001"));
@@ -26,6 +26,7 @@ import com.eactive.eai.data.entity.onl.inflow.InflowControlLogId;
@Service
@Transactional
public class InflowControlDAO extends BaseDAO {
private static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@Autowired
@@ -227,4 +228,5 @@ public class InflowControlDAO extends BaseDAO {
vo.setActivate(!"0".equals(group.getUseYn()));
return vo;
}
}
@@ -37,6 +37,7 @@ import com.eactive.eai.message.manager.StandardMessageManager;
import com.eactive.eai.message.mapper.MessageMapper;
import com.eactive.eai.message.service.InterfaceMapper;
import com.ext.eai.common.stdmessage.STDMessageKeys;
import com.eactive.eai.common.message.ServiceMessage; // jwhong
public abstract class DefaultProcess extends Process {
protected static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
@@ -252,6 +253,13 @@ public abstract class DefaultProcess extends Process {
}
// 송신결과확인
checkSendResult();
// 400 Async 에 대한 ack 오는것 500 으로 log에 저장, jwhong for kjbank
if(isAsyncSyncPattern()){
StandardMessage standardMessage = this.resEaiMsg.getStandardMessage();
standardMessage.setBizData(this.resObject, this.outboundCharset);
this.logPssSno = 500;
logSenderCtrlSendRes();
}
// SA
if (isSyncAsyncPattern()) {
try {
@@ -474,6 +482,18 @@ public abstract class DefaultProcess extends Process {
return false;
}
}
// jwhong
public boolean isAsyncSyncPattern() {
ServiceMessage firstService = this.reqEaiMsg.getSvcMsg(0);
ServiceMessage secondService = this.reqEaiMsg.getSvcMsg(1);
if (EAIMessageKeys.ASYNC_SVC.equals(this.reqEaiMsg.getSvcTsmtUsgTp())
&& EAIMessageKeys.SYNC_SVC.equals(firstService.getPsvItfTp())
&& EAIMessageKeys.ASYNC_SVC.equals(secondService.getPsvItfTp())){
return true;
}
return false;
}
public boolean isSyncAsyncPattern() {
if (!MessageUtil.checkRspErrCd(this.resEaiMsg.getRspErrCd())) {