티스토리 뷰
tomcat에서 jndi datasource 설정을 하는 방법은 전에 알아보았다.
위 글에서 간략하게 암호화 하는 과정에 대해서 알아보았는데 오늘은 이것을 구체적으로 알아보도록 하겠다.
암호화하는 역할을 하는 프로젝트를 jar로 추출한다고 했었는데 이 암호화하는 역할을 하는 DataSourceFactory를 가지고 있는 프로젝트는 다음을 참고했다. 세상엔 참 뛰어난 사람들이 많다.
이곳에서 EncryptedDataSourceFactory.java와 Encryptor.java 클래스를 가지고 와서 EncryptModule 이라는 프로젝트를 간단하게 하나 만들었다.
클래스의 내용은 위 링크에도 있지만 간략하게 알아보면 (유심히 볼 필요는 없다. 어차피 packing할거라..)
EncryptedDataSourceFactory.java
package secured;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.Properties;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.naming.Context;
import javax.sql.DataSource;
import org.apache.tomcat.jdbc.pool.DataSourceFactory;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.XADataSource;
public class EncryptedDataSourceFactory extends DataSourceFactory {
private Encryptor encryptor = null;
public EncryptedDataSourceFactory() {
try {
encryptor = new Encryptor(); // If you've used your own secret key, pass it in...
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedEncodingException e) {
System.out.println("Error instantiating decryption class." + e);
throw new RuntimeException(e);
}
}
@Override
public DataSource createDataSource(Properties properties, Context context, boolean XA) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, SQLException, NoSuchAlgorithmException,
NoSuchPaddingException {
// Here we decrypt our password.
PoolConfiguration poolProperties = EncryptedDataSourceFactory.parsePoolProperties(properties);
poolProperties.setUsername(encryptor.decrypt(poolProperties.getUsername()));
poolProperties.setPassword(encryptor.decrypt(poolProperties.getPassword()));
// The rest of the code is copied from Tomcat's DataSourceFactory.
if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
performJNDILookup(context, poolProperties);
}
org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
: new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
dataSource.createPool();
return dataSource;
}
}
tomcat의 DataSourceFactory 클래스를 상속받아 만든 클래스로 <Resource> 의 factory 부분에 해당하는 클래스이다. 이 클래스의 full path를 기억해 놓도록 한다.
Encryptor.java
package secured;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class Encryptor {
private static final String ALGORITHM = "AES";
private static final String defaultSecretKey = "asdfo23jda3sds";
private Key secretKeySpec;
public Encryptor()
throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException {
this(null);
}
public Encryptor(String secretKey)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException {
this.secretKeySpec = generateKey(secretKey);
}
public String encrypt(String plainText) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return asHexString(encrypted);
}
public String decrypt(String encryptedString) throws InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(toByteArray(encryptedString));
return new String(original);
}
private Key generateKey(String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException {
if (secretKey == null) {
secretKey = defaultSecretKey;
}
byte[] key = (secretKey).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only the first 128 bit
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
return new SecretKeySpec(key, ALGORITHM);
}
private final String asHexString(byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
private final byte[] toByteArray(String hexString) {
int arrLength = hexString.length() >> 1;
byte buf[] = new byte[arrLength];
for (int ii = 0; ii < arrLength; ii++) {
int index = ii << 1;
String l_digit = hexString.substring(index, index + 2);
buf[ii] = (byte) Integer.parseInt(l_digit, 16);
}
return buf;
}
public static void main(String[] args) throws Exception {
Encryptor aes = new Encryptor(defaultSecretKey);
String testid = "testid";
System.out.println("Id:" + aes.encrypt(testid));
String testpassword = "testpassword";
System.out.println("Pw:" + aes.encrypt(testpassword));
}
}
여기서 유심히 봐야할곳은 main 메소드이다. 이곳에서 db 접속을 위한 username과 password에 해당하는 정보를 입력 후 main 메소드를 실행해 encrypt 시키고 이 값을 잘 보관해 둔다.
그 다음은 이 프로젝트를 jar로 export를 시켜준다. 과정은 다음과 같다.
프로젝트 우클릭 > Exprot > jar 입력 > JAR file > 추출할 jar 파일명 입력 후 Finish
이렇게 하면 jar 파일이 생성이 되었을것이고 이 jar 파일을 톰캣설치경로/lib 밑에 넣어둔다. 이렇게 생성한 jar 파일 외에 commons-collections.jar, commons-dbcp.jar, commons-pool.jar 파일들도 추가적으로 넣어준다.
이렇게 한다음에 server.xml이나 context.xml 파일에
<Context>
...
<Resource name="jndi/test" auth="Container"
factory="secured.EncryptedDataSourceFactory"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@ip:port:sid"
username="암호화된id" password="암호화된pwd" maxTotal="20" maxIdle="20"
maxWaitMillis="-1"/>
</Context>
이곳의 password 부분에 아까 Encryptor.java 를 통해 생성한 암호화된id와 암호화된pwd 를 넣어준다. 또한 EncryptedDataSourceFactory 클래스의 full path도 factory 부에 기입을 한다.
이렇게 하면 tomcat의 username/password 암호화에 대한 설정은 끝이 난다.
'Server > WAS' 카테고리의 다른 글
Tomcat Context Path가 / 인 경우 manager 접근방법 (0) | 2020.08.14 |
---|---|
org.apache.catalina.loader.WebappClassLoaderBase modified 오류가 나며 무한재기동하는 현상 (0) | 2020.07.31 |
Tomcat JNDI Datasource 설정하여 Spring 연동하기 (0) | 2020.06.02 |
Jeus 인코딩 문제 해결방법 (1) | 2020.04.28 |
톰캣 프로젝트 외부 디렉토리에 있는 이미지 가지고오기 (0) | 2020.04.28 |