aspnet / Security

[Archived] Middleware for security and authorization of web apps. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
1.27k stars 600 forks source link

[Announcement] WsFederation 2.0.0-preview1 out of band release #1473

Closed Tratcher closed 6 years ago

Tratcher commented 7 years ago

WsFederation preview support is now available for ASP.NET Core 2.0.0. The Microsoft.AspNetCore.Authentication.WsFederation 2.0.0-preview1 package is available at https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.WsFederation/. This is a standalone preview that targets netstandard2.0 and should work with existing ASP.NET Core 2.0.0 applications (.NET Core 2.0 or .NET 4.6.1). A non-preview ASP.NET Core 2.0.0 compatible package will follow once we’ve addressed your feedback.

The code is available at https://github.com/aspnet/security/tree/rel/2.0.0-ws-preview1 and issues can be filed at https://github.com/aspnet/security/issues. Please give us a 👍 from the reactions menu on this post if you have successfully used this component and are ready for the final release.

This component is a port from Microsoft.Owin.Security.WsFederation and uses many of the same mechanics. It has also been updated to integrate with ASP.NET Core 2.0’s authentication model. See the samples below.

Aside from updating the usage pattern to match ASP.NET Core, there are also some functional changes to be aware of. A. This component no longer checks every form post request for sign-in messages by default. Sign-in callbacks are restricted to the "/signin-wsfed" path by default. The CallbackPath can be changed to the application root “/” used by some auth providers if you also enable SkipUnrecognizedRequests to allow sharing that request path with other components. B. This component no longer allows unsolicited logins by default. That WsFederation protocol feature is susceptible to XSRF attacks. See the AllowUnsolicitedLogins option to opt into that feature if your application requires it.

Samples:

For applications only using WsFederation (similar to using OpenIdConnect):

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
        })
        .AddWsFederation(options =>
        {
            options.Wtrealm = Configuration["wsfed:realm"];
            options.MetadataAddress = Configuration["wsfed:metadata"];
        })
        .AddCookie();
    }

    public void Configure(IApplicationBuilder app)
    {
       app.UseAuthentication();

                     // …
    }

For applications using WsFederation with Identity:

        services.AddAuthentication()
            .AddWsFederation(options =>
            {
                options.Wtrealm = Configuration["wsfed:realm"];
                options.MetadataAddress = Configuration["wsfed:metadata"];
            });
Tratcher commented 7 years ago

Good catch. Open a new issue for the events class please.

Zoxive commented 7 years ago

@lzandman There doesnt appear to be a good event hook for wsignoutcleanup1.0. The best place for this is probably custom middleware till its implemented in the WsFederationHandler itself.

Heres a quick example.. I did not test it as im using a custom wsfederationhandler (Till preview 2 comes out) and have it directly in there instead.

app.Use((context, next) =>
{
    var request = context.Request;
    // could look for a specific path as well...
    if (request.Query.TryGetValue("wa", out var wa) && wa == "wsignoutcleanup1.0")
    {
        // Your signin scheme probably cookies
        request.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

        return Task.CompletedTask;
    }

    return next();
});

This would need to be before app.UseAuthentication();

lzandman commented 7 years ago

@Zoxive Thanks. It seems to work.

lzandman commented 7 years ago

@Tratcher I've opened an issue for the WsFederationEvents class: https://github.com/aspnet/Security/issues/1520

lzandman commented 7 years ago

For a different scenario I had to disable the automatic redirect to ADFS signin. I did this by handling the RedirectToIdentityProvider event and calling HandleResponse(). It now returns a 401 status. The calling client then acts on that 401 by calling a different controller action and this controller action has to do the actual redirection to ADFS. For this it has to determine the full ADFS URL. In our legacy app I call FederatedAuthentication.WSFederationAuthenticationModule.CreateSignInRequest(). What would be the equivalent of that in AspnetCore?

Tratcher commented 7 years ago

@lzandman there is no equivalent, and I don't expect that flow to work with the current implementation. At a minimum you'd be missing the state and correlation cookie. See AllowUnsolicitedLogins above.

Are you trying to use this for an API endpoint / SPA application?

lzandman commented 7 years ago

@Tratcher Yes. We have an Angular client app that calls Web API endpoints. When it hasn't yet been authenticated, the endpoints will redirect to ADFS. We don't want that. We want to handle login from the Angular client itself. So the endpoints should return a 401, on which the client can act and handle the login. For this we have a separate login controller and in this controller we need to determine the ADFS sign-in URL (the URL that the initial endpoint call would have sent us to, if we hadn't disabled its automatic RedirectToIdentityProvider).

Tratcher commented 7 years ago

WsFed is not intended for direct use with WebApis. Look up JwtBearer + Identity Server samples.

lzandman commented 7 years ago

@Tratcher I know. But we have a working app using regular .Net. We're first trying a direct port of it to AspNetCore. Exploring other, more relevant/future-proof solutions later.

Tratcher commented 7 years ago

Then this new handler won't help you much as you've already implemented most of it as a controller. To get the APIs you need you need to go down one layer to IdentityModel. Look and the handler implementation and see what it's calling.

danroot commented 7 years ago

My understanding from the thread above is that MetadataAddress parsing newer ADFS metadata xml is broken until some other libraries come in sync. I was able to get this working by doing my own parsing, and thought I'd share a gist based on that code and a few notes for others having issues with this:

locutus80 commented 6 years ago

So auth is working (using a nightly build), when I hit my site directly. We have a portal, using the same WSFed endpoint, that loads my site in an IFRAME. Using Fiddler, I can see that our STS sees I'm signed in (to the portal) and the IFRAME redirects back to my site

/signin-wsfed but then in my site's logfiles I can see the attached error. error.txt

I've disabled token validation as much as I know how:

.AddWsFederation(options => { options.Wtrealm = Configuration["Authentication:WSFederation:Realm"]; options.MetadataAddress = Configuration["Authentication:WSFederation:Metadata"]; options.RequireHttpsMetadata = false; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() { ValidateIssuer = false, ValidateAudience = false, ValidateIssuerSigningKey = false }; })

Strikes me as odd that Fiddler says the request is made over HTTPS but the logfile says HTTP (I've changed the URL in the attachment, but just the hostname part). I'm really not sure what's going on here. Please can someone offer some thoughts?

Tratcher commented 6 years ago

Can you share the fiddler trace?

locutus80 commented 6 years ago

Working on getting the Fiddler trace - the behaviour I described earlier is inconsistent. I've attached my ConfigureServices method's code ConfigureServices.txt

The code drops into the OnRemoteFailure event and the exception I'm getting is SecurityTokenException: No token validator was found for the given token.

I appreciate your help @Tratcher!

Tratcher commented 6 years ago

Update: 2.0.0-preview2 is now available and includes several fixes for reported issues. https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.WsFederation/2.0.0-preview2

We anticipate this will be the last prerelease, please try it and let us know if everything is working as expected. If all goes well we'll release the final build in a few weeks.

danroot commented 6 years ago

I'm able to confirm this update fixes the issue I had parsing metadata xml. It also removed the need to set o.TokenValidationParameters.NameClaimType and o.TokenValidationParameters.RoleClaimType

lejafo commented 6 years ago

Hi everyone! Could someone post a full example of using this lib with sample .net core 2.0 app with ws-fed authorization?

Tratcher commented 6 years ago

There's minimal sample in the branch: https://github.com/aspnet/Security/blob/rel/2.0.0-ws-preview2/samples/WsFedSample/Startup.cs

From the application's perspective this provider works the same way as OpenIdConnect or Facebook. You can use it with either the "Work or School Accounts" or "Individual User Accounts" templates.

jeszulc commented 6 years ago

Running into an issue parsing Saml tokens with empty AttributeValue nodes using preview 2. Filed an issue over at https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/847

reicher001 commented 6 years ago

Thanks Chris.

I was able to get the WSFedSample working. We will continue to work through this implementation and report any issues we run into.

Are we still on track to have the final release out in the next few weeks?

Tratcher commented 6 years ago

Yes, especially if we get more positive feedback.

arc2018 commented 6 years ago

I am using preview2 and I followed @Zoxive sample. I am able to set the configuration correctly and am able to get the idp server's login page. But after authentication and redirect from idp to my localhost, it throws this error: Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10503: Signature validation failed. (full message attached) error.txt

ConfigureServices.txt

update: Originally I got this error: 'Microsoft.IdentityModel.Xml.XmlValidationException: IDX30207: SignatureMethod is not supported: 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'. rsa-sha1 not supported error.txt then I changed the ID server to use sha2, which resulted in the other error about validation failure.

Tratcher commented 6 years ago

@brentschmaltz can you take a look?

brownbl1 commented 6 years ago

I am also using preview2, and have followed the preceding discussion. Many of your comments were helpful, especially @lzandman 's. But I'm still having an infinite loop redirect issue and want to make sure I've configured things correctly on my side.

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
    services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
    })
    .AddWsFederation(options =>
    {
        options.Wtrealm = "http://myapp.azurewebsites.net/";
        options.MetadataAddress = "https://myidp.com/FederationMetadata/2007-06/FederationMetadata.xml";
        options.Wreply = "https://localhost:44313/signin-wsfed";
    })
    .AddCookie();

    services.AddMvc();
    }

Request/Response loop

Request
GET https://localhost:44313/

Response
302
location: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9
set-cookie :.AspNetCore.Correlation.WsFederation.rhQwjeG1hWLCa9TsldhzAywHVEdk2-WQz61zESZ87wc=N; expires=Mon, 11 Dec 2017 14:44:20 GMT; path=/signin-wsfed; secure; httponly

Request
GET https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9

Response
200
Cache-Control: no-cache, no-store
Content-Type: text/html; charset=utf-8
Set-Cookie: bt=; domain=myidp.com; expires=Tue, 12-Oct-1999 00:00:00 GMT; path=/; secure; HttpOnly
Set-Cookie: qa_IMSStsSiteRPCookie=My Sandbox App: http://myapp.azurewebsites.net=pvuy%2bpCDeZ%2flLWsPsrhIBe88tsNmzA9MsYFKLPEOtmi05NwPZotU0w%3d%3d; domain=myidp.com; path=/

Request
POST https://localhost:44313/signin-wsfed
cookie: .AspNetCore.Correlation.WsFederation.rhQwjeG1hWLCa9TsldhzAywHVEdk2-WQz61zESZ87wc=N
origin: https://myidp.com
referer: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJv2eB7jSuMoASukKZtJ-Kf9PwPh0g7jXmdfpct3pnLqJi9iYtNRHj937py-g5eEkI2_V6qv1xhSAGdTan5MNCw8zHUt0Kgqcc4rWd3kNzi8BbJenl71MHfG11AztMeAh4fYhQrOYPlk69cPFFk7QCmUZVuzUbRjjXHusK7voLAL7IQaLOy6G9-c-pS--rSZkmM5dRQkxcwYa6m4PqK7tTS9

Response
302
location: https://myidp.com/?wtrealm=http%3A%2F%2Fmyapp.azurewebsites.net%2F&wa=wsignin1.0&wreply=https%3A%2F%2Flocalhost%3A44313%2Fsignin-wsfed&wctx=CfDJ8AefLzqrkelOjmQtHNwHJJuzaseK_4GJuFNDu2FWTCHJoIsVxj8mnEUYkhP5TZoLqqlCsfn-g7TCLerk0tBEkyDhaeagXBMudoTVcQvmQKT6BQav8jNtBSj4kJkBGyty5iIyhyoEjw9FNJitXrknSu4GXG8rHWXiy0YSJKzgu2eP-aeGIZqFSDWJvyjRWEJQQadTSRbpvAnvosnVKeKRHNYCAtiUr6CrPA294kBL4r-YwOyU2i-iowTeR6rywYv0ZA
set-cookie: .AspNetCore.Correlation.WsFederation.QQiApF7s-8b2A79yT6L4CdRKiUQXajmS12-LcOAY8Dk=N; expires=Mon, 11 Dec 2017 14:44:21 GMT; path=/signin-wsfed; secure; httponly

The first and last requests have the same basic response, though I was expecting the last response to close the authentication loop and redirect me back to https://localhost:44313/. But instead, this cycle repeats indefinitely. The second response in the cycle always returns a different cookie name with the same value, so eventually there are hundreds of aspnet cookies being sent in the third request.

Does anything stick out as wrong on my side?

Thanks.

Tratcher commented 6 years ago

@itslittlejohn what do you have in Startup.Configure? You may be missing UseAuthentication, or it may be in the wrong order.

Note you shouldn't need to set Wreply.

brownbl1 commented 6 years ago

That was it! I positioned app.UseAuthentication(); to the top and it's working. Thanks!

brownbl1 commented 6 years ago

One follow up question. Say you want to access the saml token from an MVC action method once the user has been authenticated? I've been looking for a way to do that, but

(User.Identity as ClaimsIdentity).BootstrapContext

is returning null.

Tratcher commented 6 years ago

@brentschmaltz are you setting the BootstrapContext for WsFed?

brownbl1 commented 6 years ago

No, I'm not. Now that I think about it, in our old ASP.NET WebForms app we're migrating from, we are setting <identityConfiguration saveBootstrapContext="true"> in the web.config. Is this even the right approach for .net core? Essentially we would use the bootstrap context to get the Token string in order to make some REST calls.

UPDATE I found this link which caused me to realize I wasn't saving the token. But setting this causes 5 cookies to be set and I get 400. The size of the request headers is too long.

This reminded me that we've had SessionToken.IsReferenceMode = true set, but I can't find anything like this in the wsfed module.

So assuming this is the right approach, is there something like IsReferenceMode = true in this module?

UPDATE 2 I discovered that it is possible to implement your own "reference mode" by setting options.SessionStore inside the AddCookie callback. See this for what I followed.

lollisoft commented 6 years ago

Hi, I have been monitoring this issue for a while and am waiting for the final release. But as of the new preview 2 version, I tend to give it a try.

My questions are:

Is this used in ASP.Net Core 2.0.0 API clients and in the IdentityServer4?

Or is this only used in the client code?

I am interested into integrating that into IdentityServer4 running in a Docker image on .Net Core 2.

And are there samples for the integration into IdentityServer4?

Thanks for any help, Lothar

Compufreak345 commented 6 years ago

@lollisoft I am currently working on what you describe. Using it as an identity provider you consume it is not that hard if you find out how to configure it. You can get to a pretty good solution if you do it like I described in this StackOverFlow-Post - use the OnTicketReceived-EventHandler from the question together with the code in the response and you are good to go. Thanks to @leastprivilege for helping me out there. But be aware that I tried it with the MVC-example and not with an API client.

For providing a WSFederation-server you have to build against the .Net-Framework 4.6.1 and can use this example as starting point. Regarding to my issue there this WSFederation-preview-release does not help with getting it to full .Net Core, although I had a quick look at the new Identity-stuff over here and it might be possible to use it as there are also methods like "WriteMetaData", but it's quite different and I had too many knowledge-gaps to port it to pure .Net Core. There are also still quite some open issues there.

lollisoft commented 6 years ago

Why do I need the full framework for a WSFederation-server?

I have read that there are two components (XmlEncrypt and XmlDSig) missing in .Net core. (https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/500)

Why is that so complicated to provide equivalent code for these missing functionalities?

In the above topic, I read that it is blocked because they want to also make performance improvements. They also write, one could take the code into .Net core at their own to get it working without API changes and performance improvements.

Is anyone doing this and like to share?

Tratcher commented 6 years ago

@lollisoft this is not suitable for WebApi clients, it's for interactive clients similar to the OpenIdConnect and Facebook providers. It should be interchangeable with those types of providers in IdentityServer4 samples.

lollisoft commented 6 years ago

@Tratcher I don't speak about WebApi clients that run on the client machines. I meant WebApi's that use ws federation as clients, if they came from a ws federated scenario (like login from sharepoint). But I may have an understanding issue about all the auth and federation stuff. I think, the ws fed way is only for applications that do not have OAuth capabilities, such as Sharepoint.

I want to be able to support ws fed within .Net core and like to integrade a sharepoint application into the sample I like to create for my project.

But nevertheless I probably have to read a good book about identity, oauth flows and ws fed scenarios to understand the whole picture.

Currently I am running a net tcp binding (WCF) based Identity provider, but that lacks of the REST capabilities and oauth. I plan to attempt replacing that with IdentityServer4, but then it needs a ws federation capability. The overall plan is also to move toward .Net core at all.

All is still a bit vague and yet only an idea I try to follow :-)

616b2f commented 6 years ago

@lollisoft I have an fork where I try to port the example of WsFederation Implementation from @leastprivilege to aspnet core 2.0. (see here https://github.com/616b2f/IdentityServer4.WsFederation).

It's not ready but it's a starting point, any help wellcome.

lollisoft commented 6 years ago

I'll try to help where I can. I just have setup a new Windows 10 Pro machine in a VM, well licensed. Until an official release is made, I'll use a full framework, but test out aspnet core 2.0 in paralell.

First I have a look at your code and I'll give it a first test to compile and get it running here.

smcl commented 6 years ago

We've done a bit of testing against 2.0.0-preview2 and things seemed to be OK for us. Does anyone have any idea when we might be able to expect the final version released?

selvendiranj-zz commented 6 years ago

we are also eagerly waiting for the final release. we are working on a POC, we are planning to switch to different SSO provider if the final release is not going to be available soon. The Ws federation authentication/authorization feature works very well in asp.net core. it would be great if you release the final version soon. thank you

Tratcher commented 6 years ago

We're almost ready but you all keep sending us feedback 😄 . The new signout cleanup feature isn't working with ADFS so I'm re-designing that (https://github.com/aspnet/Security/issues/1581). The IdentityModel folks have also gotten a lot of feedback and need another week or two to address it.

smcl commented 6 years ago

Cool, thanks for the update! We'll keep our eyes peeled for the announcement.

Keep up the good work 👍

adonnelly commented 6 years ago

Hi, I managed to get this working and users can log in with signed secure tokens. However an encrypted and signed tokens does not work. I can see you do not provide a SecurityTokenHandler for encrypted tokens. Is this something you plan to support?

Tratcher commented 6 years ago

Encrypted tokens aren't supported in this release. See https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/734.

viktor-nikolaev commented 6 years ago

Hello @Tratcher ! What about encrypted saml1 tokens? Will be they supported?

Tratcher commented 6 years ago

@Veikedo not yet. You already found the thread in https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/734.

ryanbuening commented 6 years ago

I'm having an issue getting this to work in my environment. The code appears to be making contact to the IdP and it is returning the assertion URL with the SAML token. However, the FedAuth cookie is not getting created upon the assertion call. I end up in what appears to be an endless redirect loop.

Any ideas what would be causing the cookie to not be created?

My Startup.cs can be viewed here: https://gist.github.com/ryanbuening/d3f8b151b168c4729b518b2157737318.

Tratcher commented 6 years ago

Can you share a Fiddler trace and application logs?

viktor-nikolaev commented 6 years ago

@Tratcher sorry for annoying, but do I understand correctly that enabling saml assertion encryption is overkill?

ryanbuening commented 6 years ago

Can you share a Fiddler trace and application logs?

@Tratcher I sent an email to Tratcher at outlook.com. Thanks.

AnshulKhandelwal02 commented 6 years ago

hi, I am trying to get this added to my existing Core 2.0 + Angular 5 CLI app. I am using the preview template for it. Issue is even after adding the standard configuration, redirect doesn't happen for authentication ! I don't know If I need to add any redirect from Angular for it. But once my app has triggered, I don't think I can add a callback to login then ! Any suggestions on this ? Thanks.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
            })
            .AddWsFederation(options =>
            {
                options.Wtrealm = "[AppID URI from Azure]";
                options.MetadataAddress = "[Federation Metadata XML address from Azure]";
            })
            .AddCookie();

            services.AddMvc();

            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseSpaStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
viktor-nikolaev commented 6 years ago

@AnshulKhandelwal02 this is because your Angular (JavascriptServices) middleware lives outside of MVC pipeline. You need to use smth like this

internal class SpaAuthMiddleware
{
    private readonly RequestDelegate _next;

    public SpaAuthMiddleware(RequestDelegate next)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
    }

    public async Task Invoke(HttpContext context, IAuthorizationService authorizationService)
    {
        if (!context.User.Identity.IsAuthenticated)
        {
            await context.ChallengeAsync().ConfigureAwait(false);
        }
        else
        {
            await _next(context).ConfigureAwait(false);
        }
    }
}
public static class SpaAuthAppBuilderExtensions
{
    public static IApplicationBuilder UseSpaAuthentication(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<SpaAuthMiddleware>();
    }
}

Your Startup.Configure method should be smth like this

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseStaticFiles();

        app.UseMiddleware<WsFederationAuthCleanupMiddleware>();

        app.UseAuthentication();
        app.UseSpaAuthentication();

        app.UseSpaStaticFiles();

        app.UseMvcWithDefaultRoute();

        app.UseSpa(spa => {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                // Run SPA separately => to start Angular server run 'npm start' inside 'ClientApp' folder
                // see also https://github.com/aspnet/JavaScriptServices/issues/1288#issuecomment-346003334
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");

                // Run asp.net and spa together. Just hit F5
                // spa.UseAngularCliServer("start");
            }
        });
    }