Security App Block - Customized auth and role provider

Topics: Building and extending application blocks, Cryptography Application Block, Security Application Block
Dec 2, 2009 at 2:15 AM

I am creating a database driven ASP.Net web application that will be used over the internet. Thus security in the application will play a major role.

I already have a forms authentication login wired to a custom SQL server table. I also have custom security and roles tables setup in the same SQL server for authorization and roles. 

I have already implemented the data access block into my application.

This is my first time using the security application block. I have searched all over the internet and have yet to find a good article or example on how I can use my custom security and authentication tables and code via the security application block.

If someone can point me to an example of how I can use my custom tables for login, authorization and roles with the security application block that would be great! I am little new to Object oriented classes and such thus I am struggling to understand how to extend/customize the security application block for my needs.

Thanks! 

Dec 2, 2009 at 3:18 AM

These might get you started...

http://www.education.vic.gov.au/devreskit/appdev/Application%20Blocks/Security/security-standards-details.htm

http://www.education.vic.gov.au/devreskit/appdev/Application%20Blocks/Security/security-standards-details.htm

 

Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.

entlib.support@avanade.com

Dec 3, 2009 at 12:28 AM

Thanks for the links. I reviewed them and they did help. I actually read something similar in a book I found online.

The one thing I simply just cannot understand is in order to implement my custom auth and role provider logic, do I  a) Add the suggested custom class/code into the security application block or b) write this code into my web application and leave the security application block "as-is"?

Thanks again for all the help!

Dec 3, 2009 at 2:03 AM

Hi,

It should be the second option. Write it in your web app and leave the security application block "as-is".

Valiant Dudan
Global Technology & Solutions
Avanade, Inc.

entlib.support@avanade.com

Dec 3, 2009 at 2:44 AM

So below is the class library code that I have added into my web application. I have copied the example shown in the book of using an XML file as the store. I will change this to point to my SQL server table later. 

Is this all of what I need to do in my web application?

=====================================================================

Imports Microsoft.Practices.EnterpriseLibrary.Security
Imports Microsoft.Practices.EnterpriseLibrary.Common.Configuration
Imports Microsoft.Practices.EnterpriseLibrary.Security.Configuration
Imports System.Xml
Imports System.Collections.Specialized
Imports System.Configuration

Namespace MyWebApp.Security.Providers

  Public Class My_AuthorizationProvider : Inherits AuthorizationProvider

    Private _Users As Dictionary(Of String, MembershipUser)
    Private xmlPath As String

    Public Sub New(ByVal attributes As NameValueCollection)
      xmlPath = attributes.[Get]("XmlStore")
    End Sub


    Public Overloads Overrides Function Authorize(ByVal principal As System.Security.Principal.IPrincipal, ByVal context As String) As Boolean
      Dim name As String = principal.Identity.Name
      Dim authorized As Boolean = False
      If xmlPath = String.Empty Then
        Throw New ConfigurationErrorsException("Configuration Error: XML Store " + "Path Not Set")
      End If
      ' Open the role store
      Dim reader As New XmlTextReader(xmlPath)
      ' Check if the username is in the role
      ' specified by the context parameter
      While reader.Read()
        If reader.Name.Equals("User") Then
          If reader.GetAttribute("Name") = name AndAlso reader.GetAttribute("Role") = context Then
            authorized = True
          End If
        End If
      End While
      Return authorized

    End Function

  End Class

End Namespace

================================================================================

Dec 3, 2009 at 4:46 AM

Hi,

I think you're missing the ConfigurationElementType attribute at the class declaration.

<ConfigurationElementType(GetType(CustomAuthorizationProviderData))> _
Public Class MyAuthorizationProvider
  Inherits AuthorizationProvider

  Public Sub New(ByVal ignore As NameValueCollection)

  End Sub


  Public Overrides Function Authorize (ByVal principal As IPrincipal, ByVal context As String) As Boolean
    ' Implement the authorization logic here.
  End Function

End Class

 After that, you can now configure the Security application Block in your web config to use the custom authorization provider. The use it in your code.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Dec 3, 2009 at 3:20 PM

Ok thanks again! I will add that into the code.

I have a question on the web.config part. I actually went into that step last night and tried to add my custom class above to the security application block as the provider. I was using the GUI tool to do this and it is looking for a EXE or DLL file? How do I point it to the class in my web application?

Dec 4, 2009 at 2:10 AM

Use the web application's .dll file.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 4, 2009 at 2:24 AM

There is no singular DLL for the web application as it is a "web site" application. So how would that work?

 Another question... once I change the VB code in my class to look at my SQL server table for authorization and roles lookup, then when I goto setup the web.cofig for the custom provider what would I use in place of the attribute XmlFileName="Users.xml", the bold item below?

Do I give it the name of my SQL server DB and/or connection string?

 <?xml version="1.0" encoding="utf-8"?>

   <configuration>

       <system.web>

             <membership defaultProvider="ReadOnlyXmlMembershipProvider">

                <providers>

                    <add name="MyXmlMembershipProvider" type="MyApp.Security.Providers.MyXmlMembershipProvider, MyApp" description="XML membership provider" xmlFileName="Users.xml" />

                </providers>

             </membership>

        </system.web>

</configuration>

Dec 4, 2009 at 4:24 AM

Oh, I thought it was a web application type of project.  There's no way to do that as web site type of projects don't have  any .exe or .dll output. 

On your second question, you would use connectionStringName rather than the xmlFileName attribute - http://www.steamed-design.com/2007/10/using-custom-database-for-aspnet.html

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 10, 2009 at 2:26 AM

Ok. I changed my application type to a web application type project. Then I tried to point to the .DLL for my web application. It gave me an error stating that no class was found within DLL that implements IAuthorization or something like that? So how does that work?

On your reply to the connection string issue for my custom provider and how to set that in the XML file. The example does not work in my case, as my web application does NOT hold the connection string. I have placed the string in my separate DAL class that is referenced in my web application. My DAL class uses the application data block.

Is there anyone out there who has an actual real application example that they can share with me?  I still cannot find a good example of using custom SQL server tables for authorization and roles via the Ent lib 4.1 security application block! If someone has an example please share it with me, this is driving me absolutely crazy!!

 

Dec 10, 2009 at 5:28 AM

Hi,

Try closing the visual studio and open your solution again. Then try finding type again. If it does not work still, you could just type the full type name of your custom auth provider.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 5, 2010 at 1:21 AM

I have placed the custom membership provider in a class library.  Then I added the following entry into the web.config of the ASP.Net web application:

<membership defaultProvider="My_MembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <add name="My_MembershipProvider" applicationName="MyWebApp"
             connectionStringName="MyDB" description="My Membership provider"
          enablePasswordReset="true" enablePasswordRetrieval="true" maxInvalidPasswordAttempts="3" minRequiredNonAlphanumericCharacters="8"
          minRequiredPasswordLength="8" passwordAttemptWindow="30" requiresQuestionAndAnswer="true" requiresUniqueEmail="true"
          type="MySecurityClass.Security.Providers.My_MembershipProvider, MySecurityClass" /
      </providers >
    </membership >

This is how my class is declared in my class library:

Namespace My_SecurityClass.Security.Providers

  <ConfigurationElementType(GetType(My_MembershipProvider))> _
  Public Class My_MembershipProvider : Inherits MembershipProvider

   End Class

End Namespace 

When I run my web application and I login with a valid user ID and password, I get this error msg:

System.Configuration.ConfigurationErrorsException was caught
  BareMessage="Could not load type 'EXLNTSecurity.Security.Providers.EXLNT_MembershipProvider' from assembly 'EXLNT_Security'."
  Filename="C:\Users\Joe\Documents\Visual Studio 2008\Projects\MyWebApp\MyWebApp\web.config"
  Line=145
  Message="Could not load type 'MySecurity.Security.Providers.My_MembershipProvider' from assembly 'My_Security'. (C:\Users\Joe\Documents\Visual Studio 2008\Projects\MyWebApp\MyWebAppApp\web.config line 145)"
  Source="System.Web"
  StackTrace:
       at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase)
       at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, Boolean checkAptcaBit, Boolean ignoreCase)
       at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
       at System.Web.Configuration.ProvidersHelper.InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
       at System.Web.Security.Membership.Initialize()
       at System.Web.Security.MembershipUser..ctor(String providerName, String name, Object providerUserKey, String email, String passwordQuestion, String comment, Boolean isApproved, Boolean isLockedOut, DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate, DateTime lastLockoutDate)
       at My_Security.My_Security.Security.Providers.My_MembershipProvider.ReadMembershipDataStore() in C:\Users\Ash\Documents\Visual Studio 2008\Projects\My_Security\My_Security\Security\Providers\My_MembershipProvider.vb:line 284
       at My_Security.My_Security.Security.Providers.My_MembershipProvider.ValidateUser(String username, String password) in C:\Users\Ash\Documents\Visual Studio 2008\Projects\My_Security\My_Security\Security\Providers\My_MembershipProvider.vb:line 113
  InnerException: System.TypeLoadException
       Message="Could not load type 'MySecurity.Security.Providers.My_MembershipProvider' from assembly 'My_Security'."
       Source="mscorlib"
       TypeName="MySecurity.Security.Providers.My_MembershipProvider"
       StackTrace:
            at System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName)
            at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
            at System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
            at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
            at System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
            at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase)
       InnerException:

Jan 5, 2010 at 1:37 AM

Your membership provider is declared wrong in the web.config.  You have the type set to :

MySecurityClass.Security.Providers.My_MembershipProvider, MySecurityClass

It should be:

My_SecurityClass.Security.Providers.My_MembershipProvider, My_SecurityClass

Check other typos in the namespaces and assemblies.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 5, 2010 at 3:26 AM
Edited Jan 5, 2010 at 3:28 AM

I made the change and checked the names in all the code files and I still get this error?

System.Configuration.ConfigurationErrorsException was caught
  BareMessage="Could not load type 'My_Security.Security.Providers.My_MembershipProvider' from assembly 'My_Security'."
  Filename="C:\Users\Joe\Documents\Visual Studio 2008\Projects\MyWebApp\MyWebApp\web.config"
  Line=145
  Message="Could not load type 'My_Security.Security.Providers.My_MembershipProvider' from assembly 'My_Security'. (C:\Users\Joe\Documents\Visual Studio 2008\Projects\MyWebApp\MyWebApp\web.config line 145)"
  Source="System.Web"
  StackTrace:
       at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase)
       at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, Boolean checkAptcaBit, Boolean ignoreCase)
       at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
       at System.Web.Configuration.ProvidersHelper.InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
       at System.Web.Security.Membership.Initialize()
       at System.Web.Security.MembershipUser..ctor(String providerName, String name, Object providerUserKey, String email, String passwordQuestion, String comment, Boolean isApproved, Boolean isLockedOut, DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate, DateTime lastLockoutDate)
       at My_Security.My_Security.Security.Providers.My_MembershipProvider.ReadMembershipDataStore() in C:\Users\Joe\Documents\Visual Studio 2008\Projects\My_Security\My_Security\Security\Providers\My_MembershipProvider.vb:line 284
       at My_Security.My_Security.Security.Providers.My_MembershipProvider.ValidateUser(String username, String password) in C:\Users\Joe\Documents\Visual Studio 2008\Projects\My_Security\My_Security\Security\Providers\My_MembershipProvider.vb:line 113
  InnerException: System.TypeLoadException
       Message="Could not load type 'My_Security.Security.Providers.My_MembershipProvider' from assembly 'My_Security'."
       Source="mscorlib"
       TypeName="My_Security.Security.Providers.My_MembershipProvider"
       StackTrace:
            at System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName)
            at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
            at System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
            at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
            at System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
            at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase)
       InnerException:

Here is the changed web.config:

<membership defaultProvider="My_MembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <add name="My_MembershipProvider" applicationName="MyWebApp"
             connectionStringName="MyDB" description="My Membership provider"
          enablePasswordReset="true" enablePasswordRetrieval="true" maxInvalidPasswordAttempts="3" minRequiredNonAlphanumericCharacters="8"
          minRequiredPasswordLength="8" passwordAttemptWindow="30" requiresQuestionAndAnswer="true" requiresUniqueEmail="true"
          type="My_Security.Security.Providers.My_MembershipProvider, My_Security" />    
      </providers >
    </membership >

Jan 5, 2010 at 3:33 AM

Could you try finding all exact match of My_Security in your web.config?  The error clearly says that it is trying to load your membership provider from that assembly.  Or is it your exact assembly name and not My_SecurityClass?

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 6, 2010 at 12:28 AM

I checked the entire web.config and the names are all consistent. I still get the same error?

Jan 6, 2010 at 12:47 AM

So your assembly name is indeed My_Security and My_SecurityClass is just your namespace?

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 6, 2010 at 12:53 AM
Edited Jan 6, 2010 at 12:55 AM

As I stated before, here is how my class and namespace are defined in my class library:

Namespace My_Security.Security.Providers

  <ConfigurationElementType(GetType(My_MembershipProvider))> _
  Public Class My_MembershipProvider : Inherits MembershipProvider

  End Class

End Namespace

Can you give me your email address where I can send you my web.config and my class library code files? I do no want to post them here.

Jan 6, 2010 at 1:00 AM

Your previous post shows that your namespace is My_SecurityClass.  Email address - entlib.support@avanade.com.  It would be great if you could send a simple solution which repros the error.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 6, 2010 at 1:08 AM

ok I did make a mistake in the names of the class, my apologies. Here is the new web.config setup:

<membership defaultProvider="My_MembershipProvider">
      <providers>
        <add name="My_MembershipProvider" connectionStringName="MyDB" description="My Membership provider"
          type="My_Security.My_Security.Security.Providers.My_MembershipProvider, My_Security" />      
      </providers >   
    </membership >

I found the correct name for the type, by opening up class library in object viewer, which showed me the full type name.

This correction has got me past the "could not load assembly from type" error. Now I am getting an "invalid attribute: connectionStringName" how do I get around this? How do I assign the connection string name to the provider?

Jan 6, 2010 at 1:19 AM

Ok dont worry, I got it! I removed the attribute "connectionStringName" and it works! Thanks again for all your help!!

Jan 6, 2010 at 4:23 AM

    Public Overrides Function ValidateUser(ByVal username As String, ByVal strPasswordIn As String) As Boolean

      ' Validate input parameters
      If (String.IsNullOrEmpty(username) OrElse String.IsNullOrEmpty(strPasswordIn)) Then
        Return False
      End If

      Try
        ' Make sure the data source has been loaded
        ReadMembershipDataStore()

        Dim blnPasswordOk As Boolean = False

        ' Validate the user name and password
        Dim user As MembershipUser = Nothing
        If (_Users.TryGetValue(username, user)) Then

          '==Convert stored password to byte array
          Dim origHashedPassword As Byte() = Encoding.UTF8.GetBytes(user.Comment.ToString)

          '==Password entered by user
          Dim passwordEntered As Byte() = Encoding.UTF8.GetBytes(strPasswordIn)

          '==Compare user entered password to hashed password in system
          Return Cryptographer.CompareHash(hashProvider, passwordEntered, origHashedPassword)

        End If

        ' NOTE: A fully featured membership provider would
        ' fire an AuditMembershipAuthenticationFailure
        ' Web event here
        Return False

      Catch ex As Exception
        Return False
      End Try

    End Function

=======================================================================

Ok now I am having trouble decrypting the hashed password I have stored in my SQL server DB. How do I compare the hashed (with salt) password in my DB with the one entered on the login form by the user? I keep getting false returned by the above function. When I step through the above function in DEBUG I can see that both byte arrays, origpassword and passowrdentered are different in lengths?

Jan 6, 2010 at 5:08 AM

You should create the hash first for the origHashedPassword variable and use that to compare it with passwordEntered variable.

Dim origHashedPassword As Byte() = Encoding.UTF8.GetBytes(user.Comment.ToString)

Dim originalHashedPassword As Byte() = Cryptographer.CreateHash("MyHasher", origHashedPassword)

'Password entered by user
 Dim passwordEntered As Byte() = Encoding.UTF8.GetBytes(strPasswordIn)

'Compare user entered password to hashed password in system
 Return Cryptographer.CompareHash(hashProvider, passwordEntered, originalHashedPassword)

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 6, 2010 at 4:03 PM

I will try that tonight and let you know the outcome.

Question: Wont that "rehash" my already hashed password? The password stored in my DB was hashed with a salt value and stored in that manner?

Jan 7, 2010 at 12:00 AM

Ok I just tried your suggestion and I am still getting a "FALSE" back from this function. I still dont understand why would I need to hash the password from the DB before the compare? The password I stored in my DB is a hashed (with salt) password? Here is the code in my function.

Public Overrides Function ValidateUser(ByVal username As String, ByVal strPasswordIn As String) As Boolean

' Validate input parameters

If (String.IsNullOrEmpty(username) OrElse String.IsNullOrEmpty(strPasswordIn)) Then

Return False

End If

Try

' Make sure the data source has been loaded

ReadMembershipDataStore()

Dim blnPasswordOk As Boolean = False

' Validate the user name and password

Dim user As MembershipUser = Nothing

If (_Users.TryGetValue(username, user)) Then

'==Convert original hashed (from DB) password to byte array

Dim PasswordInDB As Byte() = Encoding.UTF8.GetBytes(user.Comment.ToString)

'==create Hash for DB stored password

Dim Hashed_DB_Password As Byte() = Cryptographer.CreateHash(hashProvider, PasswordInDB)

'==Password entered by user

Dim passwordEntered As Byte() = Encoding.UTF8.GetBytes(strPasswordIn)

'==Compare user entered password to hashed password in system

Return Cryptographer.CompareHash(hashProvider, passwordEntered, Hashed_DB_Password)

End If

' NOTE: A fully featured membership provider would

' fire an AuditMembershipAuthenticationFailure

' Web event here

Return False

Catch ex As Exception

Return False

End Try

Jan 7, 2010 at 3:23 AM
Edited Jan 7, 2010 at 3:27 AM

Take a look at this link from MSDN http://msdn.microsoft.com/en-us/library/dd140011.aspx 

That is a walkthrough on the cryptography block on how to validate a user supplied text (password) against a stored (DB) hashed text (password). In that example they even make a note that it is assumed that the stored text (password) was previously hashed.

I am thoroughly confused now!

 

Jan 8, 2010 at 4:58 AM

Yeah, got confused as well, ignore that.  How are you retrieving the password from the database?  I think you saved it as a string and then get the byte array representation of that string, am I right?  That's what's causing it to not match.  In my case, I saved the hashed password in an image database type and read it from the database casting it to byte array and got the expected result.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 8, 2010 at 3:16 PM

I'm sorry but I don’t quite follow your point. Can you show me an example, with some lines of code as to what you are referring to, please?

The password is stored in a varchar column in my SQL server table. The value in the column is the hashed and salted password the user created at the time they registered on my site. When they login I go through my custom membership provider and load the users and their passwords into the user store. Does this answer your question on how I am getting the password from the DB?

 

Jan 11, 2010 at 12:52 AM

"The password is stored in a varchar column in my SQL server table."

As for me, the hashed password is stored in the database in an image column and when I retrieve it, I cast  it to a byte array.  But in your case, you save it as a string, retrieve it as a string and get its byte array representation afterwards. 

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 11, 2010 at 1:14 AM
I still don't get your point. Can you show me with lines of code. Can you show me how it would work within my function?

Sent from my Verizon Wireless BlackBerry


From: "AvanadeSupport" <notifications@codeplex.com>
Date: 10 Jan 2010 17:52:36 -0800
To: <ashy2kc5@gmail.com>
Subject: Re: Security App Block - Customized auth and role provider [entlib:76797]

From: AvanadeSupport

"The password is stored in a varchar column in my SQL server table."

As for me, the hashed password is stored in the database in an image column and when I retrieve it, I cast it to a byte array. But in your case, you save it as a string, retrieve it as a string and get its byte array representation afterwards.

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 11, 2010 at 1:30 AM

This is how I saved my hashed password in the database.

Database db = DatabaseFactory.CreateDatabase();
string password = "password";
byte[] bytePassword = Encoding.Unicode.GetBytes(password);
byte[] hashedPassword = Cryptographer.CreateHash("MyHasher", bytePassword);
DbCommand savePassword = db.GetSqlStringCommand("INSERT INTO [User] VALUES(@hash)");
db.AddParameter(savePassword, "@hash", System.Data.DbType.Binary, System.Data.ParameterDirection.Input, 
                "Password", System.Data.DataRowVersion.Current, hashedPassword);            
db.ExecuteNonQuery(savePassword);

And this is how I retrieve it:

Database db = DatabaseFactory.CreateDatabase();
DbCommand getPassword = db.GetSqlStringCommand("SELECT Password from [User] WHERE UserId = 4");
return (byte[])db.ExecuteScalar(getPassword);

The difference is the data type we used when we saved it.  You used string and I used the image data type. You also retrieve it as a string and get the byte array representation of your hashed password while for me, I already retrieve it from the database as a byte array.

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 11, 2010 at 3:16 AM
Edited Jan 11, 2010 at 3:17 AM

ok. How do you then do the compare of the passwords at login time? Can you show me the code for that? I have tried every combination of logic I can think of and I just cannot get the "CompareHash" function in the Cryptography block to return a true.

Jan 11, 2010 at 4:32 AM
 
byte[] storedPassword = RetrievedPassword();
// Password entered by user.
byte[] passwordEntered = Encoding.Unicode.GetBytes("password");
// Compare passwords
bool isMatch = Cryptographer.CompareHash("MyHasher", passwordEntered, storedPassword);
Console.WriteLine(isMatch.ToString());
  
public byte[] RetrievedPassword()
{
             Database db = DatabaseFactory.CreateDatabase();
             DbCommand getPassword = db.GetSqlStringCommand("SELECT Password from [User] WHERE UserId = 4");
             return (byte[])db.ExecuteScalar(getPassword);
}
Jan 12, 2010 at 3:37 AM

I have tried that method as well, where I convert each of the passwords into Byte arrays and then do the compare. It still does not work. No matter what I try the array sizes are completely different for both passwords and thus the CompareHash keeps returning false?

Jan 12, 2010 at 6:34 AM

Hi,

Can you please try these code snippets:

Added the step to hash the input password first before comparing it to the saved password. Its working on my end, please try.

        static void Main(string[] args)
        {
            //SavePassword();
            byte[] storedPassword = RetrievedPassword();
            // Password entered by user.
            byte[] toBeHashed = Encoding.Unicode.GetBytes("password");
            //hash the input first
            byte[] generatedHash = Cryptographer.CreateHash("MyHasher", toBeHashed);
            // Compare passwords
            bool isMatch = Cryptographer.CompareHash("MyHasher", storedPassword, generatedHash);
            Console.WriteLine(isMatch.ToString());
            Console.ReadLine();
        }

        private static void SavePassword()
        {
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand cmd = db.GetStoredProcCommand("Insert_Password");
            string password = "password";
            byte[] inputPassword = Encoding.Unicode.GetBytes(password);
            byte[] createdHash = Cryptographer.CreateHash("MyHasher", inputPassword);
            db.AddInParameter(cmd, "@Password", System.Data.DbType.Binary, inputPassword);
            db.ExecuteNonQuery(cmd);
        }

        public static byte[] RetrievedPassword()
        {
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand getPassword = db.GetSqlStringCommand("SELECT HashedPassword from [Users] WHERE UserId = 4");
            return (byte[])db.ExecuteScalar(getPassword);
        }

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 12, 2010 at 1:43 PM

What is the column data type for the hashed password you are storing in your SQL table?

Jan 13, 2010 at 12:46 AM

As I mentioned above, the data type of the column is image.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 2, 2010 at 6:19 PM

Ok now I have got the security app block working with the hashing problems all fixed as well.

Now I am moving onto next steps with security block and so now I have implemented the security caching function into my web application. So far I have created a token for the user and managed to cache it with the security cache function. I have the properties on the security cache provider so that the items in the cache are expired.

At the time the use logs out of the web application, I have set the code to expire the token created at login time.

My questions:

1) How do I monitor for the expiration of the token on each of my web applications pages? One note on this, I have a common web page class that is inherited by all my pages. Would I need to add an "IF" condition at the start of each page to check for the token in the cache?

2) I want the application to automatically log out the user, after a specified period of inactivity. How would I do this?

Thanks!

 

Feb 3, 2010 at 4:00 AM

You mean the IIdentity object? Yes, calling GetIdentity on start of each page is a valid approach.  On your second question, you may want to ask that over asp.net forums.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 11, 2010 at 2:07 AM

Ok I think I have figured out the answer to my second question, by using FormsAuthentication.SignOut().

Back to question 1, how do I automatically log out a user based on inactivity?

Also as I am testing my application in VS2008 on my local PC, using the ASP.Net server my security cache does not seem to be expiring my token? Is is it possible to test the cache function on my local pc, with VS2008?

I have the cache provider set to expire items after 1 min.

Feb 11, 2010 at 5:23 AM

So the caching functionality resides on the server?  If it is, then the configuration for the security cache should be applied on its config file.  Or are you setting it on your local application?

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com