KnightsOfTheRoun
KnightsOfTheRoun

Reputation: 155

Identity Server 4 Multi-tenancy logout

I'm currently developing an identity server. It is multi-tenant with multiple user repositories.

I am able to pass (using Services.OpenIDConnect.Options) my tenant details from my MVC to the IDS in order to select the appropriate user repository on login

options.Events.OnRedirectToIdentityProvider = context =>
{                        
    context.ProtocolMessage.SetParameter("Tenant", "TenantDetail");
    return Task.CompletedTask;
};

I am attempting to obtain this same information for logout, however the initial call to logout has some back end process that calls CustomProfileService.IsActiveAsync(IsActiveContext context).

I am unable to obtain the tenant information from the IsActiveContext, nor am i able to read any kind of query string (as i was using for login).

Any suggestions, or even alternative methods that might be more correct than what I'm attempting, would be greatly appreciated.

Upvotes: 0

Views: 659

Answers (1)

user4864425
user4864425

Reputation:

OnRedirectToIdentityProvider will not be hit on signout. You'll need to pass the tenant information in the OnRedirectToIdentityProviderForSignOut event in your client instead.

Here's a snippet, that's far from complete:

services
    .AddOpenIdConnect("oidc", options =>
    {
        options.Events = new OpenIdConnectEvents
        {
            OnRedirectToIdentityProviderForSignOut = context =>
            {
                context.ProtocolMessage.AcrValues = "tenant:TenantDetail";
                return Task.CompletedTask;
            },
        }
    }

In IdentityServer you'll need to lookup the acr_values in the query parameters from the request. Inject IHttpContextAccessor in order to access the context:

public class ProfileService : IProfileService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ProfileService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // ...
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        // Please note that this method is called on many occasions. Check context.Caller
        // This means that you'll have to make sure that the acr_valus are present on all
        // ocassions, hence the question in my comment.

        var request = _httpContextAccessor.HttpContext.Request;
        if (request.Method == HttpMethods.Get)
        {
            // acr_values should be present on all ocassions.
            var values = (string)request.Query["acr_values"];

            // This is just a sample, you'll need to parse the values.
            var tenant = values.Split(':')[1];
        }

        // Your code where you link the repository ...

        var sub = context.Subject.GetSubjectId();
        var user = await userManager.FindByIdAsync(sub);
        context.IsActive = user != null;
    }
}

Please let me know if this solves the issue for you.

Upvotes: 1

Related Questions