AAE-25392 Convert route guards to functional - part one (#10113)

* AAE-25392 Convert route guards to functional - part one

* AAE-25392 Code improvement
This commit is contained in:
Ehsan Rezaei 2024-08-29 18:07:01 +02:00 committed by GitHub
parent aeee07d82a
commit c876058c51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 92 additions and 80 deletions

View File

@ -16,23 +16,22 @@
*/
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthGuardSsoRoleService } from './auth-guard-sso-role.service';
import { JwtHelperService } from '../services/jwt-helper.service';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { NoopTranslateModule } from '@alfresco/adf-core';
describe('Auth Guard SSO role service', () => {
let authGuard: AuthGuardSsoRoleService;
let jwtHelperService: JwtHelperService;
let routerService: Router;
const state: RouterStateSnapshot = {} as RouterStateSnapshot;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [NoopTranslateModule, MatDialogModule]
});
localStorage.clear();
authGuard = TestBed.inject(AuthGuardSsoRoleService);
jwtHelperService = TestBed.inject(JwtHelperService);
routerService = TestBed.inject(Router);
});
@ -53,54 +52,65 @@ describe('Auth Guard SSO role service', () => {
it('Should canActivate be true if the Role is present int the JWT token', async () => {
spyUserAccess(['MOCK_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard.canActivate(router)).toBeTruthy();
expect(authGuard).toBeTruthy();
});
it('Should canActivate be true if case of empty roles to check', async () => {
spyUserAccess([], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: [] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: [] };
expect(authGuard.canActivate(router)).toBeTruthy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeTruthy();
});
it('Should canActivate be false if the Role is not present int the JWT token', async () => {
spyUserAccess(['MOCK_ROOT_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(router)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
});
it('Should not redirect if canActivate is', async () => {
spyUserAccess(['MOCK_USER_ROLE'], {});
spyOn(routerService, 'navigate').and.stub();
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(router)).toBeTruthy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeTruthy();
expect(routerService.navigate).not.toHaveBeenCalled();
});
it('Should canActivate return false if the data Role to check is empty', async () => {
spyUserAccess(['MOCK_USER_ROLE', 'MOCK_ROOT_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
expect(authGuard.canActivate(router)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
});
it('Should redirect to the redirectURL if canActivate is false and redirectUrl is in data', async () => {
spyUserAccess([], {});
spyOn(routerService, 'navigate').and.stub();
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'], redirectUrl: 'no-role-url' };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'], redirectUrl: 'no-role-url' };
expect(authGuard.canActivate(router)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
expect(routerService.navigate).toHaveBeenCalledWith(['/no-role-url']);
});
@ -108,10 +118,12 @@ describe('Auth Guard SSO role service', () => {
spyUserAccess([], {});
spyOn(routerService, 'navigate').and.stub();
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(router)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
expect(routerService.navigate).not.toHaveBeenCalled();
});
@ -122,7 +134,9 @@ describe('Auth Guard SSO role service', () => {
route.params = { appName: 'mockApp' };
route.data = { clientRoles: ['appName'], roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(route)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
});
it('Should canActivate be false if hasRealm is false and hasClientRole is true', async () => {
@ -132,7 +146,9 @@ describe('Auth Guard SSO role service', () => {
route.params = { appName: 'mockApp' };
route.data = { clientRoles: ['mockApp'], roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(route)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
});
it('Should canActivate be true if both Real Role and Client Role are present int the JWT token', async () => {
@ -142,7 +158,9 @@ describe('Auth Guard SSO role service', () => {
route.params = { appName: 'mockApp' };
route.data = { clientRoles: ['appName'], roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(route)).toBeTruthy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeTruthy();
});
it('Should canActivate be false if the Client Role is not present int the JWT token with the correct role', async () => {
@ -152,7 +170,9 @@ describe('Auth Guard SSO role service', () => {
route.params = { appName: 'mockApp' };
route.data = { clientRoles: ['appName'], roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(route)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
});
it('Should canActivate be false hasRealm is true and hasClientRole is false', async () => {
@ -166,7 +186,9 @@ describe('Auth Guard SSO role service', () => {
route.params = { appName: 'mockApp' };
route.data = { clientRoles: ['appName'], roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'] };
expect(authGuard.canActivate(route)).toBeFalsy();
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeFalsy();
expect(materialDialog.closeAll).toHaveBeenCalled();
});
@ -174,18 +196,23 @@ describe('Auth Guard SSO role service', () => {
it('Should canActivate be false when the user has one of the excluded roles', async () => {
spyUserAccess(['MOCK_USER_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_ANOTHER_ROLE'], excludedRoles: ['MOCK_USER_ROLE'] };
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_ANOTHER_ROLE'], excludedRoles: ['MOCK_USER_ROLE'] };
expect(authGuard.canActivate(router)).toBe(false);
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBe(false);
});
it('Should canActivate be true when the user has none of the excluded roles', async () => {
spyUserAccess(['MOCK_ADMIN_ROLE'], {});
const router: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
router.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'], excludedRoles: ['MOCK_ROOT_USER_ROLE'] };
expect(authGuard.canActivate(router)).toBeTruthy();
const route: ActivatedRouteSnapshot = new ActivatedRouteSnapshot();
route.data = { roles: ['MOCK_USER_ROLE', 'MOCK_ADMIN_ROLE'], excludedRoles: ['MOCK_ROOT_USER_ROLE'] };
const authGuard = TestBed.runInInjectionContext(() => AuthGuardSsoRoleService(route, state));
expect(authGuard).toBeTruthy();
});
});
});

View File

@ -15,63 +15,48 @@
* limitations under the License.
*/
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { inject } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivateFn, Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { UserAccessService } from '../services/user-access.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuardSsoRoleService implements CanActivate {
constructor(private userAccessService: UserAccessService,
private router: Router,
private dialog: MatDialog) {
}
export const AuthGuardSsoRoleService: CanActivateFn = (route: ActivatedRouteSnapshot): boolean => {
const userAccessService = inject(UserAccessService);
userAccessService.fetchUserAccess();
canActivate(route: ActivatedRouteSnapshot): boolean {
this.userAccessService.fetchUserAccess();
let hasRealmRole = false;
let hasClientRole = true;
if (route.data) {
if (route.data['roles']) {
const rolesToCheck: string[] = route.data['roles'];
if (rolesToCheck.length === 0) {
hasRealmRole = true;
} else {
const excludedRoles = route.data['excludedRoles'] || [];
hasRealmRole = this.validateRoles(rolesToCheck, excludedRoles);
let hasRealmRole = false;
let hasClientRole = true;
if (route.data) {
if (route.data['roles']) {
const rolesToCheck: string[] = route.data['roles'];
if (rolesToCheck.length === 0) {
hasRealmRole = true;
} else {
const excludedRoles = route.data['excludedRoles'] || [];
if (excludedRoles?.length > 0) {
hasRealmRole = userAccessService.hasGlobalAccess(rolesToCheck) && !userAccessService.hasGlobalAccess(excludedRoles);
}
}
if (route.data['clientRoles']) {
const clientRoleName = route.params[route.data['clientRoles']];
const rolesToCheck = route.data['roles'];
hasClientRole = this.userAccessService.hasApplicationAccess(clientRoleName, rolesToCheck);
hasRealmRole = userAccessService.hasGlobalAccess(rolesToCheck);
}
}
const hasRole = hasRealmRole && hasClientRole;
if (!hasRole && route?.data && route.data['redirectUrl']) {
this.router.navigate(['/' + route.data['redirectUrl']]);
if (route.data['clientRoles']) {
const clientRoleName = route.params[route.data['clientRoles']];
const rolesToCheck = route.data['roles'];
hasClientRole = userAccessService.hasApplicationAccess(clientRoleName, rolesToCheck);
}
}
const hasRole = hasRealmRole && hasClientRole;
if (!hasRole) {
this.dialog.closeAll();
}
return hasRole;
if (!hasRole && route?.data && route.data['redirectUrl']) {
const router = inject(Router);
router.navigate(['/' + route.data['redirectUrl']]);
}
private validateRoles(rolesToCheck: string[], excludedRoles?: string[]): boolean {
if (excludedRoles?.length > 0) {
return this.hasRoles(rolesToCheck) && !this.hasRoles(excludedRoles);
}
return this.hasRoles(rolesToCheck);
if (!hasRole) {
const dialog = inject(MatDialog);
dialog.closeAll();
}
private hasRoles(roles: string[] = []): boolean {
return this.userAccessService.hasGlobalAccess(roles);
}
}
return hasRole;
};