Blazor using http.sys with Windows Authentication for all pages with few anonymous pages as exception (API)

Tibor Marchyn 21 Reputation points
2022-11-08T20:31:05.877+00:00

Hi,

I'm new to Blazor and have created app using HTTP.SYS (on .net 5, now migrating to .net 6 and later to 7 when released) and Windows Authentication. Anonymous is disabled in HTTPS.SYS.

return WebHost  
                .CreateDefaultBuilder(args)  
                .ConfigureLogging(builder =>  
                    {  
                        builder.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.None)  
                            .AddConsole();  
                    }  
                )  
                .UseStartup<Startup>()  
                .UseHttpSys(options =>  
                    {  
                        options.Authentication.Schemes = AuthenticationSchemes.Negotiate | AuthenticationSchemes.NTLM;  
                        options.Authentication.AllowAnonymous = false;  
                        options.MaxConnections = null;  
                        options.MaxRequestBodySize = 30000000;  
  
                        options.UrlPrefixes.Add("https://"+Settings.Instance.Hostname+":"+Settings.Instance.Port);  
                    }  
                );  

The thing is that now I need to publish some API Controller i.e "/api/SomethingController", but due disabled anonymous it requires authentication and authorization. When I allow anonymous, I do not know how to require authentication and authorization for all pages except mentioned API Controller. I did some tries with [Authorized] attribute and I had some success, but i.e. websockets was always throwing exception as they become anonymous and my app strictly requires Windows Authentication on all pages as each page works with impersonate and I had my own AuthorizationHandler declared as

services.AddSingleton<IAuthorizationHandler, AdGroupHandler>();  

AdGroupHandler looks like this and failing on "var userPrincipal" line

    public class AdGroupHandler : AuthorizationHandler<AdGroupRequirement>  
    {  
        private readonly IHttpContextAccessor _httpContextAccessor;  
        public AdGroupHandler(IHttpContextAccessor httpContextAccessor)  
        {  
            _httpContextAccessor = httpContextAccessor;  
        }  
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdGroupRequirement req)  
        {  
            var domainContext = new PrincipalContext(ContextType.Domain, "ad.domain.com");  
            var userPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, _httpContextAccessor.HttpContext.User.Identity.Name);  
            var groups = req.AdGroup;  
  
            try  
            {  
                if (groups.Any(group => userPrincipal != null && userPrincipal.IsMemberOf(domainContext, IdentityType.Name, group)))  
                    context.Succeed(req);  
            }  
            catch (NoMatchingPrincipalException)  
            {  
                context.Fail();  
            }  
  
            return Task.CompletedTask;  
        }  
    }  

So, I ended up that I do not know how to require authentication and authorization in WebSocket. When I launch blazor app, it authorizes me for _Host.cshtml and all root pages, but on the end of loading page it started to load WebSocket and WebSocket call AdGroupHandler and it fails as Windows Authentication is not passed/required there.

I went through Blazor docs, Authentication and Authorization page, but I have no idea how to solve this.

Any advice?

Developer technologies .NET Blazor
{count} votes

1 answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2022-11-09T23:21:43.813+00:00

    you don't specify if its blazor WASM or server, but it looks like server (as WASM authentication is only the webapi calls and the browser would handle nt authentication on the api call for you).

    you should review the docs on blazor server. blazor server is implemented as an html page, that hosts a javascript library. on page load this javascript opens a request to the server to start the server blazor code and create the signal/r hub. after this the client send browsers events as messages to the server app. and the server responds with blazor tree updates, or javascript interop requests,

    the request that starts the blazor app, does not exit until the signal/r connection is closed. this request supplies the httpcontext and user authentication information that is available to the server app (there are no more http requests).

    this is why there is limited transaction scope support. there is only one session and one transaction request for the life of the app.

    if the server app starts anonymous, then is if authentication is required, the blazer app redirects to the login page (shutting down the blazor server app), once authentication is done, the login process redirects back to the blazor server and starts up the blazor server app again this time with authentication set in the new httpcontext.

    because you are using windows nt authentication, which is an out-of-band challenge / response protocol on top of http/s, the page hosting blazor app will need to redirect to a new http request that authenticates and restarts the blazor app.

    note: blazor navigation requests are handled like any SPA. javascript captures the location changes in the browser. it then cancels the request and uses the url to pick the component to load. there is no new server request.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.