Documentation Technique - TRusTY

Version : 0.8.2-SNAPSHOT Dernière mise à jour : 2025-12-01 Architecture : Domain-Driven Design (DDD) + Clean Architecture

TRusTY est un fournisseur OpenID Connect (OIDC) implémentant les standards de sécurité FAPI 2.0, développé en Rust et Python.


Table des Matières

  1. Vue d’Ensemble de l’Architecture
  2. Serveur - Rust (Port 8081)
  3. Client - Python Flask (Port 5001/5002)
  4. Stack Technologique
  5. Base de Données & Persistance
  6. Fonctionnalités de Sécurité
  7. Déploiement

Vue d’Ensemble de l’Architecture

Architecture Haut Niveau

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌─────────────────────────────────────────────────────────────┐
│                    Écosystème TRusTY                         │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌──────────────────┐           ┌──────────────────┐        │
│  │  Client Python   │           │  Client Python   │        │
│  │  (OIDC Standard) │           │   (FAPI 2.0)     │        │
│  │  Port 5001       │           │   Port 5002      │        │
│  └────────┬─────────┘           └─────────┬────────┘        │
│           │                               │                  │
│           │    HTTP/HTTPS                 │                  │
│           └───────────────┬───────────────┘                  │
│                           │                                   │
│                  ┌────────▼────────┐                         │
│                  │ Serveur TRusTY  │                         │
│                  │  (Rust + Axum)  │                         │
│                  │  Port 8081      │                         │
│                  └────────┬────────┘                         │
│                           │                                   │
│                  ┌────────▼────────┐                         │
│                  │     SQLite      │                         │
│                  │   trusty.db     │                         │
│                  └─────────────────┘                         │
│                                                               │
└─────────────────────────────────────────────────────────────┘

Principes de Conception

  • Domain-Driven Design (DDD) : Séparation claire de la logique métier et de l’infrastructure
  • Clean Architecture : Dépendances pointant vers l’intérieur (Domain ← Application ← Infrastructure ← Presentation)
  • Principes SOLID : Responsabilité unique, Inversion de dépendances, etc.
  • Test-Driven Development : Tests unitaires et d’intégration complets

Serveur - Rust (Port 8081)

Structure du Projet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
server/
├── src/
│   ├── main.rs                    # Point d'entrée, configuration serveur
│   ├── lib.rs                     # Exports de bibliothèque
│   ├── config.rs                  # Gestion de la configuration
│   └── oidc/                      # Module OIDC (couches DDD)
│       ├── mod.rs
│       ├── domain/                # Couche Domaine (logique métier)
│       │   ├── entities/          # Racines d'agrégat & entités
│       │   │   ├── user.rs
│       │   │   ├── client.rs
│       │   │   ├── session.rs
│       │   │   ├── authorization_code.rs
│       │   │   └── authorization_session.rs
│       │   ├── repositories/      # Interfaces repository (traits)
│       │   │   ├── user_repository.rs
│       │   │   ├── client_repository.rs
│       │   │   ├── session_repository.rs
│       │   │   └── authorization_code_repository.rs
│       │   ├── services/          # Services domaine
│       │   │   ├── password_service.rs
│       │   │   └── dpop_service.rs
│       │   └── value_objects/     # Objets valeur (immuables)
│       │       ├── claims.rs
│       │       ├── scope.rs
│       │       └── jwt_request.rs
│       ├── application/           # Couche Application (cas d'usage)
│       │   ├── commands/          # Opérations d'écriture
│       │   │   └── authorize.rs
│       │   ├── queries/           # Opérations de lecture
│       │   └── services/          # Services application
│       │       ├── token_service.rs
│       │       ├── user_service.rs
│       │       ├── authorization_code_service.rs
│       │       └── session_service.rs
│       ├── infrastructure/        # Couche Infrastructure (technique)
│       │   ├── repositories/      # Implémentations repository
│       │   │   ├── sqlite/        # Implémentations SQLite
│       │   │   │   ├── user_repository.rs
│       │   │   │   ├── client_repository.rs
│       │   │   │   ├── session_repository.rs
│       │   │   │   └── mappers.rs
│       │   │   └── memory/        # En mémoire (pour tests)
│       │   │       └── ...
│       │   └── services/          # Services infrastructure
│       │       ├── jwt_service.rs
│       │       ├── jwks_service.rs
│       │       ├── dpop_validator.rs
│       │       ├── par_service.rs
│       │       ├── i18n_service.rs
│       │       └── audit_service.rs
│       └── presentation/          # Couche Présentation (HTTP/API)
│           ├── handlers/          # Gestionnaires d'endpoints HTTP
│           │   ├── auth.rs        # /auth
│           │   ├── token.rs       # /token
│           │   ├── userinfo.rs    # /userinfo
│           │   ├── par.rs         # /par
│           │   ├── login.rs       # /login
│           │   ├── logout.rs      # /logout
│           │   ├── revoke.rs      # /revoke
│           │   ├── introspect.rs  # /introspect
│           │   ├── discovery.rs   # /.well-known/openid-configuration
│           │   ├── jwks.rs        # /.well-known/jwks.json
│           │   ├── health.rs      # /health
│           │   └── observability.rs  # /observability/*
│           ├── middleware/        # Middleware HTTP
│           │   └── tracing.rs
│           ├── responses/         # DTOs de réponse
│           └── validation/        # Validation des entrées
├── migrations/                    # Migrations SQLite
│   ├── 001_initial_schema.sql
│   ├── 002_demo_data.sql
│   ├── 003_audit_and_revoked_tokens.sql
│   ├── 004_add_token_endpoint_auth_method.sql
│   ├── 005_add_post_logout_redirect_uris.sql
│   └── 006_update_fapi_client_jwks.sql
├── templates/                     # Templates HTML Handlebars
│   ├── login.hbs
│   ├── logout_confirmation.hbs
│   └── error.hbs
├── locales/                       # Traductions i18n (Fluent)
│   ├── en/
│   │   └── main.ftl
│   └── fr/
│       └── main.ftl
├── data/                          # Base de données SQLite
│   └── trusty.db
├── logs/                          # Logs d'application
├── Cargo.toml                     # Dépendances Rust
└── build.rs                       # Script de build (extraction version)

Couche Domaine

Entités (Racines d’agrégat) :

  • User - Comptes utilisateurs avec identifiants
  • Client - Clients OIDC (applications demandant l’authentification)
  • Session - Sessions utilisateur
  • AuthorizationCode - Codes de courte durée pour échange de tokens
  • AuthorizationSession - Suivi des requêtes d’autorisation

Objets Valeur :

  • Claims - Claims JWT
  • Scope - Scopes d’autorisation
  • UserId, ClientId, SessionId - IDs typés

Services Domaine :

  • PasswordService - Hachage/vérification mot de passe (bcrypt)
  • DpopService - Logique de liaison de token DPoP

Couche Application

Services (orchestrent les cas d’usage) :

  • TokenService - Génération/validation de tokens
  • UserService - Création de claims utilisateur
  • AuthorizationCodeService - Cycle de vie du code d’autorisation
  • SessionService - Gestion des sessions

Couche Infrastructure

Repositories (accès aux données) :

  • Implémentations SQLite (crate sqlx)
  • Implémentations en mémoire (pour tests)
  • Pattern Factory pour sélection du backend (configurable)

Services (implémentations techniques) :

  • JwtService - Signature/vérification JWT (RS256)
  • JwksService - Gestion des clés publiques
  • DpopValidator - Validation des preuves DPoP (RFC 9449)
  • ParService - Stockage des requêtes PAR (en mémoire, TTL 90s)
  • I18nService - Internationalisation (Fluent.rs)
  • AuditService - Journalisation d’audit vers SQLite

Couche Présentation

Handlers (endpoints HTTP) :

  • Endpoints API RESTful
  • Gestion de formulaires (login, logout)
  • Réponses d’erreur (JSON/HTML)

Client - Python Flask (Port 5001/5002)

Types de Clients Démo

Client OIDC Standard (app.py - Port 5001) :

  • Authorization Code Flow
  • PKCE (S256)
  • Authentification client_secret_post
  • Gestion d’état basée sur session

Client FAPI 2.0 (fapi_client.py - Port 5002) :

  • PAR (Pushed Authorization Request)
  • PKCE (S256 - obligatoire)
  • Authentification private_key_jwt
  • Liaison de token DPoP
  • Clés DPoP éphémères par session

Structure du Client

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
client/
├── app.py                     # Client OIDC standard (Flask)
├── fapi_client.py             # Client FAPI 2.0 (Flask)
├── generate_fapi_keys.py      # Génération clés RSA pour FAPI
├── export_fapi_key_env.py     # Export clés vers variables d'env
├── templates/                 # Templates HTML Jinja2
   ├── index.html
   ├── profile.html
   └── error.html
├── locales/                   # Traductions i18n (Flask-Babel)
   ├── en/
   └── fr/
├── static/                    # CSS, JS, images
├── requirements.txt           # Dépendances Python
├── .env.example               # Template de configuration
└── README.md                  # Documentation client

Dépendances Python

1
2
3
4
5
6
7
8
Flask==3.1.0
Flask-Session==0.8.0
requests==2.32.3
PyJWT==2.9.0
cryptography==43.0.3
Authlib==1.3.2
python-dotenv==1.0.1
Flask-Babel==4.0.0

Stack Technologique

Serveur (Rust)

ComposantTechnologieVersionObjectif
Framework WebAxum0.8Serveur HTTP async
RuntimeTokio1.0Runtime async
Base de DonnéesSQLite-Base de données embarquée
ORMsqlx0.8Toolkit SQL async
JWTjsonwebtoken9.0Signature/vérif JWT
Cryptorsa, rand0.9Clés RSA, aléatoire
Mots de passebcrypt0.15Hachage sécurisé
Sérialisationserde, serde_json1.0Parsing JSON/YAML
Templateshandlebars4.0Rendu HTML
i18nfluent-templates0.11Traductions
Loggingtracing0.1Logging structuré
TélémétrieOpenTelemetry0.24Tracing distribué
Sessionstower-sessions0.12Gestion sessions
Configserde_yaml0.9Configuration YAML

Client (Python)

ComposantTechnologieObjectif
Framework WebFlaskServeur HTTP
Client HTTPrequests, AuthlibClient OIDC
JWTPyJWTParsing de tokens
CryptocryptographyClés RSA, DPoP
i18nFlask-BabelTraductions
SessionsFlask-SessionStockage session

Base de Données & Persistance

Schéma SQLite

Tables :

  • users - Comptes utilisateur (id UUID, username, email, password_hash, created_at)
  • clients - Clients OIDC (id, client_secret, redirect_uris, jwks, auth_method, etc.)
  • sessions - Sessions utilisateur (id UUID, user_id FK, created_at, expires_at, is_active)
  • authorization_codes - Codes d’autorisation (code, user_id FK, client_id FK, redirect_uri, scope, code_challenge, created_at, expires_at, used)
  • par_requests - Requêtes PAR (request_uri, client_id, params JSON, created_at, expires_at)
  • audit_log - Événements d’audit (event_type, user_id, client_id, ip_address, user_agent, details JSON, timestamp)
  • revoked_tokens - Tokens révoqués (jti, token_type, revoked_at, expires_at)

Système de Migration

  • Fichiers de migration SQL dans server/migrations/
  • Appliqués au démarrage du serveur (idempotents)
  • Suivi de version dans table _migrations (futur)

Sélection du Backend

Configurable via config.yaml :

1
2
3
database:
  backend: Sqlite   # ou InMemory (pour tests)
  path: "server/data/trusty.db"

Le pattern Repository Factory permet l’ajout facile de PostgreSQL, MySQL, etc.


Fonctionnalités de Sécurité

Standards Implémentés

FonctionnalitéSpécificationStatut
OIDC Core 1.0OpenID Connect Core✅ Implémenté
PKCE (S256)RFC 7636✅ Obligatoire
PARRFC 9126✅ Implémenté
private_key_jwtRFC 7523✅ Implémenté
DPoPRFC 9449✅ Implémenté
FAPI 2.0FAPI 2.0 Security Profile✅ Implémenté
RP-Initiated LogoutOIDC RP-Initiated Logout 1.0✅ Implémenté
Révocation TokenRFC 7009✅ Implémenté
Introspection TokenRFC 7662✅ Implémenté

Mécanismes de Sécurité

Authentification :

  • Hachage bcrypt des mots de passe (coût 12)
  • Authentification client asymétrique (JWT RS256)
  • Authentification basée session pour l’UI

Sécurité des Tokens :

  • Signature RS256 (clés 2048-bit)
  • Tokens de courte durée (access: 1h, auth code: 90s)
  • Liaison de token avec DPoP (validation jkt)
  • Suivi des révocations de tokens

Sécurité des Requêtes :

  • PKCE (S256 uniquement, plain rejeté)
  • Paramètre state (protection CSRF)
  • Nonce (protection replay)
  • PAR (protection altération paramètres)
  • Objets de requête JWT signés

Audit :

  • Toutes les tentatives d’authentification journalisées
  • Opérations sur tokens suivies
  • Adresse IP + User-Agent capturés

Déploiement

Support Docker

Dockerfile (serveur Rust) :

1
2
3
4
FROM rust:1.83-alpine AS builder
# Construction binaire statique
FROM alpine:latest
# Structure conforme FHS: /opt/trusty/

docker-compose.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
services:
  trusty-server:
    build: ./server
    ports:
      - "8081:8081"
    volumes:
      - ./server/data:/opt/trusty/data
      - ./server/logs:/opt/trusty/logs
    environment:
      - RUST_LOG=info

  trusty-client:
    build: ./client
    ports:
      - "5001:5001"
    environment:
      - OIDC_ISSUER=http://trusty-server:8081

Déploiement Railway

CI/CD avec GitHub Actions :

  • Branche main → Environnement Production
  • Branche dev → Environnement Développement
  • PR → Tests uniquement (pas de déploiement)

Variables d’Environnement :

  • BUILD_VERSION - Tag git ou SNAPSHOT-{timestamp}
  • RUST_LOG - Niveau de log
  • DATABASE_PATH - Chemin fichier SQLite
  • ISSUER_URL - URL de l’émetteur OIDC

Structure Fichiers (Conforme FHS)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/opt/trusty/
├── bin/
│   ├── trusty              # Binaire
│   └── start.sh            # Script de démarrage
├── etc/
│   └── config.yaml         # Configuration
├── data/
│   └── trusty.db           # Base SQLite (volume)
├── logs/                   # Logs (volume)
└── migrations/             # Migrations SQL

Configuration

Config Serveur (server/config.yaml)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server:
  host: "0.0.0.0"
  port: 8081
  issuer: "http://localhost:8081"

database:
  backend: Sqlite
  path: "server/data/trusty.db"

jwt:
  private_key_path: "server/keys/jwt_private_key.pem"
  public_key_path: "server/keys/jwt_public_key.pem"
  algorithm: "RS256"
  access_token_ttl: 3600      # 1 heure
  id_token_ttl: 3600          # 1 heure
  refresh_token_ttl: 2592000  # 30 jours

logging:
  level: "info"
  directory: "server/logs"
  file_prefix: "trusty"

i18n:
  default_locale: "en"
  supported_locales: ["en", "fr"]

Config Client (client/.env)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Serveur OIDC
OIDC_ISSUER=http://localhost:8081
CLIENT_ID=demo_client
CLIENT_SECRET=demo_secret
REDIRECT_URI=http://localhost:5001/auth/callback

# Client FAPI (port 5002)
FAPI_CLIENT_ID=fapi_client
FAPI_REDIRECT_URI=http://localhost:5002/auth/callback
FAPI_PRIVATE_KEY_PATH=fapi_client_private_key.pem
FAPI_JWKS_PATH=fapi_client_public_jwks.json

Développement

Prérequis

Serveur :

  • Rust 1.83+
  • SQLite3
  • OpenSSL

Client :

  • Python 3.11+
  • pip

Installation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Serveur
cd server
cargo build --release
cargo run

# Client (OIDC Standard)
cd client
python -m venv venv
source venv/bin/activate  # ou venv\Scripts\activate sur Windows
pip install -r requirements.txt
python app.py

# Client (FAPI 2.0)
python generate_fapi_keys.py
python fapi_client.py

Tests

1
2
3
4
5
6
7
8
9
# Tests serveur
cd server
cargo test

# Tests d'intégration
cargo test --test '*'

# Couverture de code
cargo tarpaulin --out Html

Endpoints API

Voir Documentation Flux OIDC pour la documentation détaillée des endpoints.

Référence Rapide :

  • GET /.well-known/openid-configuration - Discovery OIDC
  • GET /.well-known/jwks.json - Clés publiques (JWKS)
  • GET /auth - Endpoint d’autorisation
  • POST /token - Endpoint de token
  • GET /userinfo - Endpoint UserInfo
  • POST /par - Pushed Authorization Request
  • POST /revoke - Révocation de token
  • POST /introspect - Introspection de token
  • GET /logout - Logout initié par RP
  • GET /health - Vérification santé

Monitoring & Observabilité

Logging

  • Logging structuré avec tracing
  • Format JSON pour production
  • Rotation de fichiers (logs quotidiens)
  • Niveaux de log : TRACE, DEBUG, INFO, WARN, ERROR

Métriques (Endpoints Observabilité)

  • GET /observability/sessions - Nombre de sessions actives
  • GET /observability/tokens - Statistiques de tokens
  • GET /observability/clients - Informations clients

OpenTelemetry (Futur)

  • Support tracing distribué
  • Configuration exportateur OTLP
  • Intégration Jaeger/Zipkin prête

Références


Version du Document : 2.0 Statut : Prêt pour production Dernière Révision : 2025-12-01