Test Cases: Access Control Enforcement
Module: RBAC - Access Control
Enforcement: auth-service/src/rbac.ts — requirePermission(key) middleware. SUPER_ADMIN bypasses all checks; permission set is cached per (tenant + roleCodes) for 5 minutes; DB errors fail closed (403, never 200).
Prerequisites
- Users with each role available (see RBAC index test-data table).
- Frontend route guards:
AdminRouteredirects an authenticated wrong-role user silently to/home(no 403 page); unauthenticated users go to/login.
Test Data — Users by Role
| User | Role | Primary access |
|---|---|---|
| Admin | ADMIN | Full access (all 38 permissions) |
| Juan Santos | OFFICER | Read-only visibility (members, events, dashboard, bank-accounts view) |
| Ana Reyes | FINANCE_MANAGER | Finance (invoices, payments, dues, donations, bank-accounts) + members/events view |
| Carlos Garcia | EVENT_MANAGER | Events (full) + Broadcasts (full) + members/prospects view |
| Elena Torres | MEMBERSHIP_MANAGER | Members/prospects/invitations/import + events view |
| Seung Eun Lee | COMMUNICATIONS_MANAGER | Broadcasts (full) + members/events view |
| Maria Cruz | MEMBER | Own profile, events, own invoices, directory |
| Roberto Mendoza | GUEST | Public/events only |
Test Cases
TC-RBAC-031: Admin Full Access
| Step | Action | Expected Result |
|---|---|---|
| 1 | Login as ADMIN. Open each admin group: Overview, Finance, Members, Events, Communications, Settings. | All accessible. |
| 2 | Open Settings → Roles & Permissions. | Access granted. |
TC-RBAC-032: Finance Manager — Allowed
| Step | Action | Expected Result |
|---|---|---|
| 1 | Login as Ana Reyes. Open Finance → Invoices, Payments, Donations Report. | Access granted. |
| 2 | Open All Members (view) and All Events (view). | Access granted (view-level). |
TC-RBAC-033: Finance Manager — Denied
| Step | Action | Expected Result |
|---|---|---|
| 1 | As Ana Reyes, browse to /admin/roles and /admin/settings. | Silent redirect to /home. |
| 2 | Confirm no Communications/Broadcasts and no Prospects in sidebar. | Hidden. |
| 3 | API: GET /api/broadcasts as FINANCE_MANAGER. | Status 403. |
TC-RBAC-034: Event Manager — Allowed (incl. Broadcasts)
| Step | Action | Expected Result |
|---|---|---|
| 1 | Login as Carlos Garcia. Create/edit an event; view registrations; perform check-in. | Permitted (EVENTS:*). |
| 2 | Open Communications → Broadcasts; create a draft. | Permitted — EVENT_MANAGER holds COMMUNICATIONS:*. |
TC-RBAC-035: Event Manager — Denied
| Step | Action | Expected Result |
|---|---|---|
| 1 | As Carlos, browse to /admin/invoices / /admin/payments. | No Finance sidebar; route redirects. |
| 2 | API: GET /api/billing/admin/payments as EVENT_MANAGER. | Status 403. |
TC-RBAC-036: Member — Standard Access
| Step | Action | Expected Result |
|---|---|---|
| 1 | Login as Maria Cruz. View/edit own profile; view directory; register for an event; view own invoices. | All granted. |
TC-RBAC-037: Member — Denied Admin Access
| Step | Action | Expected Result |
|---|---|---|
| 1 | As Maria, browse to any /admin/* URL. | Silent redirect to /home; no admin nav visible. |
| 2 | API: GET /api/membership/members as MEMBER. | Status 403 (no MEMBERS:VIEW:members). |
| 3 | API: POST /api/events as MEMBER. | Status 403. |
TC-RBAC-038: Guest — Public Only
| Step | Action | Expected Result |
|---|---|---|
| 1 | Login as Roberto Mendoza (GUEST). View public events. | Granted. |
| 2 | Browse to /directory and any /admin/*. | Both denied/redirected. |
TC-RBAC-039: No Token → 401
| Step | Action | Expected Result |
|---|---|---|
| 1 | Call any protected API (e.g. GET /api/admin/roles) with no Authorization header. | Status 401. |
TC-RBAC-040: Expired / Invalid Token → 401
| Step | Action | Expected Result |
|---|---|---|
| 1 | Call a protected API with an expired or malformed JWT. | Status 401. |
TC-RBAC-041: Conditional UI Rendering
| Step | Action | Expected Result |
|---|---|---|
| 1 | As MEMBER, confirm no admin sidebar groups render. | Hidden (sidebar is role-gated in branding.ts). |
| 2 | As EVENT_MANAGER, confirm the Events group + "Create Event" render. | Shown. |
TC-RBAC-042: Cross-Tenant Isolation
| Step | Action | Expected Result |
|---|---|---|
| 1 | As an RCME admin, attempt to read another tenant's resources (e.g. via a foreign ID). | Denied — not found / forbidden. Permission cache key includes tenantId. |
TC-RBAC-043: SuperAdmin Bypass
| Step | Action | Expected Result |
|---|---|---|
| 1 | Authenticate via POST /api/auth/platform/login as SuperAdmin. Call protected org APIs with the platform JWT. | requirePermission bypasses all checks (platformRoles includes SUPER_ADMIN). |
| 2 | Do NOT log SuperAdmin into the org PWA for tenant-scoped work — use the admin portal (stg-admin.membervu.com). Tenant-scoped org API calls may 401 when the JWT has tenantId: null. | Documented behaviour. |
API Permission Enforcement Matrix
Verified against current route guards (requirePermission(...)). SUPER_ADMIN returns 200 on all org endpoints (bypass) and is omitted for brevity.
| Endpoint (guard) | ADMIN | FINANCE_ MANAGER | EVENT_ MANAGER | MEMBERSHIP_ MANAGER | COMMS_ MANAGER | MEMBER | No token |
|---|---|---|---|---|---|---|---|
GET /api/admin/rolesADMIN:VIEW:roles | 200 | 403 | 403 | 403 | 403 | 403 | 401 |
POST /api/eventsEVENTS:EDIT:events | 200 | 403 | 200 | 403 | 403 | 403 | 401 |
GET /api/billing/admin/paymentsFINANCE:VIEW:payments | 200 | 200 | 403 | 403 | 403 | 403 | 401 |
GET /api/membership/membersMEMBERS:VIEW:members | 200 | 200 | 200 | 200 | 200 | 403 | 401 |
POST /api/membership/members/:id/suspendADMIN or MEMBERSHIP_MANAGER | 200 | 403 | 403 | 200 | 403 | 403 | 401 |
GET /api/broadcastsCOMMUNICATIONS:VIEW:broadcasts | 200 | 403 | 200 | 403 | 200 | 403 | 401 |
GET /api/public/eventspublic | 200 | 200 | 200 | 200 | 200 | 200 | 200 |
Corrected from prior version: GET /api/membership/members is 403 for a plain MEMBER (was wrongly 200); GET /api/broadcasts is 200 for EVENT_MANAGER (was wrongly 403). Endpoint paths were also corrected to the real mounts.