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.
Related
I have an ASP.NET Core 2.2 application where I am displaying some documents. Most documents are public, so anonymous access is fine. However, some documents are private (i.e. they require authentication/authorization), and in the future some documents might also require a valid subscription. All documents are retrieved using the same actions, so we only know the required permissions after the documents have been loaded. We also load some resources as static files (IApplicationBuilder.UseStaticFiles), but I guess that shouldn't really be an issue as StaticFileOptions.OnPrepareResponse can be used for custom authorization code.
The logic for who gets access to private documents is currently really simple. And at the moment, we only display documents, we don't allow any other kind of operation on them (editing, deletion etc.). To me, this sounds like a pretty standard case of resource-based authorization.
Anyway, I have found this article and from what I've understood, I need to define a policy (identified by a magic string - what's up with that?!) as well as a requirement and an AuthorizationHandler<MyRequirement, MyResource> which will perform the actual authorization logic. Then, inside my controller action, I will need to call IAuthorizationService.AuthorizeAsync and pass in the user, the resource and the policy name (the magic string) and, based on the result from that method, allow or deny access. That seems more than convoluted for what I'm trying to accomplish. It would probably be easier if I simply defined my own kind of "authorization service" and simply dropped the whole policy and requirement stuff. I also think it's less than ideal that I would have to replicate the if-else logic in all affected controller actions.
Surely I'm not the only one with this issue. Is there something I've missed?
If there are indeed good reasons for using policies and requirements, how would you name them in a case like this? I'm really feeling a little lost.
Maybe it would make sense to use the type of document (public, private, subscribers-only) as the policy name?
In the end, we didn't want to deal with this stuff and just wrote our own AuthorizationService, which is injected into the controller like any other service.
It loads the required permissions for all documents the first time it is used and caches them.
Our controller methods then look something like this:
[HttpGet("[action]")]
public async Task<Document> GetDocument(string documentId)
{
if (_authorizationService.MayAccess(User, documentId))
{
return _documentRepository.GetDocument(documentId);
}
else
{
Response.StatusCode = StatusCodes.Status403Forbidden;
return null;
}
}
I recommend the last approach explained in this article - https://www.red-gate.com/simple-talk/dotnet/c-programming/policy-based-authorization-in-asp-net-core-a-deep-dive/
Allows you to keep you controller clean, by just applying annotation with the name of the policy. In the handler you must implement the logic checking if person can access the resource - it can be based for example on checking a property ownerId in a resource(for example in database table column) or a member of a certain group in AD, or anything else.
EDIT:
Using Requirements and RequirementsHandlers - I have done something similiar.
I don't know how should your logic exactly work, so I am just going to assume some.
lets say you have a get endpoint: documents/documentId
You want to apply logic which will make this document accessible only to the document owner. Obviously, you need somewhere to store who is the owner of the document, so lets keep that in property of a document entity.
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IsDocumentOwner requirement, DocumentRepository documentRepository)
{
if (context.Resource is AuthorizationFilterContext ctx)
{
var documentId = ctx.RouteData.Values["documentId"]?.ToString();
//here load document from repo and check if the property ownerId is equal to current user id
var userId = context.User.Claims.FirstOrDefault(x => x.ToString().Contains(oid))?.Value;
//if yes, make the request pass to the body of a controller with the attribute
context.Succeed(requirement);
}
}
implement IsDocumentOwner:
public class IsDocumentOwner : IAuthorizationRequirement
{
}
in your Startup.cs add:
services.AddAuthorization(options =>
{
options.AddPolicy(
nameof(IsDocumentOwner),
policyBuilder => policyBuilder.AddRequirements(
new IsDocumentOwner()));
});
then, last step, apply attribute on your controller method
[Authorize(Policy = "IsDocumentOwner")]
[HttpGet("{documentId}")]
public YourDocumentObjectResultClass GetDocument([FromRoute]string documentId)
{
//stuff you do when current user is owner of the document, probably just display the doc
}
To your IsDocumentOwner handler you can inject any service by constructor(visualised by repository above), for example, to check if the user is a member of a group on azure ad
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.
I am using basic authentication mechanism in my Dropwizard application, where I am capturing logged in user details, something like this:
#POST
#Timed
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/pdf")
#Path("/")
#RolesAllowed("user,admin")
public Response function(#Auth User user) throws Exception {
//some logic around here
}
Now for auditing purposes, I want this user information to be passed at each layer of my application, I mean in services, DAOs, ExceptionMappers etc and I don't want to pass it as function parameter everywhere as it looks clumsy and also has maintainability overhead. so my question is, is there any way by which we can set some global configuration per REST call or user session and can fetch it anywhere I want?
I have been a Ruby user and in that we were able to do something like this:
Thread.current[:user] = user
which which accessible throughout per user session.
One way to achieve this is by using ThreadLocal of Java wherein you can set the User object and it will be available to that particular executor thread.
Add the following to your resource class.
private static ThreadLocal<User> localUser = new InheritableThreadLocal<>();
public static ShortenerServiceUser getUser() {
return localUser.get();
}
Whennever your function() method is invoked, you just need to set the User object into the ThreadLocal variable.
localUser.set(user);
Now, whenever you need to access the User object from the current thread context, all you need to do is as follows
User localUser = YourResource.getUser();
You can clear the User object from the context by using the ThreadLocal.remove() method.
I am using Identity Server 4 to secure an mvc app and all peripheral APIs. During principal creation I'm using the claims transformation middleware, in which I'd like to make a call to a secured API for additional information.
The claims transformation middleware is wired up in the Configure method like so:
app.UseClaimsTransformation(o => new ClaimsTransformer().TransformAsync(o));
And the ClaimsTransformer class looks like:
public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
// meat and potatoes goes here...
return context.Principal;
}
I've tried getting the access token from the ClaimsTransformationContext with the following code within TransformAsync, however this seems to result in an infinite loop back to the TransformAsync method on the ClaimsTransformer class.
var accessToken = context.Context.Authentication.GetTokenAsync("access_token");
Is it possible to retrieve the access token during the .net core claims transformation?
Or is this specific API call something htat shouldn't be done on behalf of the user and better handled one step up and suited for a more server to server approach (client credentials grant)?
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.