tasks ready
This commit is contained in:
34
specs/016-multi-user-auth/checklists/requirements.md
Normal file
34
specs/016-multi-user-auth/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Multi-User Authentication and Authorization
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-01-26
|
||||
**Feature**: [Link to spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
39
specs/016-multi-user-auth/checklists/security.md
Normal file
39
specs/016-multi-user-auth/checklists/security.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Security Requirements Checklist: Multi-User Auth
|
||||
|
||||
**Purpose**: Validate completeness and rigor of security requirements for authentication and authorization.
|
||||
**Created**: 2026-01-27
|
||||
**Feature**: [Link to spec.md](../spec.md)
|
||||
|
||||
## Authentication Security
|
||||
|
||||
- [x] CHK001 Are password complexity requirements specified for local users? [Completeness, Gap] (Covered by T037)
|
||||
- [x] CHK002 Is the exact hashing algorithm (bcrypt) and work factor specified? [Clarity, Spec §Research] (Covered by T006)
|
||||
- [x] CHK003 Are account lockout policies defined for failed login attempts? [Coverage, Gap] (Covered by T033)
|
||||
- [x] CHK004 Is the behavior for inactive/disabled accounts explicitly defined for both local and ADFS users? [Edge Case, Spec §Edge Cases] (Covered by T044)
|
||||
- [x] CHK005 Are requirements defined for session revocation (e.g., logout, admin action)? [Completeness] (Covered by T043)
|
||||
|
||||
## ADFS & SSO Security
|
||||
|
||||
- [x] CHK006 Are token validation requirements (signature, issuer, audience) specified for ADFS OIDC tokens? [Completeness] (Covered by T007)
|
||||
- [x] CHK007 Is the mapping behavior defined when an ADFS user is removed from a mapped AD group? [Edge Case, Gap] (Covered by T028)
|
||||
- [x] CHK008 Are requirements defined for handling ADFS token expiration and refresh? [Coverage] (Covered by T046)
|
||||
- [x] CHK009 Is the JIT provisioning process secure against privilege escalation (e.g., default role)? [Security, Spec §FR-008] (Covered by T028)
|
||||
|
||||
## Authorization & RBAC
|
||||
|
||||
- [x] CHK010 Are "default deny" requirements specified for plugin access? [Clarity, Spec §SC-002] (Covered by T020)
|
||||
- [x] CHK011 Is the behavior defined when a user has multiple roles with conflicting permissions? [Edge Case, Gap] (Covered by T045)
|
||||
- [x] CHK012 Are requirements specified for preventing admins from removing their own admin privileges (lockout prevention)? [Edge Case] (Covered by T022)
|
||||
- [x] CHK013 Is the scope of "Execute" vs "Read" permission clearly defined for each plugin? [Clarity] (Covered by T019)
|
||||
|
||||
## Data Protection
|
||||
|
||||
- [x] CHK014 Are requirements defined for protecting sensitive data (passwords, tokens) in logs? [Completeness, Spec §Constitution] (Covered by T047)
|
||||
- [x] CHK015 Are HttpOnly and Secure flags required for session cookies? [Clarity, Spec §Research] (Covered by T032)
|
||||
- [x] CHK016 Is the storage mechanism for ADFS client secrets defined securely? [Completeness] (Covered by T002)
|
||||
|
||||
## API Security
|
||||
|
||||
- [x] CHK017 Are authentication requirements enforced on ALL API endpoints (except login)? [Coverage] (Covered by T021)
|
||||
- [x] CHK018 Are rate limiting requirements defined for login endpoints to prevent brute force? [Gap] (Covered by T033)
|
||||
- [x] CHK019 Are error messages required to be generic to avoid username enumeration? [Clarity] (Covered by T034)
|
||||
31
specs/016-multi-user-auth/checklists/technical.md
Normal file
31
specs/016-multi-user-auth/checklists/technical.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Technical Readiness Checklist: Multi-User Auth
|
||||
|
||||
**Purpose**: Validate technical specifications, schema, and API contracts.
|
||||
**Created**: 2026-01-27
|
||||
**Feature**: [Link to spec.md](../spec.md)
|
||||
|
||||
## Data Model & Schema
|
||||
|
||||
- [x] CHK001 Are all necessary fields defined for the `User` entity (e.g., last_login)? [Completeness, Spec §Data Model] (Covered by T004)
|
||||
- [x] CHK002 Are foreign key constraints explicitly defined for `ADGroupMapping`? [Clarity, Spec §Data Model] (Covered by T027)
|
||||
- [x] CHK003 Is the uniqueness constraint for `username` and `email` specified? [Consistency] (Covered by T004)
|
||||
- [x] CHK004 Are database migration requirements defined for the new `auth.db`? [Completeness, Gap] (Covered by T005)
|
||||
|
||||
## API Contracts
|
||||
|
||||
- [x] CHK005 Are request/response schemas defined for the `login` endpoint? [Completeness, Spec §Contracts] (Covered by T009)
|
||||
- [x] CHK006 Are error response codes (401, 403, 404) standardized across all auth endpoints? [Consistency] (Covered by T012)
|
||||
- [x] CHK007 Is the structure of the JWT payload (claims) explicitly defined? [Clarity, Spec §Research] (Covered by T007)
|
||||
- [x] CHK008 Are pagination requirements defined for the "List Users" admin endpoint? [Gap] (Covered by T023)
|
||||
|
||||
## Dependencies & Integration
|
||||
|
||||
- [x] CHK009 Are version requirements specified for `Authlib` and `Passlib`? [Clarity, Spec §Plan] (Covered by T001)
|
||||
- [x] CHK010 Is the dependency on the existing `TaskManager` for plugin execution defined? [Integration] (Covered by T021)
|
||||
- [x] CHK011 Are requirements defined for the CLI admin creation tool? [Completeness, Spec §FR-009] (Covered by T008)
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
- [x] CHK012 Is the maximum acceptable latency for auth verification specified? [Clarity, Spec §Plan] (Covered by T013)
|
||||
- [x] CHK013 Are concurrency requirements defined for the SQLite `auth.db` (WAL mode)? [Completeness, Spec §Research] (Covered by T003)
|
||||
- [x] CHK014 Are logging requirements defined for audit trails (who did what)? [Completeness] (Covered by T047)
|
||||
26
specs/016-multi-user-auth/checklists/testing.md
Normal file
26
specs/016-multi-user-auth/checklists/testing.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Testing Requirements Checklist: Multi-User Auth
|
||||
|
||||
**Purpose**: Validate test scenario coverage and strategy.
|
||||
**Created**: 2026-01-27
|
||||
**Feature**: [Link to spec.md](../spec.md)
|
||||
|
||||
## Functional Coverage
|
||||
|
||||
- [x] CHK001 Are positive test scenarios defined for Local Login? [Coverage, Spec §US-1] (Covered by T049)
|
||||
- [x] CHK002 Are positive test scenarios defined for ADFS Login (mocked)? [Coverage, Spec §US-3] (Covered by T050)
|
||||
- [x] CHK003 Are negative test scenarios defined for invalid passwords? [Coverage] (Covered by T049)
|
||||
- [x] CHK004 Are negative test scenarios defined for unauthorized plugin access? [Coverage, Spec §US-2] (Covered by T049)
|
||||
- [x] CHK005 Are test scenarios defined for switching between auth methods on the same screen? [Coverage] (Covered by T050)
|
||||
|
||||
## Edge Cases
|
||||
|
||||
- [x] CHK005 Are test scenarios defined for mixed-case username handling? [Edge Case] (Covered by T049)
|
||||
- [x] CHK006 Are test scenarios defined for ADFS JIT provisioning with missing groups? [Edge Case] (Covered by T050)
|
||||
- [x] CHK007 Are test scenarios defined for accessing the API with an expired token? [Edge Case] (Covered by T049)
|
||||
- [x] CHK008 Are test scenarios defined for concurrent login sessions? [Edge Case] (Covered by T049)
|
||||
|
||||
## Integration & System
|
||||
|
||||
- [x] CHK009 Is the strategy defined for mocking ADFS during CI/CD tests? [Completeness] (Covered by T041)
|
||||
- [x] CHK010 Are end-to-end tests required for the full admin user creation flow? [Coverage] (Covered by T050)
|
||||
- [x] CHK011 Are tests required to verify the CLI admin creation tool? [Coverage] (Covered by T049)
|
||||
31
specs/016-multi-user-auth/checklists/ux.md
Normal file
31
specs/016-multi-user-auth/checklists/ux.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# UX Requirements Checklist: Multi-User Auth
|
||||
|
||||
**Purpose**: Validate user experience and interface requirements.
|
||||
**Created**: 2026-01-27
|
||||
**Feature**: [Link to spec.md](../spec.md)
|
||||
|
||||
## Login Flow
|
||||
|
||||
- [x] CHK001 Are feedback requirements defined for invalid credentials (generic message)? [Clarity, Spec §US-1] (Covered by T016)
|
||||
- [x] CHK002 Is the redirect behavior specified after successful login (dashboard vs deep link)? [Clarity, Spec §US-1] (Covered by T016)
|
||||
- [x] CHK003 Are loading states required during the ADFS redirection process? [Completeness] (Covered by T030)
|
||||
- [x] CHK004 Is the "Session Expired" user flow defined? [Edge Case, Gap] (Covered by T035)
|
||||
- [x] CHK005 Are requirements defined for the dual-mode login screen layout (Form + ADFS Button)? [Clarity, Spec §FR-013] (Covered by T030)
|
||||
|
||||
## Admin Interface
|
||||
|
||||
- [x] CHK005 Are requirements defined for the User Management list view (columns, sorting)? [Completeness] (Covered by T024)
|
||||
- [x] CHK006 Is the feedback mechanism defined for successful/failed user creation? [Clarity] (Covered by T024)
|
||||
- [x] CHK007 Are confirmation dialogs required for deleting users? [Safety, Gap] (Covered by T040)
|
||||
- [x] CHK008 Is the UI behavior defined when assigning roles (dropdown, search)? [Clarity] (Covered by T024)
|
||||
|
||||
## Navigation & Visibility
|
||||
|
||||
- [x] CHK009 Are requirements defined for hiding menu items the user lacks permission for? [Completeness, Spec §FR-006] (Covered by T025)
|
||||
- [x] CHK010 Is the behavior defined if a user tries to access a restricted URL directly? [Edge Case] (Covered by T042)
|
||||
- [x] CHK011 Are user profile/logout controls required to be visible on all pages? [Consistency] (Covered by T025)
|
||||
|
||||
## Accessibility
|
||||
|
||||
- [x] CHK012 Are keyboard navigation requirements defined for the login form? [Coverage] (Covered by T048)
|
||||
- [x] CHK013 Are error message accessibility requirements (ARIA alerts) specified? [Coverage] (Covered by T048)
|
||||
132
specs/016-multi-user-auth/contracts/api.yaml
Normal file
132
specs/016-multi-user-auth/contracts/api.yaml
Normal file
@@ -0,0 +1,132 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Authentication API
|
||||
version: 1.0.0
|
||||
paths:
|
||||
/api/auth/login:
|
||||
post:
|
||||
summary: Login with username/password
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Successful login
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Token'
|
||||
'401':
|
||||
description: Invalid credentials
|
||||
|
||||
/api/auth/login/adfs:
|
||||
get:
|
||||
summary: Initiate ADFS login flow
|
||||
responses:
|
||||
'302':
|
||||
description: Redirect to ADFS provider
|
||||
|
||||
/api/auth/callback/adfs:
|
||||
get:
|
||||
summary: ADFS callback handler
|
||||
parameters:
|
||||
- in: query
|
||||
name: code
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Successful login via ADFS
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Token'
|
||||
|
||||
/api/auth/me:
|
||||
get:
|
||||
summary: Get current user profile
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: User profile
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
|
||||
/api/admin/users:
|
||||
get:
|
||||
summary: List all users
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: List of users
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
post:
|
||||
summary: Create a new user
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserCreate'
|
||||
responses:
|
||||
'201':
|
||||
description: User created
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
schemas:
|
||||
Token:
|
||||
type: object
|
||||
properties:
|
||||
access_token:
|
||||
type: string
|
||||
token_type:
|
||||
type: string
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
roles:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
UserCreate:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
roles:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
86
specs/016-multi-user-auth/data-model.md
Normal file
86
specs/016-multi-user-auth/data-model.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Data Model: Multi-User Authentication
|
||||
|
||||
## Entities
|
||||
|
||||
### User
|
||||
Represents an identity that can authenticate to the system.
|
||||
|
||||
| Field | Type | Description | Constraints |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | UUID | Unique identifier | Primary Key |
|
||||
| `username` | String | Unique login name | Unique, Not Null |
|
||||
| `email` | String | User email address | Unique, Optional |
|
||||
| `password_hash` | String | Bcrypt hash of password | Nullable (if ADFS) |
|
||||
| `auth_source` | Enum | Source of identity | `LOCAL` or `ADFS` |
|
||||
| `is_active` | Boolean | Account status | Default `True` |
|
||||
| `created_at` | DateTime | Timestamp of creation | Auto-generated |
|
||||
| `last_login` | DateTime | Timestamp of last login | Nullable |
|
||||
|
||||
### Role
|
||||
Represents a collection of permissions.
|
||||
|
||||
| Field | Type | Description | Constraints |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | UUID | Unique identifier | Primary Key |
|
||||
| `name` | String | Human-readable role name | Unique, Not Null |
|
||||
| `description` | String | Description of role purpose | Optional |
|
||||
|
||||
### Permission
|
||||
Represents a specific capability within the system.
|
||||
|
||||
| Field | Type | Description | Constraints |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | UUID | Unique identifier | Primary Key |
|
||||
| `resource` | String | Target resource (e.g. `plugin:backup`) | Not Null |
|
||||
| `action` | Enum | Type of access | `READ`, `EXECUTE`, `WRITE` |
|
||||
|
||||
### ADGroupMapping
|
||||
Maps an Active Directory group to a local System Role.
|
||||
|
||||
| Field | Type | Description | Constraints |
|
||||
|-------|------|-------------|-------------|
|
||||
| `id` | UUID | Unique identifier | Primary Key |
|
||||
| `ad_group_name` | String | Name of the group in AD | Unique, Not Null |
|
||||
| `role_id` | UUID | ID of the local role to assign | Foreign Key -> Role.id |
|
||||
|
||||
## Relationships
|
||||
|
||||
- **User <-> Role**: Many-to-Many (via `user_roles` table)
|
||||
- A User can have multiple Roles.
|
||||
- A Role can be assigned to multiple Users.
|
||||
- **Role <-> Permission**: Many-to-Many (via `role_permissions` table)
|
||||
- A Role is defined by a set of Permissions.
|
||||
- A Permission can belong to multiple Roles.
|
||||
|
||||
## Storage Schema (SQLAlchemy)
|
||||
|
||||
```python
|
||||
# Conceptual Schema Definition
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
id = Column(String, primary_key=True, default=generate_uuid)
|
||||
username = Column(String, unique=True, index=True, nullable=False)
|
||||
password_hash = Column(String, nullable=True)
|
||||
auth_source = Column(String, default="local")
|
||||
is_active = Column(Boolean, default=True)
|
||||
roles = relationship("Role", secondary="user_roles", back_populates="users")
|
||||
|
||||
class Role(Base):
|
||||
__tablename__ = "roles"
|
||||
id = Column(String, primary_key=True, default=generate_uuid)
|
||||
name = Column(String, unique=True, nullable=False)
|
||||
permissions = relationship("Permission", secondary="role_permissions")
|
||||
users = relationship("User", secondary="user_roles", back_populates="roles")
|
||||
|
||||
class Permission(Base):
|
||||
__tablename__ = "permissions"
|
||||
id = Column(String, primary_key=True, default=generate_uuid)
|
||||
resource = Column(String, nullable=False) # e.g., "plugin:backup"
|
||||
action = Column(String, nullable=False) # e.g., "execute"
|
||||
|
||||
class ADGroupMapping(Base):
|
||||
__tablename__ = "ad_group_mappings"
|
||||
id = Column(String, primary_key=True, default=generate_uuid)
|
||||
ad_group_name = Column(String, unique=True, nullable=False)
|
||||
role_id = Column(String, ForeignKey("roles.id"), nullable=False)
|
||||
98
specs/016-multi-user-auth/plan.md
Normal file
98
specs/016-multi-user-auth/plan.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Implementation Plan: Multi-User Authentication and Authorization
|
||||
|
||||
**Branch**: `016-multi-user-auth` | **Date**: 2026-01-26 | **Spec**: [`specs/016-multi-user-auth/spec.md`](spec.md)
|
||||
**Input**: Feature specification from `specs/016-multi-user-auth/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
Implement a robust authentication system supporting local users (username/password) and corporate SSO (ADFS via OIDC/OAuth2) simultaneously. The system will enforce Role-Based Access Control (RBAC) to restrict plugin access. Data will be persisted in a dedicated SQLite database (`auth.db`), and sessions will be managed via stateless JWTs. A CLI tool will be provided for initial admin provisioning. The login interface will provide dual options (Form + SSO Button) to ensure administrator access even during ADFS outages.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Python 3.9+ (Backend), Node.js 18+ (Frontend)
|
||||
**Primary Dependencies**:
|
||||
- Backend: FastAPI, Authlib (ADFS/OIDC), Passlib[bcrypt] (Password hashing), PyJWT (Token management), SQLAlchemy (ORM for auth.db)
|
||||
- Frontend: SvelteKit (UI), standard fetch API (JWT handling)
|
||||
**Storage**: SQLite (`auth.db`) for Users, Roles, Permissions, and Mappings.
|
||||
**Testing**: pytest (Backend), vitest/playwright (Frontend)
|
||||
**Target Platform**: Linux server (Dockerized environment)
|
||||
**Project Type**: Web Application (FastAPI Backend + SvelteKit Frontend)
|
||||
**Performance Goals**: <100ms auth verification overhead per request.
|
||||
**Constraints**: Must run in existing environment without external DB dependencies (hence SQLite).
|
||||
**Scale/Scope**: ~10-100 concurrent users, ~5-10 distinct roles.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- [x] **I. Semantic Protocol Compliance**: All new modules will use `[DEF]` anchors and `@RELATION` tags.
|
||||
- [x] **II. Causal Validity**: Contracts (OpenAPI/Pydantic models) will be defined before implementation.
|
||||
- [x] **III. Immutability of Architecture**: No changes to existing core architecture invariants; adding a new `AuthModule` layer.
|
||||
- [x] **IV. Design by Contract**: All auth functions will define `@PRE`/`@POST` conditions.
|
||||
- [x] **V. Belief State Logging**: Auth events will be logged using the standard belief scope logger.
|
||||
- [x] **VI. Fractal Complexity Limit**: Auth logic will be modularized (Service, Repository, API layers).
|
||||
- [x] **VII. Everything is a Plugin**: While core auth is middleware, the *management* of users/roles will be exposed via a System Plugin or dedicated Admin API, respecting the modular design.
|
||||
- [x] **VIII. Unified Frontend Experience**: Login and Admin UI will use standard Svelte components and i18n.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/[###-feature]/
|
||||
├── plan.md # This file (/speckit.plan command output)
|
||||
├── research.md # Phase 0 output (/speckit.plan command)
|
||||
├── data-model.md # Phase 1 output (/speckit.plan command)
|
||||
├── quickstart.md # Phase 1 output (/speckit.plan command)
|
||||
├── contracts/ # Phase 1 output (/speckit.plan command)
|
||||
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── api/
|
||||
│ │ ├── auth/ # New: Auth endpoints (login, logout, refresh)
|
||||
│ │ ├── admin/ # New: Admin endpoints (users, roles)
|
||||
│ │ └── dependencies.py # Update: Add get_current_user, get_current_active_user
|
||||
│ ├── core/
|
||||
│ │ ├── auth/ # New: Core auth logic
|
||||
│ │ │ ├── jwt.py # Token handling
|
||||
│ │ │ ├── security.py # Password hashing
|
||||
│ │ │ └── config.py # Auth settings
|
||||
│ │ └── database.py # Update: Support for multiple DBs (auth.db)
|
||||
│ ├── models/
|
||||
│ │ └── auth.py # New: SQLAlchemy models (User, Role, Permission)
|
||||
│ ├── schemas/ # New: Pydantic schemas for Auth
|
||||
│ │ └── auth.py
|
||||
│ └── services/
|
||||
│ └── auth_service.py # New: Auth business logic
|
||||
└── tests/
|
||||
└── auth/ # New: Auth tests
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── lib/
|
||||
│ │ ├── auth/ # New: Frontend auth stores/logic
|
||||
│ │ └── api/ # Update: Add auth headers to requests
|
||||
│ ├── routes/
|
||||
│ │ ├── login/ # New: Login page
|
||||
│ │ └── admin/ # New: Admin dashboard (Users/Roles)
|
||||
│ └── components/
|
||||
│ └── auth/ # New: Auth components (ProtectedRoute, Login form)
|
||||
```
|
||||
|
||||
**Structure Decision**: Web application structure with separated backend (FastAPI) and frontend (SvelteKit). Auth logic is centralized in `backend/src/core/auth` and `backend/src/services`, with a new persistent store `auth.db`. Frontend will implement a reactive auth store.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
||||
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|
||||
54
specs/016-multi-user-auth/quickstart.md
Normal file
54
specs/016-multi-user-auth/quickstart.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Quickstart: Multi-User Auth
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.9+
|
||||
- Node.js 18+
|
||||
- Existing project environment
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Install Dependencies**:
|
||||
```bash
|
||||
pip install "passlib[bcrypt]" "python-jose[cryptography]" "Authlib" "sqlalchemy"
|
||||
```
|
||||
|
||||
2. **Initialize Database**:
|
||||
Run the migration script to create `auth.db` and tables.
|
||||
```bash
|
||||
python backend/src/scripts/init_auth_db.py
|
||||
```
|
||||
|
||||
3. **Create Admin User**:
|
||||
Use the CLI tool to create the initial superuser.
|
||||
```bash
|
||||
python backend/src/scripts/create_admin.py --username admin --password securepassword
|
||||
```
|
||||
|
||||
## Running the Application
|
||||
|
||||
1. **Start Backend**:
|
||||
```bash
|
||||
cd backend
|
||||
uvicorn src.app:app --reload
|
||||
```
|
||||
|
||||
2. **Start Frontend**:
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
3. **Login**:
|
||||
Navigate to `http://localhost:5173/login` and use the admin credentials created above.
|
||||
|
||||
## Configuring ADFS
|
||||
|
||||
1. Set environment variables in `.env`:
|
||||
```ini
|
||||
ADFS_CLIENT_ID=your-client-id
|
||||
ADFS_CLIENT_SECRET=your-client-secret
|
||||
ADFS_METADATA_URL=https://fs.your-company.com/adfs/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
2. Configure Group Mappings via the Admin UI or API.
|
||||
76
specs/016-multi-user-auth/research.md
Normal file
76
specs/016-multi-user-auth/research.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Research: Multi-User Authentication and Authorization
|
||||
|
||||
## 1. Authentication Strategy
|
||||
|
||||
### Decision: Hybrid Local + ADFS (OIDC)
|
||||
We will implement a dual authentication strategy:
|
||||
1. **Local Auth**: Username/Password stored in `auth.db` with bcrypt hashing.
|
||||
2. **ADFS**: OpenID Connect (OIDC) integration for enterprise SSO.
|
||||
|
||||
**Rationale**:
|
||||
- **Local Auth**: Ensures the system is usable without external dependencies (ADFS) and provides a fallback for admins.
|
||||
- **ADFS**: Requirement for corporate environment integration. OIDC is the modern standard supported by ADFS 2016+.
|
||||
- **Just-In-Time (JIT)**: ADFS users will be provisioned locally upon first successful login if they belong to a mapped AD group.
|
||||
|
||||
**Alternatives Considered**:
|
||||
- *SAML 2.0*: Older protocol, more complex to implement (XML-based) than OIDC. Rejected in favor of OIDC/OAuth2 support in `Authlib`.
|
||||
- *LDAP Direct Bind*: Requires handling credentials directly, less secure than token-based SSO.
|
||||
|
||||
## 2. Session Management
|
||||
|
||||
### Decision: Stateless JWT (JSON Web Tokens)
|
||||
Sessions will be managed using signed JWTs containing `sub` (user_id), `exp` (expiration), and `scopes` (roles).
|
||||
|
||||
**Rationale**:
|
||||
- **Stateless**: No need to query the DB for every request to validate session validity (signature check is fast).
|
||||
- **Scalable**: Works well with load balancers (though not a primary concern for this scale).
|
||||
- **Frontend Friendly**: Easy to parse in JS to get user info without an extra API call.
|
||||
|
||||
**Security Measures**:
|
||||
- Short-lived Access Tokens (e.g., 15-30 min).
|
||||
- HttpOnly Cookies for storage to prevent XSS theft.
|
||||
- Refresh Token rotation (stored in DB) for long-lived sessions.
|
||||
|
||||
## 3. Authorization Model
|
||||
|
||||
### Decision: RBAC (Role-Based Access Control)
|
||||
Permissions are assigned to Roles. Users are assigned one or more Roles.
|
||||
|
||||
**Structure**:
|
||||
- **Permissions**: Granular capabilities (e.g., `plugin:backup:execute`, `plugin:migration:read`).
|
||||
- **Roles**: Collections of permissions (e.g., `Admin`, `Operator`, `Viewer`).
|
||||
- **Users**: Assigned to Roles.
|
||||
|
||||
**Rationale**:
|
||||
- Standard industry practice.
|
||||
- Simplifies management: Admin assigns a role to a user rather than 50 individual permissions.
|
||||
- AD Group Mapping fits naturally: `AD_Group_X` -> `Role_Y`.
|
||||
|
||||
## 4. Persistence
|
||||
|
||||
### Decision: Dedicated SQLite Database (`auth.db`)
|
||||
A separate SQLite database file for authentication data.
|
||||
|
||||
**Rationale**:
|
||||
- **Separation of Concerns**: Keeps auth data distinct from task history or other app data.
|
||||
- **Relational Integrity**: Enforces foreign keys between Users, Roles, and Permissions better than JSON.
|
||||
- **Concurrency**: SQLite WAL mode handles concurrent reads/writes better than a single JSON config file.
|
||||
|
||||
**Schema Draft**:
|
||||
- `users` (id, username, password_hash, is_active, auth_source)
|
||||
- `roles` (id, name, description)
|
||||
- `permissions` (id, resource, action)
|
||||
- `role_permissions` (role_id, permission_id)
|
||||
- `user_roles` (user_id, role_id)
|
||||
- `ad_group_mappings` (ad_group_name, role_id)
|
||||
|
||||
## 5. Frontend Integration
|
||||
|
||||
### Decision: SvelteKit Stores + HttpOnly Cookies
|
||||
Authentication state will be synchronized between the server (cookies) and client (Svelte store).
|
||||
|
||||
**Mechanism**:
|
||||
- Login endpoint sets `access_token` cookie (HttpOnly).
|
||||
- Client makes API calls; browser automatically sends cookie.
|
||||
- `hooks.server.ts` (or similar middleware) validates token on server-side rendering.
|
||||
- Client-side store (`$auth`) holds user profile (decoded from token or fetched via `/me` endpoint) for UI logic (show/hide buttons).
|
||||
113
specs/016-multi-user-auth/spec.md
Normal file
113
specs/016-multi-user-auth/spec.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# Feature Specification: Multi-User Authentication and Authorization
|
||||
|
||||
**Feature Branch**: `016-multi-user-auth`
|
||||
**Created**: 2026-01-26
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Нужна поддержка многопользовательского логина. Нужно, чтобы пользователи могли логинится по связке логин/пароль, поддержка adfs, разделение прав доступа по плагинам"
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2026-01-26
|
||||
- Q: Permission Model Structure? → A: RBAC (Role-Based Access Control) - Permissions assigned to Roles, Users assigned to Roles.
|
||||
- Q: Initial Admin Provisioning? → A: CLI Command/Script - Explicit script to create the first admin user.
|
||||
- Q: ADFS User Role Assignment? → A: AD Group Mapping - Login requires valid AD group membership; AD groups map to local Roles (e.g., 'superset_admin' -> 'Admin').
|
||||
- Q: Token Management? → A: JWT (JSON Web Tokens) - Stateless, scalable, standard for SPAs.
|
||||
- Q: Persistence Layer? → A: Dedicated SQLite DB (`auth.db`) - Relational storage for Users, Roles, Permissions.
|
||||
- Q: Switching Auth Providers? → A: Dual Support - Both Local and ADFS login options are available simultaneously on the login page.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Local User Authentication (Priority: P1)
|
||||
|
||||
As a user, I want to log in using a username and password so that I can securely access the application.
|
||||
|
||||
**Why this priority**: Basic authentication is the foundation for multi-user support and is required before implementing more complex auth methods or permissions.
|
||||
|
||||
**Independent Test**: Can be fully tested by creating a local user account and successfully logging in/out without any external dependencies.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a registered user, **When** they enter valid credentials on the login page, **Then** they are redirected to the dashboard and receive a session token.
|
||||
2. **Given** a registered user, **When** they enter invalid credentials, **Then** they see an error message "Invalid username or password".
|
||||
3. **Given** an authenticated user, **When** they click logout, **Then** their session is terminated and they are redirected to the login page.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Plugin-Based Access Control (Priority: P1)
|
||||
|
||||
As an administrator, I want to assign specific plugin access rights to users so that I can control who can use sensitive tools (e.g., Backup, Migration).
|
||||
|
||||
**Why this priority**: Security is a core requirement. Without granular permissions, all authenticated users would have full administrative access, which defeats the purpose of multi-user support.
|
||||
|
||||
**Independent Test**: Create two users with different permissions (e.g., User A has access to "Backup", User B does not). Verify User A can access the Backup tool while User B receives a 403 Forbidden error.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a user with "Backup" plugin permission, **When** they navigate to the Backup tool, **Then** the page loads successfully.
|
||||
2. **Given** a user WITHOUT "Backup" plugin permission, **When** they navigate to the Backup tool, **Then** they are denied access (UI hides the link, API returns 403).
|
||||
3. **Given** an administrator, **When** they edit a user's permissions, **Then** the changes take effect immediately or upon next login.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - ADFS Integration (Priority: P2)
|
||||
|
||||
As a corporate user, I want to log in using my organization's ADFS credentials so that I don't have to manage a separate password.
|
||||
|
||||
**Why this priority**: Essential for enterprise environments but dependent on the core authentication infrastructure being in place (Story 1).
|
||||
|
||||
**Independent Test**: Configure the application with a test ADFS provider (or mock). Verify a user can initiate the SSO flow and be logged in automatically.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a configured ADFS provider, **When** a user clicks "Login with ADFS", **Then** they are redirected to the identity provider.
|
||||
2. **Given** a successful ADFS authentication, **When** the user returns to the app, **Then** a local user session is created/matched and they are logged in.
|
||||
3. **Given** a new ADFS user, **When** they log in for the first time, **Then** a local user record is automatically created (JIT provisioning) with default permissions.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when an ADFS user's account is disabled in the local system? (Should block login even if ADFS succeeds)
|
||||
- How does the system handle concurrent sessions? (Allow or restrict?)
|
||||
- What happens if a plugin is removed but users still have permission for it? (Graceful handling/cleanup)
|
||||
- What happens if the ADFS server is unreachable? (Fallback to local login if applicable, or clear error message)
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: System MUST support local user authentication via username and password.
|
||||
- **FR-002**: System MUST support authentication via ADFS (Active Directory Federation Services) using standard federation protocols.
|
||||
- **FR-003**: System MUST provide a mechanism to manage users (Create, Read, Update, Delete) - restricted to administrators.
|
||||
- **FR-004**: System MUST implement Role-Based Access Control (RBAC) where permissions are assigned to Roles, and Roles are assigned to Users.
|
||||
- **FR-005**: System MUST enforce permissions at the server level for all plugin execution requests.
|
||||
- **FR-006**: System MUST enforce permissions at the user interface level (hide navigation items/buttons for unauthorized plugins).
|
||||
- **FR-007**: System MUST securely store local user credentials.
|
||||
- **FR-008**: System MUST support Just-In-Time (JIT) provisioning for ADFS users ONLY if they belong to a mapped AD group.
|
||||
- **FR-009**: System MUST provide a CLI utility to create an initial administrator account to prevent lockout during first deployment.
|
||||
- **FR-010**: System MUST allow configuring mappings between Active Directory Groups and local System Roles.
|
||||
- **FR-011**: System MUST use JWT (JSON Web Tokens) for API session management.
|
||||
- **FR-012**: System MUST persist authentication and authorization data in a dedicated SQLite database (`auth.db`).
|
||||
- **FR-013**: System MUST provide a unified login interface supporting both Local (Username/Password) and ADFS (SSO Button) authentication methods simultaneously.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **User**: Represents a system user. Attributes: ID, Username, Email, PasswordHash, AuthSource (Local/ADFS), IsActive, Roles (List[RoleID]).
|
||||
- **Role**: Named collection of permissions. Attributes: ID, Name, Description, Permissions (List[Permission]).
|
||||
- **Permission**: Represents access capability. Attributes: ResourceID (e.g., Plugin ID), Action (Execute, Read).
|
||||
- **ADGroupMapping**: Configuration mapping AD Group names to Role IDs.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Administrators can successfully create a new local user and assign specific plugin permissions in under 2 minutes.
|
||||
- **SC-002**: Users without permission for a specific plugin are denied access 100% of the time when attempting to use its functions.
|
||||
- **SC-003**: ADFS login flow completes successfully for valid credentials and maps to the correct local user identity.
|
||||
- **SC-004**: User interface dynamically updates to show only permitted tools for the logged-in user.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The application currently has a simple or placeholder authentication mechanism.
|
||||
- "Plugin access" refers to the ability to use the plugin's functionality and view its interface.
|
||||
- A default administrator account will be available upon initial system setup to prevent lockout.
|
||||
91
specs/016-multi-user-auth/tasks.md
Normal file
91
specs/016-multi-user-auth/tasks.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Tasks: Multi-User Authentication and Authorization
|
||||
|
||||
**Feature Branch**: `016-multi-user-auth`
|
||||
**Feature Spec**: [`specs/016-multi-user-auth/spec.md`](spec.md)
|
||||
**Implementation Plan**: [`specs/016-multi-user-auth/plan.md`](plan.md)
|
||||
|
||||
## Phase 1: Setup & Infrastructure (Blocking)
|
||||
|
||||
*Goal: Initialize the auth database, core dependencies, and backend infrastructure.*
|
||||
|
||||
- [ ] T001 Install backend dependencies (Authlib, Passlib, PyJWT, SQLAlchemy) in `backend/requirements.txt`
|
||||
- [ ] T002 Implement core configuration for Auth and Database in `backend/src/core/auth/config.py`
|
||||
- [ ] T003 Implement database connection logic for `auth.db` in `backend/src/core/database.py`
|
||||
- [ ] T004 Create SQLAlchemy models for User, Role, Permission in `backend/src/models/auth.py`
|
||||
- [ ] T005 Create migration/init script to generate `auth.db` schema in `backend/src/scripts/init_auth_db.py`
|
||||
- [ ] T006 Implement password hashing utility using Passlib in `backend/src/core/auth/security.py`
|
||||
- [ ] T007 Implement JWT token generation and validation logic in `backend/src/core/auth/jwt.py`
|
||||
- [ ] T008 [P] Implement CLI tool for creating the initial admin user in `backend/src/scripts/create_admin.py`
|
||||
|
||||
## Phase 2: User Story 1 - Local User Authentication (Priority: P1)
|
||||
|
||||
*Goal: Enable users to log in with username/password and receive a JWT session.*
|
||||
|
||||
- [ ] T009 [US1] Create Pydantic schemas for User, UserCreate, Token in `backend/src/schemas/auth.py`
|
||||
- [ ] T010 [US1] Implement `AuthRepository` for DB operations in `backend/src/core/auth/repository.py`
|
||||
- [ ] T011 [US1] Implement `AuthService` for login logic (verify password, create token) in `backend/src/services/auth_service.py`
|
||||
- [ ] T012 [US1] Create API endpoint `POST /api/auth/login` in `backend/src/api/auth.py`
|
||||
- [ ] T013 [US1] Implement `get_current_user` dependency for JWT verification in `backend/src/dependencies.py`
|
||||
- [ ] T014 [US1] Create API endpoint `GET /api/auth/me` to retrieve current user profile in `backend/src/api/auth.py`
|
||||
- [ ] T043 [US1] Implement session revocation (Logout) endpoint in `backend/src/api/auth.py`
|
||||
- [ ] T044 [US1] Implement account status check (`is_active`) in authentication flow in `backend/src/services/auth_service.py`
|
||||
- [ ] T015 [US1] Implement frontend auth store (Svelte store) in `frontend/src/lib/auth/store.ts`
|
||||
- [ ] T016 [US1] Implement Login Page UI using `src/lib/ui` and `src/lib/i18n` in `frontend/src/routes/login/+page.svelte`
|
||||
- [ ] T017 [US1] Integrate Login Page with Backend API in `frontend/src/routes/login/+page.svelte`
|
||||
- [ ] T018 [US1] Implement `ProtectedRoute` component to redirect unauthenticated users in `frontend/src/components/auth/ProtectedRoute.svelte`
|
||||
- [ ] T037 [US1] Implement password complexity validation logic in `backend/src/core/auth/security.py`
|
||||
|
||||
## Phase 3: User Story 2 - Plugin-Based Access Control (Priority: P1)
|
||||
|
||||
*Goal: Restrict access to plugins based on user roles and permissions.*
|
||||
|
||||
- [ ] T019 [US2] Update `PluginBase` to include required permission strings in `backend/src/core/plugin_base.py`
|
||||
- [ ] T020 [US2] Implement `has_permission` dependency for route protection in `backend/src/dependencies.py`
|
||||
- [ ] T021 [US2] Protect existing plugin API routes using `has_permission` in `backend/src/api/routes/*.py`
|
||||
- [ ] T022 [US2] Implement `SystemAdminPlugin` inheriting from `PluginBase` for User/Role management in `backend/src/plugins/system_admin.py`
|
||||
- [ ] T023 [US2] Implement Admin API endpoints within `SystemAdminPlugin` (with pagination) in `backend/src/api/routes/admin.py`
|
||||
- [ ] T024 [US2] Create Admin Dashboard UI using `src/lib/ui` and `src/lib/i18n` in `frontend/src/routes/admin/users/+page.svelte`
|
||||
- [ ] T025 [US2] Update Navigation Bar to hide links and show user profile/logout using `src/lib/ui` in `frontend/src/components/Navbar.svelte`
|
||||
- [ ] T042 [US2] Implement `PermissionGuard` frontend component for granular UI element protection in `frontend/src/components/auth/PermissionGuard.svelte`
|
||||
- [ ] T045 [US2] Implement multi-role permission resolution logic (union of permissions) in `backend/src/services/auth_service.py`
|
||||
|
||||
## Phase 4: User Story 3 - ADFS Integration (Priority: P2)
|
||||
|
||||
*Goal: Enable corporate SSO login via ADFS and JIT provisioning.*
|
||||
|
||||
- [ ] T026 [US3] Configure Authlib for ADFS OIDC in `backend/src/core/auth/oauth.py`
|
||||
- [ ] T027 [US3] Create `ADGroupMapping` model in `backend/src/models/auth.py` and update DB init script
|
||||
- [ ] T028 [US3] Implement JIT provisioning logic (create user if maps to group) in `backend/src/services/auth_service.py`
|
||||
- [ ] T029 [US3] Create API endpoints `GET /api/auth/login/adfs` and `GET /api/auth/callback/adfs` in `backend/src/api/auth.py`
|
||||
- [ ] T030 [US3] Update Login Page to include "Login with ADFS" button using `src/lib/ui` in `frontend/src/routes/login/+page.svelte`
|
||||
- [ ] T031 [US3] Implement Admin UI for configuring AD Group Mappings in `frontend/src/routes/admin/settings/+page.svelte`
|
||||
- [ ] T041 [US3] Create ADFS mock provider for local testing and CI in `backend/tests/auth/mock_adfs.py`
|
||||
- [ ] T046 [US3] Implement token refresh logic for ADFS OIDC tokens in `backend/src/core/auth/jwt.py`
|
||||
|
||||
## Phase 5: Polish & Security Hardening
|
||||
|
||||
*Goal: Ensure security best practices and smooth UX.*
|
||||
|
||||
- [ ] T032 Ensure all cookies are set with `HttpOnly` and `Secure` flags in `backend/src/api/auth.py`
|
||||
- [ ] T033 Implement rate limiting and account lockout policy in `backend/src/api/auth.py`
|
||||
- [ ] T034 Verify error messages are generic (no username enumeration) across all auth endpoints
|
||||
- [ ] T035 Add "Session Expired" handling in frontend interceptor in `frontend/src/lib/api/client.ts`
|
||||
- [ ] T036 Final manual test of switching between Local and ADFS login flows
|
||||
- [ ] T040 Add confirmation dialogs for destructive admin actions using `src/lib/ui` in `frontend/src/routes/admin/users/+page.svelte`
|
||||
- [ ] T047 Implement audit logging for security events (login, logout, permission changes) in `backend/src/core/auth/logger.py`
|
||||
- [ ] T048 Perform UI accessibility audit (keyboard nav, ARIA alerts) for all auth components
|
||||
- [ ] T049 Implement unit and integration tests for Local Auth and RBAC in `backend/tests/auth/`
|
||||
- [ ] T050 Implement E2E tests for ADFS flow using mock provider in `tests/e2e/auth.spec.ts`
|
||||
|
||||
## Dependencies
|
||||
|
||||
1. **Phase 1** must be completed before any User Stories.
|
||||
2. **Phase 2 (Local Auth)** is the foundation for authentication and session management.
|
||||
3. **Phase 3 (RBAC)** depends on Phase 2 (needs authenticated users to check permissions).
|
||||
4. **Phase 4 (ADFS)** depends on Phase 2 (uses same session mechanism) and Phase 3 (needs roles for JIT).
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
- **MVP**: Complete Phases 1 and 2. This gives a working auth system with local users.
|
||||
- **Increment 1**: Complete Phase 3. This adds the critical security controls (RBAC).
|
||||
- **Increment 2**: Complete Phase 4. This adds corporate SSO convenience.
|
||||
Reference in New Issue
Block a user