spring-boot - online - spring encrypted properties
Creando una Propiedad de Jasypt personalizada en Springboot (2)
Estoy usando Spring Boot para crear una aplicación web simple que acceda a una base de datos. Aprovecho la funcionalidad de autoconfiguración para DataSource configurando las propiedades de spring.datasource.*
En application.properties
. Todo eso funciona de manera brillante y fue muy rápido, ¡muchachos de trabajo en la primavera!
La política de mi empresa es que no debe haber contraseñas de texto claras. Por lo tanto, necesito tener la sping.datasource.password
encriptada. Después de investigar un poco, decidí crear una implementación org.springframework.boot.env.PropertySourceLoader
que crea un jasypt org.jasypt.spring31.properties.EncryptablePropertiesPropertySource
siguiente manera:
public class EncryptedPropertySourceLoader implements PropertySourceLoader
{
private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
public EncryptedPropertySourceLoader()
{
//TODO: this could be taken from an environment variable
this.encryptor.setPassword("password");
}
@Override
public String[] getFileExtensions()
{
return new String[]{"properties"};
}
@Override
public PropertySource<?> load(final String name, final Resource resource, final String profile) throws IOException
{
if (profile == null)
{
final Properties props = PropertiesLoaderUtils.loadProperties(resource);
if (!props.isEmpty())
{
return new EncryptablePropertiesPropertySource(name, props, this.encryptor);
}
}
return null;
}
}
Luego empaqué esto en su propio jar con un archivo META-INF/spring.factories
la siguiente manera:
org.springframework.boot.env.PropertySourceLoader=com.mycompany.spring.boot.env.EncryptedPropertySourceLoader
Esto funciona perfectamente cuando se ejecuta desde maven usando mvn spring-boot:run
. El problema ocurre cuando lo ejecuto como una guerra independiente usando java -jar my-app.war
. La aplicación aún se carga pero falla cuando trato de conectarme a la base de datos ya que el valor de la contraseña aún está encriptado. Agregar el registro revela que EncryptedPropertySourceLoader
nunca se carga.
Para mí esto suena como un problema de classpath. Cuando se ejecuta bajo maven, el orden de carga del jar es estricto, pero una vez debajo del tomcat embebido no hay nada que decir que mi tarro personalizado debe cargarse antes de Spring Boot.
Intenté agregar lo siguiente a mi pom.xml para asegurarme de que se conserva la classpth, pero parece que no ha tenido ningún efecto.
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<mainClass>${start-class}</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
¿Alguien tiene alguna idea? Gracias por adelantado.
ACTUALIZAR:
Un paso adelante: me las he arreglado para hacer que la clase EncryptedPropertySourceLoader
implemente la interfaz org.springframework.core.PriorityOrdered
y devuelva HIGHEST_PRECEDENCE
de getOrder()
. Esto ahora ha solucionado el problema de que PropertySourceLoader no se utiliza. Sin embargo, ahora arroja el siguiente error cuando intenta descifrar las propiedades:
org.jasypt.exceptions.EncryptionInitializationException: java.security.NoSuchAlgorithmException: PBEWithMD5AndDES SecretKeyFactory not available
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:716)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.initialize(StandardPBEStringEncryptor.java:553)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:705)
at org.jasypt.properties.PropertyValueEncryptionUtils.decrypt(PropertyValueEncryptionUtils.java:72)
at org.jasypt.properties.EncryptableProperties.decode(EncryptableProperties.java:230)
at org.jasypt.properties.EncryptableProperties.get(EncryptableProperties.java:209)
at org.springframework.core.env.MapPropertySource.getProperty(MapPropertySource.java:36)
at org.springframework.boot.env.EnumerableCompositePropertySource.getProperty(EnumerableCompositePropertySource.java:49)
at org.springframework.boot.context.config.ConfigFileApplicationListener$ConfigurationPropertySources.getProperty(ConfigFileApplicationListener.java:490)
De nuevo, esto no ocurre cuando se ejecuta desde mvn spring-boot:run
pero sucede cuando se ejecuta desde el archivo war ejecutable. Ambos escenarios usan la misma JVM (jdk1.6.0_35). Los resultados en Google / Stackoverflow sugieren que este es un problema con la política de seguridad de Java, pero como funciona cuando se ejecuta desde Maven creo que puedo descartar eso. Posiblemente un problema de empaque ...
Hay dos problemas aquí.
1) El EncryptedPropertySourceLoader necesita cargarse más alto que el PropertiesPropertySourceLoader estándar. Esto se puede lograr implementando la interfaz PriorityOrder de la siguiente manera:
public class EncryptedPropertySourceLoader implements PropertySourceLoader, PriorityOrdered
{
private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
public EncryptedPropertySourceLoader()
{
this.encryptor.setPassword("password"); //TODO: this could be taken from an environment variable
}
@Override
public String[] getFileExtensions()
{
return new String[]{"properties"};
}
@Override
public PropertySource<?> load(final String name, final Resource resource, final String profile) throws IOException
{
if (profile == null)
{
//load the properties
final Properties props = PropertiesLoaderUtils.loadProperties(resource);
if (!props.isEmpty())
{
//create the encryptable properties property source
return new EncryptablePropertiesPropertySource(name, props, this.encryptor);
}
}
return null;
}
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE;
}
}
La clase org.springframework.core.io.support.SpringFactoriesLoader
que carga org.springframework.boot.env.PropertySourceLoader
de META-INF/spring.factories
ordena los resultados utilizando org.springframework.core.OrderComparator
. Lo que significa que esta clase debe devolverse primero y se le dará la responsabilidad de proporcionar la implementación de PropertySourceLoader para los archivos * .proerpties.
2) El segundo es un problema de carga de clases con el JAR / WAR ejecutable que parece ser causado por un error en la versión 1.1.2.RELEASE de Spring Boot en Windows. Bajando a la versión 1.1.1.RELEASE o a la versión 1.1.3.RELEASE resuelve los diversos problemas con las clases y archivos de proerpties que no se cargan cuando se ejecutan fuera de maven.
Podría probar esto: jasypt-spring-boot Básicamente, envuelve todos los PropertySource presentes en el entorno con una versión encriptable. Las dos cosas que debes hacer una vez que importas la biblioteca (agregando la dependencia si usas maven) es anotar tu clase @Configuration con @EnableEncryptableProperties, y configurar el algoritmo de encriptación y la contraseña a través de las propiedades.