Thursday, March 09, 2006

Spring PropertyPlaceholderConfigurer with encrypted property values

The problem that drove this thinking was that I needed to keep the dynamic properties of the Spring configuration file separate from the XML configuration files and I also needed to encrypt passwords in the property files. To do this I would then need to decrypt prior to having Spring do the runtime replacement.

Spring does allow for the method ''convertPropertyValue'' to be overridden but it only passes the value from the property file and you actually do not have any idea which property name it is associated with. So this makes it diffcult to know whether you need to perform any additional processing on it.

If you extend the PropertyPlaceholderConfigurer and override a couple of methods, you can get it to perform to solve the stated problem. The one drawback is that you must override and re-implement the ''convertProperties'' method which will detect an encrypted property and perform the decryption.

Caveat: this is really a description of how to extend Spring to allow for encrypted property values and not a discussion of encryption techniques

Assume that the requirements are to allow for encrypted values to be added as property values. For simplicity it is assumed that the same encryption algorithm is used to create the encrypted values as it is to decrypt or at least it is understood what the algorithm will be.

Below is an example of an extended PropertyPlaceholderConfigurer. It is just an example, it will not compile as there will certainly be decisions on the details of the encryption. Notice that the important overloaded method is convertProperties which looks for property names that begin with encrypted. to know which values to decrypt.

An example of an encrypted value would be:
encrypted.jdbc.password=*(&LHJFL#*(FELF(*%&^F=


public class PropertyPlaceholderConfigurer extends 
        org.springframework.beans.factory.config.PropertyPlaceholderConfigurer { 
 
     
    private static final String ENCRYPTED = "encrypted."; 
    private MyFavoriteEncryptor encryptor = new MyFavoriteEncryptor(); 
 
    @Override 
    protected void convertProperties(Properties props) { 
        Enumeration propertyNames = props.propertyNames(); 
        while (propertyNames.hasMoreElements()) { 
            String propertyName = (String) propertyNames.nextElement(); 
            String propertyValue = props.getProperty(propertyName); 
            String convertedValue = ""; 
            if( propertyName.startsWith(ENCRYPTED) ) { 
                // just store the property name without the encrypted prepended value 
 
                                // so encrypted.jdbc.password becomes jdbc.password 
 
                propertyName = propertyName.substring(ENCRYPTED.length()); 
                convertedValue = decryptPropertyValue(propertyValue); 
            } else { 
                convertedValue = convertPropertyValue(propertyValue); 
            } 
 
            if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) { 
                props.setProperty(propertyName, convertedValue); 
            } 
        } 
    } 
 
    /** 
     *  
     * @param base64EncryptedValue base64 encoded value of the encrypted value from MyFavoriteEncryptor class 
     * @return cleartext value. 
     */ 
    protected String decryptPropertyValue(String base64EncryptedValue) { 
         
        String decryptedValue = null; 
         
        try { 
            byte[] decodedString = Base64.decode(base64EncryptedValue); 
            decryptedValue = encryptor.decryptString(decodedString); 
        } catch( Exception e ) { 
            throw new RuntimeException(e); 
             
        } 
         
        return decryptedValue; 
    } 
 
    public PropertyPlaceholderConfigurer() { 
        super(); 
    } 
 
 } 
  

Monday, March 06, 2006

Spring/Hibernate/IdTransferringEventListener

If anyone has updated their hibernate jar to the latest 3.1.2 version and updated their code to use the merge method to save objects then you probably noticed that the ID for newly created objects is not populated in the saved object like it used to be.

Spring has a class called, IdTransferringMergeEventListener which merges the ID of the newly created object with the object that your application holds. Open up this class and read the comment about how the current implementation only works for 3.0 versions of Hibernate.

So if you use the Spring 1.2.6 or better, and hibernate 3.1.2 you will need to create an implementation of this event listener that implements the commented out version in the above class.

Thursday, March 02, 2006

Welcome

Welcome to my blog space Claire. More to come later...