1. Genèse du Projet & Problématique

L'école EPITA a migré son système de gestion des plannings vers la plateforme Auriga. Contrairement aux anciens systèmes qui fournissaient un lien iCalendar direct, Auriga est conçu sous forme d'application web Single-Page (SPA) sécurisée par OAuth2.

Pour permettre aux étudiants de retrouver automatiquement leurs cours dans Google Calendar, Apple Calendar ou Outlook sans saisie manuelle et avec une mise à jour en temps réel des changements d'emploi du temps (changement de salle, annulations), ce projet à été entièrement rétro-ingéniéré et développé.

2. Rétro-Ingénierie de l'Authentification Keycloak EPITA

L'analyse des flux réseau (via Chrome DevTools / Network tab) lors d'une connexion sur le portail Auriga a révélé que l'authentification s'appuie sur une instance **Keycloak (SSO IONIS EPITA)** utilisant le protocole OAuth2 + PKCE (Proof Key for Code Exchange).

Serveur Identity Provider (IdP) Identifié :

Domain: ionisepita-auth.np-auriga.nfrance.net Realm: npionisepita Client ID: np-front Redirect URI: https://auriga2google.pierref.eu/api/auth/epita/callback

Étape 1 : Génération du Challenge PKCE

Avant de rediriger l'utilisateur vers le portail EPITA, le serveur backend génère un `code_verifier` cryptographique aléatoire de 64 caractères, calcule son hash SHA-256 pour obtenir le `code_challenge`, et initie l'autorisation :

GET /auth/realms/npionisepita/protocol/openid-connect/auth ?client_id=np-front &response_type=code &scope=openid+profile+email &redirect_uri=https://auriga2google.pierref.eu/api/auth/epita/callback &code_challenge=[HASH_SHA256_BASE64] &code_challenge_method=S256 &state=[STATE_TOKEN]

Étape 2 : Échange du Code contre un Token JWT

Une fois l'étudiant authentifié avec ses identifiants EPITA, Keycloak redirige vers notre callback avec un `authorization_code`. Notre serveur échange immédiatement ce code en transmettant le `code_verifier` initial pour obtenir les jetons `access_token` et `refresh_token`.

3. Rétro-Ingénierie de l'API REST Auriga

En inspectant les appels API émis par le client Angular/React d'Auriga, l'endpoint interne de récupération d'emploi du temps a été mis à jour.

Spécification de l'Endpoint Privé :

GET /api/plannings/me Host: auriga.epita.fr (ou instance régionale) Headers obligatoires : Authorization: Bearer <access_token_jwt> X-Scope: frontend Accept: application/json Query Parameters : startDate=2026-09-01 endDate=2026-12-31 days=1&days=2&days=3&days=4&days=5&days=6&days=7

Format de Réponse JSON Décortiqué :

{ "interventions": [ { "id": 26926, "description": "Sécurité Réseau", "startDateTime": "2026-09-04T08:00:00Z", "endDateTime": "2026-09-04T10:00:00Z", "actualDuration": 7200, "activityType": { "id": 9, "code": "CM", "caption": { "fr": "Cours Magistral" } }, "interventionInstructors": [ { "person": { "currentFirstName": "Morgan", "currentLastName": "PIERREFEU" } } ], "interventionPopulations": [ { "population": { "caption": { "fr": "ING1 - S5 Groupe 2" } } } ], "interventionRooms": [ { "room": { "code": "310 - AMPHI PLAT" } } ] } ] }

4. Moteur de Détection de Changements SHA-256

Pour ne pas polluer l'agenda de l'utilisateur et lui signaler immédiatement les modifications d'emploi du temps, un moteur de comparaison différentielle (*Diff Engine*) a été implémenté.

Calcul de l'Empreinte SHA-256 :

Chaque cours extrait est normalisé sous forme d'empreinte SHA-256 calculée sur ses champs caractéristiques (`id`, `description`, `startDateTime`, `endDateTime`, `room`, `instructor`).

content_hash = SHA256({ "id": course.auriga_id, "title": course.title, "start": course.start_dt.isoformat(), "end": course.end_dt.isoformat(), "room": course.room, "teacher": course.teacher })

Gestion des 3 Statuts Visuels :

  • [STABLE] : Cours planifié depuis plus de 14 jours (Couleur Google Vert Sauge).
  • [NOUVEAU] : Cours récemment ajouté ou modifié depuis moins de 14 jours (Couleur Google Jaune Banane).
  • [ANNULÉ] : Cours supprimé de l'emploi du temps Auriga, conservé 7 jours pour avertir l'étudiant (Couleur Google Rouge Tomate).

5. Serveur de Flux Dynamique iCalendar (.ics)

Afin d'offrir une compatibilité universelle (Google Calendar, Apple Calendar iOS/macOS, Outlook, Thunderbird), le serveur génère dynamiquement des fichiers au format standard RFC 5545 (`text/calendar`).

GET /api/feed/custom/calendar.ics?types=CM,TD Headers de réponse : Content-Type: text/calendar; charset=utf-8 Content-Disposition: inline; filename="epita_planning.ics" Refresh-Interval: PT30M (30 minutes)

6. Chiffrement AES-256-GCM & Confidentialité

Aucun mot de passe utilisateur n'est jamais saisi ni conservé sur nos serveurs.

Les jetons de rafraîchissement Keycloak et Google OAuth2 enregistrés en base PostgreSQL sont chiffrés à l'aide de l'algorithme AES-256-GCM via la bibliothèque Fernet (Cryptography Python) avec une clé secrète stockée dans les variables d'environnement du serveur.