205 lines
9.3 KiB
TypeScript
205 lines
9.3 KiB
TypeScript
import { TestBed } from '@angular/core/testing';
|
|
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
|
|
import { roleGuard } from './role.guard';
|
|
import { AuthService } from '@services/auth.service';
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Helper: ejecuta el guard en el contexto de inyección de Angular
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
function runGuard(allowedRoles: string[], currentRole: string): boolean | any {
|
|
const route = { data: { allowedRoles } } as unknown as ActivatedRouteSnapshot;
|
|
const state = {} as RouterStateSnapshot;
|
|
const execute: CanActivateFn = (...args) =>
|
|
TestBed.runInInjectionContext(() => roleGuard(...args));
|
|
return execute(route, state);
|
|
}
|
|
|
|
describe('roleGuard — control de acceso por rol', () => {
|
|
let mockRouter: jasmine.SpyObj<Router>;
|
|
let mockAuth: jasmine.SpyObj<AuthService>;
|
|
|
|
beforeEach(() => {
|
|
mockRouter = jasmine.createSpyObj('Router', ['navigate']);
|
|
mockAuth = jasmine.createSpyObj('AuthService', ['getCurrentRole']);
|
|
|
|
TestBed.configureTestingModule({
|
|
providers: [
|
|
{ provide: Router, useValue: mockRouter },
|
|
{ provide: AuthService, useValue: mockAuth },
|
|
],
|
|
});
|
|
});
|
|
|
|
// ── Rutas solo para super-admin ────────────────────────────────────────────
|
|
describe('rutas solo para super-admin [users, roles, env-vars, import-legacy]', () => {
|
|
const onlySuperAdmin = ['super-admin'];
|
|
|
|
it('super-admin puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('super-admin');
|
|
expect(runGuard(onlySuperAdmin, 'super-admin')).toBeTrue();
|
|
});
|
|
|
|
it('ou-admin NO puede acceder → redirige a /groups', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-admin');
|
|
expect(runGuard(onlySuperAdmin, 'ou-admin')).toBeFalse();
|
|
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
|
|
});
|
|
|
|
it('ou-operator NO puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-operator');
|
|
expect(runGuard(onlySuperAdmin, 'ou-operator')).toBeFalse();
|
|
});
|
|
|
|
it('ou-minimal NO puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
|
|
expect(runGuard(onlySuperAdmin, 'ou-minimal')).toBeFalse();
|
|
});
|
|
});
|
|
|
|
// ── Rutas para super-admin + ou-admin ──────────────────────────────────────
|
|
describe('rutas para super-admin + ou-admin [commands, pxe, repositorios, etc.]', () => {
|
|
const adminRoutes = ['super-admin', 'ou-admin'];
|
|
|
|
it('super-admin puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('super-admin');
|
|
expect(runGuard(adminRoutes, 'super-admin')).toBeTrue();
|
|
});
|
|
|
|
it('ou-admin puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-admin');
|
|
expect(runGuard(adminRoutes, 'ou-admin')).toBeTrue();
|
|
});
|
|
|
|
it('ou-operator NO puede acceder → redirige a /groups', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-operator');
|
|
expect(runGuard(adminRoutes, 'ou-operator')).toBeFalse();
|
|
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
|
|
});
|
|
|
|
it('ou-minimal NO puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
|
|
expect(runGuard(adminRoutes, 'ou-minimal')).toBeFalse();
|
|
});
|
|
});
|
|
|
|
// ── Rutas para super-admin + ou-admin + ou-operator ────────────────────────
|
|
describe('rutas para admin + operador [deploy-image, partition-assistant, run-script]', () => {
|
|
const operatorRoutes = ['super-admin', 'ou-admin', 'ou-operator'];
|
|
|
|
it('super-admin puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('super-admin');
|
|
expect(runGuard(operatorRoutes, 'super-admin')).toBeTrue();
|
|
});
|
|
|
|
it('ou-admin puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-admin');
|
|
expect(runGuard(operatorRoutes, 'ou-admin')).toBeTrue();
|
|
});
|
|
|
|
it('ou-operator puede acceder', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-operator');
|
|
expect(runGuard(operatorRoutes, 'ou-operator')).toBeTrue();
|
|
});
|
|
|
|
it('ou-minimal NO puede acceder → redirige a /groups', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
|
|
expect(runGuard(operatorRoutes, 'ou-minimal')).toBeFalse();
|
|
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
|
|
});
|
|
});
|
|
|
|
// ── Verificación de redirección coherente ─────────────────────────────────
|
|
describe('redirección al acceder a rutas no permitidas', () => {
|
|
it('siempre redirige a /groups cuando el acceso es denegado', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
|
|
runGuard(['super-admin'], 'ou-minimal');
|
|
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
|
|
});
|
|
|
|
it('NO redirige cuando el acceso es permitido', () => {
|
|
mockAuth.getCurrentRole.and.returnValue('super-admin');
|
|
runGuard(['super-admin'], 'super-admin');
|
|
expect(mockRouter.navigate).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
// ── Matriz completa de rutas de la aplicación ──────────────────────────────
|
|
describe('matriz de acceso — todas las rutas protegidas de la aplicación', () => {
|
|
interface RouteCase {
|
|
path: string;
|
|
allowedRoles: string[];
|
|
}
|
|
|
|
const routes: RouteCase[] = [
|
|
// solo super-admin
|
|
{ path: 'users', allowedRoles: ['super-admin'] },
|
|
{ path: 'env-vars', allowedRoles: ['super-admin'] },
|
|
{ path: 'roles', allowedRoles: ['super-admin'] },
|
|
{ path: 'import-legacy', allowedRoles: ['super-admin'] },
|
|
// super-admin + ou-admin
|
|
{ path: 'commands', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'commands-task', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'pxe-images', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'pxe', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'pxe-boot-file', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'ogboot-status', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'dhcp-servers', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'boot-servers', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'calendars', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'repositories', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'software', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'software-profiles', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'operative-systems', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'menus', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'hardware', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'hardware-profiles', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
{ path: 'hardware-types', allowedRoles: ['super-admin', 'ou-admin'] },
|
|
// super-admin + ou-admin + ou-operator
|
|
{ path: 'commands-logs', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
|
|
{ path: 'clients/deploy-image', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
|
|
{ path: 'clients/partition-assistant',allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
|
|
{ path: 'clients/run-script', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
|
|
];
|
|
|
|
const rolesTested: Array<{ role: string; canAccess: (r: RouteCase) => boolean }> = [
|
|
{
|
|
role: 'super-admin',
|
|
canAccess: () => true, // puede acceder a todo
|
|
},
|
|
{
|
|
role: 'ou-admin',
|
|
canAccess: r => r.allowedRoles.includes('ou-admin'),
|
|
},
|
|
{
|
|
role: 'ou-operator',
|
|
canAccess: r => r.allowedRoles.includes('ou-operator'),
|
|
},
|
|
{
|
|
role: 'ou-minimal',
|
|
canAccess: () => false, // no puede acceder a ninguna ruta protegida
|
|
},
|
|
];
|
|
|
|
rolesTested.forEach(({ role, canAccess }) => {
|
|
routes.forEach(route => {
|
|
const shouldAccess = canAccess(route);
|
|
const label = shouldAccess
|
|
? `${role} PUEDE acceder a /${route.path}`
|
|
: `${role} NO PUEDE acceder a /${route.path}`;
|
|
|
|
it(label, () => {
|
|
mockAuth.getCurrentRole.and.returnValue(role);
|
|
const result = runGuard(route.allowedRoles, role);
|
|
if (shouldAccess) {
|
|
expect(result).toBeTrue();
|
|
} else {
|
|
expect(result).toBeFalse();
|
|
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
|
|
}
|
|
mockRouter.navigate.calls.reset();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|