views:

290

answers:

3

I am having difficulties implementing a custom ASP.NET RoleProvider.

First off, let me show you the relevant settings in my web.config file:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="Login.aspx"
             name="FormsAuthentication"
             path="Default.aspx"
             timeout="20"/>
    </authentication>

    <membership defaultProvider="MembershipProvider">
      <providers>
        <clear />
        <add name="MembershipProvider"
             type="CompanyName.Security.MembershipProvider" />
      </providers>
    </membership>

    <roleManager defaultProvider="RoleProvider"
                 enabled="true">
      <providers>
        <clear />
        <add name="RoleProvider"
             type="CompanyName.Security.RoleProvider" />
      </providers>
    </roleManager>
  </system.web>
  <location path="Employees.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
        <allow roles="Employees"/>
      </authorization>
    </system.web>
  </location>
</configuration>

Here's the code for the login button's event handler:

if (Membership.ValidateUser(tbxUsername.Text, tbxPassword.Text))
    Response.Redirect("./Employees.aspx");
else
{
    tbxUsername.Text = string.Empty;
    tbxPassword.Text = string.Empty;
    tbxUsername.Focus();
    lblLogin.Visible = true;
}

Side Note based on FormsAuthentication.RedirectFromLoginPage() suggestion:
[It has been suggested that I use FormsAuthentication.RedirectFromLoginPage() instead of Response.Redirect(). Eventually, I'd like to redirect the user to a different page based on his/her role. I don't know how FormsAuthentication.RedirectFromLoginPage() would allow me to do this as it does not accept a redirection url as a parameter. In addition, it is my understanding that I could call FormsAuthentication.SetAuthCookie() prior to Response.Redirect() in order to create the authentication cookie that FormsAuthentication.RedirectFromLoginPage() creates. Please let me know if my thought process here is wrong.]

After stepping through the source, I can see that Membership.ValidateUser() is executing the ValidateUser() function of my custom MembershipProvider class. However, when a valid user logs in, and is redirected to Employees.aspx, the user is returned to Login.aspx**?ReturnUrl=%2fEmployees.aspx**. I assume that this is because although the user authenticates, s/he is failing authorization to the Employees.aspx resource.

With that assumption, I created breakpoints on every function in my custom RoleProvider class to see where things run amuck. Not one of them breaks execution when I debug. Most of the code in my RoleProvider throws NotYetImplementetExceptions, but I would still expect to hit the breakpoints (and would then implement those required functions). Here are two dumbed-down functions I have implemented:

public override string[] GetRolesForUser(string username)
{
    return new string[1] {"Employees"};
}

public override bool IsUserInRole(string username, string roleName)
{
    return true;
}

I assume that since the RoleProvider code never executes, that something must be wrong with my web.config.

I've searched for an answer to this for the past two days and have tried various changes without success. Does anyone see where I'm going wrong?

Thanks in advance!

A: 

Check if user is in role:

If (Roles.IsUserInRole("Employees"))
{
}

or try if it works without role checking:

<allow users="*"/>

maybe helps configuration change:

<location path="Employees.aspx">
    <system.web>
      <authorization>        
        <allow roles="Employees"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>
Jan Remunda
I will respond to your first suggestion by updating my question.The user is redirected as expected when I eliminate role checking as you suggested.Your 3rd suggestion doesn't redirect the user as expected, but if I remove <deny users="*"/> and just have <allow roles="Employees"/>, it works.This is nice, but what bothers me is that the functions in my custom RoleProvider are still not being called.
Paul Daly
and have you overide string[] GetRolesForUser(string username) method?
Jan Remunda
yes, with "return new string[1] {"Employees"};" (for testing)However, I think the critical issue here is that it seems that none of the overriden functions are getting called (because breakpoints are not being hit).
Paul Daly
+1  A: 

After authenticating the user using Membership.ValidateUser, you should call FormsAuthentication.RedirectFromLoginPage rather than Response.Redirect to create the forms authentication ticket.

See the MSDN documentation for Membership.ValidateUser for an example.

EDIT

Or if you want to redirect to a specific page, call FormsAuthentication.SetAuthCookie to create the forms authentication ticket before calling Response.Redirect.

It redirects authenticated users to default.aspx

Actually it redirects back to the page that was originally requested, which is not necessarily default.aspx

EDIT 2

Also there is a problem with your configuration:

  • The path attribute should not point to a specific page (Default.aspx in your case), but the root directory of the site. The default is "/" because most browsers are case-sensitive and so won't send the cookie if there is a case mismatch.

      <forms loginUrl="Login.aspx"
             name="FormsAuthentication"
             path="/"
             timeout="20"/>
    
Joe
I ran across that article, but was confused by the fact that the FormsAuthentication.RedirectFromLoginPage() function does not ask for the page to which the user should be redirected. It redirects authenticated users to default.aspx.I'd like to redirect the user based on his/her role. <-- I'll add that to my question.
Paul Daly
I have added the FormsAuthentication.SetAuthCookie() function prior to the Response.Redirect() call, but am still directed back to Login.aspx?ReturnUrl=%2fEmployees.aspx.
Paul Daly
A: 

I changed the path value (see below) from "Default.aspx" to "/" and now the breakpoints in the custom RoleProvider are being hit!

Does not work:

<authentication mode="Forms">
  <forms loginUrl="Login.aspx"
         name="FormsAuthentication"
         path="Default.aspx"
         timeout="20"/>
</authentication>

Works:

<authentication mode="Forms">
  <forms loginUrl="Login.aspx"
         name="FormsAuthentication"
         path="/"
         timeout="20"/>
</authentication>
Paul Daly