Se finalmente ha funzionato. (Principalmente grazie a stephane-deraco su github)
La chiave per la soluzione è una classe che implementa ApplicationContextInitializer<ConfigurableApplicationContext>
. L'ho chiamato PropertyPasswordDecodingContextInitializer
.
Il problema principale era ottenere la primavera per usare questo ApplicationContextInitializer
. Informazioni importanti sono disponibili nello reference. Ho scelto l'approccio utilizzando un META-INF/spring.factories con seguente contenuto:
org.springframework.context.ApplicationContextInitializer=ch.mycompany.myproject.PropertyPasswordDecodingContextInitializer
Il PropertyPasswordDecodingContextInitializer
utilizza un PropertyPasswordDecoder
e una classe di attuazione, attualmente per semplicità un Base64PropertyPasswordDecoder
.
PropertyPasswordDecodingContextInitializer.java
package ch.mycompany.myproject;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.stereotype.Component;
@Component
public class PropertyPasswordDecodingContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Pattern decodePasswordPattern = Pattern.compile("password\\((.*?)\\)");
private PropertyPasswordDecoder passwordDecoder = new Base64PropertyPasswordDecoder();
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySource<?> propertySource : environment.getPropertySources()) {
Map<String, Object> propertyOverrides = new LinkedHashMap<>();
decodePasswords(propertySource, propertyOverrides);
if (!propertyOverrides.isEmpty()) {
PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides);
environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties);
}
}
}
private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
if (source instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
for (String key : enumerablePropertySource.getPropertyNames()) {
Object rawValue = source.getProperty(key);
if (rawValue instanceof String) {
String decodedValue = decodePasswordsInString((String) rawValue);
propertyOverrides.put(key, decodedValue);
}
}
}
}
private String decodePasswordsInString(String input) {
if (input == null) return null;
StringBuffer output = new StringBuffer();
Matcher matcher = decodePasswordPattern.matcher(input);
while (matcher.find()) {
String replacement = passwordDecoder.decodePassword(matcher.group(1));
matcher.appendReplacement(output, replacement);
}
matcher.appendTail(output);
return output.toString();
}
}
PropertyPasswordDecoder.java
package ch.mycompany.myproject;
public interface PropertyPasswordDecoder {
public String decodePassword(String encodedPassword);
}
Base64PropertyPasswordDecoder.java
package ch.mycompany.myproject;
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64;
public class Base64PropertyPasswordDecoder implements PropertyPasswordDecoder {
@Override
public String decodePassword(String encodedPassword) {
try {
byte[] decodedData = Base64.decodeBase64(encodedPassword);
String decodedString = new String(decodedData, "UTF-8");
return decodedString;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
Attenzione, ApplicationContext non è stato inizializzato in questa fase, quindi il meccanismo di autowiring o altri meccanismi relativi ai bean non funzionerà.
Aggiornamento: Incluso @jny 's suggerimenti.
Non penso che tu possa, se stai solo usando qualcosa di costruito in Primavera. Tuttavia, se stai caricando manualmente questo YAML, quindi lo inserisci in Spring, fallo lì. –
Suppongo di poter scrivere il mio PropertySource. Speravo di trovare un meccanismo che si applica a tutte le fonti di proprietà. –
Potresti essere interessato a [questo problema Spring Boot] (https://github.com/spring-projects/spring-boot/issues/1312) –