Я пытаюсь прослушать события приложения в 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
1
Maverick Riz 30 Май 2019 в 08:40

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 );
             }
          }
       }
0
Maverick Riz 11 Июн 2019 в 21:53

Вы можете использовать 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.

1
Punit Tiwan 7 Июн 2019 в 10:15