2

I am investigating using Windows Authentication with ASP.NET Core 5.0 MVC. I can use an Active Directory group name directly in the Authorize attribute, but that's proved problematic in the past.

I want to add claims to the list and use those values in the Authorize attributes. Various posts suggested that if I implemented an IClaimsTransformation, TransformAsync() would be called automatically but that doesn't appear to be the case. I never see the string In TransformAsync in the output in Visual Studio.

I am using VS 2019 and ASP.NET Core 5.0.

To recreate: I use a new ASP.NET Core Web App (Model-View-Controller) template:

  • Target Framework: .NET 5.0 (Current)
  • Authentication Type: Windows,
  • Configure for HTTPS: yes

When I run it, I can see that I'm authenticated from the Hello DOMAIN\User message.

These are my additions:

ADClaimsTransformation.cs:

using Microsoft.AspNetCore.Authentication; using System.Diagnostics; using System.Security.Claims; using System.Threading.Tasks; namespace SOWinAuthN1.Services { public class ADClaimsTransformation : IClaimsTransformation { public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { Debug.WriteLine("In TransformAsync"); var ci = (ClaimsIdentity)principal.Identity; var c = new Claim(ci.RoleClaimType, "Admin"); ci.AddClaim(c); return Task.FromResult(principal); } } } 

I can see from the Output window that this is never called.

In Startup.cs, I have:

using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using SOWinAuthN1.Services; namespace SOWinAuthN1 { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddTransient<IClaimsTransformation, ADClaimsTransformation>(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } } 

SecureController.cs:

using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace SOWinAuthN1.Controllers { [Authorize(Roles = "Admin")] public class SecureController : Controller { public IActionResult Index() { return View(HttpContext.User.Claims); } } } 

Index.cshtml (located in .\Views\Secure):

@model IEnumerable<System.Security.Claims.Claim> @{ ViewData["Title"] = "Claims"; } <h1>Claims</h1> <table class="table"> <thead> <tr> <th>Subject</th> <th>Type</th> <th>Value</th> <th>Issuer</th> <th>OriginalIssuer</th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@item.Subject</td> <td>@item.Type</td> <td>@item.Value</td> <td>@item.Issuer</td> <td>@item.OriginalIssuer</td> </tr> } </tbody> </table> 

_Layout.cshtml - added to the navbar ul:

<li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Secure" asp-action="Index">Claims</a> </li> 

Am I barking up the wrong tree? Is there a better approach?

Ultimately, I'm expecting to have a transformer which maps a small number of AD group claims onto a larger number of operations, such that group A maps to operations 1, 2 and 4, whilst group B maps to 2, 4 and 5, say, with the plan to keep this mapping in config somewhere.

2
  • how did you set up auth services & middleware? include those in the post, too Commented Sep 21, 2021 at 13:24
  • I've included the whole of Startup.cs - does that supply what you asked for? Core is new to me so I'm still finding my feet. Commented Sep 21, 2021 at 14:23

2 Answers 2

1

It looks like you are missing services.AddAuthentication() in your ConfigureServices method and app.UseAuthentication() in your Configure method.

You can have a look at Configure Windows Authentication in ASP.NET Core for more information on how to configure Kestrel or IIS or HTTP.sys.

Sign up to request clarification or add additional context in comments.

4 Comments

Authentication works without them, as in <p class="nav navbar-text">Hello, @User.Identity.Name!</p> from _Layout.cshtml is rendered correctly as Hello, MYDOMAIN\MyUserId! and if I comment out the [Authorize] attribute, the Secure page displays my AD group membership.
I tried adding both statements but it made no difference.
@user2871239 this is the correct answer.
@user2871239 If it's working without them it's possible IIS is doing the Authentication vs Kestrel. Run it as https instead of IIS and you won't get the same service.
0

Follow the previous instructions but it's important you add app.UseAuthentication() before app.UseAuthorization()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.