어댑터 암복호화 필터 리팩토링
- 커스텀 패키지 지정 - 변수 이동
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ import com.eactive.eai.common.util.Logger;
|
|||||||
|
|
||||||
public class HttpClient5AdapterFilterFactory {
|
public class HttpClient5AdapterFilterFactory {
|
||||||
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
|
static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
|
||||||
static String customBasePackage = "com.eactive.eai.custom.adapter.http.client.filter";
|
static String customBasePackage = "com.eactive.eai.custom.adapter.http.client.impl.filter";
|
||||||
static String basePackage = "com.eactive.eai.adapter.http.client.impl.filter";
|
static String basePackage = "com.eactive.eai.adapter.http.client.impl.filter";
|
||||||
private static ConcurrentHashMap<String, HttpClientAdapterFilter> h = new ConcurrentHashMap<>();
|
private static ConcurrentHashMap<String, HttpClientAdapterFilter> h = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ import com.eactive.eai.adapter.http.filter.AbstractCryptoFilter;
|
|||||||
* STATIC 키 모듈을 사용하는 경우 빈 Map이 기본값이므로 오버라이드 불필요.
|
* STATIC 키 모듈을 사용하는 경우 빈 Map이 기본값이므로 오버라이드 불필요.
|
||||||
*
|
*
|
||||||
* 프로퍼티 설명은 {@link AbstractCryptoFilter} 참조.
|
* 프로퍼티 설명은 {@link AbstractCryptoFilter} 참조.
|
||||||
* AAD 관련 추가 프로퍼티:
|
* AAD 관련 프로퍼티:
|
||||||
* CRYPTO_AAD_PROP tempProp에서 AAD 값을 조회할 키 이름.
|
* PROP_AAD_HEADER tempProp에서 AAD 값을 조회할 키 이름.
|
||||||
* 미설정 또는 해당 키 없으면 aad=null → IV를 AAD 대체값으로 사용.
|
* 미설정 또는 해당 키 없으면 aad=null → IV를 AAD 대체값으로 사용.
|
||||||
*/
|
*/
|
||||||
public class OutCryptoFilter extends AbstractCryptoFilter implements HttpClientAdapterFilter {
|
public class OutCryptoFilter extends AbstractCryptoFilter implements HttpClientAdapterFilter {
|
||||||
|
|
||||||
public static final String PROP_AAD_PROP = "CRYPTO_AAD_PROP";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DYNAMIC 키 도출용 컨텍스트를 구성한다.
|
* DYNAMIC 키 도출용 컨텍스트를 구성한다.
|
||||||
* STATIC 키 모듈이면 빈 Map({@code new HashMap<>()})을 반환한다.
|
* STATIC 키 모듈이면 빈 Map({@code new HashMap<>()})을 반환한다.
|
||||||
@@ -41,7 +39,7 @@ public class OutCryptoFilter extends AbstractCryptoFilter implements HttpClientA
|
|||||||
* 미설정 또는 값 없으면 null을 반환하여 GCM 기본 동작(IV를 AAD 대체값으로 사용)을 따른다.
|
* 미설정 또는 값 없으면 null을 반환하여 GCM 기본 동작(IV를 AAD 대체값으로 사용)을 따른다.
|
||||||
*/
|
*/
|
||||||
protected byte[] buildAad(Properties prop, Properties tempProp) {
|
protected byte[] buildAad(Properties prop, Properties tempProp) {
|
||||||
String propKey = prop.getProperty(PROP_AAD_PROP);
|
String propKey = prop.getProperty(PROP_AAD_HEADER);
|
||||||
if (StringUtils.isBlank(propKey) || tempProp == null) {
|
if (StringUtils.isBlank(propKey) || tempProp == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -61,8 +59,8 @@ public class OutCryptoFilter extends AbstractCryptoFilter implements HttpClientA
|
|||||||
|
|
||||||
if (SCOPE_FIELD.equals(scope)) {
|
if (SCOPE_FIELD.equals(scope)) {
|
||||||
return encryptField(body, moduleName, runtimeCtx, aad,
|
return encryptField(body, moduleName, runtimeCtx, aad,
|
||||||
getProp(prop, PROP_ENC_FROM_PATH, PATH_ROOT),
|
getProp(tempProp, PROP_ENC_FROM_PATH, PATH_ROOT),
|
||||||
getProp(prop, PROP_ENC_TO_PATH, PATH_ENCDATA));
|
getProp(tempProp, PROP_ENC_TO_PATH, PATH_ENCDATA));
|
||||||
}
|
}
|
||||||
return encryptBody(body, moduleName, runtimeCtx, aad);
|
return encryptBody(body, moduleName, runtimeCtx, aad);
|
||||||
}
|
}
|
||||||
@@ -79,8 +77,8 @@ public class OutCryptoFilter extends AbstractCryptoFilter implements HttpClientA
|
|||||||
|
|
||||||
if (SCOPE_FIELD.equals(scope)) {
|
if (SCOPE_FIELD.equals(scope)) {
|
||||||
return decryptField(body, moduleName, runtimeCtx, aad,
|
return decryptField(body, moduleName, runtimeCtx, aad,
|
||||||
getProp(prop, PROP_DEC_FROM_PATH, PATH_ENCDATA),
|
getProp(tempProp, PROP_DEC_FROM_PATH, PATH_ENCDATA),
|
||||||
getProp(prop, PROP_DEC_TO_PATH, PATH_ROOT));
|
getProp(tempProp, PROP_DEC_TO_PATH, PATH_ROOT));
|
||||||
}
|
}
|
||||||
return decryptBody(body, moduleName, runtimeCtx, aad);
|
return decryptBody(body, moduleName, runtimeCtx, aad);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,17 @@ import com.eactive.eai.common.util.Logger;
|
|||||||
* SafeNet ProtectServer HSM 연동 관리자 (JDK 8 / SunPKCS11)
|
* SafeNet ProtectServer HSM 연동 관리자 (JDK 8 / SunPKCS11)
|
||||||
*
|
*
|
||||||
* PropManager 그룹 "HSM" 에서 읽는 키:
|
* PropManager 그룹 "HSM" 에서 읽는 키:
|
||||||
* PKCS11_CONFIG - pkcs11.cfg 파일 내용 (name/library/slot 설정을 DB에 직접 저장)
|
* PKCS11_CONFIG - pkcs11.cfg 파일 내용
|
||||||
* PIN - HSM 슬롯 PIN
|
* PIN - HSM 슬롯 PIN
|
||||||
*
|
*
|
||||||
* PKCS11_CONFIG 값 예시 (개행은 \n 으로 입력):
|
* PKCS11_CONFIG 값 예시 (개행은 \n 으로 입력):
|
||||||
* name = ProtectServer
|
* name = ProtectServer
|
||||||
* library = /opt/safenet/protecttoolkit5/ptk/lib/libcryptoki.so
|
* library = /opt/safenet/protecttoolkit5/ptk/lib/libcryptoki.so
|
||||||
* slot = 0
|
* slot = 0
|
||||||
|
*
|
||||||
|
* name = SoftHSM
|
||||||
|
* library = C:/SoftHSM2/lib/softhsm2-x64.dll
|
||||||
|
* slotListIndex = 0
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class HsmManager implements Lifecycle {
|
public class HsmManager implements Lifecycle {
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ package com.eactive.eai.common.security.keyderiv;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public interface KeyDerivationStrategy {
|
public interface KeyDerivationStrategy {
|
||||||
|
|
||||||
|
public static final String PARAM_HSM_KEY_ALIAS = "hsmKeyAlias";
|
||||||
|
public static final String PARAM_CONTEXT_KEY = "contextKey";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 키를 도출한다.
|
* 키를 도출한다.
|
||||||
*
|
*
|
||||||
|
|||||||
-2
@@ -14,8 +14,6 @@ import com.eactive.eai.common.util.ApplicationContextProvider;
|
|||||||
*/
|
*/
|
||||||
public abstract class BaseHsmKeyDerivationStrategy implements KeyDerivationStrategy {
|
public abstract class BaseHsmKeyDerivationStrategy implements KeyDerivationStrategy {
|
||||||
|
|
||||||
protected static final String PARAM_HSM_KEY_ALIAS = "hsmKeyAlias";
|
|
||||||
|
|
||||||
protected byte[] getHsmKey(Map<String, String> params) throws HsmException {
|
protected byte[] getHsmKey(Map<String, String> params) throws HsmException {
|
||||||
String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
|
String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
|
||||||
return getHsmKey(hsmKeyAlias);
|
return getHsmKey(hsmKeyAlias);
|
||||||
|
|||||||
-3
@@ -23,9 +23,6 @@ import com.eactive.eai.common.util.ApplicationContextProvider;
|
|||||||
*/
|
*/
|
||||||
public class HsmContextSha256KeyDerivationStrategy implements KeyDerivationStrategy {
|
public class HsmContextSha256KeyDerivationStrategy implements KeyDerivationStrategy {
|
||||||
|
|
||||||
private static final String PARAM_HSM_KEY_ALIAS = "hsmKeyAlias";
|
|
||||||
private static final String PARAM_CONTEXT_KEY = "contextKey";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
|
public DerivedKey deriveKey(Map<String, String> params, Map<String, String> runtimeContext) throws Exception {
|
||||||
String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
|
String hsmKeyAlias = required(params, PARAM_HSM_KEY_ALIAS);
|
||||||
|
|||||||
-2
@@ -26,8 +26,6 @@ public class HsmContextXorKeyDerivationStrategy implements KeyDerivationStrategy
|
|||||||
/** DB key_deriv_strategy 컬럼에 사용하는 FQCN 참조용 상수. */
|
/** DB key_deriv_strategy 컬럼에 사용하는 FQCN 참조용 상수. */
|
||||||
public static final String STRATEGY_CLASS = HsmContextXorKeyDerivationStrategy.class.getName();
|
public static final String STRATEGY_CLASS = HsmContextXorKeyDerivationStrategy.class.getName();
|
||||||
|
|
||||||
private static final String PARAM_HSM_KEY_ALIAS = "hsmKeyAlias";
|
|
||||||
private static final String PARAM_CONTEXT_KEY = "contextKey";
|
|
||||||
private static final String PARAM_OFFSET = "offset";
|
private static final String PARAM_OFFSET = "offset";
|
||||||
private static final String PARAM_LENGTH = "length";
|
private static final String PARAM_LENGTH = "length";
|
||||||
|
|
||||||
|
|||||||
+15
-15
@@ -85,7 +85,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("1-2. buildAad — CRYPTO_AAD_PROP 설정, tempProp에 값 없음 → null")
|
@DisplayName("1-2. buildAad — CRYPTO_AAD_PROP 설정, tempProp에 값 없음 → null")
|
||||||
void testBuildAad_propSet_noTempValue_returnsNull() {
|
void testBuildAad_propSet_noTempValue_returnsNull() {
|
||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
prop.setProperty(OutCryptoFilter.PROP_AAD_PROP, "aadKey");
|
prop.setProperty(AbstractCryptoFilter.PROP_AAD_HEADER, "aadKey");
|
||||||
|
|
||||||
assertNull(filter.buildAad(prop, tempProp));
|
assertNull(filter.buildAad(prop, tempProp));
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ class OutCryptoFilterTest {
|
|||||||
void testBuildAad_propSet_tempValuePresent_returnsByte() {
|
void testBuildAad_propSet_tempValuePresent_returnsByte() {
|
||||||
String aadVal = "aad-value-xyz";
|
String aadVal = "aad-value-xyz";
|
||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
prop.setProperty(OutCryptoFilter.PROP_AAD_PROP, "aadKey");
|
prop.setProperty(AbstractCryptoFilter.PROP_AAD_HEADER, "aadKey");
|
||||||
tempProp.setProperty("aadKey", aadVal);
|
tempProp.setProperty("aadKey", aadVal);
|
||||||
|
|
||||||
assertArrayEquals(aadVal.getBytes(StandardCharsets.UTF_8), filter.buildAad(prop, tempProp));
|
assertArrayEquals(aadVal.getBytes(StandardCharsets.UTF_8), filter.buildAad(prop, tempProp));
|
||||||
@@ -118,7 +118,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("2-2. FIELD scope, fromPath='/' — body 전체 암호화 → toPath 필드명으로 래핑")
|
@DisplayName("2-2. FIELD scope, fromPath='/' — body 전체 암호화 → toPath 필드명으로 래핑")
|
||||||
void testPreFilter_field_encryptFromRoot() throws Exception {
|
void testPreFilter_field_encryptFromRoot() throws Exception {
|
||||||
String body = "{\"userId\":\"U001\"}";
|
String body = "{\"userId\":\"U001\"}";
|
||||||
Properties prop = fieldEncryptProps("/", "/encryptedData");
|
Properties prop = fieldEncryptProps(tempProp, "/", "/encryptedData");
|
||||||
|
|
||||||
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("2-3. FIELD scope — fromPath 평문 암호화 → toPath Base64 반영")
|
@DisplayName("2-3. FIELD scope — fromPath 평문 암호화 → toPath Base64 반영")
|
||||||
void testPreFilter_field_encryptSpecificPath() throws Exception {
|
void testPreFilter_field_encryptSpecificPath() throws Exception {
|
||||||
String body = "{\"data\":\"secret\",\"enc\":\"\"}";
|
String body = "{\"data\":\"secret\",\"enc\":\"\"}";
|
||||||
Properties prop = fieldEncryptProps("/data", "/enc");
|
Properties prop = fieldEncryptProps(tempProp, "/data", "/enc");
|
||||||
|
|
||||||
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("2-4. FIELD scope — fromPath 값 없음 → body 그대로 반환")
|
@DisplayName("2-4. FIELD scope — fromPath 값 없음 → body 그대로 반환")
|
||||||
void testPreFilter_field_missingFromPath_passThrough() throws Exception {
|
void testPreFilter_field_missingFromPath_passThrough() throws Exception {
|
||||||
String body = "{\"other\":\"value\"}";
|
String body = "{\"other\":\"value\"}";
|
||||||
Properties prop = fieldEncryptProps("/data", "/enc");
|
Properties prop = fieldEncryptProps(tempProp, "/data", "/enc");
|
||||||
|
|
||||||
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPreFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("3-2. FIELD scope — fromPath 복호화 → toPath 반영")
|
@DisplayName("3-2. FIELD scope — fromPath 복호화 → toPath 반영")
|
||||||
void testPostFilter_field_decryptToPath() throws Exception {
|
void testPostFilter_field_decryptToPath() throws Exception {
|
||||||
String body = "{\"enc\":\"" + CIPHER_B64 + "\",\"result\":\"\"}";
|
String body = "{\"enc\":\"" + CIPHER_B64 + "\",\"result\":\"\"}";
|
||||||
Properties prop = fieldDecryptProps("/enc", "/result");
|
Properties prop = fieldDecryptProps(tempProp, "/enc", "/result");
|
||||||
|
|
||||||
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("3-3. FIELD scope, toPath='/' — 복호화된 텍스트로 body 전체 교체")
|
@DisplayName("3-3. FIELD scope, toPath='/' — 복호화된 텍스트로 body 전체 교체")
|
||||||
void testPostFilter_field_decryptToRoot() throws Exception {
|
void testPostFilter_field_decryptToRoot() throws Exception {
|
||||||
String body = "{\"enc\":\"" + CIPHER_B64 + "\"}";
|
String body = "{\"enc\":\"" + CIPHER_B64 + "\"}";
|
||||||
Properties prop = fieldDecryptProps("/enc", "/");
|
Properties prop = fieldDecryptProps(tempProp, "/enc", "/");
|
||||||
|
|
||||||
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ class OutCryptoFilterTest {
|
|||||||
@DisplayName("3-4. FIELD scope — fromPath 값 없음 → body 그대로 반환")
|
@DisplayName("3-4. FIELD scope — fromPath 값 없음 → body 그대로 반환")
|
||||||
void testPostFilter_field_missingFromPath_passThrough() throws Exception {
|
void testPostFilter_field_missingFromPath_passThrough() throws Exception {
|
||||||
String body = "{\"other\":\"value\"}";
|
String body = "{\"other\":\"value\"}";
|
||||||
Properties prop = fieldDecryptProps("/enc", "/result");
|
Properties prop = fieldDecryptProps(tempProp, "/enc", "/result");
|
||||||
|
|
||||||
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
Object result = filter.doPostFilter("g", "a", prop, body, tempProp);
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ class OutCryptoFilterTest {
|
|||||||
void testPreFilter_body_aadFromTempProp() throws Exception {
|
void testPreFilter_body_aadFromTempProp() throws Exception {
|
||||||
String aadVal = "out-aad-value";
|
String aadVal = "out-aad-value";
|
||||||
Properties prop = bodyEncryptProps();
|
Properties prop = bodyEncryptProps();
|
||||||
prop.setProperty(OutCryptoFilter.PROP_AAD_PROP, "myAadKey");
|
prop.setProperty(AbstractCryptoFilter.PROP_AAD_HEADER, "myAadKey");
|
||||||
tempProp.setProperty("myAadKey", aadVal);
|
tempProp.setProperty("myAadKey", aadVal);
|
||||||
|
|
||||||
filter.doPreFilter("g", "a", prop, PLAIN_STR, tempProp);
|
filter.doPreFilter("g", "a", prop, PLAIN_STR, tempProp);
|
||||||
@@ -248,21 +248,21 @@ class OutCryptoFilterTest {
|
|||||||
return bodyEncryptProps();
|
return bodyEncryptProps();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties fieldEncryptProps(String fromPath, String toPath) {
|
private Properties fieldEncryptProps(Properties tempProp, String fromPath, String toPath) {
|
||||||
Properties p = new Properties();
|
Properties p = new Properties();
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_MODULE_NAME, MODULE);
|
p.setProperty(AbstractCryptoFilter.PROP_MODULE_NAME, MODULE);
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_SCOPE, "FIELD");
|
p.setProperty(AbstractCryptoFilter.PROP_SCOPE, "FIELD");
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_ENC_FROM_PATH, fromPath);
|
tempProp.setProperty(AbstractCryptoFilter.PROP_ENC_FROM_PATH, fromPath);
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_ENC_TO_PATH, toPath);
|
tempProp.setProperty(AbstractCryptoFilter.PROP_ENC_TO_PATH, toPath);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties fieldDecryptProps(String fromPath, String toPath) {
|
private Properties fieldDecryptProps(Properties tempProp, String fromPath, String toPath) {
|
||||||
Properties p = new Properties();
|
Properties p = new Properties();
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_MODULE_NAME, MODULE);
|
p.setProperty(AbstractCryptoFilter.PROP_MODULE_NAME, MODULE);
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_SCOPE, "FIELD");
|
p.setProperty(AbstractCryptoFilter.PROP_SCOPE, "FIELD");
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_DEC_FROM_PATH, fromPath);
|
tempProp.setProperty(AbstractCryptoFilter.PROP_DEC_FROM_PATH, fromPath);
|
||||||
p.setProperty(AbstractCryptoFilter.PROP_DEC_TO_PATH, toPath);
|
tempProp.setProperty(AbstractCryptoFilter.PROP_DEC_TO_PATH, toPath);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import static org.mockito.Mockito.*;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@@ -88,6 +90,47 @@ class InCryptoFilterTest {
|
|||||||
assertTrue(result.isEmpty());
|
assertTrue(result.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
@DisplayName("1-2. buildRuntimeContext 오버라이드 시 runtimeContext가 복호화 서비스에 전달된다")
|
||||||
|
void testBuildRuntimeContext_override_passedToDecrypt() throws Exception {
|
||||||
|
InCryptoFilter filterWithCtx = new InCryptoFilter() {
|
||||||
|
@Override
|
||||||
|
protected Map<String, String> buildRuntimeContext(Properties p, HttpServletRequest req) {
|
||||||
|
Map<String, String> ctx = new HashMap<>();
|
||||||
|
ctx.put("groupSeq", "G001");
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
String body = "{\"enc\":\"" + CIPHER_B64 + "\",\"result\":\"\"}";
|
||||||
|
|
||||||
|
filterWithCtx.doPreFilter("g", "a", body, fieldDecryptProps("/enc", "/result"), mockRequest, mockResponse);
|
||||||
|
|
||||||
|
ArgumentCaptor<Map> ctxCaptor = ArgumentCaptor.forClass(Map.class);
|
||||||
|
verify(mockService).decrypt(eq(MODULE), ctxCaptor.capture(), isNull(), eq(CIPHER));
|
||||||
|
assertEquals("G001", ctxCaptor.getValue().get("groupSeq"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
@DisplayName("1-3. buildRuntimeContext 오버라이드 시 runtimeContext가 암호화 서비스에 전달된다")
|
||||||
|
void testBuildRuntimeContext_override_passedToEncrypt() throws Exception {
|
||||||
|
InCryptoFilter filterWithCtx = new InCryptoFilter() {
|
||||||
|
@Override
|
||||||
|
protected Map<String, String> buildRuntimeContext(Properties p, HttpServletRequest req) {
|
||||||
|
Map<String, String> ctx = new HashMap<>();
|
||||||
|
ctx.put("groupSeq", "G001");
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
filterWithCtx.doPostFilter("g", "a", "plain-body", fieldEncryptProps("/", "/encryptedData"), mockRequest, mockResponse);
|
||||||
|
|
||||||
|
ArgumentCaptor<Map> ctxCaptor = ArgumentCaptor.forClass(Map.class);
|
||||||
|
verify(mockService).encrypt(eq(MODULE), ctxCaptor.capture(), isNull(), any(byte[].class));
|
||||||
|
assertEquals("G001", ctxCaptor.getValue().get("groupSeq"));
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 2. buildAad
|
// 2. buildAad
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -151,6 +194,19 @@ class InCryptoFilterTest {
|
|||||||
assertEquals(PLAIN_STR, result);
|
assertEquals(PLAIN_STR, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("3-4. message가 String/byte[] 외 타입 — toString() 변환 후 처리")
|
||||||
|
void testPreFilter_body_nonStringMessage_usesToString() throws Exception {
|
||||||
|
Object nonStringMsg = new Object() {
|
||||||
|
@Override
|
||||||
|
public String toString() { return CIPHER_B64; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Object result = filter.doPreFilter("g", "a", nonStringMsg, bodyDecryptProps(), mockRequest, mockResponse);
|
||||||
|
|
||||||
|
assertEquals(PLAIN_STR, result);
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 4. doPreFilter — FIELD scope 복호화
|
// 4. doPreFilter — FIELD scope 복호화
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user