dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.

Home Page:https://asp.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Group claim duplication when using Negotiate authentication on Linux AD domain member with LDAP

y4r9 opened this issue · comments

commented

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When using the Negotiate authentication on a Linux AD domain member with LDAP claim resolution as described at link, the nested groups are resolved multiple times, because in file aspnetcore/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs on line 73 a new HashSet is created in every iteration of the surrounding foreach loop. Furthermore, on Windows the claims contain the SIDs of the groups instead of the names, whereas on linux only the group names are returned. To allow for more portable code adding the SIDs would be helpful.
Adding the SIDs has also been requested previously by #31959.

Expected Behavior

  • Unique group claims should be returned upon authentication.
  • Object SIDs should be added to the claims to allow for portable claim based/policy based authorization.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

8.0.204

Anything else?

No response

commented

API change proposal:

Background and Motivation

When adding SID resolution using LDAP on Linux to solve the issue #55705 @halter73 requested to make this an optional feature in order to reduce overhead (see here). To allow for such a configuration to be added the public facing API of LdapSettings needs to be changed.

Proposed API

src/Security/Authentication/Negotiate/src/LdapSettings.cs

@@ -16,6 +16,14 @@ public class LdapSettings
     /// This is mainly used on Linux.
     /// </summary>
     public bool EnableLdapClaimResolution { get; set; }
+    
+    /// <summary>
+    /// Configure whether the SID claims should be resolved when 
+    /// EnableLdapClaimResolution is true and the LDAP connection 
+    /// is used to resolve claims.
+    /// This is mainly used on Linux.
+    /// </summary>
+    public bool EnableLdapSIDClaimResolution { get; set; }
 
     /// <summary>
     /// The domain to use for the LDAP connection. This is a mandatory setting.

and

src/Security/Authentication/Negotiate/src/PublicAPI.Shipped.txt

@@ -24,6 +24,8 @@ Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.Domain.get -> string!
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.Domain.set -> void
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.EnableLdapClaimResolution.get -> bool
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.EnableLdapClaimResolution.set -> void
+Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.EnableLdapSIDClaimResolution.get -> bool
+Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.EnableLdapSIDClaimResolution.set -> void
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.IgnoreNestedGroups.get -> bool
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.IgnoreNestedGroups.set -> void
 Microsoft.AspNetCore.Authentication.Negotiate.LdapSettings.LdapConnection.get -> System.DirectoryServices.Protocols.LdapConnection?

Usage Examples

Simply enable the optional SID claim resolution by setting the option at initialization.

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
   .AddNegotiate(options =>
   {
       if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
       {
           options.EnableLdap(settings =>
           {
               settings.Domain = "contoso.com";
               settings.EnableLdapSIDClaimResolution = true;
           });
       }
   });

Alternative Designs

Alternatively the option may be included in EnableLdapas optional parameter in NegotiateOptions:

EnableLdap(string domain, bool enableLdapSIDClaimResolution = false)

which would result in the following usage example:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate(options =>
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            options.EnableLdap("contoso.com", true);
        }
    });

Risks

Apart from not duplicating nested group claims, the added SID claims should not cause breaking changes. However, there will be a performance impact, both due to the additional LDAP queries, but also due to the increased storage demand. Nevertheless, the SID resolution is default on Windows and this change would allow to write more portable code. Furthermore, the overhead can be avoided when disabling the resolution using the newly added option proposed here.

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.