IAuthenticationFilter equivalent in MVC6 - asp.net-web-api2

I'm moving a Web Api 2 project to MVC 6, since Microsoft is merging the two APIs in ASP.NET 5. In my WebApi project I had a custom Attribute Filter class that would authenticate, authorize and prevent transaction replays using a combination of public key, private key and HMAC authentication (basically, doing this with some tweaks to fit into my project).
Now in MVC6, as far as I understand I must stop using anything in the Microsoft.Web.Http namespace and instead use Microsoft.AspNet.Mvc. So I have done that, but the Microsoft.AspNet.Mvc.Filters doesn't seem to have any equivalent of Web Api 2's IAuthenticationFilter.
This is a problem for me because my customer AuthenticationFilter implemented all of IAuthenticationFilter, with all the logic in there. More importantly, it was using the Context to temporarily store the public key of the account, so my controller could access it to load up the account in turn.
So my question is, what is the proper way to filter requests in MVC6, using an Authentication Filter-like class to intercept the requests and return the appropriate status codes? I can't find any article that goes specifically in these details (they all tend to cover MVC5).

I know it's an older question, but hopefully someone (maybe even yourself) might find value in the answer.
MVC6 does in fact have an alternative. You have an
public abstract class AuthorizationFilterAttribute :
Attribute, IAsyncAuthorizationFilter, IAuthorizationFilter, IOrderedFilter
which basically tells you, that you can create your custom class, derive it from this (namespace of all of these interfaces, btw, is Microsoft.AspNet.Mvc.Filters and that should be it. You can either decorate the action with it, or you can do this in Startup.cs, to apply to all actions:
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc(options =>
{
// add an instance of the filter, like we used to do it
options.Filters.Add(new MySpecialFilter());
});
services.AddTransient<LogFilter>();
}
If you want to use a bit more logic in the filter (e.g. my LogFilter above) which is instantiated through DI, you need to use either Service Filters or Type Filters.
You can now decorate the actions with [ServiceFilter(typeof(LogFilter))] or use o.Filters.Add(new ServiceFilterAttribute(typeof(LogFilter))); in the Startup.cs file. But keep in mind, to do this you need to register the type with the DI container, like I did above with the .AddTransient<>() call.

IAuthenticationFilter is no more and IAuthorizationFilter simply does not replace it in MVC 6
Reason: authentication is NOT EQUAL to authorization.
Therefore IMO the authentication filter should stay available!

Related

ASP.NET Core Custom Authorization

I need to implement role based authorization on a .NET 5 API but the thing is that we don't want to decorate all the controllers with attributes and a list of roles, because all that configuration will come from either a config file (JSON) or an external service (TBD), in a way that roles will be mapped to controllers and actions and we would want to have something that centralizes all this logic, in a similar way we did before with Authentication Filters and Attributes.
I've been reading that now the idea from MS is that everything is handled with policies and requirements, but I don't know how to fit all that into our desired schema. Most of all because I don't see (or can't see) how can I access the Controller and Action's descriptors to know where I'm standing when I perform the authorization process.
Is there any way to achieve this on this new model?
EDIT: I found a way to get controller and action descriptors in order to do part of what I intended. Based on some other questions and articles I read and some tinkering on my own, I got the following:
public class AuthorizationFilter : IAsyncAuthorizationFilter
{
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var descriptor = (ControllerActionDescriptor)context.ActionDescriptor; //<<-- this is the key casting :)
var ctrlName = descriptor.ControllerName;
var actionName = descriptor.ActionName;
var userPrincipal = context.HttpContext.User;
//DO STUFF AND DECIDE RESULT TYPE BASED ON USER CLAIMS AND CURRENT CONTROLLER AND ACTION
context.Result = new ForbidResult();
context.Result = new UnauthorizedResult();
return Task.CompletedTask;
}
}
Then I could add this filter the following way:
services.AddControllers(x => x.Filters.Add<AuthorizationFilter>());
This way I could achieve something similar as before with ASP.NET MVC 4/5, but from what I can read, the .NET Core team tried to go away from this path by implementing the IAuthorizationRequirement and AuthorizationHandler<T> mechanism to replace all that, so my doubt remains: is this the correct way to do it in the new .NET Core 3.x / .NET 5 architecture? Or is there some other way I'm overlooking on how to get and process the controller/action being executed and pass it along to an AuthorizationHandler?
What you are looking for is called externalized authorization also referred to as attribute-based access control. In this model:
authorization logic is decoupled from the application
authorization logic is expressed as policies that build on top of attributes
attributes are key-value pairs that describe the subject, the action, the resource, and the context of what's going on (A user wants to execute an action on an object at a given time and place)
authorization is decided based on those policies in a logical central point (logical because you could very well have multiple instances of that central point colocated with your app for performance reasons). That logical central point in abac is known as the Policy Decision Point (PDP)
authorization is enforced based on the response back from the PDP in the place where you want to enforce it. This could be at a method level or at an API level or even a UI level: you choose. The component in charge of enforcing the decision is called a Policy Enforcement Point (PEP).
There's one main standard out there called xacml and its developer-friendly notation called alfa that will let you implement attribute-based access control. It's worth noting this model and approach is applicable to any app (not .NET-specific at all).

In AspNetCore, what is this currently called and can I encapsulate it?

I'm currently making a library that interacts with a particular API that requires an oAuth OIDC connection/token and I'd like to make something that makes that particular part easier for users of this library so they don't need all this custom code.
What is this currently called and is there an example of code?
I ask because from trying to get this work, the documentation is ALL OVER THE PLACE. It looks like this particular process has undergone significant changes multiple times as things went on from before netcore to netcore2 and now netcore31.
Both AddAuthentication and AddOpenIdConnect are extension methods.
An extension method allows you to "add" methods to a type without having to modify the type directly - the methods aren't actually added to the type, but we can call them as if they had been. This is useful in situations where you'd like to extend the behaviour of a class created by a third party but don't have access to the source code.
As for what the particular pattern in question is, whilst there is no canonical name, it's merely a way of encapsulating the configuration of services and dependencies for your application.
AddAuthentication is an extension method of IServiceCollection, which is services type. AddAuthentication has a return type of AuthenticationBuilder, and AddOpenIdConnect is an extension method for AuthenticationBuilder. This is the implementation of AddOpenIdConnect, but as you're looking to encapsulate the configuration, you could probably do something like this:
public static class OpenIdConnectExtensions
{
public static AuthenticationBuilder ConfigureOpendIdConnect(
this AuthenticationBuilder builder)
{
return builder.AddOpenIdConnect(options =>
{
options.SignInScheme = IdentityConstants.ExternalScheme;
// Do whatever else you need.
});
}
}
And call it as follows:
services
.AddAuthentication()
.ConfigureOpendIdConnect()
Middleware, on the other hand, is code that executes as part of a pipeline in order to process requests and responses. The middleware sits in the middle of receiving requests and sending responses, hence the name. This allows you do things such as always adding certain headers to responses without that logic being split across your application. As you correctly mentioned, you see these being applied via calls such as app.UseXyz().

Autofac Multitenant Database Configuration

I have a base abstract context which has a couple hundred shared objects, and then 2 "implementation" contexts which both inherit from the base and are designed to be used by different tenants in a .net core application. A tenant object is injected into the constructor for OnConfiguring to pick up which connection string to use.
public abstract class BaseContext : DbContext
{
protected readonly AppTenant Tenant;
protected BaseContext (AppTenant tenant)
{
Tenant = tenant;
}
}
public TenantOneContext : BaseContext
{
public TenantOneContext(AppTenant tenant)
: base(tenant)
{
}
}
In startup.cs, I register the DbContexts like this:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
Then using the autofac container and th Multitenant package, I register tenant specific contexts like this:
IContainer container = builder.Build();
MultitenantContainer mtc = new MultitenantContainer(container.Resolve<ITenantIdentificationStrategy>(), container);
mtc.ConfigureTenant("1", config =>
{
config.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
});
mtc.ConfigureTenant("2", config =>
{
config.RegisterType<TenantTwoContext>().AsSelf().As<BaseContext>();
});
Startup.ApplicationContainer = mtc;
return new AutofacServiceProvider(mtc);
My service layers are designed around the BaseContext being injected for reuse where possible, and then services which require specific functionality use the TenantContexts.
public BusinessService
{
private readonly BaseContext _baseContext;
public BusinessService(BaseContext context)
{
_baseContext = context;
}
}
In the above service at runtime, I get an exception "No constructors on type 'BaseContext' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'". I'm not sure why this is broken....the AppTenant is definitely created as I can inject it other places successfully. I can make it work if I add an extra registration:
builder.RegisterType<TenantOneContext>().AsSelf().As<BaseContext>();
I don't understand why the above registration is required for the tenant container registrations to work. This seems broken to me; in structuremap (Saaskit) I was able to do this without adding an extra registration, and I assumed using the built in AddDbContext registrations would take care of creating a default registration for the containers to overwrite. Am I missing something here or is this possibly a bug in the multitenat functionality of autofac?
UPDATE:
Here is fully runable repo of the question: https://github.com/danjohnso/testapp
Why is line 66 of Startup.cs needed if I have lines 53/54 and lines 82-90?
As I expected your problem has nothing to do with multitenancy as such. You've implemented it almost entirely correctly, and you're right, you do not need that additional registration, and, btw, these two (below) too because you register them in tenant's scopes a bit later:
services.AddDbContext<TenantOneContext>();
services.AddDbContext<TenantTwoContext>();
So, you've made only one very small but very important mistake in TenantIdentitifcationStrategy implementation. Let's walk through how you create container - this is mainly for other people who may run into this problem as well. I'll mention only relevant parts.
First, TenantIdentitifcationStrategy gets registered in a container along with other stuff. Since there's no explicit specification of lifetime scope it is registered as InstancePerDependency() by default - but that does not really matter as you'll see. Next, "standard" IContainer gets created by autofac's buider.Build(). Next step in this process is to create MultitenantContainer, which takes an instance of ITenantIdentitifcationStrategy. This means that MultitenantContainer and its captive dependency - ITenantIdentitifcationStrategy - will be singletons regardless of how ITenantIdentitifcationStrategy is registered in container. In your case it gets resolved from that standard "root" container in order to manage its dependencies - well, this is what autofac is for anyways. Everything is fine with this approach in general, but this is where your problem actually begins. When autofac resolves this instance it does exactly what it is expected to do - injects all the dependencies into TenantIdentitifcationStrategy's constructor including IHttpContextAccessor. So, right there in the constructor you grab an instance of IHttpContext from that context accessor and store it for using in tenant resolution process - and this is a fatal mistake: there's no http request at this time, and since TenantIdentitifcationStrategy is a singleton it means that there will not ever be one for it! So, it gets null request context for the whole application lifespan. This effectively means that TenantIdentitifcationStrategy will not be able to resolve tenant identifier based on http requests - because it does not actually analyze them. Consequently, MultitenantContainer will not be able to resolve any tenant-specific services.
Now when the problem is clear, its solution is obvious and trivial - just move fetching of request context context = _httpContextAccessor.HttpContext to TryIdentifyTenant() method. It gets called in the proper context and will be able to access request context and analyze it.
PS. This digging has been highly educational for me since I had absolutely no idea about autofac's multi-tenant concept, so thank you very much for such an interesting question! :)
PPS. And one more thing: this question is just a perfect example of how important well prepared example is. You provided very good example. Without it no one would be able to figure out what the problem is since the most important part of it was not presented in the question - and sometimes you just don't know where this part actually is...

Accessing HTTP Headers in ASP.Net Core Business Logic

I am using ASP.Net core and I have a requirement to access a specific HTTP Header in a business logic class (not a controller or action).
To provide a full picture of the configuration here, I have a custom ASP.Net Core Middleware which based on some logic will add a value into a custom HTTP Header, it is the value from this header that I need to access in the business logic class.
Currently the way that I achieve this is to inject an HttpContextAccessor, using the following DI registration.
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
In the class which requires access to the HTTP Headers I then request an IHttpContextAccessor using constructor injection and use this to access the relevant HTTP Header.
Doing the above works fine and gives me the results that I require, looking around various articles on the Internet however the general consensus appears to be to avoid using HttpContext.Current in ASP.Net Core.
If the above is the case, is there a better way for my business logic class to access the value that my custom middleware is inserting into a custom HTTP Header?
I should be clear, whilst at present the middleware is storing the required value in a HTTP Header for use by the business logic class, I am open to other methods of the middleware making the required value available to the business logic class if there is a better approach.
Any questions or clarifications, please let me know.
There is no HttpContext.Current in ASP.Net Core, so it's easy to avoid using it. You would have to implement your own extension method if you wanted it, but the general feeling in the .Net Core community is that it's much better to use IHttpContextAccessor.
In earlier versions of .Net Core an implementation of IHttpContextAccessor was auto registered in the DI container. In more current version you have to register it yourself with the line of code you mentioned:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Injecting IHttpContext into your method that needs access to the headers is a workable approach. Or if you like you could use a helper method that places a copy of the headers in a simpler structure and then pass that object in to your class since it doesn't really need access to the full HttpContext.

Searching with WebAPI

I have made a web API class for my Customer model. I have the standard methods (GET, POST, PUT, DELETE). The problem is, I want to implement another GET method which is a search. Something like this:
[HttpGet]
public IEnumerable<Customer> Search(string id)
{
var customers = customerRepository.Search(id);
return customers;
}
The search method performs a search based on the account number of my customers, using the .Contains() method.
The problem is, when I navigate to: mySite.com/api/Customers/Search/123 I get a 404. What am I doing wrong here?
While Darin's answers are always of top quality this question would actually benefit from an answer that explains how searching, paging and filtering should actually be done in any API and how it should be done using the most current version of Web API (v2).
This is a post which I consider a good resource on the matter (technology indenpendent):
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
The answer should also reflect what's new in ASP.NET Web API v2 because Darin's answer is quite old.
Since this question comes up at the top when doing Google search for "asp.net web api searching" I will try to explain few things here.
To get as close as possible to REST principles with the latest version of ASP.NET Web API (v2) one should take a serious look at attribute routing that was introduced in the latest version. It is very hard to achieve RESTful routing with the old, classic, convention based routing (in global.asax.cs or RouteConfig.cs).
You should read more about that here
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
Now, to go into details how to implement the specifics you ask about.
The most common practice is to expose these types of functionality through query string parameters.
Per REST principles, you should have one endpoint for your Customers resource, for instance
/api/customers
To achieve this you would decorate your GetCustomers() action in your Web API controller like this
[HttpGet]
[Route("/api/customers")]
public HttpResponseMessage GetCustomers(string q="", string sortBy="", string sortDirection="", bool active=true, ...)
{
// q = being optional search query
// sortBy = optional sort by column/property
// sortDirection = optional sort direction
// active = filter on 'active' column/property
// ... other filters may be applicable
}
You would implement this action closely to what you did in classic MVC if you wanted to provide filtered Views.
I would only introduce new controllers and custom actions if really needed, for some custom edge cases.
with regards to a comment about SearchFilter strongly typed object, let's explain that this won't work out of the box because the default model binder will not bind to this class when using GET requests.
So I'd either take those properties out of SearchFilter class and put them on the action itself so they'd bind via query string binder or use the [FromBody] binder if you wanted to bind from the request body. As per http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
HTH
As per the default route setup only the standard controller action names are allowed (the RESTful ones and the dispatching is done based on the HTTP verb). If you want to violate the RESTful conventions and use some custom action names then you will have to modify your route setup in order to include the action name in the url: api/{controller}/{action}/{id}. Now you can send a request to /api/Customers/Search/123 which will invoke the Search action on the Customers API controller.