Open leastprivilege opened 3 years ago
I have a multi-tenancy token service built on top of IDS. I rely on Scoped services to lock me into the tenant and the current tenant's client. For my client config I have extra stuff over what IDS's Client has. One of those is
public string Issuer { get; set; }
For my use-case I wanted the Issuer to be configurable at the Client level.
To get it to work I had to make my own;
public class MyDefaultTokenService : DefaultTokenService
{
public override async Task<Token> CreateAccessTokenAsync(TokenCreationRequest request)
{
...
var client = request.ValidatedRequest.Client as ClientExtra;
var issuer = client.Issuer;
if (string.IsNullOrWhiteSpace(issuer))
{
issuer = ContextAccessor.HttpContext.GetIdentityServerIssuerUri();
}
...
}
}
The more I think about it, an IIssuerProvider
would be more suitable for DefaultTokenService to have and then it allows extensibility anywhere in the Scope.
When we think about this can we make sure that Issuer, and things like it can come from any level of the configuration? Per Tenant, Per Client, etc.
Do you want feedback on this, or do you pretty much have your plan in place already?
We haven't planned anything yet. So -yes ;)
@leastprivilege and @brockallen , Nowadays, lot of projects use this package https://www.finbuckle.com/MultiTenant/Docs/Authentication
Yes, Finbuckle is great, and I use (and contribute to) it. I do not think there is any need to replicate features from that package, but to make it easier in IS for packages like that to work harmoniously.
There really isn't much that needs to happen on IS from my experience other than guidance. I know the argument has been "there are a bunch of ways to do multi tenancy" and I suppose that's true to a degree. But just getting the guidance up to the point of here are two simple paths you could take, arc values or Uri, and show them in the context of even the simplest use case of database per tenant.
If you wanted to extend it, some sugar methods/options such as the ability to make things tenant aware would be helpful. things like the ability to modify routing based on if/where a tenant name would be in the address and options such as whether to include the tenant's name as part of the issuer if it's in the path.
But again, if there is guidance there, even the above isn't necessary.
Thanks! Looks interesting - we have some other ideas as well. But will definitely have a closer look and see how it aligns with our plans.
@natelaff , Per Tenant discovery endpoint? Per Tenant signing credential? Per Tenant Domain cookie? are some design choices.
Yes the discovery endpoint I was considering as part of routing. In IS4 I currently implement my own IEndpointRouter to use the tenant.
The cookie is easy enough to accomplish with Finbuckle. The per tenant signing would be interesting though not something I have a requirement for.
@natelaff , Multiple issuers are part of Enterprise edition which is the most expensive option.
I've been able to achieve much of this just by using Autofac's Multitenancy DI. https://github.com/autofac/Autofac.AspNetCore.Multitenant
Just an idea for whomever is looking for this capability now.
@Cephei , How many of these were you able to implement?
@maulik-modi @tmeers Hey, sorry for the delay; just got back to work today.
My needs for multi-tenancy are most likely unique and different to how Duende should implement multi-tenancy. Duende would likely be more interested in creating a pure multi-tenant solution like what you're describing. This would be similar to how Auth0, Okta, Ping, etc work.
I'll try to be succinct in describing my requirements for multi-tenancy. My company was acquired by a larger org within the past year. Since then, we've acquired four other companies & product suites. So it's been my task to create a new identity foundation and unify all products that have disparate user stores, hostnames, APIs. The best example I can provide that everyone here can probably relate-to is how Google & Youtube work. e.g. When you login to Google or gmail, you are automatically logged into youtube.com as well. And vice-versa.
So for us, when you login to Product 1/domain 1, you seamlessly login to all products N in our ecosystem - across domain boundaries. There is no SSO mechanism for this kind of functionality that browsers natively support - mainly due to browser cookie security policies. Hence the reason Google is pushing for browsers to adopt & implement First-Party-Sets. see: https://developer.chrome.com/docs/privacy-sandbox/first-party-sets/
Therefore, when I wrote earlier in this thread of multi-tenancy, I should have been more clear in my intent. Our IdentityServer solution is only administered by our organization and is not being used to create a true multi-tenant identity platform for un-related business entities. Each "tenant" for us, is owned by our parent organization and we likely want to share some of IdSrv's configuration between tenants.
To circle back to and answer your original question, we simply don't have a need for all your check boxes to be checked to meet our requirements for multi-tenancy - just a few, however, the project is still underway and I expect to refine the solution and possibly add more functionality you described.
// Extensibility points were introduced so that disparate user stores can be queried.
// Each application must be able to control the UIOptions endpoints e.g. LoginUrl
Would be nice because we have multiple APIs that all have different
scope
functionality. A single discovery doc is not desirable because we currently hide all our Scope & Claims information from being discoverable as it would be confusing.
This will be an interesting problem for us because nearly all of our large enterprise customers use their own federated identity solution to login to one of our products via SAML, WS-Fed, and OIDC. We will be migrating all of them to IdSrv and away from Auth0, our current solution. Because I've been focused on SSO within our own first-party-set of applications/clients, I haven't yet spent much time working with IdSrv's DynamicProviders except for some basic shelled-out abstractions, but it will be critical and required as it continues development. Currently, I've left authentication schemes as shared which is odd/incorrect, but just to get the ball rolling and working.
// All tokens issued are signed using our shared .NET DataProtection. Token validation will be done at the Gateway.
// Our single IdentityServer solution is being hosted/accessible by multiple domain names. ie. Multi-issuer. This typically works out-of-the-box with Duende. But this would be critical for a true multi-tenant solution.
// I think you meant to write IdentityServerOptions? Since our tenants are all first-party, we actually want to share this configuration.
// I don't think we'll have a need for this, but it's possible. TBD
IdentityServerOptions
, PersistentGrantOptions
, DynamicProviderOptions
So this is quite different than what most people here may be interested in when talking about adding multi-tenancy to Duende.
Unfortunately, I think to turn IdentityServer into a truly multi-tenant identity solution it may need to find a way to completely host all ASP.Net services (IServiceCollection) in a multi-tenant DI fashion. The only way I've seen cleanly to do this is using Autofac's multi-tenancy support (see https://autofac.readthedocs.io/en/latest/integration/aspnetcore.html#using-a-child-scope-as-a-root), however, that means hosting multiple Kestrels on different ports. I've yet to see a clean solution for hosting ASP.NET on a single port with all IServiceCollection being resolved with some kind of tenant-registration & resolver.
I've only briefly looked at Finbuckle, but perhaps it may help in some regard, though I would prefer to see Duende rollout their own implementation instead of an additional external lib dependency. It looks like Finbuckle supports loading tenants dynamically from a DB, but I think it would be necessary to plug-in IdSrv's DynamicProviders Per-Finbuckle-Tenant.
Just would like to add, with Duende's Identity Provider store, and Managed Keys store, that might check a couple boxes when using something like Finbuckle per-tenant databases. I have not tried yet but with more of Duende's config existing in the DB, and more configuration in the DB, the cleaner the path is.
i dont see a need to customize IS4 to include per tenant dicovery point as it can be achieved by injecting a query or header param depending on your Saaskit or finbuckle multitenant strategy, as for the authentication it can be achieved through the per tenantoption , but i do see a need for documentation on how to integrate them
Wanted to check in to see if this is still targeting the 7.0 release? We are starting brand new development with IS and need to implement Multi-Tenant (Clients, User Stores, Scopes, etc). Honestly, at this point I don't know what all the requirements are because those above me don't know what they need. The main thing I know is that Users must have their own user store.
The main thing I know is that Users must have their own user store.
This one is the easy one, and since that's mainly your code it's not something IdentityServer needs to do much about.
need to implement Multi-Tenant (Clients, User Stores, Scopes, etc).
If you really find you have this requirement, let us know please. Most people don't, at least in my experience.
For reference: https://github.com/DuendeSoftware/Support/issues/147
After having read several treads, I could not find a solution for the PersistedGrantDbContext operational store. I noticed that the database is required during app.UseIdentityserver() and at this point there is no HttpContext and no valid tenant. Is there a a possibility to have a per-tenant operational store or are there plans to support this?
While everything is already doable with various extensibility points etc - it would be nice to have this as a 1st class citizen
per tenant