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

Multi tenancy support #442

Closed
BradleyBarnett opened this issue Oct 26, 2016 · 26 comments
Closed

Multi tenancy support #442

BradleyBarnett opened this issue Oct 26, 2016 · 26 comments

Comments

@BradleyBarnett
Copy link

Hi guys,

We are currently building out our own OAuth server using IdentityServer4 for SSO between our various apps. However our application is multi-tenant, with hundreds of clients.

I noticed this thread regarding identity server 3 around using separate cookies for each "tenant" which would allow us to big "logged in" to more than 1 client at a time.
IdentityServer/IdentityServer3#947

Has this progressed at all with Identity Server 4?

Currently it seems the only way to manage this would be to have a separate domain for each client on the identity server? With hundreds of client this would not be ideal, and a separate cookie would be much easier to manage. (eg idsrv_)

Do you have any opinions or other options for how this design should be handled?

Thanks,
Brad

@brockallen
Copy link
Member

So what we're planning is:

  • You have control over all of the UI and login code, so you can issue multiple cookies (or a single cookie with multiple identities). This cookie would probably be different than the IdentityServer cookie.
  • You need to use our cookie to communicate to IdentityServer which identity is the "current" one.
  • You can implement the IAuthorizeInteractionResponseGenerator which allows your logic to decide if the user needs to be prompted for login or be redirected to a custom page before the authorization response is created. This custom page could be your "account chooser" page. Your logic would perhaps check if the tenant for the current authorization requests matches the current identity's tenant, then success. Otherwise send the user to an account chooser, or login page.

We don't have any docs on this, but if you want to give it a try and let us know if you're able to do what you want to, we'd appreciate it. Then if you run into any roadblocks, you can let us know so we can make changes.

@khelben
Copy link

khelben commented Nov 2, 2016

I've created a small example application on how we have tackled multitenancy https://github.com/khelben/IdsvrMultiTenantExample

Herein the IdSvr is hosted in a tenant specific route /tenants/<tenant>/...idsvr....

For extra safety, we've scoped the IdSvr cookie name with the tenant also.

I'm interested in knowing what you think about this.

Christiaan

@BradleyBarnett
Copy link
Author

Hey Brock,

The solution seems to work for a "multiple account" scenario where by you have multiple accounts and want to switch between them. (ie like gmail / gapps does if you have a "work" and a "personal" account.)

However what we are looking for is the ability to have multiple logins simultaneously where both accounts are active in different browser windows. The websites that the auth service is providing access to all run in client specific domains (eg clientname.OurAppDomain.com) which allows our support staff and our users who have logins to multiple "tenants" to access these simultaneously (as the session cookie is in separate domains once logged in).

However, when switching out app specific logins with a central auth service for our newer development which is API backed, we didn't want to have to introduce another full set of tenant domains. So we want the auth service (in a single domain -eg login.OurAppDomain.com) to auth for all tenants.

Basically what we hoped to do was attach acr_values containing the client ID we are requesting access for to each identity server call, then validate that the user has already logged in to that specific tenant on identity server. In the case they are logged into two tenants with two separate user accounts, the acr_value would help us determine the tenant specfic cookie to look for.

On the surface is seems like @khelben's solution may work. Just trying to ascertain if it has any other drawbacks.

Brad

@khelben
Copy link

khelben commented Nov 3, 2016

Hey @TooMuchTaurine,

actually we have the same idea if I understand your point correctly.

From what I understand is that you want to be able to allow to login a user with the same credentials in the different client applications which are tenant specific. Correct?

We've solved this by implementing 2 different auth servers based on IdSvr4.

The first is the multi tenant aware version (as shown in the example) hosted on https://auth.example.com/tenants/<tenant>/

The other one is a central one hosted on https://auth.example.com/.

The general idea is the following: the first one acts as a gateway in which the second one is configured as an external provider. This also allows us to configure other external providers per tenant.
So let's say when one tenant/customer wants to use his own authentication provider (SAML, google, etc...) this can be perfectly done by configuring the external provider for that tenant.

I'd love to know your ideas/remarks on this architecture.

I'll be planning another sample where this architecture is used.

Christiaan

@schatekar
Copy link
Contributor

@khelben

I have created an issue in your repo to ask a couple of questions I have on your implementation. I am trying to solve a similar problem at the moment but have a different design in mind. I will add another comment here with what I am thinking.

@schatekar
Copy link
Contributor

@brockallen @TooMuchTaurine @khelben

We have similar requirements around multi-tenancy. We have several multi-tenanted applications that need to single sign on into each other. We also need an ability to do external SSO but I will come to that later. For the internal SSO, one of the situations could be as below

There are two products - Product 1 and Product 1. and two tenants Tenant 1 and Tenant 2.

I am thinking I can make use of domains to make multi-tenancy and SSO work. Product 1 will be hosted on product1.tenant1.com and product1.tenant2.com for two tenants respectively. In the same manner, Product 2 will be hosted on product2.tenant1.com and product2.tenant2.com. Note that, it is actually a single instance of Product 1 and Product 2 that is deployed with multiple hostnames added to it.

For identity server, I will have a single deployment of it with two hostnames configured as identity.tenant1.com and identity.tenant2.com.

With this setup, any cookies issued by any of the applications will be tied to TLD which is tenant1.com for the first tenant and tenant2.com for the second tenants.

Is there any reason why this will not work?

The external SSO is a bit more complicated. Tenant 1 may need a SAML-based external SSO whereas Tenant 2 may need a custom one. I am not sure there is a way to support this without refactoring at least a part of identity server.

@schatekar
Copy link
Contributor

@TooMuchTaurine @khelben

I have setup a very basic multi-tenant version of Identity Server according to the design I described in my previous comment. You can check the code out if you want. This is not a production quality code and the does not do a lot of things aka a lot of hard-codings. I just wanted to make sure that the idea works. I coming days I will add the description of some more implementation.

Let me know what you think.

@alexsandro-xpt
Copy link

+1

@dmccaffery
Copy link

This is risky business as folks will want to use the same username and password across multiple apps, and you'll run into issues in a great many places.

If you really need to be multi-tenant, I would recommend one of the following:

  1. create a single identity system that is shared by all clients under a single brand. Rely on claims transformation to add scopes / additional app specific details as client scopes based on the client ID, if necessary.

  2. Deploy separate instances of idsrv for each client, in much the same way as you must be doing for the client-specific apps that are trying to share (but not share) the identity system.

I know 2 seems like a drag, but the only truly safe way to do multitenancy is to not share the data store depending on a tenant id; too much potential for cross-client leakage. These are just my 2c based on experience. Multitenancy is normally more trouble than it's worth, long term, especially in this day and age where deployments to IaaS are so lightweight and easier to manage.

@schatekar
Copy link
Contributor

@dmccaffery

IMO the world of multi-tenancy is not very simple. There are tens of ways where each implementation differs from the other. If you operate in B2B space then this becomes even more challenging because you have got a range of people to satisfy. You are generalising by saying "folks will want to use the same username and password". There are several other factors other than the design of your identity server that makes consumers use same or different usernames across websites.

Having said the above, I completely agree with your option 2 if you are capable of doing that with least overhead. This usually means you have automated most tasks around deployment and maintenance. If you still live the old world of manual or semi-automated deployments then that option comes with lot of overheads.

@dmccaffery
Copy link

I am generalizing; yes, but no matter how you slice it, multitenancy is an incredibly difficult problem to solve correctly and to scale correctly; especially if it wasn't a requirement up front and is an afterthought. It's certainly possible; anything is possible; I was just offering my 2cents. :)

@brockallen
Copy link
Member

For everyone involved -- How do you identity the tenant? DNS/host? QS param? Or acr_values tenant param? Also, does tenant mean to you customer isolated version of IdentityServer, or does tenant mean a way to distinguish different groups of users for authentication?

@brockallen
Copy link
Member

brockallen commented Dec 24, 2016

Related: #19

@vdecristofaro
Copy link

In my case the tenant is identified by acr_values param.
Also, the tenant offer a way to distinguish different group Of users for authentication.

@learntecno
Copy link

@brockallen
For everyone involved -- How do you identity the tenant? DNS/host? QS param? Or acr_values tenant param? Also, does tenant mean to you customer isolated version of IdentityServer, or does tenant mean a way to distinguish different groups of users for authentication?

  1. I Identify the tenant by DNS/host
    2)my case tenant means , customer isolated version of IdentityServer (eg Each tenant should have own User data store and Identityserver4 data store .
    Please refer Multi-Tenant #541

@schatekar
Copy link
Contributor

@brockallen For us, it is DNS/host name most of the times. But we have couple of complex examples involving a sub-tenant which we may send in acr values / route paramter /query string

@dguinn-oncore
Copy link

DNS/Host, Different Groups of Users

@BradleyBarnett
Copy link
Author

@brockallen we have gone ahead with DNS / hostname to separate out sessions for each tenant. This allows for users who have access to more than one tenant to avoid issues with sessions interfering with each other (The user / identities for each tenant are stored separately, so logically they are not the same identity in our identity server, even though they maybe be the same physical person with two accounts)

A complication we have found implementing this is when we need to use identity server for Mobile apps. As mobile apps are global and somewhat independent of tenant, we use a generic url configured in the app settings for mobile apps to authenticate against on initial login. The workflow is such that we redirect the user to the correct tenant host in identity server once we have established which tenant the user belongs to (established by email address on the login page). However after rolling this out in beta, we realized that the token endpoints urls as part of the Auth Code flow would need to change to the tenant specific urls after the redirect occurs.

At the moment we have done this by returning an additional parameter on the ReturnURL in the auth code flow along with the code, and then use this in a wrapper around OAuthAuthenticator2 Xamarin.Auth middleware. This is use to update the token endpoint before completing the auth code flow by requesting the access token / refresh token.

We had to jump through a number of hoops to find a way to pass this information back to the mobile app and we are a little worried that the IDSVR4 implementation may change and break this "shoe horn" into the redirectUrl.

Do you have any thoughts on this?

@brockallen
Copy link
Member

@brockallen we have gone ahead with DNS / hostname to separate out sessions for each tenant

Yep, this in effect means you're running different IdentityServers (from the browser perspective).

As mobile apps are global and somewhat independent of tenant

Ahh, you had to go and complicate things! :)

We had to jump through a number of hoops to find a way to pass this information back to the mobile app and we are a little worried that the IDSVR4 implementation may change and break this "shoe horn" into the redirectUrl.

I don't know for certain, to be honest. I considered allowing custom response params in the authorize response... if this were formalized would it help? I don't know how you're doing it now.

@BradleyBarnett
Copy link
Author

yes I think some formal way to pass information back to the client in addition to auth code would be good. At the moment we are implementing a custom AuthorizeResponseGenerator.

   services.AddTransient<IAuthorizeResponseGenerator, CustomAuthorizeResponseGenerator>();

Then in the implementation...

public async Task CreateCodeFlowResponseAsync(ValidatedAuthorizeRequest request)
{
var response = await _authorizeResponseGenerator.Value.CreateCodeFlowResponseAsync(request);

        var url = $"?tokenendpoint={_environmentConfiguration.GetIssuerUri()}/connect/token&";

        // We need to add this domain value to the returned querystring so that mobile applications are able to use the correct authservice for their token request
        request.RedirectUri += url;

        return response;
    }

@brockallen brockallen removed their assignment Jun 20, 2017
@R3vlyn
Copy link

R3vlyn commented Nov 17, 2017

Hello,

For some time i've been busy building an identity-server, some complicated structures came up as i'm trying to implemented multi-tenancy.

I would like to know if there are any security-risks regarding the approach im planning to take. Maybe others are struggling as well and could use an example-structure. The following case is present:

  • One identityserver,
  • Multiple tenants with seperate domains,
  • Multiple user-accounts possible for a user per tenant (Student & Teacher),
  • Registered with multiple tenants under different usernames/email-addresses,
  • SSO required for all tenants at once.

The structure i had in mind:
A user is logged in at the Identityserver. The available clients (applications/tenants) for which de id-server can provide authentication are presented like a hub. One is selected (Company3 for example) and the option to link an account for this specific tenant is available.

The user provides an email (Student@company3.com) and a verification is sent to the user. The identityserver-database holds data regarding a one-to-many relationship between a user and the registered client, and a one-to-many between these registrations and the verified email-addresses.

When logging into the identityserver, the token would hold the data for the tenants and the verified accounts. This token is returned and the current client verifies the token using the key from the discovery-endpoint.

An example of the custom claims would be:
{
"company3":[ "student@company3.com", "teacher@company3.com"]
"company1":[ "student@company1.com", "teacher@company1.com"]
}

Company3 would have secure confirmation that the current user has access to 2 accounts. Company1 would have the same information out the token which makes SSO between the different tenants possible.

As i see it, there wouldnt be any security risks. But, im not very experienced with Identity-servers and authentication yet. I would love some feedback regarding possible security risks.

Cheers

@leastprivilege
Copy link
Member

This seems to be a general question about IdentityServer - not a bug report or an issue.

Please use one of the our free or commercial support options

See here for more details.

Thanks!

@leastprivilege
Copy link
Member

I really can't remember all the details (nor do I want to read that thread again). Please open a more specific issue if this is still a problem.

@R3vlyn
Copy link

R3vlyn commented Nov 23, 2017

@leastprivilege
I asked my question on stackoverflow tagging Identityserver4, no useful reaction so far though. Could you take a look there?

https://stackoverflow.com/questions/47349540/are-there-security-risks-in-managing-multi-tenancy-based-on-claims-using-identit

Thanks :)

@keithpecka3
Copy link

@brockallen sorry for commenting on an old ticket but I wanted to add our experience with this.

Setting up a multi tenant system with subdomains is quite achievable when the client knows which discovery document to go to.

For mobile apps, a global discovery document and jwks endpoint can be setup which redirects to a tenant login page, but like @TooMuchTaurine says, the token, user info and session endpoints are no longer correct.

Information on the correct endpoints to use can be returned in the id_token but this is not ideal as it requires work from the client and it's not possible to change these URLs dynamically in some OpenID client libraries.

It might be nice if there was a standard for clients to use URLs returned in requests.

@lock
Copy link

lock bot commented Jan 13, 2020

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests