We've added authentication to a couple of our App Services, which are .NET Core 3.1 applications.
The implementation we have in the Startup class looks pretty much like the following excerpt.
private void AddAuthorization(IServiceCollection services)
{
services.AddAuthorization(Policies)
.AddRazorPages().AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireRole("Reader")
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<CookieAuthenticationOptions>(AzureADDefaults.CookieScheme, o =>
{
o.Events = new CookieAuthenticationEvents
{
OnRedirectToAccessDenied = (ctx) =>
{
ctx.Response.StatusCode = 403;
return Task.CompletedTask;
}
};
});
}
private static void Policies(AuthorizationOptions options)
{
options.AddPolicy("Read", builder => builder
.RequireAuthenticatedUser()
.RequireRole("Reader"));
options.AddPolicy("Write", builder => builder
.RequireAuthenticatedUser()
.RequireRole("Writer"));
}
The relevant details in the appsettings.json look like this:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "our-domain.com",
"TenantId": "3da1185c-e3b3-4034-a143-32a81c84ee77",
"ClientId": "acf0f949-2ae4-409c-bc6b-5acf22c7c50c",
"CallbackPath": "/signin-oidc"
}
}
As you can see, we're using the default authentication scheme for Azure AD, added a default policy which role users need (Reader), and using cookies to store the user details.
All is working fine with this implementation. Users can log in, make requests, etc.
The thing is. We've also started using Cypress to do end-to-end testing for our applications.
This test suite is working quite nicely when testing a different application, which is a React application interacting with a Web API using the JWT bearer scheme.
When making calls to the backend, the Authorization header is set appropriately.
However, with this 'new' application we're not using JWT bearer tokens, we're using cookies.
Just to prove stuff works we started by logging in via the regular Azure AD views with some test user. This works, but it's a bad practice to do so as we shouldn't invoke the AAD pages and we might get blocked for doing so.
We noticed our test suite isn't very stable at the moment also, because when trying to log in, the password field never shows up when running the suite on our build machine (maybe it got blocked or some other 'smart' algorithm makes this field not visible).
I've read it's recommended to use the ROPC flow when in such a scenario.
Because of this, I checked the option in our App Registration so the ROPC flow can be used. I'm now able to use appropriate AAD endpoints to get a token. This all works fine.
But now for the most important part. What do I need to put in the cookie(s) and which cookies do I need to set?
When logging in as a 'normal' user I see there's the .AspNetCore.AzureADCookie, .AspNetCore.AzureADCookieC1, .AspNetCore.AzureADCookieC2 entries with some values, but I'm lost at how to set this using a different flow and haven't got a clue what should go inside them.
Does anyone have an idea of how to get Cypress & this Cookie scheme working with AAD?
I've seen some samples for Identity Server & Auth0, which appear to be working much simpler for this kind of scenario.
