heimdall

πŸ” RBAC Implementation Plan - Heimdall SDR

Status: βœ… COMPLETE
Started: 2025-11-08
Completed: 2025-11-08
Owner: fulgidus
Progress: 24/24 tasks complete (100%)


πŸ“‹ Executive Summary

Implementation of Role-Based Access Control (RBAC) for Heimdall with the introduction of Constellations - logical groupings of WebSDR stations that can be owned, shared, and managed by users with different permission levels.

Key Concepts


🎯 Goals

  1. βœ… Introduce Constellation concept (grouping of SDR stations)
  2. βœ… Implement ownership model for Constellations, Sources, Models
  3. βœ… Add permission-based sharing (read/edit) for all owned resources
  4. βœ… Enforce role-based access control (USER/OPERATOR/ADMIN)
  5. βœ… Create frontend UI for managing Constellations and sharing
  6. βœ… Maintain backward compatibility with existing data

πŸ—οΈ Architecture Decisions

βœ… User Assignment to Constellations

Decision: Use constellation_shares table with permission field (β€˜read’|’edit’)

Rationale:

βœ… Backend RBAC Strategy

Decision: Hybrid approach

Rationale:

βœ… Frontend Guards Strategy

Decision: Dual approach

Rationale:


πŸ“Š Permission Matrix

Resource USER OPERATOR ADMIN
Constellations View assigned (read) CRUD owned/shared (edit) Full access
Sources View public/shared CRUD owned/shared Full access
Models View shared CRUD owned/shared Full access
Sessions Start on assigned constellations Full control on accessible Full control
WebSDRs View all (global) View all + assign to constellations Full access
System Settings ❌ ❌ βœ…

Role Definitions

πŸ”΅ USER

🟒 OPERATOR

πŸ”΄ ADMIN


πŸ—„οΈ Database Schema

New Tables

constellations

Represents a logical grouping of WebSDR stations.

CREATE TABLE constellations (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    name VARCHAR(255) NOT NULL,
    description TEXT,
    owner_id VARCHAR(255) NOT NULL,  -- Keycloak user ID (sub claim)
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_constellations_owner ON constellations(owner_id);

constellation_members

Many-to-many relationship: Constellations ↔ WebSDR Stations.

CREATE TABLE constellation_members (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    constellation_id UUID NOT NULL REFERENCES constellations(id) ON DELETE CASCADE,
    websdr_station_id UUID NOT NULL REFERENCES websdr_stations(id) ON DELETE CASCADE,
    added_at TIMESTAMPTZ DEFAULT NOW(),
    added_by VARCHAR(255),  -- User who added this SDR
    UNIQUE(constellation_id, websdr_station_id)
);

CREATE INDEX idx_constellation_members_constellation ON constellation_members(constellation_id);
CREATE INDEX idx_constellation_members_websdr ON constellation_members(websdr_station_id);

constellation_shares

User access permissions for constellations.

CREATE TABLE constellation_shares (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    constellation_id UUID NOT NULL REFERENCES constellations(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL,  -- Keycloak user ID
    permission VARCHAR(20) NOT NULL CHECK (permission IN ('read', 'edit')),
    shared_by VARCHAR(255) NOT NULL,  -- User who created the share
    shared_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(constellation_id, user_id)
);

CREATE INDEX idx_constellation_shares_constellation ON constellation_shares(constellation_id);
CREATE INDEX idx_constellation_shares_user ON constellation_shares(user_id);

source_shares

User access permissions for known sources.

CREATE TABLE source_shares (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    source_id UUID NOT NULL REFERENCES known_sources(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL,
    permission VARCHAR(20) NOT NULL CHECK (permission IN ('read', 'edit')),
    shared_by VARCHAR(255) NOT NULL,
    shared_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(source_id, user_id)
);

CREATE INDEX idx_source_shares_source ON source_shares(source_id);
CREATE INDEX idx_source_shares_user ON source_shares(user_id);

model_shares

User access permissions for ML models.

CREATE TABLE model_shares (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL,
    permission VARCHAR(20) NOT NULL CHECK (permission IN ('read', 'edit')),
    shared_by VARCHAR(255) NOT NULL,
    shared_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(model_id, user_id)
);

CREATE INDEX idx_model_shares_model ON model_shares(model_id);
CREATE INDEX idx_model_shares_user ON model_shares(user_id);

Modified Tables

known_sources

Add ownership and public visibility.

ALTER TABLE known_sources 
    ADD COLUMN owner_id VARCHAR(255),
    ADD COLUMN is_public BOOLEAN DEFAULT false;

CREATE INDEX idx_known_sources_owner ON known_sources(owner_id);
CREATE INDEX idx_known_sources_public ON known_sources(is_public);

models

Add ownership and description.

ALTER TABLE models 
    ADD COLUMN owner_id VARCHAR(255),
    ADD COLUMN description TEXT;

CREATE INDEX idx_models_owner ON models(owner_id);

recording_sessions

Link sessions to constellations.

ALTER TABLE recording_sessions 
    ADD COLUMN constellation_id UUID REFERENCES constellations(id);

CREATE INDEX idx_recording_sessions_constellation ON recording_sessions(constellation_id);

πŸ”§ Implementation Tasks

βœ… Phase 1: Database Foundation

Goal: Create database schema and migration scripts

βœ… Phase 2: Backend Models

Goal: Create SQLAlchemy ORM models for new tables

βœ… Phase 3: Backend RBAC Utilities

Goal: Create reusable permission checking functions

βœ… Phase 4: Backend API - Constellations

Goal: Create REST API for constellation management

βœ… Phase 5: Backend API - Existing Resources

Goal: Add RBAC checks to existing endpoints

βœ… Phase 6: Frontend Authentication

Goal: Create authentication hooks and utilities

βœ… Phase 7: Frontend UI

Goal: Create user-facing pages and components

βœ… Phase 8: Testing

Goal: Ensure correctness and reliability

βœ… Phase 9: Documentation

Goal: Document RBAC system for developers and users


πŸ“‚ File Structure

heimdall/
β”œβ”€β”€ db/
β”‚   └── migrations/
β”‚       β”œβ”€β”€ 04-add-rbac-schema.sql          [Task 1]
β”‚       └── 05-migrate-existing-data.sql    [Task 13]
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ common/
β”‚   β”‚   └── auth/
β”‚   β”‚       β”œβ”€β”€ models.py                   [Task 7 - update]
β”‚   β”‚       β”œβ”€β”€ rbac.py                     [Task 6 - new]
β”‚   β”‚       └── tests/
β”‚   β”‚           └── test_rbac.py            [Task 21]
β”‚   └── backend/
β”‚       └── src/
β”‚           β”œβ”€β”€ models/
β”‚           β”‚   β”œβ”€β”€ constellation.py        [Task 2 - new]
β”‚           β”‚   β”œβ”€β”€ shares.py               [Task 4 - new]
β”‚           β”‚   β”œβ”€β”€ db.py                   [Task 3 - update]
β”‚           β”‚   └── session.py              [Task 5 - update]
β”‚           β”œβ”€β”€ routers/
β”‚           β”‚   β”œβ”€β”€ constellations.py       [Task 8, 9 - new]
β”‚           β”‚   β”œβ”€β”€ sources.py              [Task 11 - new]
β”‚           β”‚   β”œβ”€β”€ models.py               [Task 12 - new]
β”‚           β”‚   └── sessions.py             [Task 10 - update]
β”‚           └── tests/
β”‚               └── test_constellations.py  [Task 22]
└── frontend/
    └── src/
        β”œβ”€β”€ store/
        β”‚   └── authStore.ts                [Task 16 - update]
        β”œβ”€β”€ hooks/
        β”‚   β”œβ”€β”€ useAuth.ts                  [Task 14 - new]
        β”‚   └── usePermissions.ts           [Task 14 - new]
        β”œβ”€β”€ components/
        β”‚   β”œβ”€β”€ auth/
        β”‚   β”‚   └── RequireRole.tsx         [Task 15 - new]
        β”‚   └── sharing/
        β”‚       └── ShareModal.tsx          [Task 19 - new]
        └── pages/
            β”œβ”€β”€ Constellations.tsx          [Task 17 - new]
            └── Dashboard.tsx               [Task 18 - update]

πŸ§ͺ Testing Strategy

Unit Tests

Integration Tests

End-to-End Tests


πŸš€ Deployment Checklist

Pre-Deployment

Deployment Steps

  1. Backup database (critical!)
  2. Run migration: 04-add-rbac-schema.sql
  3. Run data migration: 05-migrate-existing-data.sql
  4. Deploy backend with new RBAC code
  5. Deploy frontend with new UI
  6. Verify: Check admin can access all data
  7. Verify: Check operator can create constellations
  8. Verify: Check user can view assigned constellations

Post-Deployment


πŸ“ Progress Tracking

Completed Tasks

In Progress

None - All tasks complete!

Blocked

None

Completed

All 24 tasks completed successfully! βœ… RBAC implementation ready for production deployment.


πŸ› Known Issues / Decisions Needed

Issue 1: Default Admin User ID

Question: What is the Keycloak user ID (sub claim) for the default admin user?
Impact: Need this for data migration (Task 13)
Resolution: Check Keycloak realm export or query Keycloak API

Issue 2: WebSDR Global Visibility

Confirmed: All WebSDR stations remain globally visible (not owned).
Users with operator+ role can assign any WebSDR to their constellations.

Issue 3: Backward Compatibility

Strategy: Create a default β€œGlobal” constellation containing all existing SDRs.
Assign it to admin user. This preserves existing workflows.



πŸ“ž Questions / Clarifications

If you have questions about this implementation:

  1. Check this document first
  2. Check related documents above
  3. Ask in project discussion

Last Updated: 2025-11-08 by fulgidus
Status: βœ… COMPLETE - Ready for production deployment
Next Steps: Follow deployment checklist above to deploy RBAC to production