Open Closed

Impersonation doesn't work as expected when updating ABP from 8.2.2 to 8.3.4 #9035


User avatar
0
alina@iwell.nl created

Upgrading ABP from 8.2.2 to 8.3.4 broke impersonation, because we forgot to add changes to Angular configuration as mentioned in the migration guide. Applying these changes fixed impersonation to the extent that it works again. However, impersonating a user results in a 403 forbidden error. Furthermore, ending the impersonation results in a database concurrency exception in the backend.

We have investigated this issue, but was unable to resolve it. The following steps outline the hypothesis for the occurrence of the 403 forbidden error:

  • Impersonating a user redirects to the application root

  • This causes the canActivate guard to be triggered

  • In this guard the PermissionService is used to determine if the monitoring policy is present

  • This should be false, but returns true, as the Admin user (who can impersonate) has permissions

  • The user is being redirected to the page according to the rights of the Admin user

  • This redirect is not allowed, resulting in the 403 forbidden error - because the impersonated user doesn't have rights

Since impersonation was working before the APB upgrade, something changed from 8.2.2 to 8.3.4 that causes the PermissionService to use permissions from the original token instead of the new token


4 Answer(s)
  • User Avatar
    1
    sumeyye.kurtulus created
    Support Team Angular Expert

    Hello,

    Thank you for providing detailed steps on the issue. Based on your description, I attempted to replicate the problem but was unable to reproduce it in my environment. Here is the configuration I used for testing:

    const oAuthConfig = {
      ...
      impersonation: {
        tenantImpersonation: true,
        userImpersonation: true,
      },
    };
    

    impersonation.gif

    Could you please confirm that this configuration has been applied in your environment as well? Additionally, are there any custom configurations in your routing that impose extra permission checks?

  • User Avatar
    0
    alina@iwell.nl created

    Thank you for checking and your reply!

    I confirm that we have

    const oAuthConfig = {
      ...
      impersonation: {
        tenantImpersonation: true,
        userImpersonation: true,
      },
    };
    

    Steps to reproduce:

    • In app-routing.module.ts create routes

    const routes: Routes = [
        {
            path: '',
            loadChildren: () => import('./modules/page1.module').then((m) => m.Page1Module),
            canActivate: [
                authGuard,
                (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
                    inject(RedirectGuard).canActivate(next, state),
            ],
        },
        {
            path: 'page1',
            loadChildren: () => import('./modules/page1.module').then((m) => m.Page1Module),
        },
        {
            path: 'page2',
            loadChildren: () => import('./modules/page2.module').then((m) => m.Page2Module),
        },
    
    • create a guard canActivate

    @Injectable({
        providedIn: 'root',
    })
    export class RedirectGuard {
        constructor(private router: Router) {}
        canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
            const permissionService = inject(PermissionService);
    
            const canViewPage1 = permissionService.getGrantedPolicy('Portal.Admin');
            if (canViewPage1) {
                this.router.navigate(['/page1']);
                return true;
            }
    
            const canViewPage2 = permissionService.getGrantedPolicy('Portal.All');
            if (canViewPage2) {
                this.router.navigate(['/page2']);
                return true;
            }
            return false;
        }
    }
    
    • Page1 should be available only for admins, who can make impersonation, Page2 - for all

    • Try to impersonate with the user that doesn't have Admin rights. Get 403 error. Refresh the page. Impersonation works.
      Important: This code worked before the migration! Would be nice that 403 error doesn't happen.

    Thank you!

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you for sharing these details. Based on your description, it appears that the issue stems from the impersonation process after migration. To address this, we recommend overriding the existing impersonation logic by implementing a dedicated service, such as CustomImpersonationService.

    To proceed:

    1. Create a new service (CustomImpersonationService) to handle impersonation logic.

    // custom-impersonation.service.ts
    import { PermissionService } from '@abp/ng.core';
    import { inject, Injectable } from '@angular/core';
    import { ImpersonationService } from '@volo/abp.commercial.ng.ui/config';
    import { tap, switchMap, from } from 'rxjs';
    
    @Injectable({
      providedIn: 'root',
    })
    export class CustomImpersonationService extends ImpersonationService {
      protected permissionService = inject(PermissionService);
    
      constructor() {
        super();
      }
    
      override impersonate({
        tenantId,
        userId,
        tenantUserName,
      }: Partial<{
        tenantId: string;
        userId: string;
        tenantUserName: string;
      }>): import('rxjs').Observable<import('@abp/ng.core').AbpAuthResponse> {
        const params = {};
    
        if (tenantId) {
          params['TenantId'] = tenantId;
        }
    
        if (userId) {
          params['UserId'] = userId;
        }
    
        if (tenantUserName) {
          params['TenantUserName'] = tenantUserName;
        }
    
        return this.environment.getEnvironment$().pipe(
          tap(({ oAuthConfig: { responseType } }) => {
            if (responseType === 'code') {
              this.authService.oidc = false;
            }
          }),
          switchMap(() => {
            const promiseOfLogin = this.authService.loginUsingGrant('Impersonation', params);
            return from(promiseOfLogin).pipe(
              tap(() => {
                location.href = this.environment.getEnvironment().application?.baseUrl || '/';
              })
            );
          })
        );
      }
    }
    
    1. Register this service in the providers array within app.module.ts.

    // app.module.ts
    @NgModule({
      ...
      providers: [
        { provide: ImpersonationService, useClass: CustomImpersonationService },
      ],
      ...
    })
    

    Please note that this fix is applicable only to the latest version, as we can only publish updates for that release. Let us know if you need any further guidance—we appreciate your cooperation!

  • User Avatar
    0
    alina@iwell.nl created

    Thank you for a quick response!
    The solution works!

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