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.
Related
I have implemented token based authentication.
I want to write custom authorize attribute.
The reason behind this is, sometime UserIdentity.GetUserId() gives null.
So to handle this I have written the custom authorize attribute, like the following.
This custom Authorize calls for all the calls (anonymous or authorize call).
So I have used the property IsAuthorizeCall to check whether the call is coming from anonymous or authorized.
Can I make the calls like, I want to call this custom authorzie only when I mentioned above method. Otherwise this should not be called.
How can I do that?
public class CustomAuthorize : AuthorizationFilterAttribute
{
public bool IsAuthorizeCall { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
if (IsAuthorizeCall)
{
IdentityHelper IdentityHelper = new IdentityHelper();
if (IdentityHelper.UserId== Guid.Empty)
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
}
Referenced:
Custom Authorization in Asp.net WebApi - what a mess?
How to Customize ASP.NET Web API AuthorizeAttribute for Unusual Requirements
I have found the answer myself.
If add the filter to the global asax, then it will be called for all
the controllers and action even if mentioned or not.
So we need to remove the following from global.asax
GlobalConfiguration.Configuration.Filters.Add(new CustomAuthorize());
So now, the custom athorize will be call only when mentioned in the controller or action.
I recently asked this question and have successfully setup my custom authorize attribute.
But now I have hit another wall regarding api calls. I need these calls to also be authorized in the same fashion as the action calls. I understand that there is a difference between System.Web.Http and System.Web.Mvc Authorize attributes. So I have created a separate Api specific attribute that basically does the same thing. However, I am having trouble setting the User - principal and identity like i do in the original attribute.
My attributes simply check for some values in a cookie to authorize the request, once the attribute has read the cookie I was storing the decrypted cookie information within a custom principal/identity setup. In my Api call, when I go to retrieve this information from the identity my cast fails and i receive a null value.
This is how I store the information
Api
HttpContext.Current.User = new MyPrinciple(new MyIdentity(decCookie.Name, decCookie.UserData));
Action
filterContext.RequestContext.HttpContext.User = new MyPrinciple(new MyIdentity(decCookie.Name, decCookie.UserData));
How I retrieve the desired information I assumed would be the same
(User.principal.Identity as MyIdentity).MyData;
Questions
Do I really need to have 2 separate attributes
For the Api attribute how can I easily store the information for later use within the controller. Or basically can I not actually get/set the Identity this way for these calls?
EDIT #1
I found how to properly access my cookie value from my ApiController, I was simply missing a reference to System.Web >_<. So question #2 has been solved! but #1 still remains.
Web API and MVC have nothing in common (technically) - even when they look the same. You need two separate attributes.
You can only inherit in one class from in c#, and each authorizeattribute lives in its own namespace, so you can't do it in a single class.
You could hold it in a common namespace and then call a common class to do the lifting.
Possible solution (untested)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
namespace Common.Attributes
{
public class CustomAuthorize : System.Web.Mvc.AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!HttpContext.Current.Request.IsAuthenticated || (HttpContext.Current.User as User) != null)
return;
filterContext.HttpContext.User = Authorize.ExtractIdentity(filterContext.HttpContext);
}
}
public class CustomHttpAuthorize : System.Web.Http.AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
if (!HttpContext.Current.Request.IsAuthenticated || (HttpContext.Current.User as User) != null)
return;
System.Threading.Thread.CurrentPrincipal = Authorize.ExtractIdentity(filterContext.HttpContext);
}
}
}
public static class Authorize
{
public static IIdentity ExtractIdentity(HttpContext context)
{
// do your magic here
}
}
}
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.
How can I ensure that information isn't returned from a webmethod or mvc action by just anyone calling it from Jquery/Ajax call/HTTP post get (you get the idea).
Previously I would have used session variables or the view state to do this on every call, is this still possible. Can anyone point me to any good demos around making these calls secure, I've seen a few but they are easy to spoof or work around.
Thanks!
You can use the AuthorizeAttribute as an action filter to filter access to your controllers. You can just add this attribute to the controllers you want to limit the access to. I think the msdn has a good example for this:
http://msdn.microsoft.com/en-us/library/dd381413(v=vs.90).aspx
You can also use Session in this case.
1. create a ActionFilterAttribute class named, e.g., LoginFilterAttribute.
public sealed class LoginFilterAttribute:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//check if the user is logged in
if (Session["UserSessionKey"]==null)
//redirect to login page or do nothing
else
//return data or do something else
}
}
2. in your action, put this attribute before the action method
[LoginFilter]
public ActionResult ActionNeedLogin()
{
return View();
}
or, register the attribute in global.asax to keep all action from anonymouse access.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyHandleErrorAttribute());
filters.Add(new LoginFilterAttribute());
}
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