I tried to implement my own AuthorizeAttribute for my REST API that I've built with the WCF Web API Preview 6.
Unfortunately only the constructor gets called, but non of the methods. Am I missing something with the registration?
[BasicHttpAuthorize]
[WebGet(UriTemplate = "")]
public IEnumerable<Supertext.API.Order> Get()
{
And this is my super simplified code.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class BasicHttpAuthorizeAttribute: AuthorizeAttribute
{
public BasicHttpAuthorizeAttribute()
{
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
return true;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
//do the authorization
}
}
But as I said, neither the AuthorizeCore nor the OnAuthorization method is ever called.
Any ideas?
The AuthorizeAttribute and action filters in general are ASP.NET MVC specific artifacts. They have nothing to do with WCF. Decorating a WCF operation contract with it won't have much effect.
Since using the AuthorizeAttribute does not work with the WCF Web API, I came up with my own solution.
I've built a custom HttpOperationHandler and combined it with an Attribute, so I get a similar functionality as the MVC AuthorizeAttribute.
The result is here:
http://remy.supertext.ch/2012/02/basic-authentication-with-wcf-web-api-preview-6/
I was able to complete the implementation of above without HttpOperationHandler but inheriting from System.Web.Http.AuthorizeAttribute instead of the System.Web.Mvc.AuthorizeAttribute. Maybe once both the MCV and former WCF teams are fully merged the two implementations will come to the center, but for now, a namespace change helped out a ton!
See ref: Custom MVC AuthorizeAttribute for ASP.NET Web API
Related
I want to get Area RouthData inside AuthorizationHandlerContext .
I found this answer fetch area from the RouteData , so I need to override AuthorizeCore like
public class ActionAuthorizeAttribute : AuthorizeAttribute {
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) {
var rd = httpContext.Request.RequestContext.RouteData;
string currentAction = rd.GetRequiredString("action");
string currentController = rd.GetRequiredString("controller");
string currentArea = rd.Values["area"] as string;
}
}
But unfortunately , I got this error
'ActionAuthorizeAttribute.AuthorizeCore(HttpContextBase)':not suitable method found to overried
How can I override AuthorizeCore properly ?
The error is because there is no AuthorizeCore method on AuthorizeAttribute to override. You can view the source to see this is clearly the case.
Things are a bit different now in ASP.NET Core, and you're most likely referencing code that applies to ASP.NET MVC. Now, AuthorizeAttribute now is mostly just a catch-hold for the authorization middleware, instead of having any direct functionality of its own.
I'm not sure what you're ultimately trying to achieve, but if you're trying to do custom authorization based on something like route data, then you should actually be using policy auth for that, rather than trying to subclass AuthorizeAttribute.
I just wanted to know the life cycle of AuthorizeAttribute and started debugging the default constructor of the AuthorizeAttribute but could't get any hit.
here is the code of custom Authorize filter.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
public CustomAuthorizeAttribute() : base()
{
string test = string.Empty;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
//Some code
}
}
Anyone please help me to understand the life cycle of this AuthorizeAttribute?
Thanks
This is tricky to answer, because AuthorizeAttribute is both an Attribute and an IAuthorizationFilter.
In the context of an Attribute, it is loaded when GetAttributes() is called the first time by the MVC framework. Attributes are meta-data, so it shouldn't be surprising if this is loaded before the debugger is attached.
In the context of an IAuthorizationFilter, it depends on how the filter is registered. If registered as a global filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomAuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
Then it is clearly instantiated during the startup of the MVC application, and in this case the filters collection is static so is only instantiated once per startup.
If the filter is placed as an attribute on a controller or action method, that's when things get more confusing. When an action is run, the MVC framework loads any attributes that pertain to that action method using the FilterAttributeFilterProvider and executes them. In this case, there is an instance that is loaded as a IAuthorizationFilter which scans for another instance of the same class that is an Attribute.
If you need to explicitly control lifetime of the filter, then you can build your own IFilterProvider that can do just that.
But there is no way to control the lifetime of an attribute. You should just assume that it is always loaded as a singleton and there is no way to create or destroy it.
The default behavior of AuthorizeAttribute (as a filter) scans for another instance of AuthorizeAttribute (as an attribute) in order to read the user/group metadata that it contains. The filter does the heavy lifting, the attribute is just a marker. If this is too confusing, you can separate them into 2 separate classes as per Passive Attributes.
I have a project with both MVC and Web API controllers in it. It uses Windows Auth. However I want to protect a particular Web API action with a custom attribute. I have created the following just to get the basic flow set up (ultimately it will check the users IP address):
using System.Web;
using System.Web.Http;
using System.Web.Http.Filters;
namespace UoB.People.UserInterface.Mvc.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class IPAuthorize : AuthorizationFilterAttribute
{
protected bool AuthorizeCore(HttpContextBase httpContext)
{
return true;
}
}
}
I have decorated my Web API action with a call to this attribute. Problem is, when I run my code locally, the attribute code is never hit. The action is. This particular action belongs to a controller which does not use Windows Auth.
Why is my attribute not being called? Does it need to be registered somewhere? Is there a conflict because my project contains both MVC and Web API controllers? Have I made a simple error somewhere?
Thanks.
You need to register your attribute in RegisterGlobalFilters in your FilterConfig.cs class.
Hope this helps.
Finally figured out my problem. I actually needed to override OnAuthorization and AuthorizeCore. The following example demonstrates this:
public class IPAuthorize : AuthorizeAttribute
{
public string AuthorisedIPs { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
if (AuthorizeCore((HttpContextBase)actionContext.Request.Properties["MS_HttpContext"]))
return;
base.HandleUnauthorizedRequest(actionContext);
}
protected bool AuthorizeCore(HttpContextBase httpContext)
{
// Logic here.
}
}
Hope this helps if anyone else is having trouble.
I have a web application which is secured down by Windows authentication. However, I have one controller which needs to be available globally to anyone, so they do not need a Windows account on the server to be granted access.
I have got this to work by enabling both Windows authentication, and Anonymous Authentication in IIS. My controllers now look like this:
[Authorize]
public class MyController : Controller
{
public Index()
{
}
public DoStuff()
{
}
etc...
}
My anonymous controller is the same, except I have removed the [Authorise] attribute from the start of it.
Am I right in saying that this instructs the web application to only allow those users with a Windows account to use the majority of controllers, except for the controller which I want to allow anonymous access to?
It seems to work just fine, but I wanted to ensure I have not left a gaping security hole open by doing this?
Are there any issues with enabling both methods of authentication, and setting the application up in this way?
First of all, the way you are doing it, there is no gaping hole in the security of your application and it will behave the way you are anticipating. But there is a better way ...
The problem with Authorize attribute is that it's easy to forget to the new controller you add to your application and if you don't add it, your controller is open to the public.
If you were using MVC 4, you could add the Authorize attribute as a global filter and then use AllowAnonymous attribute on your anonymous controller(s) because Authorize attribute respects AllowAnonymous attribute by Default. MVC 3, on the other hand, doesn't ship with AllowAnonymous attribute. T
The way around is to create the AllowAnonymous attribute yourself in your project like so:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class AllowAnonymousAttribute : Attribute { }
Now, you can subclass from the built in Authorize attribute to customize that and look for Anonymous attribute applied to your controller. If you find the attribute, you can skip the authorization. Here is an example implementation:
public sealed class AuthorizeWithAnonymousSupportAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
if (!skipAuthorization)
{
base.OnAuthorization(filterContext);
}
}
}
You will have to add this attribute to the global filters of your site. In your Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
filters.Add(new AuthorizeWithAnonymousSupportAttribute ());
filters.Add(new HandleErrorAttribute());
}
Now, the last step. You can simply add the AllowAnonymous attribute to any controller you want to be anonymous:
[AllowAnonymous]
public class MyController : Controller
{
public Index()
{
}
public DoStuff()
{
}
etc...
}
The benefit of doing all of the above is that you don't have to worry about putting Authorize attribute to the controllers you add to your application. Instead, you will have to explicitly tell the application which controllers are open to the public.
Thanks and hope this helps.
I got a problem as i am writing a custom SSO solution for my company. To mkae it simple, i've made a custom authentication httpmodule that intercepts all requests so as to check user authentication state. If not authenticated, user is redirected to my custom sso login page.
The thing is, when user is not authenticated, i'd like to check if he can access the requested page/resource... With Webforms, no problem, i add an authorization block in web.config, and i use UrlAuthorizationModule.CheckUrlAccessForPrincipal with an anonymous user. Everything works fine...
But when i apply my module to an MVC (3) web site, this does not work anymore (for obvious reasons, like the possibility to access the same controller and/or action from differents urls when using routing, and because authorizations are made through controller attributes).
How can I achieve this ?? I've been searching all day long, didn't find anything about that :/
ASP.NET MVC 3 Internet Application template includes a basic AccountController which implements the following actions (along with the associated models and views):
LogOn
Register
ChangePassword / ChangePasswordSuccess
You simply need the [Authorize] attribute on the Actions or classes you wish to secure. But if you need something really custom you can do something like I've done.
I created a custom class to override security in my application.
public class AuthorizeActivityAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
HttpContext currentContext = HttpContext.Current;
//Do your custom authentication stuff here and return true or false depending on results
Return true;
}
}
And now in my Controller I have the following:
[AuthorizeActivity]
public ActionResult Index()
{
ViewBag.Message = "Welcome";
return View();
}
I had the same problem.
See solution here: MVC equivalent of Webforms "UrlAuthorizationModule.CheckUrlAccessForPrincipal"
You would have to read the information from the other controller. This
can be done by instantiating its context and the Descriptor, then
instantiating the AuthorizationContext for that controller and read
the filter info.