I've came across a controller method marked with System.Web.Http.OverrideAuthenticationAttribute in my current Web API project and I'm curious what this is for?
Searching in Google and Stackoverflow doesn't answer the question. MSDN documentation doesn't contain much information. It only says the following:
Represents a filter attribute that overrides authentication filters
defined at a higher level.
Also, I've taken a look into the sources:
public sealed class OverrideAuthenticationAttribute : Attribute, IOverrideFilter, IFilter
{
public bool AllowMultiple
{
get
{
return false;
}
}
public Type FiltersToOverride
{
get
{
return typeof(IAuthenticationFilter);
}
}
}
But this doesn't shed much light.
So could anybody explain what is the purpose of using the OverrideAuthenticationAttribute? And please give some use cases of it for better understanding.
The OverrideAuthentication attribute is used to suppress global authentication filters, which means that all global Authentication filters (implementing IAuthenticationFilter) will be disabled when using this filter.
Let's say you have a global authentication filter called BasicAuth:
public class BasicAuthAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{ }
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
And the filter is configured as a Global filter for all controllers with this code:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new BasicAuthAttribute());
}
}
Let's say you want to use a different authentication strategy on a single controller or controller action. In that case you could disable the global auth. filters using the OverrideAuthentication attribute, and then configure a new filter you want to use for that specific action. This is helpful when you are integrating with external login providers, and you don't want any existing Global auth filters to mess up your external login authentication.
In the code below the global authentication filters are disabled, and then the HostAuthentication filter is enabled for a single action to enable external login providers (e.g. Facebook):
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(Startup.ExternalCookieAuthenticationType)]
[AllowAnonymous]
[HttpGet("ExternalLogin", RouteName = "ExternalLogin")]
public async Task<IHttpActionResult> ExternalLogin(string provider)
{
// Auth code
}
OverrideAuthentication is for overriding the authentication filters configured at higher levels. Say, you have an authentication filter applied globally like this.
// Applied globally in WebApiConfig
config.Filters.Add(new MyAuthenticationFilter());
And, you want to stop this filter from running for a specific action method or a controller. You can use OverrideAuthentication at that level, like this.
public class ValuesController : ApiController
{
[OverrideAuthentication]
public string Get()
{ ... }
}
Now, in the above example, you have MyAuthenticationFilter applied globally. Say, you want to override that and run another filter, say MyAnotherAuthenticationFilter only for the Post action method. You can do something like this.
public class ValuesController : ApiController
{
// Removes all filters applied globally or at the controller level
[OverrideAuthentication]
[MyAnotherAuthentication] // Puts back only MyAnotherAuthenticationFilter
public string Post(...)
{ ... }
}
More info here. Check out the "Filter Overrides" section.
Related
I would like to make use of AllowAnonymous and a custom AuthenticationFilter. Can someone point me in the right direction to make use of AllowAnonymous or another alternative? Thanks
I've created my own custom filter that inherits from System.Attribute and implements System.Web.Http.Filters.IAuthenticationFilter
public class MyCustomAuthenticationAttribute : Attribute, IAuthenticationFilter
I have been able to successfully add the logic for the AuthenticateAsync method
public async Task AuthenticateAsync(
HttpAuthenticationContext context,
CancellationToken cancellationToken) {}
My problem is that I need to ignore some of my Web API controller actions or controllers. I thought that I could use System.Web.Http.AllowAnonymousAttribute to do this. For example here is a really simple example showing intent.
[MyCustomAuthentication]
public class HomeController : ApiController
{
// no authentication needed allow anonymous
[HttpGet]
[Route("hianonymous")]
[AllowAnonymous]
public IHttpActionResult Hello(string name) {
return Ok(new { message = "hello " + name });
}
// needs to be authenticated
[HttpGet]
[Route("hiauthenticated")]
public IHttpActionResult Hello() {
var name = User.Identity.Name;
return Ok(new { message = "hello authenticated user " + name });
}
}
The problem is that Authenticate() is still called on MyCustomAuthenticationAttribute. I would like to use AllowAnonymous or some other method to accomplish this. Thanks for any input.
I know that I can use my custom authentication attribute at the action level and not controller level but there are cases I would like an entire controller or even as a global filter so I need to be able to excluded on an individual action or controller basis.
Your implementation of IAuthenticationFilter should do NOTHING if it does not find an Authorization scheme it does not recognize.
http://www.asp.net/web-api/overview/security/authentication-filters
// 2. If there are no credentials, do nothing.
if (authorization == null)
{
return;
}
// 3. If there are credentials but the filter does not recognize the
// authentication scheme, do nothing.
if (authorization.Scheme != "Basic")
{
return;
}
The idea is that your filter is simply a way to AUTHENTICATE using a known scheme.
You will still need to use the built in AuthorizeAttribute and AllowAnonymousAttribute to control AUTHORIZATION.
I basically want to check if the session is still valid for every GET and POST request in my application, however, I don't really want to keep copying and pasting the same code in to every Action Method, I was thinking of using a Base Controller so I can inherit the usage or a static helper controller class (if this can be done??). Are either of these ways the best (or even correct) approach to take?
Example of code
[HttpGet]
[ValidateInput(false)]
public ActionResult SimpleSearch()
{
// I want to run this code of every ActionResult for a GET AND POST
if (!SessionStaticClass.IsUserLoggedIn())
{
return RedirectToAction("Login, Login");
}
}
Thanks
You can use an action filter:
public class NotLoggedInFilter : FilterAttribute, IResultFilter
{
public void OnResultExecuting(ResultExecutingContext filterContext)
{
if (!SessionStaticClass.IsUserLoggedIn())
{
filterContext.Result = new RedirectToAction("Login, Login");
}
}
}
You can then decorate controllers or actions with the attribute, or even have it run for all actions by adding it to the global filter collection.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new NotLoggedInFilter());
}
However, you might want to have a look at authentication filters as a way of handling user authentication instead of using the SessionStaticClass class. A good overview of filter types in MVC can be found here.
I want to add a functionality to application such that only admin can create users and he can provide access to particular pages to user.
He can create roles and can provide users different roles.
I am using Visual Studio 2010 and building this application in MVC3.
Please give me suggestions to make over it.
Thanks in advance.
1.Decorate your user creation and permission setting actions with Authorize attribute
(Notify, that usage of Roles property of AuthorizeAttribute requires implementation of MembershipProvider (standart or custom) and registering it in web.config)
public class AccountController : Controller
{
[HttpGet, Authorize(Roles = "Admin")]
public ViewResult CreateUser()
{
return View();
}
[HttpPost, Authorize(Roles = "Admin")]
public ActionResult CreateUser()
{
//... call service method to create user
}
[HttpPost, Authorize(Roles = "Admin")]
public ActionResult AssignPageToUser(int userId, string controllerName, string ActionName)
{
//... insert record into table (UserPermissions) with attributes (userId, actionName, controllerName)
}
// other methods without decoration by authorize attribute
}
Next paragraphs are correct if you really want to have full control on action permissions separately for each user.
If you think, that your permissions can group in finite and small number on roles - you can decorate all actions/controllers by authorize attribute and specify roles, for which action/controller available: [Authorize("Customer, Manager, RegionalAdmin")] and give admin possibility to assign roles to users. But remember, that in is enough to be in only 1 of listed roles to get access, you can't require by this attribute, for example and Admin, and Manager roles.
If you want to require necessarily more than 1 role, use multiple attributes:
public class MyController:Controller
{
[Authorize(Roles = "Manager")]
[Authorize(Roles = "Admin")]
public ActionResult Action1()
{
//...
}
}
2.For your pages you can create your own filter attribute, inherited from authorize attribute, that will check, if action is available for user (i think you want to assign actions but not views to user).
public UserPermissionRequiredAttribute: AuthorizeAttribute
{
public OnAuthorization(AuthorizationContext filterContext)
{
var isAuthenticated = filterContext.HttpContext.User.Identity.IsAuthenticated;
var userName = filterContext.HttpContext.User.Identity.Name;
var actionName = filterContext.ActionDescriptior.ActionName;
var controllerName = filterContext.ActionDescriptior.ControllerDescriptor.ControllerName;
if (isAuthenticated && myUserActionPermissionsService.UserCanAccessAction(userName, actionName, contollerName)
{
filterContext.Result = HttpUnauthorizedResult(); // aborts action executing
}
}
}
3.Decorate actions (controllers), that accessible for users granted by admin:
MySpecialController: Controller
{
[UserPermissionRequired]
Action1()
{
//...
}
[UserPermissionRequired]
Action2()
{
//...
}
Action3()
{
//...
}
}
I don't recommend to use base controller for that aim, because attribute usage is more flexible (you have control on action/controller level instead of only controller level), it is better way to implement separated responsibility. Base controller and filter attribute usage correlated as polymorphism and switch operator.
You're asking a very broad question, and it would take some time to review all your requirements. In any case, you could start by adding a user property to a controller from which all other controllers inherit. Then, you could interrogate that user instance to determine whether they have access to the current route. This solution should give you the foundation you need to add some administrative views for your business requirements.
public class MegaController
{
protected User CurrentUser { get; set; }
protected override void Initialize(RequestContext context)
{
if (requestContext.HttpContext.User.Identity.IsAuthenticated)
{
var userRepository = new UserRepository();
CurrentUser = userRepository.GetUser(
requestContext.HttpContext.User.Identity.Name);
}
}
}
The User and UserRepository types can be your own design. You could use LINQ To Entities to wrap a table named "User" and then within your controllers, you could have access to any fields in that table.
Then, subclass all controllers from MegaController
public class AdminController : MegaController
{
public ActionResult Action1()
{
return View();
}
}
public class SomeOtherController : MegaController
{
public ActionResult Action1()
{
return View();
}
}
Now, this doesn't completely solve your "admin" issue. To do so, you could include logic in MegaController.Initialize() to interrogate the request information. Once you have the requested route and user in context, your code could make a decision whether to allow the request, redirect it, etc.
protected override void Initialize(RequestContext context)
{
// ...
if(context.HttpContext != null)
{
if(context.HttpContext.Request.Path == "some/restricted/route"
&& CurrentUser.Role != "Admin")
{
// or similar error page
var url = Url.Action("UnAuthorized", "Error");
context.HttpContext.Response.Redirect(url);
}
}
}
One caveat with this method is that any new controllers added to your application would have to inherit from MegaController, an architecture that could be easily missed by future developers on the project.
Read about plain old forms authentication to add support for roles and user management.
Then use the [Authorize(Roles="RoleName1")] on controllers or actions to control access.
Check MvcMembership, also available on Nuget. You will have all the basics for User Management in an ASP.NET MVC 3 site.
You will need a user / role provider. Read this tutorial to learn how to setup a database that will hold your users and roles. Once it is setup, you will have all the stored procedures needed for first setup / manual testing created.
title pretty much says it all.
I have a website which will only run behind a login so I want to ensure that nothing can be accessed unless you're logged in. This includes ActionResults, JsonResults etc...
Currently, I have [Authorize] all over my controllers which is quite tedious and not very DRY :)
So can I protect the entire website with 1 magic line of code? (The login page will obviously need to be accessible)
Also, please note that I will still need to further protect some of the Actions to only be used by certain Users/Roles
If you have multiple controllers, then make a AuthorizeController from which you inherit your controllers that must be protected. Just set the [Authorize] attribute to the AuthorizeController:
[Authorize]
public class AuthorizeController: Controller
{
}
public class HomeController : AuthorizeController
{
...
}
// don't inherit AccountController from AuthorizeController
public class AccountController : Controller
{
public ActionResult Login()
{
...
}
}
If you are trying to secure an entire website, you could use a global filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
}
}
See here for more information http://visualstudiomagazine.com/blogs/tool-tracker/2013/06/authenticating-users-in-aspnet-mvc-4.aspx
Nevermind! I think I found it!
Placing [Authorize] above the Controller class seems to protect all actions, and is further customisable on a per-action basis. YES!
[Authorize]
public class SomeController : Controller
{
// All logged in users
public ActionResult Index()
{
...
}
[Authorize(Roles="Admin")] // Only Admins
public ActionResult Details()
{
...
}
}
I made a new action filter (attribute, similar to [Authorize]) which authorizes access to a controller action based on a session value. However, I'm basically decorating all my controller actions with that attribute (with the exception of very few).
So, I thought it would be better to have that Action Filter always executed except in cases where I attach an [ExemptFromAuthorize] attribute to a controller action? (Maybe via inheriting to my own Controller class?)
How can I do this?
Running with jeef3's answer, I came up with this. It could use more error checking and robustness like multiple delimited actions, but the general idea works.
In your specific case, you could test for the session value and decide to return out of the authorization also.
public class AuthorizeWithExemptionsAttribute : AuthorizeAttribute
{
public string Exemption { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.RouteData.GetRequiredString("action") == Exemption)
return;
base.OnAuthorization(filterContext);
}
}
Usage:
[AuthorizeWithExemptions(Roles="admin", ExemptAction="Index")]
public class AdminController : Controller
...
Check out my article on codeproject -
http://www.codeproject.com/KB/web-security/AuthorizeWithExemptions.aspx
In this article, I'll provide you with a solution for securing ASP.NET MVC application's controllers in a way that all the actions are secured except those you define as unsecure.
snipper from the code:
public override void OnAuthorization(AuthorizationContext filterContext)
{
ActionDescriptor action = filterContext.ActionDescriptor;
bool IsUnsecured = action.GetCustomAttributes(
typeof(UnsecuredActionAttribute), true).Count() > 0;
//If doesn't have UnsecuredActionAttribute - then do the authorization
filterContext.HttpContext.SkipAuthorization = IsUnsecured;
base.OnAuthorization(filterContext);
}
I understand the question is pretty outdated but anyway.. If you wish to apply filter to all actions just add following lines into Global.asax:
protected void Application_Start()
{
// your code here and then
RegisterGlobalFilters(GlobalFilters.Filters);
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyActionFilterAttribute());
}
And in action filter you can just check if action has any other attributes in following way:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.ActionDescriptor.IsDefined(typeof(AnotherActionAttribute), false))
{
// do what you want to do
}
}
Maybe try and add an Except property to your first attribute?
[MyAuthenticate(Exempt="View")]
public class MyController : Controller
{
public ActionResult Edit()
{
// Protected
}
public ActionResult View()
{
// Accessible by all
}
}
You can add the attribute to the class to have it apply to all methods in that class
[Authenticate]
public class AccountController : Controller
{
public ActionResult Index()
{
return View();
}
}
I don't know how to exclude a specific method from a class-level attribute. Maybe use a separate controller for unauthenticated requests?
For anyone reading this in 2013+, MVC4 now supports the use of
[AllowAnonymous]
You can put Authorize on the controller, and then Allow Anonymous on
any functions you do not want to authorize.
Example:
[Authorize]
public class HomeController : Controller {
[AllowAnonymous]
public ActionResult Index()
{
}
}
Would this work with a custom [MyAuthorize] filter or does it only work with [Authorize]
For anyone reading this in 2013+, MVC4 now supports the use of [AllowAnonymous]
You can put Authorize on the controller, and then Allow Anonymous on any functions you do not want to authorize.
Example:
[Authorize]
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
}
}