I am using Fluent NHibernate (1.2), and am working on implementing column-level encryption. I have a custom type that handles encryption, so that the domain model can have native cleartext datatypes (simple strings, ints, DateTimes, etc.), and all the encryption/decryption work is behind the scenes.
I would like to specify which properties in each domain model to encrypt via an attribute, and use a Convention to specify the custom type for these properties, so that the domain models are nice POCOs with no mention of the custom type:
public class EncryptedAttribute : Attribute {}
public class UserRecord {
public virtual Guid Id { get; set; }
public virtual string Username { get; set; }
[Encrypted]
public virtual string EmailAddress { get; set; }
[Encrypted]
public virtual DateTime DateOfBirth { get; set; }
[Encrypted]
public virtual PersonName LegalName { get; set; }
// etc.
}
public class PersonName {
public virtual string Given { get; set; }
public virtual string Middle { get; set; }
public virtual string Family { get; set; }
}
public class EncryptedColumnConvention
: AttributePropertyConvention<EncryptedAttribute> {
protected override void Apply(
EncryptedAttribute attribute, IPropertyInstance instance)
{
var dbType = typeof(EncryptedColumnType<>).MakeGenericType(domainType);
instance.CustomType(dbType);
}
}
public class UserRecordMap : ClassMap<UserRecord> {
public UserRecordMap() {
Id(o => o.Id);
Map(o => o.Username);
Map(o => o.EmailAddress);
Map(o => o.DateOfBirth);
Component(o => o.LegalName).ColumnPrefix("LegalName");
// etc.
}
}
public class PersonNameMap : ComponentMap<PersonName> // etc.
As shown above, I am trying to tie this all together with an AttributePropertyConvention. This works well for simple properties, e.g. EmailAddress will get a custom type of EncryptedColumnType.
But it is not working for properties which are complex types (e.g. LegalName) that are mapped via Components. What I want is to encrypt every property of LegalName because I decorated it with [Encrypted]. In other words, I want the UserRecord db table to have three encrypted
name fields–given, middle, and family.
It seems that the AttributePropertyConvention is just not getting applied at all to the LegalName or any of its member properties. Perhaps I need to use another type of Convention to handle this case?
I know I can just decorate the individual properties within PersonName with [Encrypted], instead of decorating the [LegalName] property within UserRecord. I tested this and it works fine. I can fall back to this approach if necessary, but am interested in trying to get the approach outline above to work instead.
Following up, I did not find a way to directly implement what I described. I could see it being difficult or impossible to implement such a thing based on how attributes work in C#.
Instead, I just added the
[Encrypted]attribute to each property of thePersonNameclass, and let thosePersonNamecolumns in the resulting database table always be encrypted. In the future, if I do need to mapPersonNameas a non-encrypted “component” of another entity, I could perhaps decorate the non-encrypted class with an attribute that disables encryption for all of its mapped columns/components, overriding any[Encrypted]attributes found in that class’s property/component mappings.