Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a multitenant auth options sample #4126

Open
HaoK opened this issue Apr 11, 2018 · 8 comments
Open

Add a multitenant auth options sample #4126

HaoK opened this issue Apr 11, 2018 · 8 comments
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer
Milestone

Comments

@HaoK
Copy link
Member

HaoK commented Apr 11, 2018

See aspnet/Security#1718 for more context

@HaoK HaoK self-assigned this Apr 11, 2018
@aagarwal10
Copy link

hi @HaoK - I have scenario of multi-tenant auth, where I need to dynamically add OAuth2 Scheme based on tenant (each tenant has its own OAuth Options) and wire it with cookie scheme for my aspnet core web app (not implemented with any Javascript framework). Please suggest if this is possible with these auth samples. Thanks

@HaoK
Copy link
Member Author

HaoK commented May 18, 2018

Try doing something like this sample aspnet/AuthSamples#44

@aagarwal10
Copy link

aagarwal10 commented May 22, 2018

@HaoK - Is it also possible to add Auth Handler dynamically, similar to adding/removing auth scheme from a controller?

for example in a controller action method, can we do something like?

.AddScheme<SimpleOptions, SimpleAuthHandler>("fromAction", o => o.DisplayMessage = "I am from controller action.")

Also, even if this possible, how can this whole dynamic auth handler registration via action method be done for application running in a web farm.

Actually I have a case where a tenant gets dynamically registered to the web application passing there OAuth Options on the fly. This is scenario of SMART on FHIR (HL7 Standard)

@HaoK
Copy link
Member Author

HaoK commented May 22, 2018

Yes, you can just use the IAuthenticationSchemeProvider and call AddScheme, but you would probably have to have your implementation of this use some kind of shared data store backing the implementation to make them consistent across the web farm.

@aagarwal10
Copy link

aagarwal10 commented Jun 1, 2018

@HaoK -- So I am trying to get PostConfigureOptions going my "SimpleOptions" by registering like this;

 public void ConfigureServices(IServiceCollection services)
       {
            services.AddAuthentication();

           services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();
           services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<SimpleOptions>, SimpleOptionsPostConfigureOptions<SimpleOptions, SimpleAuthHandler>());

           services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
       } 

But the PostConfigure method in my SimpleOptionsPostConfigureOptions never hits ?

here is my SimpleOptionsPostConfigureOptions class, Please suggest whats missing;

public class SimpleOptionsPostConfigureOptions<SimpleOptions, SimpleAuthHandler> : IPostConfigureOptions<SimpleOptions>
       where SimpleOptions : AuthenticationSchemeOptions, new()
       where SimpleAuthHandler : AuthenticationHandler<SimpleOptions>
   {
       public void PostConfigure(string name, SimpleOptions options)
       {
           throw new NotImplementedException();
       }
   }

@muratg
Copy link
Contributor

muratg commented Oct 24, 2018

@HaoK will this be in 2.2, or should we move this out?

@HaoK
Copy link
Member Author

HaoK commented Oct 24, 2018

You can move it out, there's some weird build flakiness that this sample introduces, I will merge it into master once its consistently passing on CI

@natemcmaster natemcmaster transferred this issue from aspnet/AuthSamples Nov 20, 2018
@natemcmaster natemcmaster added this to the 3.0.0-preview2 milestone Nov 20, 2018
@natemcmaster natemcmaster added the area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer label Nov 20, 2018
@muratg muratg modified the milestones: 3.0.0-preview3, 3.0.0 Jan 31, 2019
@HaoK HaoK modified the milestones: 3.0.0, Backlog Apr 17, 2019
@HaoK HaoK removed their assignment Sep 12, 2019
@dasiths
Copy link
Member

dasiths commented May 10, 2020

Assuming we have some sort of middleware that sets the HttpContext.RequestServices for the tenant, If we now resolve the IAuthenticationSchemeProvider we get the correct options for the tenant. But the AuthenticationMiddleware has this injected at construction as a singleton as you know.

Do you see any problems doing this custom AuthenticationMiddleware that has IAuthenticationSchemeProvider injected per request? (In the Invoke() method) Why is it a Singleton to begin with?

Now we can easily have a "container" per tenant with Authentication schemes/options defined there.

Example from:

  1. https://michael-mckenna.com/multi-tenant-asp-dot-net-core-application-tenant-containers
  2. https://michael-mckenna.com/multi-tenant-asp-dot-net-core-application-tenant-specific-authentication
/// <summary>
/// AuthenticationMiddleware.cs from framework with injection point moved
/// </summary>
public class TenantAuthMiddleware
{
    private readonly RequestDelegate _next;

    public TenantAuthMiddleware(RequestDelegate next)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
    }
    
    public async Task Invoke(HttpContext context, IAuthenticationSchemeProvider Schemes)
    {
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });

        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name) 
                as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }

        var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
        if (defaultAuthenticate != null)
        {
            var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
        }
        
        await _next(context);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer
Projects
None yet
Development

No branches or pull requests

7 participants