We help IT Professionals succeed at work.

ASP.NET Authentication based on Access Permissions

asp_net2
asp_net2 asked
on
Medium Priority
393 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

Comment
Watch Question

Top Expert 2013

Commented:
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.

Author

Commented:
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)
Top Expert 2013

Commented:
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.

Author

Commented:
yeah, i have a book that talks about that but was wondering how to do it from a programming stand point instead.

Author

Commented:
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
Top Expert 2013

Commented:
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

Author

Commented:
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
Top Expert 2013

Commented:
what value is assigned to "accessright " ...is correct value returned from DB?

Author

Commented:
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.
Top Expert 2013

Commented:
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.

Author

Commented:
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
Top Expert 2013

Commented:
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.

Author

Commented:
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").
Top Expert 2013

Commented:
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...

Author

Commented:
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>
Top Expert 2013
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
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.
Top Expert 2013

Commented:
Not sure if I got that part...can you explain with example / flow..about what behavior you are seeing

Author

Commented:
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!!
Top Expert 2013

Commented:
did you set the roles properly in your web.config?
Can you share that portion.
Top Expert 2013

Commented:
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...

Author

Commented:
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.
Top Expert 2013

Commented:
can you attach the code you have so far...

Author

Commented:
Ok, i'm going to attach what i have so far.
EE-Code.txt
Top Expert 2013

Commented:
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.




Author

Commented:
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
Top Expert 2013

Commented:
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.

Author

Commented:
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.
Top Expert 2013

Commented:
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.
Top Expert 2013

Commented:
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">
       

Author

Commented:
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?
Top Expert 2013

Commented:
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.

Author

Commented:
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!!!
Top Expert 2013

Commented:
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.