Я пытаюсь прослушать события приложения в Spring и расшифровать свойства приложения, которые зашифрованы (имеет префикс шифрования). Идея состоит в том, чтобы создать компонент Spring, который будет автоматически дешифровать свойства пружины при загрузке среды, если значение свойства зашифровано.
Это необходимо для работы с унаследованными весенними приложениями (без весенней загрузки), в которых есть файлы application.env.properties, а также с более поздними весенними загрузочными приложениями, свойства которых определены в файлах yaml. Должна быть возможность дешифровать любое свойство пружины независимо от источника и не должен зависеть от весенней загрузки и работать с любой весенней версией.
public class DecryptingPropertiesListener
implements ApplicationListener<ContextRefreshedEvent>, Ordered {
public static final String PREFIX_KEY = "{decrypt}";
private String prefix;
private Encrypter encrypter = Encrypter.defaultInstance();
@Override
public void onApplicationEvent(ContextRefreshedEvent event ) {
Environment environment = event.getApplicationContext().getEnvironment();
prefix = environment.getProperty(PREFIX_KEY, "{encrypted}");
final MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
Set<String> encryptedKeys = getKeysOfEncryptedPropertyValues(environment, propertySources);
addDecryptedValues(environment, propertySources, encryptedKeys);
}
private Set<String> getKeysOfEncryptedPropertyValues(Environment environment, MutablePropertySources propertySources) {
return streamFromIterator(propertySources.iterator())
.filter(EnumerablePropertySource.class::isInstance)
.map(EnumerablePropertySource.class::cast)
.flatMap(source -> asList(source.getPropertyNames()).stream())
.filter(this::isNotEncryptionConfigProperty)
.filter(key -> isEncrypted(environment.getProperty(key)))
.collect(toSet());
}
private boolean isNotEncryptionConfigProperty(String key) {
return !PREFIX_KEY.equals(key);
}
private Stream<PropertySource<?>> streamFromIterator(Iterator<PropertySource<?>> iterator) {
Iterable<PropertySource<?>> iterable = () -> iterator;
return StreamSupport.stream(iterable.spliterator(), false);
}
private void addDecryptedValues(Environment environment, MutablePropertySources propertySources, Set<String> encryptedKeys) {
Map<String, Object> decryptedProperties = encryptedKeys.stream()
.collect(toMap(
key -> key,
key -> decryptPropertyValue(environment.getProperty(key))));
propertySources.addFirst(new MapPropertySource("decryptedValues", decryptedProperties));
}
private String decryptPropertyValue(String encryptedPropertyValue) {
try {
return encrypter.decryptIfEncrypted(encryptedPropertyValue);
}
catch (EncryptionException e) {
throw new RuntimeException("Unable to decrypt property value '" + encryptedPropertyValue + "'", e);
}
}
private boolean isEncrypted(Object propertyValue) {
return propertyValue != null && propertyValue instanceof String && ((String)propertyValue).startsWith(prefix);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
Но проблема в том, что я не вижу свойств приложения, возвращаемых в этой строке (среда (ConfigurableEnvironment)) .getPropertySources (); Я могу видеть свойства системы здесь, но не приложение. Любая идея, как я могу загрузить свойства приложения здесь и расшифровать их? Спасибо
РЕДАКТИРОВАТЬ: Добавление образца файла свойств. Идея состоит в том, чтобы добавить этот универсальный jar-файл в зависимости от различных веб-приложений, как старых, так и новых. Файл свойств ниже имеет формат myapp.env.properties, а для myapp.system.properties определен env. Но весенние загрузочные приложения используют файлы .yaml. Служебный и защитный пароль необходимо расшифровать, так как они имеют префикс.
base.url=http://localhost:8080/myapp
service.password={decrypt}123456789==
security.password={decrypt}abcdefgh==
help.email.address=support@gmail.com
2 ответа
Я закончил реализацию пользовательского ApplicationContextInitializer и переопределил initialize (), чтобы расшифровать свойства из среды и вставить их с высоким приоритетом, чтобы они переопределяли зашифрованные значения.
public class PropertyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize( ConfigurableApplicationContext applicationContext ) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for ( PropertySource<?> propertySource : environment.getPropertySources() ) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
// call to decrypt method
decryptProperty( propertySource, propertyOverrides );
if ( !propertyOverrides.isEmpty() ) {
PropertySource<?> decodedProperties = new MapPropertySource( "decrypt " + propertySource.getName(),
propertyOverrides );
environment.getPropertySources().addBefore( propertySource.getName(), decodedProperties );
}
}
}
Вы можете использовать EncryptablePropertyPlaceholderConfigurer
и предоставить экземпляр StringEncryptor
, и он будет обрабатывать расшифровку свойств для вас. Вы также можете расширить класс для загрузки дополнительных свойств, если хотите.
Примере:
@Configuration
public class PropertyConfiguration {
@Bean(name="envPropertyConfigurer")
public EncryptablePropertyPlaceholderConfigurer getConfigurer() {
return new EncryptablePropertyPlaceholderConfigurer (encryptor());
}
private StringEncryptor encryptor() {
StandardPBEStringEncryptor s_encryptor = new StandardPBEStringEncryptor();
s_encryptor.setAlgorithm("PBEWithMD5AndDES");
s_encryptor.setPassword("secretKey");
return s_encryptor;
}
}
Вы также можете сделать это в весенней конфигурации XML, как это
<bean id="envPropertyEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="algorithm" value="secretKey" />
</bean>
<bean id="envPropertyConfigurer" class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="envPropertyEncryptor" />
</bean>
Вы также можете прочитать секретный ключ из файла вместо прямой установки здесь. Вы можете сделать это, установив свойство StandardPBEStringEncryptor config
с помощью FileStringPBEConfig
.
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].