Open Closed

The impersonate in ImpersonationService not working #3886


User avatar
0
Pinebits created
  • ABP Framework version: v6.0
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): MVC
  • Exception message and stack trace:
  • Steps to reproduce the issue:"

Usign OpenIdDict

I try to utilize the impersonate({ tenantId, userId }) function in ImpersonationService through Angular in Abp Commercial, but whenever I use it I get the following stack trace in my log:

The event OpenIddict.Validation.OpenIddictValidationEvents+ProcessAuthenticationContext was marked as rejected by OpenIddict.Validation.OpenIddictValidationHandlers+ValidateToken.

The impersonateTenant and impersonateUser in ImpersonationService are both working, but I need to be able to impersonate a tenant user from the host.


4 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    but I need to be able to impersonate a tenant user from the host.

    This is not supported by default, can you share your code?

  • User Avatar
    0
    Pinebits created

    So the function impersonate in ImpersonationService that have tenantid and userid as parameters - this does not work?

    I knew how to do this in Identity Server - but have no reference for Openiddict - do have no code for now! Just trying to use the impersonate function. And I can see that the call is made and that the payload is correct when looking at ImpersonateUser or ImpersonateTenant. But the server code somehow does not work correctly.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Please share the full logs and access_token

  • User Avatar
    1
    Pinebits created

    I have now solved this by doing an override of the existing functionality. Providing code here for others reference:

    1. Create ExtendedImpersonationExtensionGrant.cs in HttpApi.Host
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Volo.Abp.Account.Web.ExtensionGrants;
    using Volo.Abp.Data;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Identity;
    using Volo.Abp.MultiTenancy;
    using Volo.Abp.OpenIddict.ExtensionGrantTypes;
    
    namespace xxx.xxxxxx
    {
        public class ExtendedImpersonationExtensionGrant : ImpersonationExtensionGrant
        {
            protected IDataFilter _dataFilter { get; set; }
    
            public override Task<IActionResult> HandleAsync(ExtensionGrantContext context)
            {
                _dataFilter = ServiceProviderServiceExtensions.GetRequiredService<IDataFilter>(context.HttpContext.RequestServices);
    
                return base.HandleAsync(context);
            }
    
            protected async override Task<IActionResult> ImpersonateUserAsync(ExtensionGrantContext context, ClaimsPrincipal principal, Guid? tenantId, Guid userId)
            {
                if (!tenantId.HasValue && !this.currentTenant.IsAvailable)
                {
                    IdentityUser foundUser = null;
    
                    using (_dataFilter.Disable<IMultiTenant>())
                    {
                        // host user
                        foundUser = await this.userManager.FindByIdAsync(userId.ToString());
                    }
    
                    if (foundUser != null) // impersonate directly into user in tenant!
                    {
                        return await base.ImpersonateUserAsync(context, principal, foundUser.TenantId, foundUser.Id);
                    }
                }
    
                return await base.ImpersonateUserAsync(context, principal, tenantId, userId);
            }
    
            protected async override Task<IActionResult> BackToImpersonatorAsync(ExtensionGrantContext context, ClaimsPrincipal principal, Guid? tenantId, Guid userId)
            {
                IdentityUser foundUser = null;
    
                using (_dataFilter.Disable<IMultiTenant>())
                {
                    // host user
                    foundUser = await this.userManager.FindByIdAsync(userId.ToString());
                }
    
                if (foundUser != null && !foundUser.TenantId.HasValue) // Possible to revert back to host user
                {
                    return await base.BackToImpersonatorAsync(context, principal, foundUser.TenantId, foundUser.Id);
                }
                
                return await base.BackToImpersonatorAsync(context, principal, tenantId, userId);
            }
        }
    }
    
    
    1. in HttpApi.HostModule.cs under ConfigureServices(ServiceConfigurationContext context) function add the following:
    this.Configure<AbpOpenIddictExtensionGrantsOptions>((Action<AbpOpenIddictExtensionGrantsOptions>)(options =>
    {
        options.Grants.Remove("Impersonation");
        options.Grants.Add("Impersonation", (IExtensionGrant)new ExtendedImpersonationExtensionGrant());
    }));
    

    Then it works calling the following in Angular - and you can log in to a user under a tenent directly from a host and back again using standard functions:

    this.impersonationService.impersonateUser(entity.id).subscribe((result) => {
      this.toaster.success('::Logged in - please wait');
    })
    
Made with ❤️ on ABP v9.1.0-preview. Updated on November 11, 2024, 11:11