Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor Server - how to configure for on-premises ADFS Security?

I have an existing Blazor (Server) app addressing .NET Core 3.1 preview 2.

I need to retrospectively add on-prem ADFS (not Azure) security. I've been trying to follow Microsoft's Authenticate users with WS-Federation in ASP.NET Core and it's stubbornly ignoring the security. The article is of course written for ASP.NET, not Blazor...

What I've done so far is:

public static void ConfigureServices(IServiceCollection services)
{
    services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddAuthentication()
        .AddWsFederation(options =>
        {
            options.MetadataAddress = "https://adfs.Server.com/FederationMetadata/2007-06/FederationMetadata.xml";
            options.Wtrealm = "https://localhost:44323/";
        });

    services.AddAuthorization();

    services.AddRazorPages();
    services.AddServerSideBlazor();

    ....

One thing of concern - the DB currently has tables in it supporting an earlier authentication pattern (membership?) (used by the application we're re-writing). It has the tables [AspNetRoles] [AspNetUserClaims] [AspNetUserLogins] [AspNetUserRoles] and [AspNetUsers]. Will any of this get overwritten?

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }    

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (optionsBuilder != null)
        {
            if (optionsBuilder.IsConfigured == false)
            {
                IConfigurationRoot configuration = new ConfigurationBuilder()
                    .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                    .AddJsonFile($"appsettings.{Startup.CurrentEnvironment}.json")
                    .Build();

                optionsBuilder
                    .UseSqlServer(configuration.GetConnectionString("MyDatabase"), 
                           providerOptions => providerOptions.CommandTimeout(60));
            }
        }

        base.OnConfiguring(optionsBuilder);
    }
}

In the Configure method, I've added (though I'm not clear on whether I needed to):

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

In the App.razor, I have:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            @*<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />*@
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

And in one of my razor pages (MyPage.razor), I've got:

@page "/myRoute"    
@attribute [Authorize]

When I browse to the page with the Autorize attribute, I get the message:

Not authorized

So it's not calling out to my ADFS server. Shouldn't it just do this automatically - the user shouldn't have to click a "log me in" button.

I've referenced the following NuGet packages:

<PackageReference Include="Microsoft.AspNetCore.Authentication.WsFederation" Version="3.1.0-preview2.19528.8" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.0-preview2.19528.8" />

I have even followed Microsoft's example for Use WS-Federation without ASP.NET Core Identity, but with no luck.

like image 289
DrGriff Avatar asked Nov 12 '19 20:11

DrGriff


People also ask

How do I add authentication to Blazor?

To enable authentication for the Blazor server-side app, select the Configure for HTTPS check box in the Advanced section. Then, click the Change link in the Authentication section. Step 4: A new dialog will appear. In that, select the Individual User Accounts option and then click OK.

How do you secure Blazor WebAssembly?

Blazor WebAssembly apps are secured in the same manner as single-page applications (SPAs). There are several approaches for authenticating users to SPAs, but the most common and comprehensive approach is to use an implementation based on the OAuth 2.0 protocol, such as OpenID Connect (OIDC).

How do I authorize a component in Blazor?

[Authorize] attribute Only use [Authorize] on @page components reached via the Blazor Router. Authorization is only performed as an aspect of routing and not for child components rendered within a page. To authorize the display of specific parts within a page, use AuthorizeView instead.


Video Answer


1 Answers

This I an older post, but still pops up first in Google for me so..

I had more or less arrived at the same issue. The OP's post in this thread helped me:

Blazor - Securing using ADFS with local DB repository: how/when to hook into SQL

More specifically, the middleware added to Configure() method made a difference. I ended up with this in my solution:

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

app.Use(async (context, next) =>
{
    ClaimsPrincipal user = context.User;

    if (!user.Identities.Any(x => x.IsAuthenticated))
    {
       await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme).ConfigureAwait(false);
    }

    if (next != null)
    {
       await next().ConfigureAwait(false);
    }
});            
like image 126
Alistair Avatar answered Dec 29 '22 13:12

Alistair