Skip to content

Commit 77d221d

Browse files
Ryan Baxterryanjbaxter
andauthored
Add the ability for FailsafeTextEncryptor to have a delegate. (#1349)
Related to spring-cloud/spring-cloud-config#2330 Co-authored-by: Ryan Baxter <[email protected]>
1 parent e120edb commit 77d221d

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/TextEncryptorUtils.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,40 @@ public static boolean isLegacyBootstrap(Environment environment) {
177177
*/
178178
public static class FailsafeTextEncryptor implements TextEncryptor {
179179

180+
private TextEncryptor delegate;
181+
182+
/**
183+
* You can set a delegate that can be used to encrypt/decrypt values if later on
184+
* after the initial initialization of the app we have the necessary values to
185+
* create a proper {@link TextEncryptor}. Depending on where the encryption keys
186+
* are set we might not have the right values to create a {@link TextEncryptor}
187+
* (this can happen if the keys are in application.properties for example, but we
188+
* create the text encryptor during Bootstrap). The delegate functionality allows
189+
* us the option to set the delegate later on when we have the necessary values.
190+
* @param delegate The TextEncryptor to use for encryption/decryption
191+
*/
192+
public void setDelegate(TextEncryptor delegate) {
193+
this.delegate = delegate;
194+
}
195+
196+
public TextEncryptor getDelegate() {
197+
return this.delegate;
198+
}
199+
180200
@Override
181201
public String encrypt(String text) {
202+
if (this.delegate != null) {
203+
return this.delegate.encrypt(text);
204+
}
182205
throw new UnsupportedOperationException(
183206
"No encryption for FailsafeTextEncryptor. Did you configure the keystore correctly?");
184207
}
185208

186209
@Override
187210
public String decrypt(String encryptedText) {
211+
if (this.delegate != null) {
212+
return this.delegate.decrypt(encryptedText);
213+
}
188214
throw new UnsupportedOperationException(
189215
"No decryption for FailsafeTextEncryptor. Did you configure the keystore correctly?");
190216
}

spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/encrypt/EncryptionIntegrationTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,28 @@ public void decryptAfterRefresh() {
142142
TestConfigDataLocationResolver.config.clear();
143143
}
144144

145+
@Test
146+
public void failsafeTextEncryptor() {
147+
ConfigurableApplicationContext context = new SpringApplicationBuilder(
148+
EncryptionIntegrationTests.TestConfiguration.class).web(WebApplicationType.NONE).properties().run();
149+
then(context.getBean(TextEncryptor.class)).isInstanceOf(TextEncryptorUtils.FailsafeTextEncryptor.class);
150+
}
151+
152+
@Test
153+
public void failsafeShouldHaveDelegate() {
154+
TestConfigDataLocationResolver.config.put("foo.password",
155+
"{cipher}bf29452295df354e6153c5b31b03ef23c70e55fba24299aa85c63438f1c43c95");
156+
ConfigurableApplicationContext context = new SpringApplicationBuilder(TestAutoConfiguration.class)
157+
.web(WebApplicationType.NONE)
158+
.properties("spring.config.import=testdatasource:,classpath:application-failsafe.properties",
159+
"createfailsafedelegate=true")
160+
.run();
161+
ConfigurableEnvironment env = context.getBean(ConfigurableEnvironment.class);
162+
then(env.getProperty("foo.password")).isEqualTo("test");
163+
context.close();
164+
TestConfigDataLocationResolver.config.clear();
165+
}
166+
145167
@Configuration(proxyBeanMethods = false)
146168
@EnableConfigurationProperties(PasswordProperties.class)
147169
protected static class TestConfiguration {

spring-cloud-context/src/test/java/org/springframework/cloud/context/test/TestConfigDataLocationResolver.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,15 @@
2929
import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
3030
import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
3131
import org.springframework.boot.context.properties.bind.Bindable;
32+
import org.springframework.cloud.bootstrap.encrypt.KeyProperties;
33+
import org.springframework.cloud.bootstrap.encrypt.RsaProperties;
34+
import org.springframework.cloud.bootstrap.encrypt.TextEncryptorUtils;
35+
import org.springframework.core.Ordered;
36+
import org.springframework.security.crypto.encrypt.TextEncryptor;
3237

33-
public class TestConfigDataLocationResolver implements ConfigDataLocationResolver<TestConfigDataResource> {
38+
import static org.assertj.core.api.Assertions.assertThat;
39+
40+
public class TestConfigDataLocationResolver implements ConfigDataLocationResolver<TestConfigDataResource>, Ordered {
3441

3542
public static AtomicInteger count = new AtomicInteger(1);
3643

@@ -52,6 +59,20 @@ public List<TestConfigDataResource> resolve(ConfigDataLocationResolverContext co
5259
context.getBootstrapContext().registerIfAbsent(aClass, supplier);
5360
}
5461
String myplaceholder = context.getBinder().bind("myplaceholder", Bindable.of(String.class)).orElse("notfound");
62+
boolean createFailsafeDelegate = context.getBinder().bind("createfailsafedelegate", Bindable.of(Boolean.class))
63+
.orElse(Boolean.FALSE);
64+
if (createFailsafeDelegate) {
65+
assertThat(context.getBootstrapContext().isRegistered(TextEncryptor.class)).isTrue();
66+
TextEncryptor textEncryptor = context.getBootstrapContext().get(TextEncryptor.class);
67+
assertThat(textEncryptor).isInstanceOf(TextEncryptorUtils.FailsafeTextEncryptor.class);
68+
KeyProperties keyProperties = context.getBinder().bindOrCreate(KeyProperties.PREFIX,
69+
Bindable.of(KeyProperties.class));
70+
assertThat(TextEncryptorUtils.keysConfigured(keyProperties)).isTrue();
71+
RsaProperties rsaProperties = context.getBinder().bindOrCreate(RsaProperties.PREFIX,
72+
Bindable.of(RsaProperties.class));
73+
((TextEncryptorUtils.FailsafeTextEncryptor) textEncryptor)
74+
.setDelegate(TextEncryptorUtils.createTextEncryptor(keyProperties, rsaProperties));
75+
}
5576
HashMap<String, Object> props = new HashMap<>(config);
5677
props.put(TestEnvPostProcessor.EPP_VALUE, count.get());
5778
if (count.get() == 99 && myplaceholder.contains("${vcap")) {
@@ -61,4 +82,9 @@ public List<TestConfigDataResource> resolve(ConfigDataLocationResolverContext co
6182
return Collections.singletonList(new TestConfigDataResource(props));
6283
}
6384

85+
@Override
86+
public int getOrder() {
87+
return -1;
88+
}
89+
6490
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
encrypt.key=pie

0 commit comments

Comments
 (0)