Chris Love CNM | Tech Blog

Jun/11

16

Encrypting Spring 3 Java Based Configurations Values With Jasypt

7 Flares Twitter 3 Facebook 0 Google+ 0 LinkedIn 4 Reddit 0 Filament.io Made with Flare More Info'> 7 Flares ×

Since I have gotten a TON of comments and traffic in regards to my intial spring configuration post located here, I thought I would add another post about spring config and @values.

Encrypting passwords is always a pain in the butt. No other way to put it. To add insult to injury we needed to encrypt a password with-in a spring based web application. Well jasypt (Java Simplified Encryption) project to the rescue. They support basic spring property value replacement of encrypted value with-in spring 2.0 supported xml out of the box.

You have nothing special to do to integrate Jasypt with Spring, as all of the encryption tools (digesters and encryptors) in jasypt have the adequate design to be correctly instantiated and dependency-injected from a Spring application context. 1

I have created a properties loader that supports spring 3.0 @value injection. On to the examples that can be d/l from my github repo.

Basic Spring Config

	<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentPBEConfig"
		p:algorithm="PBEWithMD5AndDES" p:passwordSysPropertyName="APP_PASS" />

	<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
		p:config-ref="environmentVariablesConfiguration" />

	<bean id="propertyConfigurer"
		class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer"
		p:locations-ref="passwordProps">
		<constructor-arg ref="configurationEncryptor" />
	</bean>

	<util:list id="passwordProps">
		<value>classpath:/cnm.properties</value>
	</util:list>
	
	<bean id="testBean" class="test.beans.BeanTestImpl" p:foo="${cnm.foo}" />

In this example, the encryption password will be read from an system variable called “APP_PASS”. This is the password that is used to decrypt encrypted values. The EncryptablePropertyPlaceholderConfigurer will read the cnm.properties file and make its values accessible as ${vars}. A “configurationEncryptor” bean (which implements org.jasypt.encryption.StringEncryptor) is set as a constructor arg.

Simple Spring Unit Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:/applicationContext-jasypt.xml"})
public class BasicJasyptTest {
	
	@Autowired
	private ITestBean testBean;
	
	@BeforeClass
	public static void setupEnvVar() {
		System.setProperty("APP_PASS", "151987thisismysalt!!");
	}
	
	@Test
	public void testBean() {
		assertThat(testBean.getFoo(), equalTo("MyPassword"));
	}

}

The above test creates the spring application context and injects the decrypted values correctly. The jaspypt beans are using a system property that contains the password that is used to decrypt the values. When the context is created the jasypt components loads and decrypts the properties values that are delimited with the ‘ENC()’ marker.

For example:

  • cnm.username=clove is left alone
  • cnm.foo=ENC(1FTzaim1KT6w12vRRyCICP/6lPklg1Jw) is decrypted

Well that is awesome and all … but very XML intensive, and not cool enough for me. So lets move on to using @value’s in spring 3.0.

Spring Config Using 3.0 Contexts

<context:component-scan base-package="test.beans" />

<bean id="pbeConfig" class="net.cnmconsulting.spring.config.util.FileStringPBEConfig"
		p:algorithm="PBEWithMD5AndDES" p:passwordName="classpath:/cnm.token">
</bean>

<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
		p:config-ref="pbeConfig" />
	
<bean id="propertyConfigurer"
	class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer"
	p:locations-ref="passwordProps" p:searchSystemEnvironment="true">
	<constructor-arg ref="configurationEncryptor" />
</bean>

<bean id="props"
	class="net.cnmconsulting.spring.config.PropertiesFactoryBean"
	p:locations-ref="passwordProps">
	<constructor-arg ref="configurationEncryptor" />
</bean>

<util:set id="passwordProps">
	<value>classpath:/cnm.properties</value>
</util:set>

So two new components are in the spring config above. First we are using context:component to load beans automatically, and secondly our PropertiesFactoryBean is being used that allows for @value injections. Let’s look at part of the the bean.

Spring Bean with encrypted @value

@Service("propTest")
public class PropTestBeanImpl implements PropTest {
	
	@Value("#{props['cnm.username']}")
	protected String username;

	@Value("#{props['cnm.foo']}")
	protected String password;

The bean is pretty self explanatory. Set the cnm.foo value to the field password, and this is what the PropertiesFactoryBean does.

Let’s test it!

Spring Bean Unit Test for Encypted @Value

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:/applicationContext-cmn-props.xml"})
public class CNMPropertiesFactoryBeanTest {

	// Inject the bean for testing
	@Autowired
	private PropTest propTest;

	@BeforeClass
	public static void setupEnvVar() {
		System.setProperty("APP_PASS", "151987thisismysalt!!");
	}
	/*
	 * Test will assure that the propTest bean will have the correct values injects,
	 * and the encypted values are decrypted upon injection
	 */
	@Test
	public void testProp() {
		assertNotNull(propTest.getUsername());
		assertThat(propTest.getFoo(), equalTo("MyPassword"));
		assertThat(propTest.getUsername(), equalTo("clove"));
	}

}

As you can see the propTest bean is tested to ensure that the password and username are set correctly.

Again the examples are located in my github repo. Please download fork and improve!

In closing let me mention that jasypt (Java Simplified Encryption) project is very useful and wraps multiple encryption components very elegantly. Check out the feature list. Also you may wonder, how the heck do I create the encrypted passwords using jasypt. My PropertyAppContextReplaceTest unit test provides an example.

· · ·

2 comments

  • Matt · November 2, 2011 at 1:59 am

    Thanks, pretty helpful. Might also be helpful to post a copy of your custom PropertiesFactoryBean. I eventually figured out how to create my own after searching the web for another solution first.

  • Admin comment by chrislovecnm · November 28, 2011 at 10:56 pm

    Is that not on my github account? https://github.com/chrislovecnm/Blog-Projects

Leave a Reply

<<

>>

7 Flares Twitter 3 Facebook 0 Google+ 0 LinkedIn 4 Reddit 0 Filament.io 7 Flares ×