Revert "PTL_USER 암호화 적용, SafeDB Wrapper 클래스 추가"

This reverts commit 790f9092fe.
This commit is contained in:
Rinjae
2025-09-26 17:59:58 +09:00
parent 790f9092fe
commit 202261d1e6
11 changed files with 11 additions and 498 deletions
@@ -5,14 +5,13 @@ import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.ApprovalStatus;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.RoleCode;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums.UserStatus;
import com.eactive.ext.kjb.safedb.SafeDBMNotRnnoConverter;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@@ -29,9 +28,8 @@ public class PortalUser extends Auditable implements Serializable, com.eactive.e
@GeneratedValue(generator = "uuid-gen", strategy = GenerationType.IDENTITY)
private String id;
@Column(name = "login_id", length = 200, nullable = false)
@Column(name = "login_id", length = 32, nullable = false)
@Comment("로그인ID")
@Convert(converter = SafeDBMNotRnnoConverter.class)
private String loginId;
@Column(name = "password_hash", length = 60)
@@ -42,19 +40,16 @@ public class PortalUser extends Auditable implements Serializable, com.eactive.e
@Comment("사용자이름")
private String userName;
@Column(name = "phone_number", length = 50)
@Column(name = "phone_number", length = 12)
@Comment("전화번호")
@Convert(converter = SafeDBMNotRnnoConverter.class)
private String phoneNumber;
@Column(name = "mobile_number", length = 50)
@Column(name = "mobile_number", length = 20)
@Comment("휴대폰 번호")
@Convert(converter = SafeDBMNotRnnoConverter.class)
private String mobileNumber;
@Column(name = "email_addr", length = 200)
@Column(name = "email_addr", length = 30)
@Comment("이메일주소")
@Convert(converter = SafeDBMNotRnnoConverter.class)
private String emailAddr;
@ManyToOne(fetch = FetchType.EAGER)
@@ -1,19 +0,0 @@
package com.eactive.ext.kjb.safedb;
import java.lang.reflect.InvocationTargetException;
public abstract class SafeDBBroker extends SafeDBFaker{
private Object instance;
protected void initialize() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> clazz = Class.forName("com.initech.safedb.SimpleSafeDB");
instance = clazz.getMethod("getInstance").invoke(null);
}
protected Object methodInvoke(String methodName, Class<?>[] paramTypes, Object[] params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
if (instance == null) {
throw new IllegalStateException("SafeDBBroker is not initialized.");
}
return instance.getClass().getMethod(methodName, paramTypes).invoke(instance, params);
}
}
@@ -1,51 +0,0 @@
package com.eactive.ext.kjb.safedb;
public enum SafeDBColumns {
RNNO("RNNO"),
PSWD("PSWD"),
NOT_RNNO("NOT_RNNO"),;
private final String value;
SafeDBColumns (String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static boolean contains(String test) {
for (SafeDBColumns c : SafeDBColumns.values()) {
if (c.name().equals(test)) {
return true;
}
}
return false;
}
public static boolean isEqualsIgnoreCase(SafeDBColumns column, String test) {
if (column == null || test == null) {
return false;
}
return column.getValue().equalsIgnoreCase(test);
}
public static SafeDBColumns fromString(String text) {
for (SafeDBColumns b : SafeDBColumns.values()) {
if (b.name().equalsIgnoreCase(text)) {
return b;
}
}
throw new IllegalArgumentException("No constant with text " + text + " found");
}
public boolean isEqualsIgnoreCase(String test) {
if (test == null) {
return false;
}
return this.value.equalsIgnoreCase(test);
}
}
@@ -1,73 +0,0 @@
package com.eactive.ext.kjb.safedb;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
/**
* SafeDBFaker provides a fake encryption method for testing purposes when the real SafeDB library is not available.
*/
public abstract class SafeDBFaker {
private static final String AES_256_KEY = "1234567890123456" + "1234567890123456";
public String fakeEncrypt(String userId, String table, String column, String data) {
if (SafeDBColumns.PSWD.isEqualsIgnoreCase(column)) {
// SHA256 + Base64 인코딩된 가짜 비밀번호 반환
return sha256Base64(data);
} else {
// AES256 암호화된 가짜 데이터 반환
return aes256Encrypt(data);
}
}
public String fakeDecrypt(String userId, String table, String column, String data) {
if (SafeDBColumns.PSWD.isEqualsIgnoreCase(column)) {
// 비밀번호는 복호화하지 않음
throw new UnsupportedOperationException("Password decryption is not supported.");
} else {
// AES256 복호화된 가짜 데이터 반환
return aes256Decrypt(data);
}
}
private String sha256Base64(String data) {
try {
MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
// JVM 옵션을 따라가기 위해 캐릭터셋을 명시 하지 않음.
byte[] hash = digest.digest(data.getBytes());
return java.util.Base64.getEncoder().encodeToString(hash);
} catch (Exception e) {
throw new RuntimeException("Error generating SHA-256 hash", e);
}
}
// AES256 암호화
private String aes256Encrypt(String data) {
try {
Cipher cipher = javax.crypto.Cipher.getInstance("AES");
SecretKeySpec keySpec = new javax.crypto.spec.SecretKeySpec(AES_256_KEY.getBytes(), "AES");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(data.getBytes());
return java.util.Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("Error during AES encryption", e);
}
}
private String aes256Decrypt(String encryptedData) {
try {
Cipher cipher = javax.crypto.Cipher.getInstance("AES");
SecretKeySpec keySpec = new javax.crypto.spec.SecretKeySpec(AES_256_KEY.getBytes(), "AES");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, keySpec);
byte[] decodedBytes = java.util.Base64.getDecoder().decode(encryptedData);
byte[] decrypted = cipher.doFinal(decodedBytes);
return new String(decrypted);
} catch (Exception e) {
throw new RuntimeException("Error during AES decryption", e);
}
}
}
@@ -1,81 +0,0 @@
package com.eactive.ext.kjb.safedb;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
@Slf4j
public class SafeDBMNotRnnoConverter implements AttributeConverter<String, String> {
/**
* 암호화
* @param attribute the entity attribute value to be converted
* @return
*/
@Override
public String convertToDatabaseColumn(String attribute) {
log.debug("DB 암호화 #1 - {} / {}", attribute, SafeDBColumns.NOT_RNNO);
String originalAttribute = attribute;
if (StringUtils.isNotEmpty(attribute)) {
SafeDBWrapper safeDBWrapper = SafeDBWrapper.getInstance();
attribute = safeDBWrapper.encryptNotRnno(attribute);
}
log.debug("DB 암호화 #2 : {} -> {}", originalAttribute, attribute);
return attribute;
}
/**
* 복호화
* @param dbData the data from the database column to be
* converted
* @return
*/
@Override
public String convertToEntityAttribute(String dbData) {
log.debug("DB 복호화 #1 - {} / {}", dbData, SafeDBColumns.NOT_RNNO);
String dbDataOriginal = dbData;
if (StringUtils.isNotEmpty(dbData)) {
if (this.isEncrypted(dbData)) {
SafeDBWrapper safeDBWrapper = SafeDBWrapper.getInstance();
dbData = safeDBWrapper.decryptNotRnno(dbData);
} else {
log.debug("DB 복호화 경고: Base64 형식이 아님. 복호화하지 않고 원본 반환. dbData={}", dbData);
}
}
log.debug("DB 복호화 #2 : {} -> {}", dbDataOriginal, dbData);
return dbData;
}
/**
* 암호화 여부 확인(base64 인코딩 여부로 판단, 또는 0-9, - 로 구성된 경우 암호화 되지 않은 걸로 판단(연락처))
* @param data
* @return
*/
private boolean isEncrypted(String data) {
if (StringUtils.isEmpty(data)) {
return false;
}
data = data.trim();
// Base64 형식 체크
if (SafeDBWrapper.isBase64(data)) {
return true;
}
// 숫자, - 로만 구성된 경우 암호화 되지 않은 걸로 판단 (ex: 연락처)
if (data.matches("^[0-9-]+$")) {
return false;
}
return false;
}
}
@@ -1,91 +0,0 @@
package com.eactive.ext.kjb.safedb;
public class SafeDBWrapper extends SafeDBBroker {
private static SafeDBWrapper instance;
private boolean isRealSafeDB = false;
public static SafeDBWrapper getInstance() {
if ( instance == null ) {
synchronized ( SafeDBWrapper.class ) {
if ( instance == null ) {
instance = new SafeDBWrapper();
}
}
}
return instance;
}
public static 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);
}
private SafeDBWrapper() throws SafeDBWrapperException {
synchronized ( SafeDBWrapper.class ) {
// "com.initech.safedb.SimpleSafeDB" 클래스 존재 여부 확인
try {
Class.forName("com.initech.safedb.SimpleSafeDB");
isRealSafeDB = true; // 클래스가 존재하면 true로 설정
} catch (ClassNotFoundException e) {
isRealSafeDB = false; // 클래스가 존재하지 않으면 false로 설정
} catch (Exception e) {
throw new SafeDBWrapperException(("[SafeDBWrapper] Classloader error: " + e.getMessage()), e);
}
if (isRealSafeDB) {
try {
super.initialize();
} catch (Exception e) {
throw new SafeDBWrapperException("[SafeDBWrapper] Initialization error: " + e.getMessage(), e);
}
}
}
}
public String encrypt(String userId, String table, String column, String data) throws SafeDBWrapperSdkException {
if (isRealSafeDB) {
try {
return (String) super.methodInvoke("encrypt",
new Class<?>[]{String.class, String.class, String.class, String.class},
new Object[]{userId, table, column, data});
} catch (Exception e) {
throw new SafeDBWrapperSdkException("[SafeDBWrapper] Encrypt error: " + e.getMessage(), e);
}
} else {
return super.fakeEncrypt(userId, table, column, data);
}
}
public String encryptNotRnno(String data) throws SafeDBWrapperSdkException {
return this.encrypt("SAFEDB", "SAFEDB.POLICY", "NOT_RNNO", data);
}
public String decrypt(String userId, String table, String column, String data) throws SafeDBWrapperSdkException {
if (isRealSafeDB) {
try {
return (String) super.methodInvoke("decrypt",
new Class<?>[]{String.class, String.class, String.class, String.class},
new Object[]{userId, table, column, data});
} catch (Exception e) {
throw new SafeDBWrapperException("[SafeDBWrapper] Decrypt error: " + e.getMessage(), e);
}
} else {
return super.fakeDecrypt(userId, table, column, data);
}
}
public String decryptNotRnno(String data) throws SafeDBWrapperSdkException {
return this.decrypt("SAFEDB", "SAFEDB.POLICY", "NOT_RNNO", data);
}
public boolean isRealSafeDB() {
return isRealSafeDB;
}
}
@@ -1,46 +0,0 @@
package com.eactive.ext.kjb.safedb;
public class SafeDBWrapperException extends RuntimeException {
private Exception cause;
private int errcode;
public SafeDBWrapperException() {
}
public SafeDBWrapperException(String message) {
super(message);
}
public SafeDBWrapperException(String message, Throwable cause) {
super(message, cause);
}
public SafeDBWrapperException(String message, Exception cause) {
super(message);
this.cause = cause;
}
public SafeDBWrapperException(int errcode, String message) {
super(message);
this.errcode = errcode;
}
public SafeDBWrapperException(String errcode, String message) {
super(message);
this.errcode = new Integer(errcode);
}
public Throwable getCause() {
return this.cause;
}
public String getMessage() {
return this.cause != null ? super.getMessage() + "\n caused by [ " + this.cause.getMessage() + " ]" : super.getMessage();
}
public int getErrorCode() {
return this.errcode;
}
}
@@ -1,18 +0,0 @@
package com.eactive.ext.kjb.safedb;
public class SafeDBWrapperSdkException extends SafeDBWrapperException {
public SafeDBWrapperSdkException(Exception ex) {
super(ex.getMessage(), ex);
}
public SafeDBWrapperSdkException(String message) {
super(message);
}
public SafeDBWrapperSdkException(String message, Exception ex) {
super(message, ex);
}
public SafeDBWrapperSdkException() {
}
}