I'm ready to use Asp.Net core, but here's what I am doing. In MVC 5, I have an Http module that is handling the PostAuthenticate event in order to create the claim where I am doing some stuff to determine roles for the user. I see no way to do this same thing in Core. Note that this is using Windows Authentication so there is no login method to handle.
From the current httpModule that hooks up to the PostAuthenticate because I want to initialize some things for the user.
context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
Note that httpModules no longer exist with Core and that is being moved to middleware.. I don't see how to tap into that event from there though.
I just did this for the first time today. Two basic steps here.
First:
Create a class that implements the IClaimsTransformer interface.
public class MyTransformer : IClaimsTransformer
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context )
{
//don't run if user isn't logged in
if(context.Principal.Identity.IsAuthenticated)
{
((ClaimsIdentity)context.Principal.Identity)?.AddClaims(...);
}
}
return Task.FromResult(context.Principal);
}
Second:
Add this line to Startup.cs in
public void Configure(IApplicationBuilder app, ..., ...)
{
//app.Use...Authentication stuff above, for example
app.UseOpenIdConnectAuthentication( new OpenIdOptions
{
//or however you like to do this.
});
app.UseClaimsTransformation(o => new MyTransformer().TransformAsync(o));
//UseMvc below
app.UseMvc(...);
}
Keep in mind that TransformAsync is going to run on every request, so you might want to look into using sessions or caching if you're hitting a database with it.
Windows Authentication is performed by the hosts (IIS or HttpSys/WebListener) at the start of your application pipeline. The first middleware in your pipeline is the equivalent of PostAuthenticateRequest in this case. Operate on HttpContext.User as you see fit.
Related
I am working in Multi-tenant solution primarily there are 2 type of applications
WebAPI
Console app to process message from queue
I have implemented dependency injection to inject all services. I have crated TenantContext class where I am resolving tenant information from HTTP header and it's working fine for API, but console application getting tenant information with every message (tenant info is part of queue message) so I am calling dependency injection register method on every incoming message which is not correct, do you have any suggestion/solution here?
The way I am resolving ITenantContext in API
services.AddScoped<ITenantContext>(serviceProvider =>
{
//Get Tenant from JWT token
if (string.IsNullOrWhiteSpace(tenantId))
{
//1. Get HttpAccessor and processor settings
var httpContextAccessor =
serviceProvider.GetRequiredService<IHttpContextAccessor>();
//2. Get tenant information (temporary code, we will get token from JWT)
tenantId = httpContextAccessor?.HttpContext?.Request.Headers["tenant"]
.FirstOrDefault();
if (string.IsNullOrWhiteSpace(tenantId))
//throw bad request for api
throw new Exception($"Request header tenant is missing");
}
var tenantSettings =
serviceProvider.GetRequiredService<IOptionsMonitor<TenantSettings>>();
return new TenantContext(tenantId, tenantSettings );
});
Create two different ITenantContext implementations. One for your Web API, and one for your Console application.
Your Web API implementation than might look as follows:
public class WebApiTenantContext : ITenantContext
{
private readonly IHttpContextAccessor accessor;
private readonly IOptionsMonitor<TenantSettings> settings;
public WebApiTenantContext(
IHttpContextAccessor accessor,
IOptionsMonitor<TenantSettings> settings)
{
// Notice how the dependencies are not used in this ctor; this is a best
// practice. For more information about this, see Mark's blog:
// https://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/
this.accessor = accessor;
this.settings = settings;
}
// This property searches for the header each time its called. If needed,
// it can be optimized by using some caching, e.g. using Lazy<string>.
public string TenantId =>
this.accessor.HttpContext?.Request.Headers["tenant"].FirstOrDefault()
?? throw new Exception($"Request header tenant is missing");
}
Notice that this implementation might be a bit naive for your purposes, but hopefully you'll get the idea.
This class can be registered in the Composition Root of the Web API project as follows:
services.AddScoped<ITenantContext, WebApiTenantContext>();
Because the WebApiTenantContext has all its dependencies defined in the constructor, you can do a simple mapping between the ITenantContext abstraction and the WebApiTenantContext implementation.
For the Console application, however, you need a very different approach. The WebApiTenantContext, as shown above, is currently stateless. It is able to pull in the required data (i.e. TenantId) from its dependencies. This probably won't work for your Console application. In that case, you will likely need to manually wrap the execution of each message from the queue in a IServiceScope and initialize the ConsoleTenantContext at the beginning of that request. In that case, the ConsoleTenantContext would look merely as follows:
public class ConsoleTenantContext : ITentantContext
{
public string TenantId { get; set; }
}
Somewhere in the Console application's Composition Root, you will have to pull messages from the queue (logic that you likely already have), and that's the point where you do something as follows:
var envelope = PullInFromQueue();
using (var scope = this.serviceProvider.CreateScope())
{
// Initialize the tenant context
var context = scope.ServiceProvider.GetRequiredService<ConsoleTenantContext>();
content.TenantId = envelope.TenantId;
// Forward the call to the message handler
var handler = scope.ServiceProvider.GetRequiredService<IMessageHandler>();
handler.Handle(envelope.Message);
}
The Console application's Composition Root will how have the following registrations:
services.AddScoped<ConsoleTenantContext>();
services.AddScoped<ITenentContext>(
c => c.GetRequiredServices<ConsoleTenantContext>());
With the registrations above, you register the ConsoleTenantContext as scoped. This is needed, because the previous message infrastructure needs to pull in ConsoleTenantContext explicitly to configure it. But the rest of the application will depend instead on ITenantContext, which is why it needs to be registered as well. That registration just forwards itself to the registered ConsoleTenantContext to ensure that both registrations lead to the same instance within a single scope. This wouldn't work when there would be two instances.
Note that you could use the same approach for Web API as demonstrated here for the Console application, but in practice it's harder to intervene in the request lifecycle of Web API compared to doing that with your Console application, where you are in full control. That's why using an ITenantContext implementation that is itself responsible of retrieving the right values is in this case an easier solution for a Web API, compared to the ITenantContext that is initialized from the outside.
What you saw here was a demonstration of different composition models that you can use while configuring your application. I wrote extensively about this in my series on DI Composition Models on my blog.
I am facing an issue related to handling multiple authentication schemes in an asp.net core application which exposes API.
In particular, I am attempting to make two different authentication modes available, by registering two schemes, each with its own handler.
At the moment my configuration code (simplified) looks like this:
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services
.AddAuthentication()
.AddScheme<AuthenticationSchemeOptions, BasicAuthHandler>("Basic", o => {});
.AddScheme<AuthenticationSchemeOptions, ApiKeyAuthHandler>("ApiKey", o => {});
services.AddAuthorization(o => {
o.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("Basic", "ApiKey").Build();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
...
app.UseAuthentication();
app.UseAuthorization();
...
}
}
public class BasicAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
Console.WriteLine("Challenging Basic Authentication");
if( ... ) {
return AuthenticateResult.Success(...);
}
return AuthenticateResult.Fail(...);
}
}
public class ApiKeyAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() {
Console.WriteLine("Challenging ApiKey Authentication");
if( ... ) {
return AuthenticateResult.Success(...);
}
return AuthenticateResult.Fail(...);
}
}
The ApiKeyAuthHandler authenticates requests depending on a custom header (say X-ApiKey) value, the BasicAuthHandler authenticates requests depending on credentials provided through Authorization: Basic BASE_ENCODED_USERNAME_AND_PASSWORD header.
Both handlers work fine: I can provide Authorization header with basic auth credentials and I can provide an api-key through the custom header.
Generally speaking, the two registered handlers are executed sequentially, in the same order I've registered them. So far, so good.
However, when I provide both basic credentials in Authorization header and api-key through X-ApiKey header, I noticed that
the first handler (BasicAuthHandler) is executed, returning AuthenticateResult.Success
the second handler (ApiKeyAuthHandler) is executed, even the first already authenticated the request successfylly, also returning AuthenticateResult.Success
the identity finally available in my controller is the one built by the second handler
I'm wondering why the second handler is executed after the first completed authentication successfully: I googled about this but can't found any configuration flags to enable a sort of short-circuit after the first success result.
The reason seems to be this foreach statement that iterates over all available authentication schemes regardless of theirs results.
Does anyone have any idea of a way to challenge available authentication scheme while no one is successful, stopping when the first succeeds?
No doubt I could implement a CompositeAuthHandler in order to manage this requirement, but I would prefer an already-made, official solution to my problem.
A note about the context which justifies the requirement of short-circuit handler evaluation: the example provided above is simplified and uses two very cheap authentication handlers, but the real case I'm facing off involves at least one very slow handler, that perform paid calls to an external system - so I would like to avoid calling it for requests already authenticated by former handlers.
I will be accessing several tables to determine if a user is "Validated" or not as well as adding custom roles to a Windows authenticated user for authorization. For now I'm running a test in a basic .net Core web application just to see how I should be doing this. I have setup a RequiredClaim in my Fallback Policy and a ClaimsLoader and it works great:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddTransient<IClaimsTransformation, ClaimsLoader>();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireClaim("ValidatedUser")
.Build();
});
}
public class ClaimsLoader : IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claimsIdentity = (ClaimsIdentity)principal.Identity;
claimsIdentity.AddClaim(new Claim("ValidatedUser", ""));
return await Task.FromResult(principal);
}
}
As long as that AddClaim line is in there, they can access the app, without it they get a not-authorized response which is what I want.
Based on what I've read I thought any claims/roles I add in the transformation should come back each time but they do not. In the code above I have the AddClaim running every time so it's working, but in reality I will be going to a database to determine if I should add that claim which is an expensive process. I want to persist the results across multiple requests. So I want to check if the claim is already there and not bother getting it again if it is. For whatever reason it is NEVER there when it comes back for a second request.
From what I've read here back in 2.x the claims should persist:
https://philipm.at/2018/aspnetcore_claims_with_windowsauthentication.html
But here in my 3.1 application they do not.
Consider that I have .NET Controller with Policy-based authorization:
public class ImportantController: Controller {
[HttpGet]
[Authorize(Policy = "CanAccessVIPArea")]
public IActionResult ShowInformation() {
...
return OK(VipData);
}
[HttpPost]
[Authorize(Policy = "CanChangeVIPData")]
public IActionResult SaveInformation([FromBody] VipData) {
...
return CreatedAtAction(...);
}
}
Obviously, the real example is much more complex; I apologize if my simplification leads to too much make-believe in it. Also, real application is SPA with Angular front end; but I don't think it makes any difference for the purposes of this question.
When the user calls ShowInformation() I show a lot of data. On that page I have Save button that calls SaveInformation(). Authorization middleware checks for the right policy and it all works fine.
The problem is that by the time the user presses Save, she entered a lot of data, only to find out that she doesn't have the permissions to save. Obviously, leading to bad experience. I want to check for permissions on SaveInformation in the middleware that gets invoked when the user calls ShowInformation. I would prefer not to check for the hardcoded policy because it is on the server and it can change (we have pretty sophisticated permission management system that manipulates permissions at runtime). Invocation of SaveInformation is in the same Angular service as ShowInformation, and it is very easy to check...
I would like to invoke something like /api/SaveInformation?dryrun that will short-circuit the pipeline after authorization middleware with success or failure.
You can inject an IAuthorizationService and ask to evaluate a policy by name:
public class ImportantController: Controller
{
private readonly IAuthorizationService authorization;
public ImportantController(IAuthorizationService authorization)
{
this.authorization = authorization;
}
public async Task<IActionResult> ShowInformation()
{
// ...
var result = await authorizationService.AuthorizeAsync(User, "IsLucky");
return OK(VipData);
}
}
My pratice is to include all permission claims in the id token, when the user first login to the system, the id token will return to the client side. The client side then render the page according to the permission claims.
Is there any way this. I want to invoke an action with parameter (or parameterless at least) like below.
My situation is;
Interceptor not contains any reference from MVC, Interceptor is located at ApplicationService layer.
This is a service Interceptor.
public class ControllerInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var retVal = (ResponseDTOBase) invocation.ReturnValue;
if (retVal.ResponseCode == UsrNotAuth)
{
//Invoke Controller Action With passsing parameter (retVal)
}
invocation.Proceed();
}
}
Any ideas ? Thanks.
May I offer you another approach for request authorization. MVC is a state machine in its core principle. State machines have actions, triggers and guards. There is already such a 'guard' in MVC for the very purpose of intercepting controller actions and checking for the user privileges. This is the AuthorizeAttribute. This class implements IAuthorizationFilter. Another aspect is that authorization and authentication should happen before they reach your services. What I mean exactly is that there are two types of authorization :
Action Authorization and
Data Authorization.
The first type of authorization you can implement with AuthorizeAttribute or your custom attribute implementation of IAuthorizationFilter + FilterAttribute. Here is an example implementation of such an attribute for a SPA (Single Page Application) that works with ajax requests :
The attribute :
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class LoggedOrAuthorizedAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);
}
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
// If Result is null, we’re OK: the user is authenticated and authorized.
if (filterContext.Result == null)
return;
// If here, you’re getting an HTTP 401 status code. In particular,
// filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here.
// User is logged in but this operation is not allowed
if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.HttpContext.Request.IsAjaxRequest())
{
//filterContext.HttpContext.Response.StatusCode = 401;
JsonNetResult jsonNetResult = new JsonNetResult();
jsonNetResult.Data = JsonUtils.CreateJsonResponse(ResponseMessageType.info, "msgOperationForbiddenYouAreNotInRole");
filterContext.Result = jsonNetResult;
//filterContext.HttpContext.Response.End();
}
}
}
If you use pure MVC there is an example implementation here.
The usage :
In your controller
[LoggedOrAuthorized(Roles = Model.Security.Roles.MyEntity.Create)]
public ActionResult CreateMyEntity(MyEntityDto myEntityDto)
{
...
}
You can apply this on every controller action and block the user even before the controller is reached.
You can supply Loggers and other 'plumbing' through Castle Windsor inside your filters in order to record the events.
A very good and important links and comments are available in this answer of a similar question. These links provide very good guide for proper implementation too.
The other type of authorization - Data Access Authorization can be handled in the service or in the controller. I personally prefer to handle all kinds of authorization as soon as possible in the pipeline.
General practice is not to show to the user any data or action that he is not authorize to view or to execute commands upon it. Of course you have to double check this because the user can modify the POST and GET requests.
You can make simple interface with implementation IDataAccessService and control data access by passing user id and entity id to it.
Important thing is that you should not throw exception when the user is not authorized because this is no exception at all. Exception means that your program is in an unexpected state which prohibits its normal execution. When a user is not authorized this is not something unexpected - it is very well expected. That is why in the example implementation a message is returned rather then exception.
Another subtlety is that "exceptions" are handled differently by the .NET framework and they cost a lot more resources. This means that your site will be very vulnerable to easy DDOS outages or even they can perform not as they can. General rule is that if you control your expected program flow through exceptions you are not doing it properly - redesign is the cure.
I hope this guides you to the right implementation in your scenario.
Please provide the type of the authorization you want to achieve and parameters you have at hand so I can suggest a more specific implementation.