WebApi Restricting Access via config file - asp.net-web-api2

With WebAPI, you can restrict access by user-name with the overload Authorize attribute
// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
Is there a way to set these in the web.config file?
(Matching to Controller(class) or individual Methods on a Controller)
I've looked and looked...and the searches are too ambiguous. (too many results or not many).

Related

access ResourceInfo in Quarkus / Vertx HttpAuthenticationMechanism

In Quarkus (resteasy reactive), is there a way to get hold of the "ResourceInfo" in an HTTP Authentication Mechanism?
What I'm trying to do is read an annotation that is defined on the resource class or method, in order to choose an authentication mechanism based on it.
Injecting the ResourceInfo directly in the mechanism class does not work (and also, it is application scoped and not request scoped, so not sure it could work). I also couldn't find the info I need in the RoutingContext parameter.
I have also tried adding a ContainerRequestFilter, in which injecting the ResourceInfo with #Context works well, but I think perhaps the filters are called after the httpAuthenticationMechanism.authenticate(), because it's not called in my test when the endpoint requires authentication.
Is there another way to do this?
----> To clarify with code what I would like to do:
have different JAX-RS resources with a custom #Authorization annotations with different "api names" like this:
#Path("/jwttest")
#ApplicationScoped
#Authorization("jwttest")
public class JWTTestController {
...
}
#Path("/oidctest")
#ApplicationScoped
#Authorization("myoidc")
public class OIDCTestController {
...
}
and then different configs like this:
myframework.auth.jwttest.type=jwt
myframework.auth.jwttest.issuer=123
myframework.auth.jwttest.audience=456
myframework.auth.myoidc.type=oidc
myframework.auth.myoidc.auth-server-url=myurl
And in the HttpAuthenticationMechanism, find the value of #Authorization, and based on it, call another provider like suggested in https://quarkus.io/guides/security-customization#dealing-with-more-than-one-httpauthenticationmechanism with the right api name so that it can load the config.

How to override "OnActionExecuting" defined in the Startup class inside a controller?

This code run for every incoming request to check whether it contains a valid JWT token.
services.AddMvc(options =>
options.Filters.Add(typeof(JwtAttribute)));
That's what I want in most case, except for the first time (when the user is attempting to log in). Because it's running at every request, user can't log in.
I've tried to add an attribute on top of the login action, but it's still not working.
[HttpPost]
[AllowAnonymous]
public async Task<JsonResult> Login([FromBody]Credentials formData)
{
}
What should I do to override the OnActionExecuting in the startup class just in this one case, so that user can log in.
Thanks for helping
By using a custom filter, instead of the built-in authentication and authorization system, you will not be able to use [AllowAnonymous] here since that is directly linked to the auth framework.
What you can do is add additional metadata which you then check as part of your JwtAttribute filter. For example, create another attribute like so:
public class DisableJwtAttribute : Attribute, IFilterMetadata
{ }
You can now add this attribute to your controller action with [DisableJwt].
And inside of your JwtAttribute filter, you can now check for that filter’s existence to stop processing the request. E.g. if your filter is an authorization filter, that would look like this:
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context.Filters.Any(item => item is DisableJwtAttribute))
return;
// filter is active
}
That being said, the better solution would be to embrace the authentication system and have your JWT validation be part of the normal authentication process. That way, you could actually benefit from all the authentication and authorization things within ASP.NET Core.

.Net core Authorize attribute in inherited controller

I am having some trouble with Authorization policies. I have a baseWebApiController with an action
[HttpDelete("{id}"), Authorize(Policy = "Administrator")]
public virtual async Task<IActionResult> Delete(int id) {}
But in a certain controller which inherits from the above I want to give access to users also, with a policy like:
[HttpDelete("{id}"), Authorize(Policy = "All")]
public override Task<IActionResult> Delete(int id){}
It seems regular users cannot access this action. Do I have to search further for errors in my policy configuration, or since the controller is inherited,m it's attributes are neglected?
Thanks
The AuthorizeAttribute is an attribute that is inherited and that allows itself to be applied multiple times.
That means when inheriting your method which already has an AuthorizeAttribute, that will be carried over. So the final function definition in your subclass would look like this:
[Authorize(Policy = "Administrator")]
[Authorize(Policy = "All")]
public override Task<IActionResult> Delete(int id)
So the route now has two policies in place. This is kind of a problem because policies are designed to be cumulative. So all policies have to pass in order for the authentication to succeed.
Of course, this will not work for you because you actually wanted to “wash out” the original policy from the base class. This is not possible though, so you would have to remove the policy from the base class and maybe introduce a second administrator-only class for those policies.
The general problem here is that your policy design seems to be based on roles. You are using policies, but effectively, you are checking on roles there. Instead, you should consider working with requirements: For example, to delete something, a user would need to fulfill the “DeletionAllowed” requirement. This allows for a much more fine-grained policy system. And the big benefit? Requirement handlers are disjunctive: So one handler that is able to fulfill the requirement is enough to pass it.

API Endpoints and Structure

I am creating a Web Api with ASP.NET Core and I have the following:
public class MessageApiController : Controller {
[HttpGet("messages/{id}")]
public async Task<IActionResult> GetById() { }
}
public class UserApiController : Controller {
[HttpGet("users/{id}")]
public async Task<IActionResult> GetById() { }
}
Now I need to get all messages for a user. I know two options:
[HttpGet("messages")]
public async Task<IActionResult> GetMessagesByUser(Int32 userId) { }
Or
[HttpGet("users/{userId}/messages")]
public async Task<IActionResult> GetMessagesByUser(Int32 userId) { }
I have a few questions:
Which is more common? I think I could even use both ...
When using "users/{userId}/messages" would you place this action in MessageApiController or UserApiController?
It depends on how you want your consumers to use the service.
The question you need to ask yourself, does it make sense to call /messages to obtain all messages (from all users) or should it only be ever possible to obtain messages from 1 user (and exclude the possibility to ever obtain messages from all users).
This question is important, because it will tell you which one to use or if you should use both.
When there is no plans to ever allow users to obtain message from all users, you better go with users/{userId}/messages because this will enforce this rules. In this case users/{userId}/messages is a resource of messages for user userId.
On other side, the expectation is that messages will allow you to query all users messages or at least the ones the user has permission too (i.e. an administrative user would get all users messages back on this endpoint) and you could filter this via query parameters (rather than encoding in the path). If you do not want this, then messages will be an invalid route or just misleading.
Which is more common? I think I could even use both ...
users/{userId}/messages is more expressive and from the url it's clear, that you want all messages from a given user.
messages can be used, if you also have a permission system to allow certain users see messages from other users (i.e. a companies worker should be able to see all messages of the company, not just the ones sent directly to him) with query filters to reduce this (by single or multiple users).
When using "users/{userId}/messages" would you place this action in MessageApiController or UserApiController?
To MessageApiController, because it's operating on the message, not on the user. The user is just a mandatory parameter.
On a side note:
You can simplify your controller routings by putting a route on the controller type rather than having the route template completely on the action.
[Route("[controller]")]
public class MessageController : Controller
{
[HttpGet("id}")]
public async Task<IActionResult> GetById()
{
}
}
Notice that I removed the "Api" from controller name, because the [controller] placeholder takes the class name minus "Controller" as route parameter. The Route on MessageController acts as prefix, so GetById() still gets message/{id} as a route, but you don't have to repeat the "message" part on each action.

Windows authentication and Asp.Net Web API

I have an Intranet application with Windows authentication based on MVC4.
When I need the WindowsIdentity for authorization purpose in a Controller I just use
HttpContext.User.Identity
Now I wanted to use the new Asp.Net WebAPI for some Ajax calls.
Is there a way to get the WindowsIdenty object in the same easy way as in an MVC Controller?
Please don't reference the HttpContext from a controller.
You can access the Controllers User property which is way of accessing the Identity through without a dirrect reference to HttpContext.
public class MyController : ApiController
{
public string Get()
{
var indenty = this.User.Identity;
}
}
Why
The controllers User property provides a level of abstraction which allows for easier mocking and thus unit testing. This abstraction also allows for greater portability e.g. if this was WebApi Self Host you wouldn't even have access to HttpContext.
To read more about how to unit test and mock the User property read here. For more information re: portability read here.