microsoft / fluentui-blazor

Microsoft Fluent UI Blazor components library. For use with ASP.NET Core Blazor applications
https://www.fluentui-blazor.net
MIT License
3.8k stars 367 forks source link

fix: FluentIcon fails to load the SVG when using the default authorization policy from Azure AD as global fallback policy #262

Closed alfosua closed 1 year ago

alfosua commented 1 year ago

πŸ› Bug Report

The component FluentIcon fails to load the SVG when using the default authorization policy as a global fallback policy. Microsoft.Identity.Web (based on Azure Active Directory) is the backend used for authentication and where the issue is currently happening to me.

πŸ’» Repro or Code Sample

With the web application built and run as next:

// Program.cs
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.Fast.Components.FluentUI;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();

builder.Services.AddAuthorization(o =>
{
    // This sets the default policy (requiring an authenticated use only) for
    // every route which doesn't specify any authorization or anonymous filter.
    o.FallbackPolicy = o.DefaultPolicy;
});

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();

builder.Services.AddHttpClient();
builder.Services.AddFluentUIComponents();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

And with any usage of a valid Fluent icon:

@* Pages/Index.razor *@
@page "/"

<FluentIcon Name="@FluentIcons.Add" />

πŸ€” Expected Behavior

It should render the icon, just as we would expect.

😯 Current Behavior

After some seconds of trying to load the SVG file for the icon, the authorization pipeline redirects to the AD instance with the following error:

image

We can't sign you in. JavaScript is required to sign in. Your browser either does not support JavaScript or it is being blocked. Enable JavaScript in your browser or use one which supports it.

πŸ’ Workaround

Aside from removing the default policy as the fallback policy and setting up authorization manually for every view.

Also, I could fix it by providing the default policy only to razor pages on the Program.cs:

builder.Services.AddRazorPages()
    .AddMvcOptions(o =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        o.Filters.Add(new AuthorizeFilter(policy));
    });

And it can have a similar solution to what I intended initially (at least, inside my context.

However, I think the library itself should mark its static files in the icons folder to allow anonymous requests, or at least, optionally be configurable easily that way. This should be solvable out of the box as the Program.cs shown above is mostly based on the current template of Blazor in .NET 7 when using SingleOrg authentication option.

🌍 Your Environment

vnbaaij commented 1 year ago

Going by the example you posted above of the Index page. Are you not getting the icon there when you are logged in with AD? Or did you do anything to view the homepage unauthorized/anonymous? I'm asking because I tried to replicate the problem by: 1) Creating Blazor Server app from template with Microsoft Identity Platform 2) Configuring AD, etc 3) Adding FluentUI package 4) Changing the Index.razor page to what you have

After running and signing in, I get:

image

(i.e. the icon is shown)

I don't see how I would need to do something special for the .svg files. They are just assets like the site.css and the Bootstrap resources and nothing is done anywhere to mark them for anonymous access, I believe (I'm not an identity/authorization authority so could very well be wrong here)

Differences between your code and the template/my code: You have using Microsoft.AspNetCore.Mvc.Authorization; which I don't have

I have

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

where you just have

app.UseRouting();
app.MapControllers();

Maybe that is what is causing the issue?

alfosua commented 1 year ago

I will try using your two spare lines and come back and say if that solves the problem. If not, I will upload an example demo so you can replicate the issue.

alfosua commented 1 year ago

With the following information about my .NET tooling and using .NET 7 as the default framework:

❯ dotnet --info
.NET SDK:
 Version:   7.0.100
 Commit:    e12b7af219

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\7.0.100\

Host:
  Version:      7.0.0
  Architecture: x64
  Commit:       d099f075e4

.NET SDKs installed:
  6.0.400 [C:\Program Files\dotnet\sdk]
  7.0.100 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Did create a new app from the template with the following command:

dotnet new blazorserver --auth SingleOrg -n BlazorServerWithAzureAdAndFluentUI -o .
dotnet add package Microsoft.Fast.Components.FluentUI -v 2.0.0-rc-1

Then did the extra steps to set up FluentUI and set up my Azure AD information at the appsettings.json. And with the template mostly untouched aside from the code required for FluentUI setup, the problem still persists.

The app tries to load the SVG: image

Then it redirects here: image

Now, I added the two extra lines you used:

app.UseAuthentication();
app.UseAuthorization();

And surprisingly it now works! It's weird though. I have to say that the new template from .NET does not add the last two lines to UseAuthentication, and UseAuthorization.

You can find my repo replicating the problem: alfosua/fluentui-blazor-issue. I commented the fixing lines so you can see it's happening. You will need to setup your Azure AD configuration when trying the app.

vnbaaij commented 1 year ago

The two lines did get added in my experiment. Difference is I created the project in VS. I guess that is where the difference comes from.

As you are able to get it working with the lines included, can you close this issue now?

vnbaaij commented 1 year ago

Consider this solved by adding the UseAuthentication and UseAuthorization lines.

smartinick commented 1 year ago

i had a similar issue with a slightly different problem/solution, so i want to update this thread for any other readers:

In my case i used the blazor server app example without fluent/fast,... but with the builtin bootstrap. then i added userdetection in program.cs like this:

        builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
                .AddNegotiate();
            builder.Services.AddAuthorization(options =>
            {
                options.FallbackPolicy = options.DefaultPolicy;
            });

which leads my program to know the user, check against windows-ad for group-memberships,... but NOT to have the user to provide login data. - sort of single-signon. and the 2 lines you discussed above are commented out, not used in my scenario (well, so far...):

        //app.UseAuthorization(); //not needed for getting userid
        //app.UseAuthentication(); //force login-dialog

when i migrated the project manually to this fast/fluent lib, i had the problem that the fluenticons, e.g.

Button with icon in 'start' slot

(just from the samples page...) did not display the icons.

after some hours i stumbled over this issue, commented out the addauth block above and the icons worked. using the addauth again, i came to this version:

        app.UseAuthorization(); //not needed for getting userid, but needed for fluent icons to display
        //app.UseAuthentication(); //force login-dialog

which still does not trigger the login-dialog, and also displays the fast-fluent-icons....

So what i'd suggest from this post: please add this details to the readme to safe others some time.... or fix it this issue ;)