Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

ASP.NET Authentication based on Access Permissions

Posted on 2009-07-02
34
Medium Priority
?
334 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 18
  • 16
34 Comments
 
LVL 41

Expert Comment

by:guru_sami
ID: 24764694
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
ID: 24764872
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
ID: 24764946
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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Author Comment

by:asp_net2
ID: 24765036
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
ID: 24765369
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
ID: 24765598
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
ID: 24765697
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
ID: 24765754
what value is assigned to "accessright " ...is correct value returned from DB?
0
 
LVL 4

Author Comment

by:asp_net2
ID: 24765801
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
ID: 24765905
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
ID: 24767394
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
ID: 24767504
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
ID: 24767908
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
ID: 24768041
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
ID: 24768100
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 2000 total points
ID: 24768272
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
ID: 24769437
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
 
LVL 41

Expert Comment

by:guru_sami
ID: 24772591
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
ID: 24773369
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
ID: 24773481
did you set the roles properly in your web.config?
Can you share that portion.
0
 
LVL 41

Expert Comment

by:guru_sami
ID: 24773623
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
ID: 24775029
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
ID: 24775047
can you attach the code you have so far...
0
 
LVL 4

Author Comment

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

Expert Comment

by:guru_sami
ID: 24775143
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
ID: 24775297
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
ID: 24775329
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
ID: 24775358
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
ID: 24775393
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
ID: 24775415
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
ID: 24775628
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
ID: 24775717
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
ID: 31599235
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
ID: 24777309
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A quick way to get a menu to work on our website, is using the Menu control and assign it to a web.sitemap using SiteMapDataSource. Example of web.sitemap file: (CODE) Sample code to add to the page menu: (CODE) Running the application, we wi…
IntroductionWhile developing web applications, a single page might contain many regions and each region might contain many number of controls with the capability to perform  postback. Many times you might need to perform some action on an ASP.NET po…
Video by: ITPro.TV
In this episode Don builds upon the troubleshooting techniques by demonstrating how to properly monitor a vSphere deployment to detect problems before they occur. He begins the show using tools found within the vSphere suite as ends the show demonst…
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…

636 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