AzureAD/azure-activedirectory-library-for-dotnet

ASP.NET Core 2.2 Azure AD Authorisation Middleware Not Handling Overages

Opened this issue · 3 comments

Cross-posted from this issue on ASP.NET Core GitHub library after being referred to this repo.

Describe the bug

I've recently set up authentication on an ASP.NET Core website I'm working on, and am now trying to authorize users based on their membership to a security group. I'm using this tutorial to assist me with the setup.

I've set up my AAD application with and received admin approval for the API permissions: User.Read and Directory.Read.All. I can tell that the basic AAD application is hooked up to our website correctly, since our application can successfully read a user's basic profile information after sign-on.

I have also enabled "groupMembershipClaims": "SecurityGroup" in the application manifest to provide all group membership claims to our application.

However, when I attempt to restrict access to a controller with the following attribute:

[Authorize(Policy = "Admins")]

The result comes back unauthorized.

To investigate, I ran the following command to retrieve the list of all security group claims for a given user:

List<Claim> groups = User.Claims.Where(c => c.Type == "groups").ToList();

The result comes back with a Group Overage Claim indirection link ("_group_claims" and "group_sources"), leading me to believe that this might be caused by how the AAD authorization SDK handles group overages.

Is there anyting I've missed here?

To Reproduce

appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "microsoft.onmicrosoft.com",
    "TenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
    "ClientId": "a3fc9157-32af-49a2-xxxx-xxxxxxxxxxxx",
    "CallbackPath": "/signin-oidc"
  },
  "AzureSecurityGroup": {
    "AdminObjectId": "48e5a47d-d6a2-44d8-xxxx-xxxxxxxxxxxx"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

startup.cs:

public void ConfigureServices(IServiceCollection services)
{
	services.Configure<CookiePolicyOptions>(options =>
	{
		// This lambda determines whether user consent for non-essential cookies is needed for a given request.
		options.CheckConsentNeeded = context => true;
		options.MinimumSameSitePolicy = SameSiteMode.None;
	});

	services.AddAuthorization(options =>
	{
		options.AddPolicy(
			"Admins",
			policyBuilder => policyBuilder.RequireClaim(
				"groups",
				this.Configuration.GetValue<string>("AzureSecurityGroup:AdminObjectId")));
	});

	services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
		.AddAzureAD(options => this.Configuration.Bind("AzureAd", options))
		.AddCookie();

	services.Configure<CookieAuthenticationOptions>(
		AzureADDefaults.CookieScheme,
		options =>
		{
			options.AccessDeniedPath = $"/Error/403";
			options.LoginPath = $"/Error/401";
		});

	services.AddMvc(options =>
	{
		var policy = new AuthorizationPolicyBuilder()
			.RequireAuthenticatedUser()
			.Build();
		options.Filters.Add(new AuthorizeFilter(policy));
	})
	.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Secured controller:

[Authorize(Policy = "Admins")]
public class AdminController : Controller
{
    ...
}

-->

Further technical details

  • ASP.NET Core version: 2.2
  • Include the output of dotnet --info
.NET Core SDK (reflecting any global.json):

Version:   3.1.101

Commit:    b377529961

 

Runtime Environment:

OS Name:     Windows

OS Version:  10.0.18363

OS Platform: Windows

RID:         win10-x64

Base Path:   C:\Program Files\dotnet\sdk\3.1.101\

 

Host (useful for support):

  Version: 3.1.1

  Commit:  a1388f194c

 

.NET Core SDKs installed:

  2.1.700 [C:\Program Files\dotnet\sdk]

  2.2.300 [C:\Program Files\dotnet\sdk]

  3.1.101 [C:\Program Files\dotnet\sdk]

 

.NET Core runtimes installed:

  Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

  Microsoft.AspNetCore.All 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

  Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

  Microsoft.AspNetCore.All 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

  Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

  Microsoft.AspNetCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

  Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

  Microsoft.AspNetCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

  Microsoft.AspNetCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

  Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

  Microsoft.NETCore.App 2.1.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

  Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

  Microsoft.NETCore.App 2.2.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

  Microsoft.NETCore.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

  Microsoft.WindowsDesktop.App 3.1.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  • The IDE (VS / VS Code/ VS4Mac) you're running on, and it's version: VS2019

@jublair : this is not an ADAL.NET issue.
Would you mind looking at the following sample and see if this solves your issue?
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/5-WebApp-AuthZ/5-2-Groups

Thanks for the quick reply @jmprieur. Not sure which repo is the right one to contact here, since the ASP.NET Core devs referred me in this direction. Do you know the right repo to which I should file this issue, if it's not here nor there?

I have attempted the guidance listed here, but to no avail. The section just above it discussing overage claims appears to refer to processing overage claims when calling Graph API directly, but not in relation to the ASP.NET Core middleware libraries.

I've identified that the best workaround in this case (and one that also improves code reliability) is to make use of AAD Enterprise Application Roles, rather than checking group claims directly. That way I can continue to use the default AAD SDK, with just a few tweaks.

startup.cs:

services.AddAuthorization(options =>
{
    options.AddPolicy("Admins", policy => policy.RequireClaim(ClaimTypes.Role, "Admin"));
});