Finbuckle.MultiTenant
Finbuckle.MultiTenant copied to clipboard
WithClaimsStrategy not working on IdentityServer with LocalApiAuthentication
I'm using IdentityServer for authenticating my services using OpenIdConnect. This works fine and the tenant is set correctly when I authenticate. For this, I have used a custom strategy that makes use of the IIdentityServerInteractionService to get the tenant from the ACR values.
I have also added IdentityServer's local API authentication by using AddLocalApiAuthentication. This also works correctly as I can access the protected endpoints and return data but not from the DB Context. The problem is that the WithClaimsStrategy doesn't set the tenant => ITenantInfo is null on the DB context.
The services are configured as follows:
services.AddIdentityServer(x =>
{
x.IssuerUri = "null";
x.Authentication.CookieLifetime = TimeSpan.FromHours(2);
x.UserInteraction = new UserInteractionOptions()
{
LogoutUrl = "/account/logout",
LoginUrl = "/account/login",
LoginReturnUrlParameter = "returnUrl"
};
})
.AddSigningCredential(Certificate.Get())
.AddAspNetIdentity<ApplicationUser>()
.AddConfigurationStore(options => options.ConfigureDbContext = builder => builder.UseDatabase(dbProvider, rootConnectionString))
.AddOperationalStore(options => options.ConfigureDbContext = builder => builder.UseDatabase(dbProvider, rootConnectionString))
.Services.AddTransient<IProfileService, ProfileService>();
services.AddLocalApiAuthentication();
services
.AddDbContext<TenantDbContext>((p, m) =>
{
var databaseSettings = p.GetRequiredService<IOptions<DatabaseSettings>>().Value;
m.UseDatabase(databaseSettings.DBProvider!, databaseSettings.ConnectionString!);
})
.AddMultiTenant<CustomTenantInfo>()
.WithStrategy<IdentityServerMultiTenantStrategy>(ServiceLifetime.Transient)
.WithClaimStrategy(AppClaims.Tenant)
//.WithPerTenantAuthentication()
.WithEFCoreStore<TenantDbContext, CustomTenantInfo>()
.Services
.AddScoped<ITenantService, TenantService>();
The configuration of the app builder is as follows:
app.UseForwardedHeaders();
app.Use((context, next) => { context.Request.Scheme = "https"; return next(); });
app.UsePathBase(builder.Configuration);
app.UseStaticFiles();
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.None,
MinimumSameSitePolicy = SameSiteMode.None,
Secure = CookieSecurePolicy.Always
});
app.UseCorsPolicy();
app.UseRouting();
app.UseRequestLocalization();
app.UseAuthentication();
app.UseMultiTenancy();
app.UseAuthorization();
app.UseIdentityServer();
app.UseCurrentUser();
app.UseCustomHangfireDashboard(builder.Configuration);
app.MapDefaultControllerRoute();
app.MapControllers().RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName);
app.MapHealthChecks("/hc", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
I have also tried different orders for the app builder configuration but I can't seem to make it work.
I feel like I'm missing something or I'm doing something wrong. How can I correctly set the TenantInfo based on user claims?
Thanks!
Hi, just to confirm, are you setting the claim value for '__tenant__' to the tenant identifier on the user?
Hi, yes. I am using a custom claim name for the tenant but yes, I am setting its value in the user claims. I can see the claim when decoding the token.
Any luck on this? I recommend when using ClaimsStrategy
to usually call UseMultiTenant
before UseAuthentication
especially if you have per tenant authentication settings in place. I don't see anything obviously wrong. What is the value of AppClaims.Tenant
and do you see that claim on the user?
@boroneaionut
Can you please share your IdentityServerMultiTenantStrategy? I'm struggling with this as well and wanted to see if you figured it out.