Verify Antiforgery Token Inside Function - asp.net-core

I'm using .netcore 3.0, currently i have an API that will accept external (without Antiforgery token) and internal (with Antiforgery token) call, in this case i will need to add [IgnoreAntiforgeryToken] on the api method and base on the request to determine whether to check the antiforgery token.
Would like to know is there anyway to validate the antiforgery token inside the api function? Thanks in advance.

As far as I know, if you want to call the Antiforgery class to validate the antiforgery token, you could directly call the IAntiforgery service in your api and then use ValidateRequestAsync to validate the token.
More details, you could refer to below codes:
1.Add services.AddHttpContextAccessor(); in the startup.cs ConfigureServices method
2.Add below codes in your controller:
public class HomeController : Controller
{
private readonly IAntiforgery _antiforgery;
private readonly IHttpContextAccessor _httpcontextaccessor;
public HomeController(IAntiforgery defaultAntiforgery, IHttpContextAccessor httpcontextaccessor)
{
_antiforgery = defaultAntiforgery;
_httpcontextaccessor = httpcontextaccessor;
}
public async Task<IActionResult> PrivacyAsync()
{
try
{
await _antiforgery.ValidateRequestAsync(_httpcontextaccessor.HttpContext);
}
catch (Exception)
{
throw;
}
return View();
}
}

I use the similar method as #Brando Zhang
var _antiforgery=(IAntiforgery)this.HttpContext.RequestServices.GetService(typeof(IAntiforgery));
var IsValid = _antiforgery.IsRequestValidAsync(this.HttpContext).Result;
return IsValid;

Related

Accessing JWT claims in ASP.NET Core Web API

My app consists of a Blazor WebAssembly SPA and an ASP.NET Core Web API. For the API I also use the repository pattern. Here's how UsersController.cs looks like:
namespace MyApp.Controllers
{
[Authorize]
[Route("[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
private IUserRepository userRepository;
public UsersController(IUserRepository userRepository)
{
this.userRepository = userRepository;
}
[HttpGet]
public async Task<IActionResult> GetUsers([FromBody] SearchSortFilter Options)
{
try
{
var users = await userRepository.GetUsers(Options);
return Ok(users);
}
catch (Exception ex)
{
return StatusCode(500, ex.Message);
}
}
}
}
While authentication and authorization with Azure AD B2C work very well, I need to access claims data from the JWT token as in the request header.
What is the best way I can do this? Do I just use Request.Authorization, then slice the string to leave out the Bearer part, before using JwtSecurityTokenHandler() to decode into claims?
I was wondering if there was anything like User.Indentity.Name that would allow me to access claims in an opinionated way rather than having to manually do string slicing and decode it.

Resource based authorization in SignalR

I have web API with custom policies and authorization handlers.
I wanted to reuse authorization handlers but HttpContext is null when attribute is used on signalr's hub.
For example this is my controller.
[Authorize]
public sealed class ChatsController : ControllerBase
{
[HttpPost("{chatId}/messages/send")]
[Authorize(Policy = PolicyNames.ChatParticipant)]
public Task SendMessage() => Task.CompletedTask;
}
And this my my authorization handler. I can extract "chatId" from HttpContext and then use my custom logic to authorize user.
internal sealed class ChatParticipantRequirementHandler : AuthorizationHandler<ChatParticipantRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ChatParticipantRequirementHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ChatParticipantRequirement requirement)
{
if(_httpContextAccessor.HttpContext != null)
{
// Logic
}
return Task.CompletedTask;
}
}
However this won't work with Azure SignalR because I don't have access to HttpContext. I know that I can provide custom IUserIdProvider but I have no idea how to access "chatId" from "Join" method in my custom authorization handler.
[Authorize]
public sealed class ChatHub : Hub<IChatClient>
{
[Authorize(Policy = PolicyNames.ChatParticipant)]
public async Task Join(Guid chatId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, chatId.ToString());
}
Is it possible to reuse my authorization handlers?
I would like to avoid copypasting my code.
One solution is to extract my authorization code to separate services but then I have to manually call those from my hubs and abandon [Authorize] way.
Your chat is a resource, and you want to use resource based authorization. In this case declarative authorization with an attribute is not enough, because chat id is known at runtime only. So you have to use imperative authorization with IAuthorizationService.
Now in your hub:
[Authorize]
public sealed class ChatHub : Hub<IChatClient>
{
private readonly IAuthorizationService authService;
public ChatHub(IAuthorizationService authService)
{
this.authService = authService;
}
public async Task Join(Guid chatId)
{
// Get claims principal from authorized hub context
var user = this.Context.User;
// Get chat from DB or wherever you store it, or optionally just pass the ID to the authorization service
var chat = myDb.GetChatById(chatId);
var validationResult = await this.authService.AuthorizeAsync(user, chat, PolicyNames.ChatParticipant);
if (validationResult.Succeeded)
{
await Groups.AddToGroupAsync(Context.ConnectionId, chatId.ToString());
}
}
}
Your authorization handler should look different, because it needs the chat resource in its signature to do this kind of evaluation:
internal sealed class ChatParticipantRequirementHandler : AuthorizationHandler<ChatParticipantRequirement, Chat>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ChatParticipantRequirementHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ChatParticipantRequirement requirement, Chat chat)
{
// You have both user and chat now
var user = context.User;
if (this.IsMyUserAuthorizedToUseThisChat(user, chat))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
return Task.CompletedTask;
}
}
Edit: there is actually another option I didn't know about
You can make use of HubInvocationContext that SignalR Hub provides for authorized methods. This can be automatically injected into your AuthorizationHandler, which should look like this:
public class ChatParticipantRequirementHandler : AuthorizationHandler<ChatParticipantRequirement, HubInvocationContext>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ChatParticipantRequirement requirement, HubInvocationContext hubContext)
{
var chatId = Guid.Parse((string)hubContext.HubMethodArguments[0]);
}
}
Hub method will be decorated normally with [Authorize(Policy = PolicyNames.ChatParticipant)]
You still will have two authorization handlers, AuthorizationHandler<ChatParticipantRequirement> and AuthorizationHandler<ChatParticipantRequirement, HubInvocationContext>, no way around it. As for code dublication, you can however just get the Chat ID in the handler, either from HttpContext or HubInvocationContext, and than pass it to you custom written MyAuthorizer that you could inject into both handlers:
public class MyAuthorizer : IMyAuthorizer
{
public bool CanUserChat(Guid userId, Guid chatId);
}

How to get the access token in a service in .net core?

I have an application and I want to use a hybrid flow to call an API from my MVC web application. The API is secured and requires an access token (JWT). The code part on the API side is done.
But how can I send my access token from my MVC application to the API in a service? I want to use a "generic" service for this that uses an httpclient.
I know that in controllers you can use
var accessToken = await HttpContext.GetTokenAsync("access_token");
or
var accessToken = await HttpContext.GetUserAccessTokenAsync();
But how can I access the access token in a service?
Tried this too, but didn't work
var accessToken = _httpContextAccessor.HttpContext.Request.Headers[HeaderNames.Authorization];
Side question: how can I set the access token for the httpclient in the constructor of my service? (Using async methods is not possible) so I can't use this:
protected HttpClient HttpClient { get; private set; }
public MyGenericHttpClientService(IHttpContextAccessor httpContextAccessor)
{
var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
HttpClient.SetBearerToken(accessToken);
}
If you are using IHttpClientFactory, you can configure your HttpClient as follows by adding a DelegatingHandler in Startup.cs:
services.AddTransient<TokenHandler>();
services.AddHttpClient().AddHttpMessageHandler<TokenHandler>();
And TokenHandler can be as follows:
public class TokenHandler : DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
public TokenHandler(
IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var token = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
return await base.SendAsync(request, cancellationToken);
}
}
For more information on IHttpClientFactory, you can see this article.

How can I get id_token in identity server, before redirecting to client?

After the user successfully signed in and before redirecting him to the client site I want to store the id_token in db. Actually the id_token is available in the client side but I don't know how to get it on the login process of identity server.
I would appreciate any help.
You can create a custom ITokenService by inheriting DefaultTokenService and store Id_token after creation.
public class CustomTokenService : DefaultTokenService
{
public CustomTokenService(
IClaimsService claimsProvider,
IReferenceTokenStore referenceTokenStore,
ITokenCreationService creationService,
IHttpContextAccessor contextAccessor,
ISystemClock clock,
ILogger<DefaultTokenService> logger)
: base(claimsProvider, referenceTokenStore, creationService, contextAccessor, clock, logger)
{
}
public override async Task<string> CreateSecurityTokenAsync(Token token)
{
strign jwt = await base.CreateSecurityTokenAsync(token);
// store token
return jwt;
}
}
And also you need to register CustomTokenService
builder.Services.TryAddTransient<ITokenService, CustomTokenService>();
You can use one of the built-in events : TokenIssuedSuccessEvent :
Modify your Startup.cs :
services.AddIdentityServer(options =>
{
options.Events.RaiseSuccessEvents = true;
});
Create your custom IEventSink :
public Task PersistAsync(Event evt)
{
if (evt.Id.Equals(EventIds.TokenIssuedSuccess))
{
var _test = evt as TokenIssuedSuccessEvent;
var tokens = _test.Tokens.ToList();
}
return Task.CompletedTask;
}
Then you can find id token by checking type of each tokens .
At last register the event in Startup.cs:
services.AddScoped<IEventSink, MyEventSink>();

Custom Authorization Filter in .NET Core API

I want to authorize users before accessing any data using my core api, so I tried is using JWT authentication.
I have successfully generated token while signing in user using api and saved that token on client side in session, now whenever user wants to access any data using api, I'll send that token in header to api and I want to validate that JWT token using custom authorization filter. I have created custom authorization filter and applied it on my GetMenu api and I'm able to validate that token successfully but after token validation in authorization filter it is not hitting it on my GetMenu api.
Here is my AccountController code:
[Filters.Authorization]
[AllowAnonymous]
[HttpPost]
[Route("GetMenu")]
public IActionResult GetMenu(string clientid, int rolecode, string repcode)
{
//further process
}
Here is my Filters.Authorization code:
public class Authorization: AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (!ValidateToken(filterContext.HttpContext.Request.Headers["token"]))
{
filterContext.Result = new UnauthorizedResult();
}
}
}
I have breakpoints on OnAuthorization method and on GetMenu api.
I'm calling my GetMenu api through postman to test, it is successfully hitting it on OnAuthorization method in Filters.Authorization and validating my JWT Token and displays Status Code: 200 in postman but after successful token validation it should hit on GetMenu api for further data processing but it is not hitting.
What can be the issue? what am i missing? please help.
You should not set the filterContext.Result if the request is successfully authorize.
//
// Summary:
// A context for authorization filters i.e. Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter
// and Microsoft.AspNetCore.Mvc.Filters.IAsyncAuthorizationFilter implementations.
public class AuthorizationFilterContext : FilterContext
{
//
// Summary:
// Gets or sets the result of the request. Setting Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result
// to a non-null value inside an authorization filter will short-circuit the remainder
// of the filter pipeline.
public virtual IActionResult Result { get; set; }
}
You only need to set Result when it's failed.
public class Authorization: AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (!ValidateToken(filterContext.HttpContext.Request.Headers["token"]))
{
filterContext.Result = new UnauthorizedResult();
}
}
}