Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Multiple authentication schemes and global filters (ASP.NET Core 2) #1559

Closed
johnkors opened this issue Nov 30, 2017 · 12 comments
Closed

Multiple authentication schemes and global filters (ASP.NET Core 2) #1559

johnkors opened this issue Nov 30, 2017 · 12 comments

Comments

@johnkors
Copy link

johnkors commented Nov 30, 2017

Hi,

I'm struggling to get the following auth working in an OK manner, which of I find a quite common use case. I want to co-host a API and a UI within the same ASP.NET Core MVC 2 host, but keeping the authorization setup separate.

  • /api
    Every route starting with /apishould have JWT bearer auth requiring the tokens to contain a specific scope.

  • /anyotherurl :
    Any other URI should use cookies and openid connect, and use a global filter forcing authenticated users, so I don´t need to add an [Authorize] attribute on every new UI controller added to the project now or later.

Issue I'm facing
When I add global filters for cookies, they are applied to my API bits as well. This is undesirable.

            services.AddAuthorization(o =>
            {
     
                var authorizationPolicy = new AuthorizationPolicyBuilder(authenticationSchemes: OpenIdConnectDefaults.AuthenticationScheme)
                    .RequireAuthenticatedUser()
                    .Build();

                o.AddPolicy("RequireLoggedOnUsers", authorizationPolicy);
            });

          services.AddMvc(
                o =>
                {
                    o.Filters.Add(new AuthorizeFilter("RequireLoggedOnUsers"));
                });

I've tried using IActionModelConventions , but it does not seem to do anything to globally applied filters (e.g if I add a global filter for OIDC, I cannot "remove" it from the API routes filters).

Is there any other good way of seperating auth (APIs / UI) whilst also keeping the good parts of having global auth policies applied ..?

A [DisableGlobalFiltersFor("/api")], or a convention that allows for rejecting global filters?

@Eilon
Copy link
Member

Eilon commented Nov 30, 2017

Hi @johnkors , this is indeed an area that is not very easy to work with in 2.0. We are working on some improvements that should make this better in the 2.1 milestone, which you can follow via this issue: #1546

@Eilon Eilon closed this as completed Nov 30, 2017
@johnkors
Copy link
Author

johnkors commented Dec 1, 2017

Not sure I follow how #1546 handles this scenario. #1546 looks like just an helper overload for doing cookies+social. That's not what I'm concerned about here.

@johnkors
Copy link
Author

johnkors commented Dec 1, 2017

Is it not possible to create something that makes a policy only applicable for provided set of routes? In the Katana world, one could at least just use middleware to accomplish seperation.

app.Map(IsApiRequest()), a => a.UseBearer());
app.Map(!IsApiRequest()); a => a.UseCookiesAndOpenId());

@Tratcher
Copy link
Member

Tratcher commented Dec 3, 2017

See #1546 (comment). Map almost worked with Core 1.x, but it won't work at all with the 2.0 design.

@johnkors
Copy link
Author

johnkors commented Dec 14, 2017

Right, thanks. I ended up with something working setting it up like this.

services.AddAuthentication()
    .AddVirtualScheme(VirtualAuthDAuthenticationScheme, VirtualAuthDAuthenticationScheme, o =>
    {
        o.DefaultSelector = c =>
        {           
            if (c.Request.Path.StartsWithSegments("/api"))
            {
                return JwtBearerDefaults.AuthenticationScheme;
            }
            return OpenIdConnectDefaults.AuthenticationScheme;
        };
    })
    .AddCookie()
    .AddOpenIdConnect()
    .AddJwtBearer();
    });

services.AddAuthorization(o =>
{
    var authorizationPolicy = new AuthorizationPolicyBuilder(VirtualAuthDAuthenticationScheme)
        .RequireAuthenticatedUser()
        .Build();
    o.AddPolicy("RequireLoggedOnUsers", authorizationPolicy);
});

services.AddMvc(o =>
{
    o.Filters.Add(new AuthorizeFilter("RequireLoggedOnUsers"));
});

@akashdeep1024
Copy link

@johnkors do you have git hub sample solution of Multiple Scheme and global filter ?

@johnkors
Copy link
Author

johnkors commented Feb 2, 2018

@akashdeep1024 : In the comment above, there's a global filter RequireLoggedOnUsers and 3/4 schemes.

@roa-nyx
Copy link

roa-nyx commented May 7, 2018

@johnkors Sorry to revive this, but I can't find any reference to AddVirtualScheme anywhere offline or online except for some patch notes regarding APIs that are being made public. Is this something that might have been deprecated? Is this still working for you?

EDIT: Nevermind, my apologies. I see now it's a class available in the referenced issue.

@HaoK
Copy link
Member

HaoK commented May 8, 2018

We did tweak things a bit starting in preview2, we enabled the forwarding in all schemes, so you can forward in all existing schemes (i.e. cookies, OAuth, google), AddVirtualScheme was renamed AddPolicyScheme for the scenario where you want a pure virtual scheme that isn't attached to any specific auth handler logic.

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddCookie()
    .AddOpenIdConnect(o.FowardDefaultSelector = c =>
        {           
            if (c.Request.Path.StartsWithSegments("/api"))
            {
                return JwtBearerDefaults.AuthenticationScheme;
            }
            return null; // Don't change the default, could also just return the OIDC default as well
        };
)
    .AddJwtBearer();
    });

@roa-nyx
Copy link

roa-nyx commented May 8, 2018

@HaoK Sounds amazing, can't wait to hack around with that. But I'm working on some production-bound code and need to figure out how to get something done now.

Essentially I am using .AddCookie().AddGoogle() on my authenticationbuilder, but when that comes back with a user I need to A) check that the email ends with a specific domain and B) ask the user to enter a user-specific password or PIN. I've been banging my head against the wall for a while now, and can use any assistance that might be available.

@HaoK
Copy link
Member

HaoK commented May 8, 2018

So you are basically doing two factor auth with Google + PIN/local password? You will just need to build that flow yourself, it shouldn't look that different than what the templates do today, if you didn't want to use identity to do the password verification you would just replaces those calls to your own password verification logic

@hempels
Copy link

hempels commented May 18, 2018

@HaoK, I have a different scenario for combining authentication methods that I'm wondering if it can be handled via VirtualSchemes or (even better) can be achieved without them? Due to the nature of our app (education software) we can have users coming in via a wide number of auth providers, many of them using OAuth 1.0 (specifically, LTI). Rather than always creating a new user account whenever we don't recognize a login and then having to deal with complex identity merges later, we want to invite 'new' users to identify themselves via OpenID (Google and Microsoft primarily since that covers most schools.) We could ask them for their U/P, except we don't do U/P - we have always preferred to only support login via 3rd party identity providers and don't really want to change that.

So the scenario is that one authentication scheme (LTI/OAuth1.0) receives the user's identity info, recognizes that this identity is new to our system, and then forwards a challenge to our default scheme. Upon completion of that scheme (either successful auth or declining (i.e. NoResult)) we would ideally return to the original scheme to complete either creating a new user using the provided claims or adding an additional login to the existing user. Once all of that was complete, the final AuthenticationTicket would be returned and the request would process normally.

https://stackoverflow.com/questions/50421604/

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants