16

In my old .NET MVC app, I could enable Windows Authentication in IIS and disable anonymous. Then in my web.config file I just had to put in this:

<authorization> 
  <allow roles="Domain\MyADGroupToHaveAccess" />
  <deny users="*" /> 
</authorization> 

In .NET Core 2.0 this will not work – it denies anonymous correctly, but it authorizes all users no matter what.

If I do this:

[Authorize(Roles = "Domain\\MyADGroupToHaveAccess")]

on my HomeController, it works, but I don't want to hardcode this setting in my project as it's something that needs to be changed for other environments.

How can I make web.config to work with AD Authorization? Or is there another way to not hardcode this setting in ASP.NET Core?

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Morten_564834
  • 1,479
  • 3
  • 15
  • 26
  • Hello. If I understand this correct, then I should be able to create a group (aka an OU?) in AD and then by referencing the same group/OU in attribute [Authorize(Role="MyADGroup")] then AD administrator or OU group delegate can add/remove/modify group members and effectively grant access to my controller, yes? If this is not correct, then what am I missing? See my question: https://stackoverflow.com/questions/50498225/how-to-bind-authorization-of-asp-core-controller-to-an-ou?noredirect=1#comment88009352_50498225 – Adam Cox May 24 '18 at 04:11

3 Answers3

30

I solved this by making it into a policy which is able to call appsettings.json. This way other people who have access to the server can then edit the group to their own.

In Startup.cs:

services.AddAuthorization(options =>
{
    options.AddPolicy("ADRoleOnly", policy => policy.RequireRole(Configuration["SecuritySettings:ADGroup"]));
});

services.AddMvc(config =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();

    config.Filters.Add(new AuthorizeFilter(policy));
});

In appsettings.json (or perhaps appsettings.production.json if you have different):

"SecuritySettings": {
  "ADGroup": "YourDomain\\YourADGroup"
}

In your controllers you can then decorate it with this attribute:

[Authorize(Policy = "ADRoleOnly")]

Hope this can help other people

I have still to figure out how to apply this policy globally, so I don't have to authorize every controller, I'd figure it can be done in the services.AddMvc somehow?

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Morten_564834
  • 1,479
  • 3
  • 15
  • 26
  • Here's a write-up on how to apply it to controllers by default: https://joonasw.net/view/apply-authz-by-default – Aage Feb 14 '19 at 08:25
  • How would you go about allowing access via membership in any of several AD groups (as opposed to just one)? Would you create several roles? Or several Policies? When you add AuthorizeFilters, are they added as `or` or `and`? – RagingRoosevelt Apr 17 '19 at 16:11
6

To expand on Morten_564834's answer, here is our approach for this problem. Create a base controller that all controllers inherit from.

[Authorize(Policy = "AdUser")]
public class FTAControllerBase : Controller
{
    private readonly ApplicationDbContext _db;
    private readonly ILogHandler _logger;

    public FTAControllerBase(ApplicationDbContext DbContext, ILogHandler Logger, IWindowsAccountLinker WinAccountLinker)
    {
        _db = DbContext;
        _logger = Logger;

        /// get registered user via authenticated windows user.
        //var user = WinAccountLinker.LinkWindowsAccount();
    }
}

Then in your other controllers:

public class LettersController : FTAControllerBase
{ ... }

If you want granular permissions on methods:

[Authorize("GenerateLetterAdUser")]
[HttpGet]
public IActionResult Generate()
{
    return View();
}

Startup.cs:

// add authorization for application users
var section = Configuration.GetSection($"AuthorizedAdUsers");
var roles = section.Get<string[]>();
services.AddAuthorization(options =>
{
    options.AddPolicy("AdUser", policy => policy.RequireRole(roles));
});

AppSettings.json:

"AuthorizedAdUsers": [
"domain\\groupname"
],
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
sam
  • 320
  • 3
  • 14
  • So GenerateLetterAdUser would be another policy that needs to be added? And it would have another entry in AppSettings.json to hold the relevant group name? – Mike Jul 01 '20 at 00:52
  • 1
    GenerateLetterAdUser would be a group in Active Directory and you would map users to the AD group. So domainname\\generateletteraduser would be the usage.So you map all the groups you want to use in the appsettings.json, in AD map the users to the groups. This will make it use both AD and .net core roles and policies. – sam Jul 04 '20 at 08:12
0

I was able to reproduce the web.config settings with the following:

In Program.cs:

builder.Services.AddAuthorization(options => {
    builder.Configuration.GetSection("SecuritySettings").GetChildren().ToList().ForEach(
        ss => options.AddPolicy(ss.Key, policy => policy.RequireRole(ss.Value))
    );

    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireRole(new string[] { builder.Configuration["SecuritySettings:Access"] })
        .Build();
});

In appsettings.json:

"SecuritySettings": {
  "Access": "YourDomain\\YourADGroup"
}
Alex
  • 1,979
  • 16
  • 24