0

I am having trouble trying to use the standard Authorize attribute. It seems to be just ignored. My attempt to get around the problem was to write my own, which is being called but the parameters is not being passed.

The default constructor for BasicAuthorizeAttribute gets called but the one that takes the string parameter is never called. OnAuthorization is called too, but the Roles property is never set.

We are using Windows Authentication although the Authentication is set to None in the web.config. Changing this to Windows made no difference.

We are using MVC 5 and Castle Windsor, which I suspect is causing my problems.

On the controller as well as the action I have:

[BasicAuthorize(Roles = "Developer")]

The attribute filter

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class BasicAuthorizeAttribute : ActionFilterAttribute, IAuthorizationFilter
{
    public string Roles { get; set; }

    public BasicAuthorizeAttribute()
    {
    }

    public BasicAuthorizeAttribute(string roles)
    {
        Roles = roles;
    }

    public void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (!string.IsNullOrWhiteSpace(Roles))
        {
            // Check user roles here

            // User not in role
            filterContext.Result = new HttpUnauthorizedResult(); // mark unauthorized
        }
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
        var user = filterContext.HttpContext.User;
        if (user == null || !user.Identity.IsAuthenticated)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }
}

The Castle Windsor is set up as follows.

...
Component.For<FilterAttribute>().ImplementedBy<BasicAuthorizeAttribute>().LifeStyle.PerWebRequest.Named(typeof(BasicAuthorizeAttribute).FullName)
...

In the web.config we have the following

...
<authentication mode="None" />
...
<modules>
        <remove name="FormsAuthenticationModule" />
</modules>
...

I spent over a day on this and Google is not my friend any more. Anyone with advice on how to resolve this? Or preferably use the default [Authorize(Roles = "...")] attribute?

EDIT

I found the culprit. The following lines was causing the problems.

var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Pieter
  • 2,188
  • 20
  • 27
  • Are you using default action invoker? Windsor will not create your attribute. The action invoker will – Krzysztof Kozmic Aug 27 '15 at 10:55
  • I do not know Windsor at all. How do I know whether it is using the default action invoker? The attribute is being called, the breakpoints gets hit. It is just not passing the parameters in. – Pieter Aug 27 '15 at 10:57
  • Windsor is not involved here at all – Krzysztof Kozmic Aug 27 '15 at 10:58
  • If I remove the "Component.For()..." code for Windsor then my attribute is completely ignored and the breakpoints don't hit – Pieter Aug 27 '15 at 11:02
  • It's hard to say with the information provided. Normally it should work so there must be something in how your app is set up that breaks it. I'd advise trying to get it working without Windsor, strip all the customisations and see if that works. – Krzysztof Kozmic Aug 27 '15 at 11:52
  • In the OnAuthorization method the following brings back the property with the value set: filterContext.ActionDescriptor.GetCustomAttributes(inherit: false).FirstOrDefault(). Its Guid is the same as this.TypeId's Guid too. – Pieter Aug 27 '15 at 11:58
  • 2
    After removing the Castle Windsor it all works. So that must be what is set up wrong. Thank you for your help. – Pieter Aug 27 '15 at 13:12

2 Answers2

1

I found the culprit. The following lines was causing the problems.

var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
Pieter
  • 2,188
  • 20
  • 27
0

Since you are not providing any custom logic, you should just use the AuthorizeAttribute.

[Authorize(Roles = "Developer")]

The ideal way to use it is to register it as a global filter. Then you will have white list security (secure by default).

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
}

This means that all users must login in order to use any actions. And then on your controller, you can either override by user or role or by providing an AllowAnonymousAttribute.

public class HomeController : Controller
{
    // Everyone has access
    [AllowAnonymous]
    public ActionResult Index()
    {
        return View();
    }

    // Only logged in users have access
    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";

        return View();
    }

    // Only admins have access
    [Authorize(Roles = "Admin")]
    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";

        return View();
    }
}

Do note that AuthorizeAttribute requires some sort of authentication system in order to do anything. To get that working, the simplest solution is to select either the Windows or Web MVC template from Visual Studio. Note that the latest Visual Studio 2015 Community Edition is now free and contains many of the features that were missing from previous free editions.

As for DI, attributes are instantiated automatically by the .NET runtime so there is no way to inject them directly. You should not attempt to register the AuthorizeAttribute with the container because there would be no point.

See this answer if you need to customize the AuthorizeAttribute and thus need to actually make a DI-friendly authorization filter.

Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • Thank you for the detailed answer. The problem is that the Authorize attributes are completely ignored. If I write my own and set them up in Castle Windsor then they work but the Roles property does not get set. – Pieter Aug 28 '15 at 09:12