Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor Server authorization fails with Microsoft.AspNetCore.Authentication.Negotiate #17527

Closed
akorchev opened this issue Dec 2, 2019 · 6 comments
Labels

Comments

@akorchev
Copy link

@akorchev akorchev commented Dec 2, 2019

Describe the bug

It seems that the Authorize attribute does not work with Microsoft.AspNetCore.Authentication.Negotiate authentication and roles.

To Reproduce

  1. Create a server-side blazor application with Windows Authentication.
  2. Add the Microsoft.AspNetCore.Authentication.Negotiate package.
  3. Enable it
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
  1. Use middleware to challenge the authentication scheme:
 services.AddScoped<ValidateAuthentication>();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseMiddleware<ValidateAuthentication>();
    internal class ValidateAuthentication : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            if (context.User.Identity.IsAuthenticated)
                await next(context);
            else
                await context.ChallengeAsync();
        }
    }
  1. Add authorize attribute to Index.razor with some group that your windows user is a member of.
@attribute [Authorize(Policy = "TestGroup")]
  1. Important !!! Run with the default profile from launch settings and not IIS Express!!! (it works with IIS Express). After logging in the app would show you that you are not authorized even though you are a member of the group.
    image

Strangely enough if you debug IsInRole("TestGroup") returns true.
image

I suspect it is related to the authentication scheme which one normally could pass to the Authorize attribute. However Blazor doesn't allow setting the AuthenticationSchemes property of the Authorize attribute:

NotSupportedException: The authorization data specifies an authentication scheme. Authentication schemes cannot be specified for components.
Microsoft.AspNetCore.Components.Authorization.AuthorizeViewCore.EnsureNoAuthenticationSchemeSpecified(IAuthorizeData[] authorizeData)

Further technical details

  • ASP.NET Core version: 3.1.100-preview3-014645
  • Visual Studio 2019 Preview 6, Windows 10 Pro
@blowdart

This comment has been minimized.

Copy link
Member

@blowdart blowdart commented Dec 3, 2019

This isn't blazor related, but an actual limitation of our kerberos middleware. We're tracking adding group/role support but right now it simply isn't there, because you don't get enough information in a kerberos ticket.

@akorchev

This comment has been minimized.

Copy link
Author

@akorchev akorchev commented Dec 3, 2019

@blowdart why does IsInRole work then? I also see all groups added as claims. Another thing that works is this:

 endpoints.MapBlazorHub()
      .RequireAuthorization( new AuthorizeAttribute { 
        AuthenticationSchemes =  NegotiateDefaults.AuthenticationScheme, 
        Roles="TestGroup" 
});             

Obviously I can't use it as makes all pages require that role but still.

@akorchev

This comment has been minimized.

Copy link
Author

@akorchev akorchev commented Dec 3, 2019

The linked issue gave me an idea - to test with the group id:

@attribute [Authorize( Roles = "S-1-5-21-193572532-2712524652-3721290085-1001")]

which worked!

@blowdart

This comment has been minimized.

Copy link
Member

@blowdart blowdart commented Dec 3, 2019

Oh I see. Luck kind of. WindowsIdentity is special, it doesn't bring the roles names with it, role name resolution is done through the WindowsIdentity class, which makes a call out to the server. IIS and IIS Express resolve WindowsIdentity, but "plain" kerberos auth, using the negotiate middleware does not as yet.

@akorchev

This comment has been minimized.

Copy link
Author

@akorchev akorchev commented Dec 3, 2019

I ended up using a claims transformation which somewhat works:

    public class CustomClaimsTransformation : IClaimsTransformation
    {
        public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
        {
            var identity = principal.Identity as WindowsIdentity;
            foreach (var groupId in identity.Groups)
             {
                var group = groupId.Translate(typeof(NTAccount));
                var c = new Claim(identity.RoleClaimType, group.Value.Split("\\").Last());
                identity.AddClaim(c);
            }

            return Task.FromResult(principal);
        }
    }
@blowdart

This comment has been minimized.

Copy link
Member

@blowdart blowdart commented Dec 3, 2019

That works, but if you're thinking about cross platform you'd need a null check in there after the cast, in case you're not running under Windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.