Unmanaged CRM solution

Dec 1, 2012 at 2:00 AM

This is a very interesting project! It is exactly what we need for our current project.
I added a salt+hash mechanism to the membership provider and extended the CRM solution with a field to store the salt. Are you interested in the code?

Is it possible for you to supply the unmanaged CRM solution as well?

Jan 15, 2013 at 11:27 AM

I was looking at this project and thought the exact same thing. I am interested in the salt code, as I couldn't deploy this with plain text passwords. Did you ever get the unmanaged solution?

Apr 10, 2013 at 1:43 PM
The same here. I´m also planning to extend the solution in order to add salt+hash. Did you ever get the unmanaged solution? This is a very useful project!
Thanks
Apr 10, 2013 at 5:25 PM
We ended up rolling our own solution. With a slightly different approach. If you want to use this membership provider then you can create your own solution as well. For the start I just copied the fields of the managed solution to work with this. The fields can be set in the web.config which makes it easy to adapt your own solution with different attribute names.

Here is what I added for salt+hash in the MembershipProvider class:
    private string GenerateSalt()
    {
        var buffer = new byte[16];
        (new RNGCryptoServiceProvider()).GetBytes(buffer);
        return Convert.ToBase64String(buffer);
    }

    private string HashPassword(string Password, string salt)
    {
        HMACSHA1 hashingAlgorithm = new HMACSHA1() { Key = Encoding.Unicode.GetBytes(salt) };
        byte[] unicodeEncodedPassword = Encoding.Unicode.GetBytes(Password);
        byte[] hashedPassword = hashingAlgorithm.ComputeHash(unicodeEncodedPassword);
        return Encoding.Unicode.GetString(hashedPassword);
    }
Add a password salt field (passwordSaltField or choose a different name) in the web.config and add this property:
    public string PasswordSaltField
    {
        get { return Settings.Parameters["passwordSaltField"]; }
    }

    public override MembershipUser CreateUser(...)
    {
     ....
            var passwordSalt = GenerateSalt();
            var hashedPassword = HashPassword(password, passwordSalt);
            MemberEntity = new Entity(EntityName);
            MemberEntity.SetAttributeValue<string>(PasswordField, hashedPassword);
            MemberEntity.SetAttributeValue<string>(PasswordSaltField, passwordSalt);
     ....
    }
Of course you have to modify ChangePassword() and ResetPassword() accordingly as well.
And to validate the user I simply re-hash the password with the database salt:
    public override bool ValidateUser(string username, string password)
    {
        Entity entity = RetrieveMemberBy(UserNameField, username);
        if (entity != null && entity.GetAttributeValue<string>(PasswordField).Equals(HashPassword(password, entity.GetAttributeValue<string>(PasswordSaltField)), StringComparison.InvariantCulture))
        {
            DateTime dt = DateTime.Now;
            entity.SetAttributeValue<DateTime>(LastLoginDateField, dt);
            entity.SetAttributeValue<DateTime>(LastActivityDateField, dt);
            CrmCommon.UpdateEntity(entity);
            return true;
        }
        else
        {
            return false;
        }
    }
Apr 10, 2013 at 5:47 PM
Many thanks nklein!