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

Official implementation of multitenancy #2673

Closed
alanrezendee opened this issue Oct 2, 2018 · 11 comments
Closed

Official implementation of multitenancy #2673

alanrezendee opened this issue Oct 2, 2018 · 11 comments
Labels

Comments

@alanrezendee
Copy link

Describe the solution you'd like

Definitely and directly, does identity server 4 support multi tenancy?
Could you forward the documentation link with a get starter where you implement this feature?
Thank you!

@brockallen
Copy link
Member

Definitely and directly, does identity server 4 support multi tenancy?

there's nothing in IdentityServer that prevents it. but the problem is that your definition of it is possibly different than many others. much like the whole authentication system, this would be something you would need to implement according to your semantics.

@alanrezendee
Copy link
Author

alanrezendee commented Oct 3, 2018

Definitely and directly, does identity server 4 support multi tenancy?

there's nothing in IdentityServer that prevents it. but the problem is that your definition of it is possibly different than many others. much like the whole authentication system, this would be something you would need to implement according to your semantics.

The multitenancy definition I have in mind for my project is world standard, considering the approach of having only one database, separating the records of each tenancy by the tenantId.
Taking into account your answer, I will consider that if I implement multitenancy in an identity server project when approaching an identity server as a gateway, I will have to implement all infrastructure for multitenancy approach, such as the implementation of tenant identification, the creation of tenantId columns in the model entities that identity implements by default and all other dependencies.

If I do not have anything to add I will close the issue.

@brockallen
Copy link
Member

brockallen commented Oct 3, 2018

separating the records of each tenancy by the tenantId

which records? user records? clients? apis?

also, how do you want to present the tenant identifier? acr_values, host name, something else?

i don't think there's a "world standard" and that's why i said multi-tenancy is different for different people, therefore there are different strategies based on what the real requirements are.

@alanrezendee
Copy link
Author

alanrezendee commented Oct 3, 2018

separating the records of each tenancy by the tenantId

which records? user records? clients? apis?

also, how do you want to present the tenant identifier? acr_values, host name, something else?

i don't think there's a "world standard" and that's why i said multi-tenancy is different for different people, therefore there are different strategies based on what the real requirements are.

Lets go...
Think with me:
In a simple use case we have on one side an api multitenancy web api catering to any business area and on the other side totally uncoupled we have an identity server in the approach of a gateway.
In this model whenever a user interface requires, for example, to register or login a user, I redirect it to an endpoint of my identity server directly without passing through anything (identity as a gateway), and there I need to have implemented a host identification layer to correctly identify the tenancy of the request, and then to follow the flow of the transaction accordingly, ensuring consistency and isolation in tenancy data persistence.

In front of this use case, my question is whether the identity server has some native implementation, and if you do not have it, if it is legal to implement all this control within the identity server, even if this approach is not cool, have some idea at the architecture level of how to implement this control with regard to authentication and authorization, since in multitenancy model, considering the approach I suggested, I need to have in a same database of my identity server, isolated records by tenantId.

In direct answer to your questions:

which records? user records? customers? apis

All records required for isolation: As users, roles, claims, and so on.

do you want to display the tenant identifier? acr_values, hostname, anything?

host

There is a worldwide standard and a person who is multi-tenancy is different for different people

Sorry, I expressed myself very poorly citing a world standard.
It is actually a very common pattern used by the community that implements SASS multitenancy projects, where the data isolation approach is done by the lease tenant id.

@brockallen
Copy link
Member

All of what you are asking for is possible. But some coding must be done on your part to implement these semantics. It's not a built-in feature, though.

@alanrezendee
Copy link
Author

All of what you are asking for is possible. But some coding must be done on your part to implement these semantics. It's not a built-in feature, though.

OK understood! Thank you

@nikoudel
Copy link

nikoudel commented Oct 12, 2018

I'm really struggling with this problem too at the moment. In my case I need IdentityServer to authenticate multiple clients (web applications) like this:

A user goes to http://webserver/app1 and gets redirected to https://identityserver for authentication. Then he opens another tab and goes to http://webserver/app2 expecting to get redirected for authentication again (it's ok if authentication for app1 is lost at that point). What really happens is different - he is already signed in to https://identityserver so gets back to app2 with a wrong identity.

@brockallen here you mentioned:

you can issue multiple cookies (or a single cookie with multiple identities)

But IdentityServerAuthenticationService (in 2.2.0) has this piece of code which rules out multiple identities:

private void AssertRequiredClaims(ClaimsPrincipal principal)
{
    // for now, we don't allow more than one identity in the principal/cookie
    if (principal.Identities.Count() != 1) throw new InvalidOperationException("only a single identity supported");
    if (principal.FindFirst(JwtClaimTypes.Subject) == null) throw new InvalidOperationException("sub claim is missing");
}

The other option is to use multiple cookies but, again, IdentityServerAuthenticationService won't allow that because it relies on the default authentication scheme (i.e. single cookie):

public async Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{
    var defaultScheme = await _schemes.GetDefaultSignInSchemeAsync();
    var cookieScheme = await GetCookieAuthenticationSchemeAsync();

    if ((scheme == null && defaultScheme?.Name == cookieScheme) || scheme == cookieScheme)
    {
        AugmentPrincipal(principal);

        if (properties == null) properties = new AuthenticationProperties();
        await _session.CreateSessionIdAsync(principal, properties);
    }

    await _inner.SignInAsync(context, scheme, principal, properties);
}

So my question is if I need IdentityServer to be multitenant do I have to replace the whole cookie authentication layer?

public static IIdentityServerBuilder AddCookieAuthentication(this IIdentityServerBuilder builder)
{
    builder.Services.AddAuthentication(IdentityServerConstants.DefaultCookieAuthenticationScheme)
        .AddCookie(IdentityServerConstants.DefaultCookieAuthenticationScheme)
        .AddCookie(IdentityServerConstants.ExternalCookieAuthenticationScheme);

    builder.Services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, ConfigureInternalCookieOptions>();
    builder.Services.AddSingleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureInternalCookieOptions>();
    builder.Services.AddTransientDecorator<IAuthenticationService, IdentityServerAuthenticationService>();
    builder.Services.AddTransientDecorator<IAuthenticationHandlerProvider, FederatedSignoutAuthenticationHandlerProvider>();

    return builder;
}

@asharda1
Copy link

asharda1 commented Feb 5, 2019

@brockallen, I am trying to get to the answer from long but not getting anything complete in any discussion thread.
I have very simple multitenancy case, where user login depends on tenantId passed in acr_values by Tenant argument,
Now, I want to pass this claim back to the user by ProfileService, Please do let me know How we can do this.
also this implementation will work for Silent refresh end point or not.

@nikoudel
Copy link

nikoudel commented Feb 5, 2019

Update: my initial plan with http://webserver/app1 and http://webserver/app2 didn't work because of the nonce cookie which is issued for the domain. That's a wrong path.

The proper approach is to use separate subdomains for each application like this: http://app1.webserver, http://app2.webserver. Now each domain has it's own cookies and everything works fine.

@asharda1 the client already passes the clientId claim so it's possible to implement multi-tenancy by using just that. It requires a helper table mapping clients to tenants though.

@AmarPotki
Copy link

@nikoudel It is possible to prepare an example

@lock
Copy link

lock bot commented Jan 11, 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 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

6 participants
@brockallen @AmarPotki @nikoudel @alanrezendee @asharda1 and others