dari CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is an IT infrastructure management system (DARI) that provides centralized user management, VPN access, Linux account provisioning, and LDAP-based authentication. The system manages Linux accounts, LDAP directory, VPN access with OTP, and user lifecycle management.
Architecture
Multi-Service Docker Architecture
- Frontend: SvelteKit application with SSR (port 3000 internally)
- Backend: Django + Django Ninja REST API (port 8080 internally)
- Database: PostgreSQL 13
- LDAP: OpenLDAP server for Linux authentication (port 636)
- VPN: OpenVPN server with OTP authentication (port 1194/udp)
- Reverse Proxy: Caddy server handling HTTPS and access control
- Task Queue: Celery with RabbitMQ for async tasks (user removal, deactivation)
Key Integration Points
- LDAP Authentication: All regular users authenticate via LDAP with passwords stored as SSHA hashes
- LDAP Sync: Backend maintains LDAP directory synchronized with Django database for Linux PAM authentication
- VPN Auth: OpenVPN uses openvpn-auth-ldap plugin to authenticate directly against LDAP server + PAM for OTP validation
- Session Management: Frontend uses cookies for Django session authentication
- IP Whitelisting: Caddy restricts most routes to configured networks (default: 10.125.0.0/16, 164.125.0.0/16)
Data Flow
- Registration: User registers via
/api/register→ Backend atomically creates:- Django User + Profile + LinuxInfo
- LDAP entry with SSHA-hashed password
- Home directory with proper ownership
- First user automatically becomes superuser
- Login: User logs in via frontend → Backend authenticates via LDAP (regular users) or Django auth (guest users) → Creates session
- Password Management: User changes password via
/api/password→ Backend updates LDAP password (SSHA hash) - VPN Setup: User enables VPN → Backend generates Google Authenticator QR code → Stores in
/etc/qr/→ VPN server validates OTP + LDAP password
Development Commands
Environment Setup
# Copy and configure environment variables
cp .env.example .env
# Edit .env with required credentials (DB, LDAP, secrets)
Development Mode (compose-dev.yml)
# Start all services with hot-reload and debug enabled
docker compose -f compose-dev.yml up --build
# Access frontend at http://localhost:8080
# Backend DEBUG=True, logs to /dev/null
# Volumes mount source code for hot-reload
Production Mode (compose.yml)
# Start production services
docker compose up -d --build
# View logs
docker compose logs -f [service_name]
# Services: db, caddy, ldap, rabbitmq, celery_worker, celery_beat, vpn, backend, frontend
Backend Development
# Enter backend container
docker compose exec backend bash
# Run Django migrations
python manage.py makemigrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Run Django shell
python manage.py shell
# Test Celery tasks
celery -A backend inspect active
Frontend Development
# Enter frontend container (dev mode)
docker compose -f compose-dev.yml exec frontend sh
# Install dependencies
cd /app && pnpm install
# Build for production
pnpm run build
# Preview production build
pnpm run preview
Database Operations
# Access PostgreSQL
docker compose exec db psql -U dari -d dari
# Backup database
docker compose exec db pg_dump -U dari dari > backup.sql
# Restore database
docker compose exec -T db psql -U dari dari < backup.sql
Critical Backend Components
backend/backend/api.py
Main API endpoints using Django Ninja. Key routes:
/api/register- Register new user with Linux/LDAP account and password (creates everything atomically)/api/login- Authenticates via LDAP (regular users) or Django auth (guest users)/api/password- Change user's LDAP password (requires old password verification)/api/qr- Generates Google Authenticator for VPN OTP/api/group- Manages LDAP groups with member synchronization/api/user- Updates user attributes including password resets (admin only)/api/guest- Creates or updates guest user accounts (admin only)
backend/backend/utils.py
Core utilities:
LDAPOpsclass - Manages LDAP operations (add/delete users/groups, password management)add_user()- Creates LDAP entry with optional password (SSHA hash)set_password()- Updates user's LDAP passwordauthenticate_user()- Validates username/password against LDAP
send_email()- Bulk email to active users via SMTP/IMAP
backend/auth/models.py
Django models:
Profile- User profile with name, status (sta), expiration datesLinuxInfo- Linux account details (username, UID, GID, shell)VPNInfo- VPN/OTP enablement flagGuestInfo- Guest user metadataLinuxGroup- LDAP group with membersServer- Managed servers with IP addresses
backend/auth/tasks.py
Celery scheduled tasks (run daily at midnight):
remove_users()- Archives and deletes expired users after 6 monthsdeactivate_users()- Marks users inactive after expiration dateupdate_users_sta()- (Placeholder for status sync)
Critical Frontend Components
frontend/src/lib/fetch.js
API client for backend communication. Handles:
- Cookie-based authentication (sessionid + CSRF token)
- Automatic header injection
- Base URL configuration via
API_BASE_URLenv var (defaults tohttp://backend:8080/api/)
frontend/src/routes/+layout.server.js
Root layout server load function:
- Fetches brand info (sitename, logo)
- Validates user session via
/api/me - Redirects to
/loginif unauthenticated - Forces admin to
/initif sitename not configured - Sets up i18n locale from cookies
Route Groups
(nonadmin)/- Regular user pages: profile, VPN, Linux accounts, groupsadmin/- Admin pages: user management, groups, servers, settings, emailinit/- Initial setup page for first adminlogin/,logout/- Authentication
Important Configuration
LDAP Integration
- LDAP domain derived from
LDAP_DOMAINenv var (e.g., "dari" → dc=dari) - Admin credentials:
cn=admin,dc=...withLDAP_ADMIN_PASSWORD - Two OUs:
ou=usersandou=groupsunder base DN - Users:
cn=<username>,ou=users,dc=...with posixAccount + inetOrgPerson objectClasses - Groups:
cn=<groupname>,ou=groups,dc=...with posixGroup objectClass - Passwords stored as SSHA hashes in
userPasswordattribute
User Management
- Regular Users: Authenticate via LDAP, passwords stored as SSHA hashes in LDAP
- Guest Users: Authenticate via Django, passwords stored as Django password hashes
- User Creation: Use
/api/registerendpoint or admin panel - Password Changes: Regular users use
/api/password, admins can reset via/api/userPATCH endpoint
Home Directory Management
- Production:
/mnt/dari-home/<username>(mounted volume) - Development:
./dari-home/<username>(local directory) - Created from
/etc/skeltemplate with proper UID/GID ownership
VPN OTP Flow
- User requests QR via
/api/qr→ Backend runsgoogle-authenticator→ Stores secret in/etc/qr/<username> - VPN server uses two authentication plugins in sequence:
openvpn-auth-ldap.so- Validates username/password against LDAP (ou=users,dc=bce)openvpn-plugin-auth-pam.so- Validates OTP code via Google Authenticator PAM module
- VPN access granted only if both LDAP password and OTP are valid
- Configuration: vpn/auth-ldap.conf and vpn/server.conf
Deployment Notes
Required Environment Variables
See .env.example for all variables. Critical ones:
SECRET_KEY- Django secret (generate withopenssl rand -base64 32)LDAP_ADMIN_PASSWORD- LDAP admin passwordLDAP_DOMAIN- LDAP domain (e.g., "dari" becomes dc=dari)RABBITMQ_DEFAULT_USER/PASS- RabbitMQ credentials for CelerySITE_DOMAIN- Domain for Caddy HTTPS certificates
Note: External authentication environment variables are no longer required. The system uses LDAP-based authentication with passwords managed directly in LDAP.
Volume Mounts
Production volumes in ./db/:
postgres_data/- PostgreSQL databaseldap_data/,ldap_config/,ldap_certs/- LDAP directory, config, and auto-generated TLS certificatescaddy_data/,caddy_config/- Caddy certificates and configvpn_easy_rsa/- VPN PKI and auto-generated certificatesovpn/- Generated OpenVPN client profileqr/- VPN OTP secretsip_addresses- Server IP whitelist file
Access Control
Caddy enforces IP whitelist for all routes except /guest/{uuid}. Add IPs via admin interface → backend writes to /etc/ip_addresses.
Testing
The test/ directory contains Docker configuration for testing LDAP/PAM integration with nslcd on a client container.