Создание пользовательского Jasypt PropertySource в Springboot

Я использую Spring Boot для создания простого веб-приложения, которое обращается к базе данных. Я использую функциональность автоконфигурации для источника данных, настраивая spring.datasource.* свойства в application.properties, Это все работает блестяще и очень быстро - отличная работа, ребята @ 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;
    }
}

Затем я упаковал это в свою банку с META-INF/spring.factories файл следующим образом:

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

Это отлично работает при запуске из Maven с помощью mvn spring-boot:run, Проблема возникает, когда я запускаю ее как отдельную войну, используя java -jar my-app.war, Приложение все еще загружается, но не удается, когда я пытаюсь подключиться к базе данных, так как значение пароля все еще зашифровано. Добавление регистрации показывает, что EncryptedPropertySourceLoader никогда не загружается

Для меня это звучит как проблема с classpath. При запуске под maven порядок загрузки банок является строгим, но однажды под встроенным котом нет ничего, что говорило бы о том, что мой кастом 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/Stackru показывают, что это проблема политики безопасности Java, но, поскольку она работает при запуске из Maven, я думаю, что могу не учитывать это. Возможно, проблема с упаковкой...

2 ответа

Решение

Здесь есть два вопроса.

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 от META-INF/spring.factories упорядочивает результаты, используя org.springframework.core.OrderComparator, Это означает, что этот класс должен быть возвращен первым, и ему будет поручено предоставить реализацию PropertySourceLoader для файлов *.proerpties.

2) Вторым является проблема загрузки класса с исполняемым JAR/WAR, которая, по-видимому, вызвана ошибкой в ​​версии 1.1.2.RELEASE Spring Boot для Windows. Переход к версии 1.1.1.RELEASE или версии 1.1.3.RELEASE решает различные проблемы с файлом классов и свойств, которые не загружаются при запуске вне maven.

Вы можете попробовать это: jasypt-spring-boot. Он в основном оборачивает весь PropertySource, присутствующий в среде, в зашифрованную версию. 2 вещи, которые вам нужно сделать после импорта библиотеки (добавление зависимости, если вы используете maven), - аннотировать класс @Configuration с помощью @EnableEncryptableProperties и настраивать алгоритм шифрования и пароль через свойства.

Другие вопросы по тегам