damienbod / BlazorServerOidc

Blazor Server OpenID Connect authentication and session security
https://damienbod.com/2024/01/03/securing-a-blazor-server-application-using-openid-connect-and-security-headers/
MIT License
24 stars 3 forks source link

Error when running on Azure WebApp: Nonce already defined, RemoteNavigationManager already initialized #4

Open Jan1503 opened 1 week ago

Jan1503 commented 1 week ago

Hi Damien,

I have a weird issue here and can't find the initial error thats causing it:

My project is nearly an exact copy of your 'BlazorWebFormBlazorServerOidc' project and runs absolutely fine locally.

As soon as I deploy it to an Azure Windows WebApp, I get a Server Error 500 response saying "Nonce already defined" as stated in BlazorNonceService.cs. If I comment this line out, another error is raised: 'RemoteNavigationManager already initialized'.

Attached is the stacktrace from Application Insights, maybe you could find some hint. It looks like the Middleware chain is broken or something.

There is an error raised in line 11 in NonceMiddleware.cs which is line 19 in your repo 'await next.Invoke(context);' and in line 68 in NetEscapades SecurityHeadersMiddleware.cs which is 'await _next(context);'


System.InvalidOperationException:
   at Microsoft.AspNetCore.Components.NavigationManager.Initialize (Microsoft.AspNetCore.Components, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.AspNetCore.Components.Server.Circuits.RemoteNavigationManager.Initialize (Microsoft.AspNetCore.Components.Server, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.AspNetCore.Components.Endpoints.EndpointHtmlRenderer+<InitializeStandardComponentServicesAsync>d__9.MoveNext (Microsoft.AspNetCore.Components.Endpoints, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Components.Endpoints.RazorComponentEndpointInvoker+<RenderComponentCore>d__4.MoveNext (Microsoft.AspNetCore.Components.Endpoints, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext+<>c+<<InvokeAsync>b__10_0>d.MoveNext (Microsoft.AspNetCore.Components, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware+<Invoke>d__11.MoveNext (Microsoft.AspNetCore.Authorization.Policy, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext (Microsoft.AspNetCore.Authentication, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware+<Invoke>d__3.MoveNext (Microsoft.AspNetCore.Diagnostics, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at xxx.NonceMiddleware+<Invoke>d__2.MoveNext (xxx, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: D:\!Repos\xxx\xxx\NonceMiddleware.cs:11)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at NetEscapades.AspNetCore.SecurityHeaders.SecurityHeadersMiddleware+<Invoke>d__9.MoveNext (NetEscapades.AspNetCore.SecurityHeaders, Version=0.22.0.0, Culture=neutral, PublicKeyToken=null: /_/src/NetEscapades.AspNetCore.SecurityHeaders/SecurityHeadersMiddleware.cs:68)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl+<HandleException>d__11.MoveNext (Microsoft.AspNetCore.Diagnostics, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
Jan1503 commented 1 week ago

Ok, I think I found the issue:

I'm using the updated code from Javier in App.razor

This creates a nonce in case it's null like this:

Span<byte> bytes = stackalloc byte[32];
RandomNumberGenerator.Fill(bytes);
nonce = Convert.ToBase64String(bytes);
Context.Items["nonce"] = nonce;

return nonce;

The original code just return null in this case.

I think this interferes with the NonceMiddleware which causes the error, that the nonce was already defined (in the updated code in App.razor).

But even if I ignore this already defined nonce, the upcoming error message about the 'RemoteNavigationManager already initialized' seems strange to me.

Jan1503 commented 6 days ago

It's still not working as expected. I published the code to my Azure WebApp and it runs as expected when browsing to the site using it's default url like xxx.azurewebsites.net. But as soon as I try to reach it using its custom domain name, the same error appears again.

Clearing all browsing data does not help, too.

Think I need to remove the nonce and csp-stuff for now, I'm out of ideas why this is not working :(

damienbod commented 6 days ago

Hi @Jan1503

I'll look at this, see if I see something

It does not work with the custom domain, otherwise it works, correct?

Greetings Damien

Jan1503 commented 5 days ago

Ok, the error with the custom domain was not related. It was caused by some other little bug in the code.

I have no clue what's going on, maybe its related to the authentication against EntraID? If the graph-call throws an MsalUIRequiredException I let the ConsentHandler handle it. It then reloads the site and the authentication is successful.

Here's the piece of code in MainLayout.razor:


protected override async Task OnInitializedAsync()
{
    var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
    UserName = authState.User.FindFirstValue("name");
    Email = authState.User.FindFirstValue("preferred_username");

    try
    {
        var photoStream = await GraphServiceClient.Me.Photos["48x48"].Content.Request().GetAsync();
        var photoString = Convert.ToBase64String((photoStream as MemoryStream)!.ToArray());
        UserPhoto = $"data:image/jpeg;base64,{photoString}";
    }
    catch (Exception ex1)
    {
        if (ex1.InnerException?.Message.Contains("IDW10502", StringComparison.InvariantCultureIgnoreCase) == true)
            ConsentHandler.HandleException(ex1);
        else
        // Ignore photo retrieval errors...
        UserPhoto = "icons/azure-user-icon.svg";
    }

    await base.OnInitializedAsync();
}