Solved

ASP.NET Authentication based on Access Permissions

Posted on 2009-07-02
34
273 Views
Last Modified: 2012-05-07
Hi EE,

I'm looking for some help on finishing some code that i have. Basically i would lke to redirect a user to his/her appropriate page based on their access permissions that are stored in the database.

I'm going to attach the code that i have now that authenticates by username and password Hash and Password Salt but need help with the rest. I think i need a Select Case but not sure how to implement that into what i have now.

Thanks in advance!!!

Public Function gfCreatePasswordHash(ByVal vstrPwd As String, ByVal vstrSalt As String) As String

        Dim strSaltAndPwd As String = String.Concat(vstrPwd, vstrSalt)

        Dim strHashedPwd As String = FormsAuthentication.HashPasswordForStoringInConfigFile(strSaltAndPwd, "SHA1")

        Return strHashedPwd

    End Function
 

    Protected Sub btnAuthenticate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAuthenticate.Click
 

        Dim strSaltFromDB As String

        Dim hashPwdInDB As String

        Dim hashPwdEnterd As String
 

        Session("username") = txtUsername.Text
 

        Dim connectionString As String = ConfigurationManager.ConnectionStrings("DemoSql").ConnectionString

        Dim conn As SqlConnection = New SqlConnection(connectionString)
 

        Dim comm As SqlCommand
 

        comm = New SqlCommand("AuthenticateLogin", conn)

        comm.CommandType = System.Data.CommandType.StoredProcedure
 

        comm.Parameters.Add("@username", SqlDbType.VarChar, 50)

        comm.Parameters("@username").Value = txtUsername.Text
 

        Try

            conn.Open()

            Dim myreader As SqlDataReader

            myreader = comm.ExecuteReader(CommandBehavior.CloseConnection)

            If myreader.Read() Then
 

                hashPwdInDB = myreader("passwordhash").ToString

                strSaltFromDB = myreader("passwordsalt").ToString
 

                hashPwdEnterd = gfCreatePasswordHash(txtPassword.Text, strSaltFromDB)

                If hashPwdEnterd = hashPwdInDB Then

                    FormsAuthentication.RedirectFromLoginPage(txtUsername.Text, True)
 

                Else

                    lblError.Text = "your login credentials are invalid!!!"

                End If

            End If

            myreader.Close()

        Catch

            lblError.Text = "the pssa database is currently offline."

        Finally

            conn.Close()

        End Try
 

    End Sub

Open in new window

0
Comment
Question by:asp_net2
  • 18
  • 16
34 Comments
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
Since you did not provide much info on "access permissions that are stored in the database" here is what I think.
Modifications you need is here:

If hashPwdEnterd = hashPwdInDB Then
  'Note the use of SetAuthCookie
         FormsAuthentication.SetAuthCookie(txtUsername.Text, True)
  ' Get Access Rights From DB
  ' Redirect the user based on access right
  if access right = edit
        Response.Redirect("Edit.aspx")
if access right = Readonly
         Response.Redirect("Readonly.aspx")
...and so on
   
                   Else
lblError.Text = "your login credentials are invalid!!!"
End If

Now the problem here is....if any authenticated user who knows the url of your pages can navigate directly to those pages by typing the url in browser address bar..
i.e. say you redirect user to Readonly.aspx but if the user types in the address bar edit.aspx they will be given access to since they are authenticated.

So in that case your next best option would be using Roles.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
Hi guru_sami,

Sorry, the field name in my DB for access permissions is called accessperm and it's an int. Now if i wanted to use the name instead of int would i need to create an inner join in my SP that retrieves the username, passwordsalt, passwordhash?

Current SP:

ALTER PROCEDURE [dbo].[AuthenticateLogin]
@username varchar(50)
AS
SELECT username, passwordhash, passwordsalt FROM EmpSalt WHERE username = @username

TABLE with Access Permissions:

Table Name = ACPER
id = int  PK
acid = int  ID for Access Permissions
acname = varchar Name of Access Permission (Admin, Member, User)
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
I would suggest you to set up roles table instead of what you have. This will make things more easier and meaningful.
Check here: http://aspnet.4guysfromrolla.com/articles/082703-1.aspx
Follow the article and you will get better idea.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
yeah, i have a book that talks about that but was wondering how to do it from a programming stand point instead.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
ok, i modified the following below but i'm not recieving any errors when i run it, HOWEVER i'm not going anywhere based on the access permission either :(

Also, I modified my web.config file using <location> on each page unless the user is successful in logging in they can't access.

Protected Sub btnAuthenticate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAuthenticate.Click

        Dim strSaltFromDB As String
        Dim hashPwdInDB As String
        Dim accessright As Integer
        Dim hashPwdEnterd As String

        Session("username") = txtUsername.Text

        Dim connectionString As String = ConfigurationManager.ConnectionStrings("DemoSql").ConnectionString
        Dim conn As SqlConnection = New SqlConnection(connectionString)

        Dim comm As SqlCommand

        comm = New SqlCommand("AuthenticateLogin", conn)
        comm.CommandType = System.Data.CommandType.StoredProcedure

        comm.Parameters.Add("@username", SqlDbType.VarChar, 50)
        comm.Parameters("@username").Value = txtUsername.Text

        Try
            conn.Open()
            Dim myreader As SqlDataReader
            myreader = comm.ExecuteReader(CommandBehavior.CloseConnection)
            If myreader.Read() Then

                hashPwdInDB = myreader("passwordhash").ToString
                strSaltFromDB = myreader("passwordsalt").ToString

                hashPwdEnterd = gfCreatePasswordHash(txtPassword.Text, strSaltFromDB)
                If hashPwdEnterd = hashPwdInDB Then
                    'Note the use of SetAuthCookie
                    FormsAuthentication.SetAuthCookie(txtUsername.Text, True)
                    ' Get Access Rights From DB
                    ' Redirect the user based on access right
                    accessright = myreader(CInt("acperid")).ToString
                    If accessright = 10 Then
                        Response.Redirect("Edit.aspx")
                    End If
                    If accessright = 11 Then
                        Response.Redirect("Readonly.aspx")
                    End If
                End If
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
set breakpoints on If here and see if accessright is assigned correct value.
Also I see accessright is an int and you are assigning it a String value....
 accessright = myreader(CInt("acperid")).ToString
                    If accessright = 10 Then
                        Response.Redirect("Edit.aspx")
                    End If
                    If accessright = 11 Then
                        Response.Redirect("Readonly.aspx")
                    End If
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
I didn't see anything after setting a breakpoint I changed to the following below.

Dim accessright As Integer = Convert.ToInt32(myreader("acperid"))

                hashPwdEnterd = gfCreatePasswordHash(txtPassword.Text, strSaltFromDB)              
                If hashPwdEnterd = hashPwdInDB Then
                    'Note the use of SetAuthCookie
                    FormsAuthentication.SetAuthCookie(txtUsername.Text, True)
                    ' Get Access Rights From DB
                    ' Redirect the user based on access right
                    accessright = myreader(CInt("acperid")).ToString
                    If accessright = 10 Then
                        Response.Redirect("Edit.aspx")
                    End If
                    If accessright = 11 Then
                        Response.Redirect("Readonly.aspx")
                    End If
                End If
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
what value is assigned to "accessright " ...is correct value returned from DB?
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
acperid, yes it is a "int" field in the DB and has a value assigned to it. The only values for acperid in the DB are 10 and 11.
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
Yes but when you do this:
Dim accessright As Integer = Convert.ToInt32(myreader("acperid"))

What value is assigned to accessright is it 10 or 11 or something else
i.e. myreader("acperid") is getting right value when you execute the SP.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
it would be either 10 or 11

when i execute my SP and when i enter a username it displays everything along with the acperid for example: username: jdoe would return 10 as the acperid
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
I do understand it would return either 10 or 11 but when debug and you login as a particular user say jdoe...what is it returning?

Consider the code below:

                hashPwdEnterd = gfCreatePasswordHash(txtPassword.Text, strSaltFromDB)              
                If hashPwdEnterd = hashPwdInDB Then
                    'Note the use of SetAuthCookie
                    FormsAuthentication.SetAuthCookie(txtUsername.Text, True)
                    ' Get Access Rights From DB
                    ' Redirect the user based on access right
      Dim accessright As Integer = Convert.ToInt32(myreader("acperid"))

-->                  If accessright = 10 Then
                        Response.Redirect("Edit.aspx")
                    End If
-->                    If accessright = 11 Then
                        Response.Redirect("Readonly.aspx")
                    End If
                End If

When you set breakpoints at --> and say you have loggedin as jdoe ...hover over the accessright and see what value are you getting.
If say you are getting 10 ...then on pressing F11 does the control move to  Response.Redirect("Edit.aspx") ?
or where does the control go.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
ok i set breakpoints at the places you mentioned and yes the value i'm getting for accessright is 10 and when i press f11 the control moves to response.redirect("edit.aspx").
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
So then aren't you redirectd to edit.aspx?
i mean do you have a page called edit.aspx?
so Response.Redirect(url);
url is where you want the user to get redirected if  accessright = 10?
Or do you stay on the same page ?
Can you tell what is happening i.e. do you still stay authenticated or something else happening...
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
guru_sami,

Ok, i did make a mistake with the values 10 and 11 it was 1 and 2 :( I'm very sorry.

That part works now i have another issue that is related to this login though. If i navigage to those pages i get send to the login page which is GREAT, however no matter what the acperid is it lets me in, i want to restrict based on the value such as 1 or 2. See how my web.config is.

Do i need to add the code below somewhere?

Dim ticket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, USER_USERNAME.Text, DateTime.Now, DateTime.Now.AddMinutes(30), True, "1", FormsAuthentication.FormsCookiePath)

Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
Response.Cookies.Add(New HttpCookie(FormsAuthentication.FormsCookieName, encTicket))

Response.Redirect("1.aspx")



Dim ticket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, USER_USERNAME.Text, DateTime.Now, DateTime.Now.AddMinutes(30), True, "2", FormsAuthentication.FormsCookiePath)

Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
Response.Cookies.Add(New HttpCookie(FormsAuthentication.FormsCookieName, encTicket))

Response.Redirect("2.aspx")



Dim ticket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, USER_USERNAME.Text, DateTime.Now, DateTime.Now.AddMinutes(30), True, "3", FormsAuthentication.FormsCookiePath)

Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
Response.Cookies.Add(New HttpCookie(FormsAuthentication.FormsCookieName, encTicket))

Response.Redirect("3.aspx")


  <location path="admin/index.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>

  <location path="member/index.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>

  <location path="user/index.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>
0
 
LVL 41

Accepted Solution

by:
guru_sami earned 500 total points
Comment Utility
Alrite thats exactly what I meant in my Very first Post...when I said you will need roles... also the link I provided before does the same.
Anyways...The modified code should go something like this:

If hashPwdEnterd = hashPwdInDB Then
   ' Get Access Rights From DB
     Dim accessright As Integer = Convert.ToInt32(myreader("acperid"))

  'Note we are not using SetAuthCookie but manually creating FA Cookie
        Dim ticket As New FormsAuthenticationTicket(1, Username.Value, DateTime.Now, DateTime.Now.AddMinutes(30), True,  accessright.ToString, _
FormsAuthentication.FormsCookiePath)
Dim hash As String = FormsAuthentication.Encrypt(ticket)
Dim cookie As New HttpCookie(FormsAuthentication.FormsCookieName, hash)
If ticket.IsPersistent Then
    cookie.Expires = ticket.Expiration
End If
Response.Cookies.Add(cookie)
 
  ' Redirect the user based on access right
  ' make sure you put your right code below
     If accessright = 10 Then
                        Response.Redirect("Edit.aspx")
                    End If
   If accessright = 11 Then
                        Response.Redirect("Readonly.aspx")
                    End If

 Else
lblError.Text = "your login credentials are invalid!!!"
End If

Now in your Global.asax you need to add this:
Protected Sub Application_AuthenticateRequest(ByVal sender As [Object], ByVal e As EventArgs)
    If HttpContext.Current.User IsNot Nothing Then
        If HttpContext.Current.User.Identity.IsAuthenticated Then
            If TypeOf HttpContext.Current.User.Identity Is FormsIdentity Then
                Dim id As FormsIdentity = DirectCast(HttpContext.Current.User.Identity, FormsIdentity)
                Dim ticket As FormsAuthenticationTicket = id.Ticket
               
                ' Get the stored user-data, in this case, our roles
                Dim userData As String = ticket.UserData
                Dim roles As String() = userData.Split(",")
                HttpContext.Current.User = New GenericPrincipal(id, roles)
            End If
        End If
    End If
End Sub
 
And your web.config should change like this:
<location path="admin/index.aspx">
    <system.web>
      <authorization>
        <allow roles="1"/> //assuming 1 means Admin users....
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

and similarly others..

Code is adapted from link below:
http://www.codeproject.com/KB/web-security/formsroleauth.aspx
Follow the article and to understand what has been done....and also check the previous link I provided.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
Hi guru_sami,

Ok, i implemented everything from above, HOWEVER if i load admin/index.aspx page it redirects me back to my login (which is what i needed it to do) BUT when i login with a different set of credentials it redirects me to the appropriate page. I would like to display a message such as "Invalid Credentials" if a user tries to navigagte to a page and has to login before accessing.

Also, If a username is correct but password is bad then it still directs me to the page as if both username and password and accesspermissions where correct.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
Not sure if I got that part...can you explain with example / flow..about what behavior you are seeing
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
If i naviage to members/index.aspx and run the page without logging in first it redirects me to the main login.aspx page (which works as I needed to prevent unauthorized access without first logging in). However, if i where to enter credentials for access to admin/index.aspx instead of credentials for members/index.aspx then it redirects me to admin/index.aspx instead of displaying an error message stating that I entered incorrect credentials for members/index.aspx.

The main login.aspx page works as i needed which redirects the user to the appropriate page based on there credentials thanks to you!!
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
did you set the roles properly in your web.config?
Can you share that portion.
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
I see whats happening....need some modification in the login code...

'store any returnUrl queryStringParam in a variable
Dim returnUrl As String = Request.Params("ReturnUrl")
If accessright = 10 Then
     If returnUrl IsNot Nothing Then
         Response.Redirect(returnUrl.ToString)
     Else
         Response.Redirect("Edit.aspx")
     End If
End If

'same for other respective accessright check.

Now in your Login Page Load add this check:

If Not Page.IsPostBack Then          
If Request.IsAuthenticated AndAlso Not String.IsNullOrEmpty(Request.QueryString("ReturnUrl")) Then              
 ' This is an unauthorized, authenticated request...                
lblError.Text = "UnAuthorized Access!"        
 End If      
End If

Hope that should do...
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
No, still not working right. Now when i run member/index.aspx it redirects to the login.aspx page which is what i need, however now when i login at the login.aspx page to verify my credentials to access the member/index.aspx page if I enter credentials that are in the DB it will still redirect me to the member/index.aspx page even if that user is not in that particular role.
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
can you attach the code you have so far...
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
Ok, i'm going to attach what i have so far.
EE-Code.txt
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
Try accessing membmes/index.aspx page....login with non-member credentials i.e say admin user...
set breakpoints at following lines in your code and debug:
1-->If returnUrl IsNot Nothing Then
2-->                   Response.Redirect(returnUrl.ToString)
                        Else
3-->                    Response.Redirect("admin/index.aspx")
      End If

PageLoad
If Not Page.IsPostBack Then
         If Request.IsAuthenticated AndAlso Not String.IsNullOrEmpty(Request.QueryString("ReturnUrl")) Then
                ' This is an unauthorized, authenticated request...                
4-->               lblError.Text = "UnAuthorized Access!"
            End If
        End If

Now what to note:
1: Value of returnUrl variable
2: Do you hit breakpoint 2 or 3 or none
3: If you hit breakpoint 2 you should hit breakpoint 4

Also you did not share your global.aspx code and web.config settings in your attachement. Please share that as well.




0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
Ok, i'm attaching a text file with the results of the breakpoints and my web.conifg and global.asax code.
EE-CODE-1.txt
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
You have <deny users="?"/> in your web.config in location section .. that is the reason you are not hitting breakpoint 4
It should be <deny users="*"/> i.e. star
Check my previous post ID - 24768272 ...
So it should be like this:
<location path="admin/index.aspx">
    <system.web>
      <authorization>
        <allow roles="Admin"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

Try this and let me know how it goes...i.e run the previous test and see if you hit breakpoint 4.
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
ok, i changed <deny users="?"> to <deny users="*"> and i went through the breakpoints again but it never hits breakpoint 4 only breakpoint 1 & 2 and then it goes to my Catch in 'Try Catch Finally' and then it opens the members/index.aspx as if i logged in with the correct credentials for this page which i did not.
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
how about running the same test again .... but put this check in your members/index.aspx page Load..
If User.IsInRole("Admin") Then
5 -->    Response.Redirect("admin/index.aspx")
End If

Set one more breakpoint as  5 above.
Also you say you are hitting Catch... can you change your it to like this and set breakpoint 6:
 Catch ex As Exception
6-->    Response.Write(ex.Message.ToString())

I think there is some small miss which I am not able to catch.
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
Also just want to confirm you did change
<deny users="?"/> to
 <deny users="*"/>
for members/index.aspx location as well right?

Oh one more thing I see in your code:
you have
<location path="member/index.aspx">
I believe it should be
<location path="members/index.aspx"> // you see missin 's' in 'member'

Also I would recommend changing admin/index.asp and members/index.aspx path to just like below. It is just an enhancement and not related to the problem you are seeing.
<location path="admin">
<location path="members">
       
0
 
LVL 4

Author Comment

by:asp_net2
Comment Utility
ok, after implementing everything that you provided from above then the application is now working as i needed it to. I did not have <deny users="?"> so i made that change and ran it and all was fine, however i have a few questios to ask below.

1.) Do i really need a global.asax file? If so, why?
2.) Do i need the code for member/index.aspx Page_Load that checks for User.IsInRole?
3.) Do i still need the code for Page_Load in login.aspx? If so, what does this actually do then?
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
1.) Do i really need a global.asax file? If so, why?
Yes that is required...because it is used by asp.net authorization module to make decision based on roles i.e. <allow roles="Admin"/>. So everytime you access a page the urlAuthorization Module will check against the roles for current logged-in user that was added here:
HttpContext.Current.User = New GenericPrincipal(id, roles) //in global.aspx pages.

2.) Do i need the code for member/index.aspx Page_Load that checks for User.IsInRole?
No that was for troubleshooting purpose to determine if your Roles are working properly. This work is already done for you by UrlAuthorizationModule. Also User.IsInRole check was possible due to code in global.aspx. So you can remove this check.

3.) Do i still need the code for Page_Load in login.aspx? If so, what does this actually do then?
Yes that code is required. That code is for setting your labelText. If you remove that code, you will just be redirect to login.aspx without any message.
So this is what is happening:
a)you try to navigate to members/index.aspx
b)you will be redirected to login.aspx with returnUrl=members/index.aspx
c)now you login as admin ..after successful user credentials validation...you hit this line:
   Response.Redirect(returnUrl.ToString)
d)you are redirected to members/index.aspx since returnUrl is not null
e)but asp.net urlauthorization module check this from your web.config
<allow roles="Member"/>
        <deny users="*"/>
Oh the user is not in Member role(because user is in Admin Role)...so moves to next deny ..i.e. it will deny everyone else..
f)So you will be redirected to login.aspx with returnUrl=members/index.aspx.
g) in Login_Pageloge there is a check is Request Authenticated(it will be yes...because admin user was authenticated but not authorized to view member area) and returnUrl is not null....so set the labelText.

Hope this answers all your questions.

0
 
LVL 4

Author Closing Comment

by:asp_net2
Comment Utility
Thank you VERY MUCH for all your help. I never would have figured this out without your help. Is there a way that i could learn more about this type of stuff? If so where should i start?

Thanks again for all you did!!!
0
 
LVL 41

Expert Comment

by:guru_sami
Comment Utility
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

AJAX ModalPopupExtender has a required property "TargetControlID" which may seem to be very confusing to new users. It means the server control that will be extended by the ModalPopup, for instance, if when you click a button, a ModalPopup displays,…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now