Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

Comparison of byte arrays with NHibernate


The following Linq to NHibernate query results in a System.NotSupportedException .

IEnumerable<File> FindByMd5(byte[] md5) { return this.Session.Query<File>().Where(f => f.Md5.SequenceEqual(md5)).ToList(); }

How should I do this using Linq to NHibernate or QueryOver<File>() ?

Due to the fact that the error is already indicating that NHibernate does not support that feature. I would create a named query and solve the equation within a query. I have tested it with mysql (using a common username and password comparison as example) and the following statement returns the desired row (password is a BINARY(32) field):

SELECT * FROM `user` WHERE `password` = MD5('test');

Using mssql you can do:

SELECT * FROM [user] WHERE [password] = HASHBYTES('MD5', 'test')

So to extend this to a named query you would create an .hbm.xml file like 'User.hbm.xml' with the following content:

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="My.Model" namespace="My.Model"> <sql-query name="GetUserByCredentials"> <return class="My.Model.User, My.Model" /> <![CDATA[ SELECT * FROM User WHERE Username = :Username AND Password = MD5(:Password) ]]> </sql-query> </hibernate-mapping>

To configure this I used Fluent NHibernate but something similar would be possible with just plain NHibernate:

Fluently.Configure() .Database(MySqlConfiguration.Standard .ConnectionString(x => x.FromConnectionStringWithKey("Test")) .AdoNetBatchSize(50)) .Cache(c => c .UseQueryCache() .ProviderClass<HashtableCacheProvider>()) .Mappings(m => { m.FluentMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>().Conventions.Add(ForeignKey.EndsWith("Id")); m.HbmMappings.AddFromAssemblyOf<IHaveFluentNHibernateMappings>(); }) .BuildConfiguration();

This statement looks for the ".hbm.xml" files in the assembly with the interface named "IHaveFluentNHibernateMappings"

With this in place you can do the following at session level:

public User GetUserByCredentials(string username, string password) { IQuery query = Session.GetNamedQuery("GetUserByCredentials"); query.SetParameter("Username", username); query.SetParameter("Password", password); return query.UniqueResult<User>(); }

And by calling the the GetUserByCredentials method, the custom query will be executed.

As you can see password is a string, so you need to convert your MD5 byte array to a string first by using:

System.Text.StringBuilder s = new System.Text.StringBuilder(); foreach (byte b in md5ByteArray) { s.Append(b.ToString("x2").ToLower()); } password = s.ToString();

Good luck!

Viewing all articles
Browse latest Browse all 12749