Created
February 29, 2012 14:22
-
-
Save jfromaniello/1941179 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Data; | |
using NHibernate; | |
using NHibernate.SqlTypes; | |
using NHibernate.UserTypes; | |
using System.Collections.Generic; | |
namespace MyUserTypes | |
{ | |
/// <summary> | |
/// Hashes a string when it's saved | |
/// and salt hashes it when it gets it from the database. | |
/// </summary> | |
public class EncryptedString : IUserType, IParameterizedType | |
{ | |
private IEncryptor encryptor; | |
/// <summary> | |
/// Retrieve an instance of the mapped class from a Ado.Net resultset. | |
/// Implementors should handle possibility of null values. | |
/// </summary> | |
/// <param name="rs"></param> | |
/// <param name="names"></param> | |
/// <param name="owner"></param> | |
/// <returns></returns> | |
public object NullSafeGet(IDataReader rs, string[] names, object owner) | |
{ | |
//treat for the posibility of null values | |
object passwordString = NHibernateUtil.String.NullSafeGet(rs, names[0]); | |
if (passwordString != null) | |
{ | |
return encryptor.Decrypt((string) passwordString); | |
} | |
return null; | |
} | |
/// <summary> | |
/// Write an instance of the mapped class to a prepared statement. | |
/// Handle possibility of null values. | |
/// A multi-column type should be written to parameters starting from index. | |
/// </summary> | |
/// <param name="cmd"></param> | |
/// <param name="value"></param> | |
/// <param name="index"></param> | |
public void NullSafeSet(IDbCommand cmd, object value, int index) | |
{ | |
if (value == null) | |
{ | |
NHibernateUtil.String.NullSafeSet(cmd, null, index); | |
return; | |
} | |
string hashedPassword = encryptor.Encrypt((string) value); | |
NHibernateUtil.String.NullSafeSet(cmd, hashedPassword, index); | |
} | |
/// <summary> | |
/// Return a deep copy of the persistent state, | |
/// stopping at entities and at collections. | |
/// </summary> | |
/// <param name="value"></param> | |
/// <returns></returns> | |
public object DeepCopy(object value) | |
{ | |
return value == null ? null : string.Copy((string) value); | |
} | |
/// <summary> | |
/// During merge, replace the existing (target) value in the entity we are | |
/// merging to with a new (original) value from the detached entity we are | |
/// merging. For immutable objects, or null values, it is safe to simply | |
/// return the first parameter. For mutable objects, it is safe to return a | |
/// copy of the first parameter. For objects with component values, it might | |
/// make sense to recursively replace component values. | |
/// </summary> | |
/// <param name="original">the value from the detached entity being merged</param> | |
/// <param name="target">the value in the managed entity</param> | |
/// <param name="owner">the managed entity</param> | |
/// <returns>Returns the first parameter because it is inmutable</returns> | |
public object Replace(object original, object target, object owner) | |
{ | |
return original; | |
} | |
/// <summary> | |
/// Reconstruct an object from the cacheable representation. | |
/// At the very least this method should perform a deep copy if the type is mutable. | |
/// (optional operation) | |
/// </summary> | |
/// <param name="cached">the object to be cached</param> | |
/// <param name="owner">the owner of the cached object</param> | |
/// <returns>a reconstructed string from the cachable representation</returns> | |
public object Assemble(object cached, object owner) | |
{ | |
return DeepCopy(cached); | |
} | |
/// <summary> | |
/// Transform the object into its cacheable representation. | |
/// At the very least this method should perform a deep copy if the type is mutable. | |
/// That may not be enough for some implementations, however; | |
/// for example, associations must be cached as identifier values. | |
/// (optional operation) | |
/// </summary> | |
/// <param name="value"></param> | |
/// <returns></returns> | |
public object Disassemble(object value) | |
{ | |
return DeepCopy(value); | |
} | |
/// <summary> | |
/// The SQL types for the columns mapped by this type. | |
/// In this case just a SQL Type will be returned:<seealso cref="DbType.String"/> | |
/// </summary> | |
public SqlType[] SqlTypes | |
{ | |
get { return new[] {new SqlType(DbType.String)}; } | |
} | |
/// <summary> | |
/// The returned type is a <see cref="string"/> | |
/// </summary> | |
public Type ReturnedType | |
{ | |
get { return typeof (string); } | |
} | |
/// <summary> | |
/// The strings are not mutables. | |
/// </summary> | |
public bool IsMutable | |
{ | |
get { return false; } | |
} | |
/// <summary> | |
/// Compare two <see cref="string"/> | |
/// </summary> | |
/// <param name="x">string to compare 1</param> | |
/// <param name="y">string to compare 2</param> | |
/// <returns>If are equals or not</returns> | |
public new bool Equals(object x, object y) | |
{ | |
if (ReferenceEquals(x, y)) | |
{ | |
return true; | |
} | |
if (x == null || y == null) | |
{ | |
return false; | |
} | |
return x.Equals(y); | |
} | |
public int GetHashCode(object x) | |
{ | |
if (x == null) | |
{ | |
throw new ArgumentNullException("x"); | |
} | |
return x.GetHashCode(); | |
} | |
#region Implementation of IParameterizedType | |
public void SetParameterValues(IDictionary<string,string> parameters) | |
{ | |
if (parameters != null) | |
{ | |
object parmValue = parameters["encryptor"]; | |
encryptor = (IEncryptor)Activator.CreateInstance(Type.GetType(parmValue)); | |
parmValue = parameters["encryptionKey"]; | |
if (parmValue != null) | |
{ | |
encryptor.EncryptionKey = parameters["encryptionKey"].ToString(); | |
} | |
} | |
else | |
{ | |
encryptor = new uNHAddinsEncryptor(); | |
} | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MyUserTypes | |
{ | |
public interface IEncryptor | |
{ | |
string Encrypt(string password); | |
string Decrypt(string encryptedPassword); | |
string EncryptionKey { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class User | |
{ | |
public string Password { get; set; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8" ?> | |
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" | |
assembly="uNhAddIns.Test" | |
namespace="uNhAddIns.Test.UserTypes" default-lazy="false"> | |
<typedef class="MyUserTypes.EncryptedString, MyAssembly" name="SuperEncrypted"> | |
<param name="encryptor">MyEncryptor.Blabla.uNHAddinsEncryptor, MyAssembly</param> | |
<param name="encryptionKey">mykey</param> | |
</typedef> | |
<class name="User" table="Users"> | |
<id name="Id" type="int"> | |
<generator class="assigned"/> | |
</id> | |
<property name="Name"/> | |
<property name="Password" | |
type="SuperEncrypted" | |
not-null="false"/> | |
</class> | |
</hibernate-mapping> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment