1

I've been racking my brain over this for the past week, and none of the answers I've found here or elsewhere seem to be doing anything. I have an ASP.NET MVC5 application that uses SimpleMembership. I have a controller called OrganisationsController that has the following attribute:

[Authorize(Roles = "Administrator")]

I've checked the database and the user I'm logging in with is indeed in the "Administrator" role. However, neither the Authorize attribute nor User.IsInRole() return "true" for this role.

In Authorize attribute not working with roles it is suggested that

The AuthorizeAttribute calls the IsInRole method on the IPrincipal instance stored in HttpContext.User. By default IPrincipal has no roles, and in this case IsInRole will always return false. This is why access to your action is denied.

I've used the following code as suggested in that answer, but authTicket.UserData remains empty.

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie != null)
    {
      FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
      string[] roles = authTicket.UserData.Split(',');
      GenericPrincipal userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
      Context.User = userPrincipal;
    }
}

I can't figure out what's going wrong. Why can I log in, but can't any of the roles be found?

Here's some relevant parts of the web.config:

 <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
      <providers>
        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
      </providers>
    </roleManager>


    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>

    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" cookieless="UseCookies" />
    </authentication>

and this is the InitializeSimpleMembershipAttribute I've defined:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
    private static SimpleMembershipInitializer _initializer;
    private static object _initializerLock = new object();
    private static bool _isInitialized;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Ensure ASP.NET Simple Membership is initialized only once per app start
        LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
    }

    private class SimpleMembershipInitializer
    {
        public SimpleMembershipInitializer()
        {
            Database.SetInitializer<UsersContext>(null);

            try
            {
                using (var context = new UsersContext())
                {
                    if (!context.Database.Exists())
                    {
                        // Create the SimpleMembership database without Entity Framework migration schema
                        ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                    }
                }

                if (!WebSecurity.Initialized)
                {
                    WebSecurity.InitializeDatabaseConnection("VerhaalLokaalDbContext", "UserProfile", "UserId", "UserName", autoCreateTables: true);
                }
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
            }
        }
    }
}

The InitializeSimpleMembershipAttribute is only set on the AccountController.

What's exactly is going on here? Why can't the roles, which are defined and tied to users in the database, be found?

Community
  • 1
  • 1
Bas
  • 1,946
  • 21
  • 38
  • Seems like you answered this yourself: "InitializeSimpleMembershipAttribute is only set on the AccountController". You are requesting something from the OrganizationController, so the RoleProvider does not get initialized. – Tieson T. Dec 04 '15 at 21:46
  • It doesn't work in the AccountController either, so that can't be it. – Bas Jan 07 '16 at 14:07

1 Answers1

1

We used the System.Web.Security.Roles.GetRolesForUser(...) call and then brute force check those role arrays for an intersection. In our case this all happens inside a custom AuthorizeAttribute classes' () call. An extended attribute may not necessary for you but I wanted to give the following code snippet some context. We only used the principal to get the user name.

e.g.,

var userRoles = System.Web.Security.Roles.GetRolesForUser(username);
var allowedRoles = Roles.Split(','); // Roles is a property on the Authorize attribute
var matches = userRoles.Intersect(allowedRoles).ToArray();
if ( matches.Length > 0 ) // true if user is in an allowed role, otherwise it is not

Hope that helps! I'm sure there is a more efficient way, I just dusted off what we have been using for two years now.

Hunter-Orionnoir
  • 2,015
  • 1
  • 18
  • 23