在Spring Boot中创建自定义Jasypt PropertySource

时间:2014-06-27 11:49:52

标签: spring-boot jasypt

我使用Spring Boot创建一个访问数据库的简单Web应用程序。我通过在spring.datasource.*中设置application.properties属性,充分利用了DataSource的自动配置功能。这一切都很出色,非常快 - 很棒的工作人员@Spring!

我公司的政策是不应该有明文密码。因此,我需要加密sping.datasource.password。经过一番挖掘后,我决定创建一个org.springframework.boot.env.PropertySourceLoader实现,创建一个jasypt org.jasypt.spring31.properties.EncryptablePropertiesPropertySource,如下所示:

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;
    }
}

然后我将它打包在自己的jar中,其中包含META-INF/spring.factories文件,如下所示:

org.springframework.boot.env.PropertySourceLoader=com.mycompany.spring.boot.env.EncryptedPropertySourceLoader

使用mvn spring-boot:run从maven运行时,这非常有效。当我使用java -jar my-app.war将其作为独立战争运行时,会出现此问题。当我尝试连接到数据库时,应用程序仍然加载但失败,因为密码值仍然是加密的。添加日志记录表明永远不会加载EncryptedPropertySourceLoader

对我而言,这听起来像是一个类路径问题。在maven下运行时,jar加载顺序是严格的,但是在嵌入的tomcat下,没有什么可说的,我的自定义jar应该在Spring Boot之前加载。

我已尝试将以下内容添加到我的pom.xml中,以确保保留classpth,但它似乎没有任何效果。

<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>

有没有人有任何想法?提前谢谢。

更新:

向前迈出的一步:我已设法通过EncryptedPropertySourceLoader类实现org.springframework.core.PriorityOrdered接口并从HIGHEST_PRECEDENCE返回getOrder()来解决此问题。这已经解决了未使用PropertySourceLoader的问题。但是,当它尝试解密属性时,它现在抛出以下错误:

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)

mvn spring-boot:run运行时,这不会发生,但从可执行war文件运行时确实会发生这种情况。两种方案都使用相同的JVM(jdk1.6.0_35)。 Google / Stackoverflow上的结果表明这是java安全策略的一个问题,但是当它从maven运行时确实有效,我想我可以打折。可能是包装问题......

2 个答案:

答案 0 :(得分:6)

这里有两个问题。

1)需要加载EncryptedPropertySourceLoader高于标准的PropertiesPropertySourceLoader。这可以通过实现PriorityOrder接口来实现,如下所示:

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;
    }
}

org.springframework.core.io.support.SpringFactoriesLoader加载org.springframework.boot.env.PropertySourceLoader的{​​{1}}类使用META-INF/spring.factories对结果进行排序。这意味着应首先返回此类,并且将负责为* .proerpties文件提供PropertySourceLoader实现。

2)第二个是可执行JAR / WAR的类加载问题,这似乎是由Windows上的Spring Boot 1.1.2.RELEASE版本中的错误引起的。删除版本1.1.1.RELEASE或版本1.1.3.RELEASE解决了在maven外部运行时没有加载类和proerpties文件的各种问题。

答案 1 :(得分:6)

你可以尝试一下:jasypt-spring-boot 它基本上使用加密版本包装环境中存在的所有PropertySource。导入库后要做的两件事(如果使用maven则添加依赖关系)是使用@EnableEncryptableProperties注释@Configuration类,并通过属性配置加密算法和密码。