Commits

bostanio  committed 1b3f836

Use composition of UserType to allow us to add the default configuration logic to all the existing jasypt hibernate UserTypes.

  • Participants
  • Parent commits 6c94d6b
  • Branches defaultParametersUserType

Comments (0)

Files changed (20)

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/AbstractGormEncryptedStringType.groovy

-package com.bloomhealthco.jasypt
-
-import org.codehaus.groovy.grails.commons.ConfigurationHolder
-import org.jasypt.hibernate.type.AbstractEncryptedAsStringType
-import org.jasypt.hibernate.type.ParameterNaming
-import org.jasypt.encryption.pbe.PBEStringEncryptor
-
-public abstract class AbstractGormEncryptedStringType extends AbstractEncryptedAsStringType {
-
-    PBEStringEncryptor retrieveEncryptor() {
-        setParameterValues(null)
-        checkInitialization()
-        return encryptor    
-    }
-
-    void setParameterValues(Properties parameters) {
-        def params = config + (parameters ?: [:]) as Properties
-        super.setParameterValues(params)
-    }
-
-    /**
-     *  you can define an encryptor in your grails-app/conf/spring/resources.groovy file that
-     *  contains an encryptor with a default name of 'gormEncryptor'
-     *  ex:
-     *  beans = {
-     *     hibernateStringEncryptor(org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor) {
-     *         registeredName = "gormEncryptor"
-     *         algorithm = "PBEWithMD5AndTripleDES"
-     *         password = "s3kr1t"
-     *         keyObtentionIterations = 1000
-     *     }
-     *  }
-     *
-     *  or bouncy castle AES:
-     *
-     *  beans = {
-     *     hibernateStringEncryptor(org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor) {
-     *         registeredName = "gormEncryptor"
-     *         providerName = "BC"
-     *         algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC"
-     *         password = "s3kr1t"
-     *         keyObtentionIterations = 1000
-     *     }
-     *  }
-     *
-     * @return a default config that expects an encryptor name of gormEncryptor
-     */
-    def getConfig() {
-        def config = [:] + jasyptConfig
-        if (
-            !config[ParameterNaming.ALGORITHM] &&
-            !config[ParameterNaming.PASSWORD] &&
-            !config[ParameterNaming.KEY_OBTENTION_ITERATIONS] &&
-            !config[ParameterNaming.ENCRYPTOR_NAME]
-        ) {
-           config[ParameterNaming.ENCRYPTOR_NAME] = 'gormEncryptor'
-        }
-
-        return config
-    }
-
-    /**
-     * You can create a jasypt stanza in your grails-app/conf/Config.groovy (or another config file that
-     * Config.groovy pulls in).  This stanza can either override the default encryptor name and
-     * set a new encryptorRegisteredName that you define in your Spring resources.groovy file, ex:
-     *
-     * jasypt {
-     *     encryptorRegisteredName = "fooBar"
-     * }
-     *
-     * otherwise, you can actually configure the encryptor right there using the other properties
-     * available in org.jasypt.hibernate.type.ParameterNaming, ex with triple-DES:
-     *
-     * jasypt {
-     *     algorithm = "PBEWithMD5AndTripleDES"
-     *     password = "s3kr1t"
-     *     keyObtentionIterations = 1000
-     * }
-     *
-     * or Bouncy Castle AES:
-     *
-     * jasypt {
-     *     algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC"
-     *     providerName = "BC"
-     *     password = "s3kr1t"
-     *     keyObtentionIterations = 1000
-     * }
-     *
-     * @return the jasypt config specified in Config.groovy
-     */
-    def getJasyptConfig() {
-        return ConfigurationHolder.config?.jasypt ?: [:]
-    }
-}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/DefaultParametersUserType.groovy

+package com.bloomhealthco.jasypt
+
+import java.sql.PreparedStatement
+import java.sql.ResultSet
+import org.hibernate.usertype.ParameterizedType
+import org.hibernate.usertype.UserType
+
+/**
+ * A wrapper class that supports providing default parameters to UserTypes
+ * implement the getDefaultParameters to provide the configuration you want
+ *
+ * We use composition so that we can add this behavior to otherwise declared final UserTypes.
+ * We'd love to use a Mixin but Hibernate's reflection utils don't play nice with Groovys ryntime mixins
+ * @param < T > the existing Parameterized UserType we want to add the default parmaters to
+ */
+abstract class DefaultParametersUserType<T extends UserType & ParameterizedType> implements UserType, ParameterizedType {
+
+    // Nifty little reflection trick to figure out the actual class the subclass provides
+    // UserTypes have to have a default parameterless constructor so we're safe to call it here
+    private final T innerType = this.class.genericSuperclass.actualTypeArguments[0].newInstance()
+
+    protected T getInnerType() {
+        innerType
+    }
+
+    int[] sqlTypes() {
+        innerType.sqlTypes()
+    }
+
+    Class returnedClass() {
+        innerType.returnedClass()
+    }
+
+    boolean equals(final Object x, final Object y) {
+        innerType.equals(x, y)
+    }
+
+    int hashCode(final Object x) {
+        innerType.hashCode(x)
+    }
+
+    Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object owner) {
+        innerType.nullSafeGet(resultSet, names, owner)
+    }
+
+    void nullSafeSet(final PreparedStatement preparedStatement, Object value, int index) {
+        innerType.nullSafeSet(preparedStatement, value, index)
+    }
+
+    Object deepCopy(final Object value) {
+        innerType.deepCopy(value)
+    }
+
+    boolean isMutable() {
+        innerType.isMutable()
+    }
+
+    Serializable disassemble(final Object value) {
+        innerType.disassemble(value)
+    }
+
+    Object assemble(final Serializable cached, final Object owner) {
+        innerType.assemble(cached, owner)
+    }
+
+    Object replace(Object original, Object target, Object owner) {
+        innerType.replace(original, target, owner)
+    }
+
+    void setParameterValues(final Properties properties) {
+        def params = defaultParameters + (properties ?: [:]) as Properties
+        innerType.setParameterValues(params)
+    }
+
+    abstract Map getDefaultParameters()
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBigDecimalAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBigDecimalAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBigDecimalAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBigDecimalType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBigDecimalType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBigDecimalType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBigIntegerAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBigIntegerAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBigIntegerAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBigIntegerType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBigIntegerType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBigIntegerType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBinaryType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBinaryType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBinaryType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedBooleanType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedBooleanType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedBooleanAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedByteAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+public class GormEncryptedByteAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedByteAsStringType> {
+
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedCalendarAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+public final class GormEncryptedCalendarAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedCalendarAsStringType> {
+
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedDateAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedDateAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedDateAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedDoubleAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedDoubleAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedDoubleAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedFloatAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedFloatAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedFloatAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedIntegerAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedIntegerAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedIntegerAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedLongAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedLongAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedLongAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedShortAsStringType.groovy

+package com.bloomhealthco.jasypt
+
+class GormEncryptedShortAsStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedShortAsStringType> {
+}

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/GormEncryptedStringType.groovy

 package com.bloomhealthco.jasypt
 
-public class GormEncryptedStringType extends AbstractGormEncryptedStringType {
-    
-    protected Object convertToObject(String stringValue) { stringValue }
+public class GormEncryptedStringType extends JasyptConfiguredUserType<org.jasypt.hibernate3.type.EncryptedStringType> {
 
-    Class returnedClass() { String }
 }

File jasypt-encryption/src/groovy/com/bloomhealthco/jasypt/JasyptConfiguredUserType.groovy

+package com.bloomhealthco.jasypt
+
+import org.codehaus.groovy.grails.commons.ConfigurationHolder
+import org.hibernate.usertype.ParameterizedType
+import org.hibernate.usertype.UserType
+import org.jasypt.hibernate3.type.ParameterNaming
+
+class JasyptConfiguredUserType<T extends UserType & ParameterizedType> extends DefaultParametersUserType<T> {
+    
+    /**
+     *  you can define an encryptor in your grails-app/conf/spring/resources.groovy file that
+     *  contains an encryptor with a default name of 'gormEncryptor'
+     *  ex:
+     *  beans = {
+     *     hibernateStringEncryptor(org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor) {
+     *         registeredName = "gormEncryptor"
+     *         algorithm = "PBEWithMD5AndTripleDES"
+     *         password = "s3kr1t"
+     *         keyObtentionIterations = 1000
+     *     }
+     *  }
+     *
+     *  or bouncy castle AES:
+     *
+     *  beans = {
+     *     hibernateStringEncryptor(org.jasypt.hibernate.encryptor.HibernatePBEStringEncryptor) {
+     *         registeredName = "gormEncryptor"
+     *         providerName = "BC"
+     *         algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC"
+     *         password = "s3kr1t"
+     *         keyObtentionIterations = 1000
+     *     }
+     *  }
+     *
+     * @return a default config that expects an encryptor name of gormEncryptor
+     */
+    Map getDefaultParameters() {
+        def defaultParameters = [:] + jasyptConfig
+        if (
+                !defaultParameters[ParameterNaming.ALGORITHM] &&
+                        !defaultParameters[ParameterNaming.PASSWORD] &&
+                        !defaultParameters[ParameterNaming.KEY_OBTENTION_ITERATIONS] &&
+                        !defaultParameters[ParameterNaming.ENCRYPTOR_NAME]
+        ) {
+            defaultParameters[ParameterNaming.ENCRYPTOR_NAME] = 'gormEncryptor'
+        }
+
+        return defaultParameters
+    }
+
+    /**
+     * You can create a jasypt stanza in your grails-app/conf/Config.groovy (or another config file that
+     * Config.groovy pulls in).  This stanza can either override the default encryptor name and
+     * set a new encryptorRegisteredName that you define in your Spring resources.groovy file, ex:
+     *
+     * jasypt {
+     *     encryptorRegisteredName = "fooBar"
+     * }
+     *
+     * otherwise, you can actually configure the encryptor right there using the other properties
+     * available in org.jasypt.hibernate.type.ParameterNaming, ex with triple-DES:
+     *
+     * jasypt {
+     *     algorithm = "PBEWithMD5AndTripleDES"
+     *     password = "s3kr1t"
+     *     keyObtentionIterations = 1000
+     * }
+     *
+     * or Bouncy Castle AES:
+     *
+     * jasypt {
+     *     algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC"
+     *     providerName = "BC"
+     *     password = "s3kr1t"
+     *     keyObtentionIterations = 1000
+     * }
+     *
+     * @return the jasypt config specified in Config.groovy
+     */
+    def getJasyptConfig() {
+        return ConfigurationHolder.config?.jasypt ?: [:]
+    }
+}

File test-jasypt/grails-app/domain/com/bloomhealthco/domain/Patient.groovy

 package com.bloomhealthco.domain
 
 import com.bloomhealthco.jasypt.GormEncryptedStringType
+import com.bloomhealthco.jasypt.GormEncryptedDateAsStringType
 
 class Patient {
 	String firstName
 	String lastName
+    Date birthDate
     String correlationId
 
     static constraints = {
         firstName maxSize: 384
+        birthDate nullable: true
     }
 
 	static mapping = {
     	firstName type: GormEncryptedStringType
         lastName type: GormEncryptedStringType
+        birthDate type: GormEncryptedDateAsStringType
     }
 }

File test-jasypt/test/integration/com/bloomhealthco/domain/JasyptDomainEncryptionTests.groovy

     }
 
     void testTwoWayStringEncryption() {
-		def originalPatient = new Patient(firstName: "foo", lastName: "bar", correlationId: CORRELATION_ID)
+        def birthDate =  new Date(1970, 2, 3)
+		def originalPatient = new Patient(firstName: "foo", lastName: "bar", birthDate: birthDate, correlationId: CORRELATION_ID)
 		originalPatient.save(failOnError: "true")
 		
         withPatientForCorrelationId(CORRELATION_ID) { patient, rawPatient ->
             assertEquals "foo", patient.firstName
             assertEquals "bar", patient.lastName
+            assertEquals birthDate, patient.birthDate
             assertTrue "foo" != rawPatient.FIRST_NAME
             assertTrue "bar" != rawPatient.LAST_NAME
+            assertTrue birthDate.toString() != rawPatient.BIRTH_DATE
             assertTrue rawPatient.FIRST_NAME.endsWith("=")
             assertTrue rawPatient.LAST_NAME.endsWith("=")
+            assertTrue rawPatient.BIRTH_DATE.endsWith("=")
         }
     }