Some things sound too easy to do, but still end up eating a lot of time researching how to do it. Recently I made a small Web Application that had to integrate with Active Directory. To be precise: only a specific set of Active Directory groups is allowed to make use of the website functionality. All others should be met with a custom page telling them they are not allowed to do anything. Nothing special, right?
First of all: what is authorization? There is a difference between authentication and authorization. Authorization means that you are who you say you are. Compare it with an ID card: the card has information about you, and somebody checking your ID card can use that information to verify that you are the one on the ID card. Authorization means that you are allowed to do what you want to do. Compare with a drivers license: it has the name and personal code (BSN in The Netherlands) of the person that is allowed to drive a car. (A drivers license is also often used as authorization, but that is beside the point).
Authentication
Setting up Active Directory authorization in .NET Core was pretty easy. We’re using IIS, so add the following to ConfigureServices()
services.Configure<IISServerOptions>(Configuration);
services.AddAuthentication(IISDefaults.AuthenticationScheme);
When building the project using dotnet publish, a web.config file will automatically be created for usage, no need to edit that.
Next, enable Windows Authentication in IIS itself (which is done by adding the Windows Feature found as IIS > World Wide Web Services > Security > Windows Authentication) and restart the host machine.
Lastly, enable only Windows Authentication in IIS for this website (or web application) under the Authentication feature.
The last thing to do is to publish the output to IIS. Easy Peasy
Authorization
Authorization was a bit more difficult. Eventually, this was made possible in four steps: Creating an Authorization Policy, configuring the groups to authorize, annotating the methods that need authorization and setting up a page to display if the user is not authorized.
Configuration
Configuring the groups is the most easy part. In appsettings.json, we’ve added a configuration item which lists the groups to authorize. For example:
{
"AuthorizedGroups" : ["Group1", "Group2", "Group3"]
}
These can be read like this:
var groups = Configuration.GetValue<List<string>>("AuthorizedGroups");
or something similar.
Creating policy
Setting up a Policy is the next step. For that, we can do this:
services.AddAuthorization(options =>
var groups = Configuration.GetValue<List<string>>("AuthorizedGroups");
options.AddPolicy("MyPolicy", policy =>
{
policy.RequireAuthenticatedUser().RequireRole(groups);
}
)
This should be easily extendable to multiple properties, by simply reading other settings and creating other policies based on those groups. Notice that we named the policy “MyPolicy”. This is important for the next step, where we will enforce the policy on restricted methods.
Enforcing policy
In the Controller we want to restrict, we can use the Authorize attribute to annotate the POST method:
[HttpPost]
[Authorize(Policy = "MyPolicy")]
public async Task<IActionResult> DoAction()
{
// Do the action here...
}
public IActionResult Index()
{
return View();
}
This will prevent unauthorized users for performing this POST function.
Unauthorized page
As you can see, the Index() method is not annotated with Authorize. We do want to show a page when an unauthorized user, but a bit altered. We can do this by adding a new Blazor layout. First, on all the pages we want to protect with authorization, we use a different layout file like this:
@{
Layout = "Authorized";
// ....
}
Next, add a Blazor page in the Shared directory named Authorized.cshtml, with the following content:
@using Microsoft.AspNetCore.Authorization
@{
Layout = "_Layout";
bool authorized = (await AuthorizationService.AuthorizeAsync(User, "MyPolicy")).Succeeded;
}
@if (authorized)
{
@RenderBody()
}
else
{
IgnoreBody();
<p>You are not authorized to view this page.</p>
}
@section Scripts {
@(await RenderSectionAsync("Scripts", false))
}
@* If you use other sections (e.g. css) render them here as well *@
This page will check if the user is authorized. If so, it will render the page normally. If not, it will display a simple message that the current user is not authorized. The trick here is that two layouts are used: this one first and then the “default” layout page.
Conclusion
Adding Active Directory authorization is done with a few steps in .NET Core, in a way that you can extend it later to use more fine-grained policies. Also we’ve created a custom view when a user is not authorized to view a page. We are using IIS however, so it is not clear how to establish this using a different hosting service.