Open Closed

Error - Impersonating user from tenant #3022


User avatar
0
webking-abp2 created
  • ABP Framework version: v5.2.1
  • UI type: Angular
  • DB provider: MongoDB
  • Tiered (MVC) or Identity Server Separated (Angular): no
  • Exception message and stack trace:

Request url: https://localhost:44308/connect/token

Request payload: access_token: **** grant_type: Impersonation Client_Id: **** Client_Secret: null TenantId: **** UserId: ****

This is from the log: [ERR] Grant validation error: Value cannot be null. (Parameter 'value')

System.ArgumentNullException: Value cannot be null. (Parameter 'value') at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue) at System.Security.Claims.Claim..ctor(String type, String value) at Volo.Abp.Account.Web.ExtensionGrantValidators.ImpersonationExtensionGrantValidator.ImpersonateUserAsync(ExtensionGrantValidationContext context, Nullable`1 tenantId, Guid userId) at Volo.Abp.Account.Web.ExtensionGrantValidators.ImpersonationExtensionGrantValidator.ValidateAsync(ExtensionGrantValidationContext context) at IdentityServer4.Validation.ExtensionGrantValidator.ValidateAsync(ValidatedTokenRequest request)

  • Steps to reproduce the issue:"
  1. Create a tenant with two user accounts
  2. Login as a tenant admin user.
  3. Go to identity management, users page
  4. Select a user to impersonate
  5. The following error is logged and impersonation fails

4 Answer(s)
  • User Avatar
    0
    PSTEELNZ created

    I have also reproduced this same issue in my application

    **ABP Framework version: ** v5.2.1 **UI type: ** Angular **DB provider: ** Entity Framework Core Tiered (MVC) or Identity Server Separated (Angular): no

    [11:36:13 DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:396534cd-6df9-2a23-e034-3a030f5495eb,n:AbpIdentity.Users.Impersonation [11:36:13 DBG] Found in the cache: pn:U,pk:396534cd-6df9-2a23-e034-3a030f5495eb,n:AbpIdentity.Users.Impersonation [11:36:13 DBG] PermissionStore.GetCacheItemAsync: pn:R,pk:admin,n:AbpIdentity.Users.Impersonation [11:36:13 DBG] Found in the cache: pn:R,pk:admin,n:AbpIdentity.Users.Impersonation [11:36:13 DBG] PermissionStore.GetCacheItemAsync: pn:C,pk:ePlus_App,n:AbpIdentity.Users.Impersonation [11:36:13 DBG] Found in the cache: pn:C,pk:ePlus_App,n:AbpIdentity.Users.Impersonation [11:36:13 ERR] Grant validation error: Value cannot be null. (Parameter 'value') System.ArgumentNullException: Value cannot be null. (Parameter 'value') at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue) at System.Security.Claims.Claim..ctor(String type, String value) at Volo.Abp.Account.Web.ExtensionGrantValidators.ImpersonationExtensionGrantValidator.ImpersonateUserAsync(ExtensionGrantValidationContext context, Nullable`1 tenantId, Guid userId) at Volo.Abp.Account.Web.ExtensionGrantValidators.ImpersonationExtensionGrantValidator.ValidateAsync(ExtensionGrantValidationContext context) at IdentityServer4.Validation.ExtensionGrantValidator.ValidateAsync(ValidatedTokenRequest request)

  • User Avatar
    0
    webking-abp2 created

    @PSTEELNZ Thanks for your response. I have hope that abp support sees this so we can get an answer, because we are not getting anywhere here with this "bug" at the moment. It seems like there might be something wrong when you download the Framework maybe from the beginning?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I will check this.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    solution:

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.RemoveAll(x => x.ImplementationType == typeof(ImpersonationExtensionGrantValidator));
        context.Services.AddTransient<IExtensionGrantValidator, MyImpersonationExtensionGrantValidator>();
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using IdentityServer4.Validation;
    using Microsoft.Extensions.Localization;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Volo.Abp.Account.Localization;
    using Volo.Abp.Account.Public.Web;
    using Volo.Abp.Account.Web.ExtensionGrantValidators;
    using Volo.Abp.Authorization.Permissions;
    using Volo.Abp.Identity;
    using Volo.Abp.MultiTenancy;
    using Volo.Abp.Security.Claims;
    using Volo.Abp.Users;
    
    namespace MyCompanyName.MyProjectName;
    
    public class MyImpersonationExtensionGrantValidator : ImpersonationExtensionGrantValidator
    {
        private readonly ITenantStore _tenantStore;
    
        public MyImpersonationExtensionGrantValidator(
            ITokenValidator tokenValidator,
            IPermissionChecker permissionChecker,
            ICurrentTenant currentTenant,
            ICurrentUser currentUser,
            IdentityUserManager userManager,
            ICurrentPrincipalAccessor currentPrincipalAccessor,
            IdentitySecurityLogManager identitySecurityLogManager,
            ILogger<MyImpersonationExtensionGrantValidator> logger,
            IStringLocalizer<AccountResource> localizer,
            IOptions<AbpAccountOptions> abpAccountOptions,
            Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<IdentityUser> claimsFactory, ITenantStore tenantStore)
            : base(tokenValidator, permissionChecker, currentTenant, currentUser, userManager, currentPrincipalAccessor, identitySecurityLogManager, logger, localizer, abpAccountOptions, claimsFactory)
        {
            _tenantStore = tenantStore;
        }
    
         protected async override Task ImpersonateUserAsync(ExtensionGrantValidationContext context, Guid? tenantId, Guid userId)
        {
            if (userId == CurrentUser.Id)
            {
                context.Result = new GrantValidationResult
                {
                    IsError = true,
                    Error = Localizer["Volo.Account:YouCanNotImpersonateYourself"]
                };
                return;
            }
    
            if (AbpAccountOptions.ImpersonationUserPermission.IsNullOrWhiteSpace() ||
                await PermissionChecker.IsGrantedAsync(AbpAccountOptions.ImpersonationUserPermission))
            {
                using (CurrentTenant.Change(tenantId))
                {
                    var user = await UserManager.FindByIdAsync(userId.ToString());
                    if (user != null)
                    {
                        var sub = await UserManager.GetUserIdAsync(user);
    
                        var additionalClaims = new List<Claim>();
                        if (CurrentUser.Id?.ToString() != CurrentUser.FindClaim(AbpClaimTypes.ImpersonatorUserId)?.Value)
                        {
                            additionalClaims.Add(new Claim(AbpClaimTypes.ImpersonatorUserId, CurrentUser.Id.ToString()));
                            additionalClaims.Add(new Claim(AbpClaimTypes.ImpersonatorUserName, CurrentUser.UserName));
                            if (CurrentTenant.IsAvailable)
                            {
                                additionalClaims.Add(new Claim(AbpClaimTypes.ImpersonatorTenantId, CurrentTenant.Id.ToString()));
    
                                var tenantConfiguration = await _tenantStore.FindAsync(CurrentTenant.Id.Value);
                                if (tenantConfiguration != null && !tenantConfiguration.Name.IsNullOrWhiteSpace())
                                {
                                    additionalClaims.Add(new Claim(AbpClaimTypes.ImpersonatorTenantName, tenantConfiguration.Name));
                                }
                            }
                        }
    
                        await AddCustomClaimsAsync(additionalClaims, user, context);
    
                        context.Result = new GrantValidationResult(
                            sub,
                            GrantType,
                            additionalClaims.ToArray()
                        );
    
                        //save security log to user.
                        var userPrincipal = await ClaimsFactory.CreateAsync(user);
                        userPrincipal.Identities.First().AddClaims(additionalClaims);
                        using (CurrentPrincipalAccessor.Change(userPrincipal))
                        {
                            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
                            {
                                Identity = IdentitySecurityLogIdentityConsts.Identity,
                                Action = "ImpersonateUser"
                            });
                        }
                    }
                    else
                    {
                        context.Result = new GrantValidationResult
                        {
                            IsError = true,
                            Error = Localizer["Volo.Account:ThereIsNoUserWithId"].ToString()
                                .Replace("{UserId}", userId.ToString())
                        };
                    }
                }
            }
            else
            {
                context.Result = new GrantValidationResult
                {
                    IsError = true,
                    Error = Localizer["Volo.Account:RequirePermissionToImpersonateUser"].ToString()
                        .Replace("{PermissionName}", AbpAccountOptions.ImpersonationUserPermission)
                };
            }
        }
    }
    
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11