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?

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

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

    Hi,

    How do you configure the subdomain tenant resolver?

    Could you share your steps?

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    hitaspdotnet created

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

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

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

    And it works for me

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

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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=<scopes>&response_mode=form_post&nonce=<nonce>&access_token=<token>&tenantid=bec78466-c1c3-d8dc-beb3-3a112a214a25&tenantusername=admin&returnurl=https%3A%2F%2Fapp.tonner.io%2FSaas%2FHost%2FTenants&state=<state>&x-client-SKU=ID_NET8_0&x-client-ver=7.0.3.0
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

    Hi,

    Will this can help you?

    https://github.com/abpframework/abp-samples/blob/master/DomainTenantResolver/MVC-TIERED/src/Acme.BookStore.Web/BookStoreWebModule.cs#L162-L176

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    hitaspdotnet created

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

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    liangshiwei created
    Fullstack Developer

    Hi,

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

    Then you can test it locally to see if it works

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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?

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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?

    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?

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • 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

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.