Allow encoded properties in application.yml
main.class
public static void main(final String[] args) { SpringApplication application=new SpringApplication(IdpUiApplication.class); application.addInitializers(new PropertyDecodingContextInitializer()); application.run(args); }
PropertyDecodingContextInitializer.class
package com.ahold.api.idp.ui;import java.io.UnsupportedEncodingException;import java.util.Base64;import java.util.LinkedHashMap;import java.util.Map;import java.util.Base64.Decoder;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.lang3.StringUtils;import org.springframework.context.ApplicationContextInitializer;import org.springframework.context.ConfigurableApplicationContext;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;import lombok.extern.slf4j.Slf4j;@Component@Slf4jpublic class PropertyDecodingContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { private static final Pattern base64Pattern = Pattern.compile("base64\\((.*?)\\)"); /** * Handle every property and check if it is base64 encoded. overwrite the value with the decoed value. */ @Override public void initialize(ConfigurableApplicationContext applicationContext) { log.debug("initialize: scanning for encoded properties"); ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySource<?> propertySource : environment.getPropertySources()) { Map<String, Object> propertyOverrides = new LinkedHashMap<>(); decodeProperties(propertySource, propertyOverrides); if (!propertyOverrides.isEmpty()) { PropertySource<?> decodedProperties = new MapPropertySource("decoded " + propertySource.getName(), propertyOverrides); environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties); } } } /** * Decode all encoded properties and put them in the overrides map. Also the * original properties without encoding are added to the map. * * @param source - source of the properties * @param propertyOverrides - resulting map of decoded properties */ private void decodeProperties(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) { // Only strings can represent a base64 encoded value String decodedValue = decodeBase64InString((String) rawValue); propertyOverrides.put(key, decodedValue); } } } } /** * @param input - possible base64 code * @return decoded string */ private String decodeBase64InString(String input) { if (StringUtils.isBlank(input)) return input; StringBuffer output = new StringBuffer(); Matcher matcher = base64Pattern.matcher(input); while (matcher.find()) { String replacement = decodeBase64(matcher.group(1)); matcher.appendReplacement(output, replacement); } matcher.appendTail(output); return output.toString(); } /** * @param encoded - base64 value * @return decoded value */ private String decodeBase64(String encoded) { try { Decoder base64Decoder = Base64.getDecoder(); byte[] decodedData = base64Decoder.decode(encoded); String decodedString = new String(decodedData, "UTF-8"); return decodedString; } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } }}