Open Closed

ImpersonateTenant not work with subdomain tenant resolver #6813


User avatar
0
hitaspdotnet created
  • ABP Framework version: v8.1.0-rc.1

  • UI Type: MVC

  • Database System: MongoDB

  • Tiered (for MVC) or Auth Server Separated (for Angular): yes/ ABP Studio Microservice

  • Exception message and full stack trace: N/A

  • Steps to reproduce the issue: N/A

Hi, I added subdomain tenant resolver to my abp application. everything works except "login as this tenant" and user menus "Security Log" & "My Account" has invalid url (actually I fixed it with {0} replacer).
When I trying to impersonate tenant from host dashboard it's just redirect to the host home page. I think this is related to the tenant resolver. I expected it to impersonate the tenant on the host domain. Do we have a list of resolvers? Can we fix this by resolvers ordering?


12 Answer(s)
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    How do you configure the subdomain tenant resolver?

    Could you share your steps?

  • User Avatar
    0
    hitaspdotnet created

    Hi,

    How do you configure the subdomain tenant resolver?

    Could you share your steps?

    in web, web.public & authserver I added:

    Configure<AbpTenantResolveOptions>(options =>
    {
        options.AddDomainTenantResolver(configuration["TenantDomain"]);
    });
    

    also this config in their appSettings:

    "TenantDomain": "https://{0}.app.domain.com"
    ...
    "TenantDomain": "https://{0}.pub.domain.com"
    ...
    "TenantDomain": "https://{0}.auth.domain.com"
    

    in authserver module:

    PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
    {
        options.EnableWildcardDomainSupport = true;
        options.WildcardDomainsFormat.Add(configuration["WildCardDomains:AuthServer"]);
        options.WildcardDomainsFormat.Add(configuration["WildCardDomains:Web"]);
        options.WildcardDomainsFormat.Add(configuration["WildCardDomains:PublicWeb"]);
    });
    

    and authserver's appSettings:

    "WildCardDomains": {
        "AuthServer": "https://{0}.auth.domain.com",
        "Web": "https://{0}.app.domain.com",
        "PublicWeb": "https://{0}.pub.domain.com"
    }
    

    then in web & web.public :

    if (Convert.ToBoolean(configuration["AuthServer:IsOnK8s"]))
    {
        context.Services.Configure<OpenIdConnectOptions>(
            "oidc", options =>
            {
                options.MetadataAddress = configuration["AuthServer:MetaAddress"]!.EnsureEndsWith('/') +
                                          ".well-known/openid-configuration";
    
                var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider;
                options.Events.OnRedirectToIdentityProvider = async ctx =>
                {
                    ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') + "connect/authorize";
    
                    var currentTenant = ctx.HttpContext.RequestServices.GetRequiredService<ICurrentTenant>();
                    var tenantDomain = configuration["TenantDomain"];
    
                    if (currentTenant.IsAvailable && !string.IsNullOrEmpty(tenantDomain))
                    {
                        ctx.ProtocolMessage.IssuerAddress =
                            ctx.ProtocolMessage.IssuerAddress.Replace("{0}", $"{currentTenant.Name}");
                    }
                    else
                    {
                        ctx.ProtocolMessage.IssuerAddress =
                            ctx.ProtocolMessage.IssuerAddress.Replace("{0}.", string.Empty);
                    }
    
                    if (previousOnRedirectToIdentityProvider != null)
                    {
                        await previousOnRedirectToIdentityProvider(ctx);
                    }
                };
    
                var previousOnRedirectToIdentityProviderForSignOut =
                    options.Events.OnRedirectToIdentityProviderForSignOut;
                options.Events.OnRedirectToIdentityProviderForSignOut = async ctx =>
                {
                    // Intercept the redirection for signout so the browser navigates to the right URL in your host
                    ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') +
                                                        "connect/logout";
    
                    var currentTenant = ctx.HttpContext.RequestServices.GetRequiredService<ICurrentTenant>();
                    var tenantDomain = configuration["TenantDomain"];
                    if (currentTenant.IsAvailable &&
                        !string.IsNullOrEmpty(tenantDomain))
                    {
                        ctx.ProtocolMessage.IssuerAddress =
                            ctx.ProtocolMessage.IssuerAddress.Replace("{0}", $"{currentTenant.Name}");
                    }
                    else
                    {
                        ctx.ProtocolMessage.IssuerAddress =
                            ctx.ProtocolMessage.IssuerAddress.Replace("{0}.", string.Empty);
                    }
    
                    if (previousOnRedirectToIdentityProviderForSignOut != null)
                    {
                        await previousOnRedirectToIdentityProviderForSignOut(ctx);
                    }
                };
            }
        );
    }
    

    and the userMenu in web & web.public

    var authServerUrl = _configuration["AuthServer:Authority"] ?? "~";
    var returnUrl = _configuration["App:SelfUrl"] ?? "";
    
    var currentTenant = context.ServiceProvider.GetRequiredService<ICurrentTenant>();
    var tenantDomain = _configuration["TenantDomain"];
    
    if (currentTenant.IsAvailable && !string.IsNullOrEmpty(tenantDomain))
    {
        authServerUrl = authServerUrl.Replace("{0}", $"{currentTenant.Name}");
        returnUrl = tenantDomain.Replace("{0}", $"{currentTenant.Name}");
    }
    else
    {
        authServerUrl = authServerUrl.Replace("{0}.", string.Empty);
    }
    

    I kept gateways and services as before except openIddict data seeder.

  • User Avatar
    0
    hitaspdotnet created

    is it possible to impersonate tenant on the host domain? If yes, please guide me!

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    There should be work. because the tenant is first determined from the current user and not the domain

    image.png

    And it works for me

    Configure<AbpTenantResolveOptions>(options =>
    {
        options.AddDomainTenantResolver("{0}.localhost");
    });
    

    2024-03-07 15.31.43.gif

  • User Avatar
    0
    hitaspdotnet created

    Do I need to config AuthServer:Authority in authServer too? After clicking on Login I see redirect to auth.domain.com which is host's issuer and then redirected to host home page.
    the url after click on login:

    https://auth.tonner.io/connect/authorize?client_id=Web&redirect_uri=https%3A%2F%2Fapp.tonner.io%2Fsignin-oidc&response_type=code%20id_token&scope=&response_mode=form_post&nonce=&access_token=&tenantid=bec78466-c1c3-d8dc-beb3-3a112a214a25&tenantusername=admin&returnurl=https%3A%2F%2Fapp.tonner.io%2FSaas%2FHost%2FTenants&state=&x-client-SKU=ID_NET8_0&x-client-ver=7.0.3.0
    
  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer
  • User Avatar
    0
    hitaspdotnet created

    NO, I shared my code as you asked, and already added this.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    Hi,

    Can you try to remove the if (Convert.ToBoolean(configuration["AuthServer:IsOnK8s"])) code?

    image.png

    Then you can test it locally to see if it works

  • User Avatar
    0
    hitaspdotnet created

    Hi,
    seems we have a PR related to this issue, Enable Login with this tenant for templates contains microservice-template label.
    please guide me using that PR if possible.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The PR is basically the same as your code.

    Did you remove the if (Convert.ToBoolean(configuration["AuthServer:IsOnK8s"])) code?

  • User Avatar
    0
    hitaspdotnet created

    hi

    The PR is basically the same as your code.

    Did you remove the if (Convert.ToBoolean(configuration["AuthServer:IsOnK8s"])) code?

    image.png
    now I see an error, my application is running on k8s, so the value is always true. I'm not sure why it made effect. however, how I can solve this error?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please remember to configure the ImpersonationTenantPermission and ImpersonationUserPermission permissions

    See https://docs.abp.io/en/commercial/latest/modules/account/impersonation

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
Do you need assistance from an ABP expert?
Schedule a Meeting
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.2.0-preview. Updated on March 25, 2025, 11:10