Aller au contenu
Table des matières

SpringBootFilesUploader

SpringBootFilesUploader est une API REST en Kotlin construite sur Spring Boot 2.6.3. Son nom décrit sa première tâche : recevoir un fichier, en placer les octets dans un compartiment compatible S3 et sa description dans MongoDB, puis le resservir par son identifiant. Le code va plus loin que le nom. La même application liste et contrôle des conteneurs Docker, interroge un serveur Caddy et exécute des commandes par SSH, le tout derrière une authentification JWT à trois rôles. Le dernier commit date de février 2022 et le README tient en une ligne : tout ce qui suit vient du code source.

API backendAPIDocker
Kotlin 1.6Spring Boot 2.6Spring SecurityJWTMongoDBS3 / MinIOdocker-javaApache MINA SSHDspringdocGradle
  • Mis à jour

1. Aperçu

Six contrôleurs composent l’API. Les chemins partent de la racine du serveur ; /auth/** et la documentation de l’API sont publics, tout le reste exige un jeton porteur (SecurityConf.kt).

ContrôleurPoints d’accèsRôles dans @PreAuthorize
AuthController (/auth)POST /signin, POST /signup, POST /signup/adminpublics ; /signup/admin exige ADMIN
FilesController (/files)POST /documents (champ multipart document), GET /{id}envoi : MODERATOR ou ADMIN ; téléchargement : tout rôle
UserController (/user)GET /{id}/page, GET /profile, GET /mod, GET /adminselon le point d’accès
DockerController (/containers)GET /ping, GET /list, PUT /create, POST /start/{name}, /stop/{name}, /restart/{name}, /rename/{name}/{newName}MOD ou ADMIN ; création et renommage ADMIN
CaddyController (/caddy)GET /pingauthentifié
SSHController (/ssh)POST /cliADMIN

La page OpenAPI est servie par springdoc à /api-docs (application.yml).

2. Cas d’utilisation

API Spring Boot en Kotlin qui range les fichiers téléversés dans MinIO/S3 derrière des rôles JWT, avec des routes Docker et SSH.

Diagramme de cas d’utilisation de SpringBootFilesUploader : S'inscrire et obtenir un JWT; Téléverser un document; Télécharger un fichier stocké; Gérer des conteneurs Docker; Lancer une commande SSHSpringBootFilesUploaderS'inscrire et obtenir un JWTTéléverser un documentTélécharger un fichier stockéGérer des conteneurs DockerLancer une commande SSHUtilisateur de l'APIModérateur ou admin«système»MinIO S3 et MongoDB
Acteurs à gauche (personnes) et à droite (systèmes externes) ; chaque ovale est un cas d’utilisation appuyé par les fichiers cités ci-dessous.
S'inscrire et obtenir un JWT
Utilisateur de l'APIMinIO S3 et MongoDB

POST /auth/signup enregistre l'utilisateur dans MongoDB avec son mot de passe haché et ses rôles ; POST /auth/signin renvoie un JwtResponse avec le jeton et les rôles (AuthController.kt, JwtUtils.kt).

Téléverser un document
Modérateur ou adminMinIO S3 et MongoDB

POST /files/documents (modérateur ou admin) valide l'extension avec DOC_FILE_EXTENSION_REGEX, écrit le fichier dans le bucket S3 sous files/<uuid>/<nom> et note ses métadonnées dans MongoDB.

Télécharger un fichier stocké
Utilisateur de l'APIMinIO S3 et MongoDB

GET /files/{id} retrouve la fiche du fichier dans MongoDB, lit l'objet dans S3 et le renvoie en pièce jointe avec son type et sa taille.

Gérer des conteneurs Docker
Modérateur ou admin

Les routes /containers listent, créent, démarrent, arrêtent, redémarrent et renomment des conteneurs avec docker-java, sur l'hôte Docker défini dans application.yml (tcp://127.0.0.1:2375).

Lancer une commande SSH
Modérateur ou admin

POST /ssh/cli (admin seulement) ouvre une session Apache SSHD avec l'hôte, le port et les identifiants reçus, puis renvoie la sortie de la commande.

2.1. Scénario : Déposer un PDF puis le récupérer

  1. Démarrer MongoDB sur localhost:27017 et MinIO sur localhost:9000, comme le prévoit application.yml, puis lancer ./gradlew bootRun.
  2. Envoyer POST /auth/signup avec un nom d'utilisateur, un courriel, un mot de passe et le rôle « mod ».
  3. Appeler POST /auth/signin et copier le JWT de la réponse.
  4. Envoyer le PDF à POST /files/documents dans le champ multipart « document » avec le jeton Bearer ; la réponse donne fileId et fileName.
  5. Appeler GET /files/{fileId} pour télécharger le PDF, ou parcourir les routes dans Swagger UI à /api-docs.

Fichiers consultésbuild.gradle.ktssrc/main/resources/application.ymlsrc/main/kotlin/com/api/project/controller/AuthController.ktsrc/main/kotlin/com/api/project/controller/FilesController.ktsrc/main/kotlin/com/api/project/controller/DockerController.ktsrc/main/kotlin/com/api/project/controller/SSHController.ktsrc/main/kotlin/com/api/project/service/FilesService.ktsrc/main/kotlin/com/api/project/config/security/SecurityConf.kt

3. Parcours d’un envoi

sequenceDiagram
  participant C as Client
  participant F as Filtre JWT
  participant FC as FilesController
  participant FS as FilesService
  participant S3 as FileS3 (S3 / MinIO)
  participant M as FilesMongo (MongoDB)
  C->>F: POST /files/documents, jeton Bearer, multipart "document"
  F->>FC: utilisateur authentifié avec ses rôles
  FC->>FC: @PreAuthorize MODERATOR ou ADMIN, contrôle de l’extension
  FC->>FS: addDocument(octets, nom, ext, contentType, taille)
  FS->>S3: putObject(compartiment "fus", "files/{uuid}/{nom}")
  FS->>M: getNewFileId() = nombre + 1, enregistre FileModel
  FS-->>C: 200 {fileId, fileName}
  C->>FC: GET /files/{fileId}
  FC->>M: getFile(id) → chemin, nom, type, taille
  FC->>S3: getObject(chemin)
  FC-->>C: octets avec Content-Disposition attachment
  1. AuthTokenFilter lit le jeton porteur, JwtUtils le valide avec le jwtSecret de la configuration, et les rôles de l’utilisateur viennent de MongoDB.
  2. FilesController.addDocument refuse une partie manquante et vérifie le nom de fichier avec DOC_FILE_EXTENSION_REGEX : tableurs, documents Word, PDF, images courantes, MP4, MOV, ZIP, MP3, WAV, ISO et RAR. Seule l’extension est vérifiée, pas le contenu. Le contrôle de taille est en commentaire.
  3. FilesService.addDocument construit la clé d’objet files/{UUID aléatoire}/{nom d’origine} et écrit les octets par l’interface FileRepository, implémentée par FileS3 avec le SDK AWS. FileS3 crée le compartiment au démarrage s’il n’existe pas.
  4. Le service demande ensuite un identifiant à FilesMongo, qui vaut le nombre de documents de la collection plus un, puis enregistre un FileModel (identifiant, chemin, nom, extension, UUID, type de contenu, taille).
  5. Un téléchargement cherche l’identifiant dans MongoDB, lit l’objet à son chemin enregistré et le renvoie avec le type et la longueur conservés.

Les octets sont écrits avant les métadonnées. Si l’enregistrement MongoDB échoue, l’objet reste dans le compartiment sans rien qui pointe vers lui.

4. Structure du projet

Vérifiée sur l’arborescence du dépôt. Tout se trouve sous src/main/kotlin/com/api/project/, y compris deux fichiers Java.

SpringBootFilesUploader/
├── build.gradle.kts, settings.gradle.kts, gradlew   build Gradle en DSL Kotlin (version 0.0.3)
├── Dockerfile                                         image openjdk11 qui lance build/libs/project-0.0.2.jar
├── docker-compose.yml                                 vide
└── src/
    ├── main/kotlin/com/api/project/
    │   ├── Application.kt
    │   ├── config/            S3Config, DockerConfig, WebClientConfig, SpringDocOpenAPI, GeneralConfig
    │   │   └── security/      SecurityConf (filtre JWT, sessions sans état, chemins publics)
    │   ├── constants/         MAX_DOCUMENT_FILE_SIZE, DOC_FILE_EXTENSION_REGEX
    │   ├── controller/        Auth, Files, User, Docker, Caddy, SSH (+ un DockerComposeController.java vide)
    │   │   └── dto/           FileDTO, DockerDTO, SSHDTO, request/ (connexion, inscription), response/ (JWT, message)
    │   ├── exception/         ApiError, BasicException
    │   ├── models/            UserModel, RoleModel, FileModel, DockerModel, SSHModel, enum/ (ERole, DockerStatus, FilesStatus)
    │   ├── repository/
    │   │   ├── file/          FileRepository (interface), FileS3, FilesMongo
    │   │   ├── user/          UserRepository, RoleRepository (Spring Data MongoDB)
    │   │   ├── docker/        DockerClientAPI, DockerMongo, DockerCompose.java (ébauche)
    │   │   ├── caddy/         CaddyMongo
    │   │   └── SSHRepository.kt
    │   └── service/
    │       ├── FilesService, SSHService
    │       ├── docker/        DockerService, DockerComposeService
    │       ├── caddy/         CaddyAPI, CaddyService, conversion de configuration et modèle JSON
    │       └── jwt/           JwtUtils, AuthTokenFilter, AuthEntryPointJwt, UserDetails*
    ├── main/resources/        application.yml, application-local.yml
    └── test/kotlin/.../ApplicationTests.kt   un seul test contextLoads()

5. Services externes

L’application s’attend à joindre ces services, avec les valeurs par défaut de application.yml et application-local.yml :

ServiceValeur par défautUtilisé par
MongoDBmongodb://localhost:27017/demoutilisateurs, rôles, métadonnées des fichiers, fiches Docker et Caddy
Stockage compatible S3 (MinIO)http://localhost:9000, compartiment fus, clés minioadminoctets des fichiers
API Docker Enginetcp://127.0.0.1:2375points d’accès /containers par docker-java
API d’administration Caddylocalhost:2019/caddy/ping et conversion de configuration
Serveur Spring Cloud Confighttp://localhost:8888 (profil local)configuration externe
Hôtes SSHfournis dans chaque requête /ssh/cliSSHService par Apache MINA SSHD

6. Dépendances

Tirées de build.gradle.kts. Les versions absentes viennent des BOM Spring Boot 2.6.3 et Spring Cloud 2021.0.1.

BibliothèqueVersionRôle
Starters Spring Boot : web, webflux, security, data-mongodb, validation2.6.3API HTTP, WebClient réactif, sécurité, dépôts MongoDB, validation des requêtes
Kotlin JVM, plugin.spring, kotlin-reflect, kotlin-stdlib-jdk81.6.10Langage et intégration Spring, cible Java 11
Spring Cloud starter-config, starter-bootstrap2021.0.1Configuration venant d’un serveur de configuration
spring-security-oauth2-joseBOMClasses JOSE / JWT
io.jsonwebtoken:jjwt0.9.1Signature et lecture des jetons d’accès
com.amazonaws:aws-java-sdk-s31.12.159Client S3 / MinIO pour les octets
com.github.docker-java:docker-java + transport-httpclient53.2.13Client de l’API Docker Engine
org.apache.sshd:sshd-core2.8.0Client SSH pour /ssh/cli
org.springdoc:springdoc-openapi-ui + -webflux-ui1.6.6Document OpenAPI et Swagger UI
com.squareup.okhttp3:okhttp4.9.3Client HTTP
com.googlecode.json-simple:json-simple1.1.1Réponses JSONArray pour la liste des conteneurs
Tests : spring-boot-starter-test, spring-security-test, io.mockk:mockk 1.12.2, com.ninja-squad:springmockk 3.1.0, mockwebserver d’OkHttpOutils de test, presque inutilisés

spring-boot-starter-parent est déclaré comme dépendance implementation alors que c’est un POM parent, et une BOM Testcontainers (1.15.3) est importée sans aucune dépendance Testcontainers.

7. Démarrage

Démarrez MongoDB et MinIO en local (le docker-compose.yml du dépôt est vide), puis lancez l’application avec le profil local, que application.yml active par défaut :

docker run -d -p 27017:27017 mongo
docker run -d -p 9000:9000 -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin minio/minio server /data
./gradlew bootRun

Le profil local pointe aussi vers un serveur Spring Cloud Config sur le port 8888. Les rôles sont lus dans la collection de rôles de MongoDB et rien dans le code ne les crée : insérez ROLE_USER, ROLE_MODERATOR et ROLE_ADMIN avant de vous inscrire.

8. Limites

  • Rôle de modérateur en libre-service. POST /auth/signup transforme un rôle demandé "mod" en ROLE_MODERATOR : n’importe qui peut créer un compte autorisé à envoyer des fichiers.
  • Des noms de rôles qui ne correspondent jamais. DockerController vérifie hasRole('MOD'), mais les rôles sont ROLE_USER, ROLE_MODERATOR et ROLE_ADMIN ; seuls les administrateurs passent ces contrôles.
  • Identifiants séquentiels et concurrents. getNewFileId() renvoie le nombre de documents plus un : deux envois simultanés peuvent obtenir le même identifiant, et une suppression fait entrer le suivant en collision.
  • Envois sans limite, en mémoire. Les limites multipart sont fixées à 500 000 Mo, le contrôle de taille est en commentaire et document.bytes charge tout le fichier en mémoire avant l’envoi vers S3.
  • Exécution de commandes à distance, par conception. /ssh/cli ouvre un shell sur n’importe quel hôte et y exécute la commande donnée pour un administrateur, et /containers parle à un socket TCP Docker sans authentification.
  • Valeurs par défaut versionnées. jwtSecret: secret, les clés MinIO minioadmin, un mot de passe du serveur de configuration et une adresse courriel personnelle se trouvent dans les fichiers YAML.
  • Build et documentation. Le Dockerfile copie project-0.0.2.jar alors que le build produit la version 0.0.3, le fichier Compose et le README sont vides, et le seul test vérifie que le contexte se charge.

9. Sources

10. Pipeline CI/CD

Aucun pipeline CI/CD dans le dépôt. Le code se construit et se lance à la main, comme décrit plus haut.

Généré à partir du code au commit 3be3bbc.

11. Schéma de déploiement

Mermaid Schéma de déploiement
flowchart LR
  repo[("Dépôt GitHub")]
  image["Image Docker<br/>FROM adoptopenjdk/openjdk11:alpine"]
  repo -->|"docker build"| image

12. Dépendances externes

25 paquets déclarés (20 à l’exécution, 5 pour le développement) dans build.gradle.kts.

Tableau des paquets 25
Dépendances externes
PaquetVersionUsageRôleRegistre
org.springframework.boot:spring-boot-starter-web—exécutionCadriciel webcentral.sonatype.com
org.springframework.boot:spring-boot-starter-parent:2.6.3—exécution—central.sonatype.com
com.amazonaws:aws-java-sdk-s3:1.12.159—exécution—central.sonatype.com
com.squareup.okhttp3:okhttp:4.9.3—exécution—central.sonatype.com
org.jetbrains.kotlin:kotlin-reflect—exécution—central.sonatype.com
org.jetbrains.kotlin:kotlin-stdlib-jdk8—exécution—central.sonatype.com
org.springframework.cloud:spring-cloud-starter-bootstrap—exécutionInterface utilisateurcentral.sonatype.com
org.springframework.cloud:spring-cloud-starter-config—exécution—central.sonatype.com
org.springframework.boot:spring-boot-starter-validation—exécution—central.sonatype.com
org.springframework.boot:spring-boot-starter-data-mongodb—exécutionAccès aux donnéescentral.sonatype.com
org.springframework.boot:spring-boot-starter-security—exécutionAuthentification et sécuritécentral.sonatype.com
org.springframework.boot:spring-boot-starter-webflux—exécutionCadriciel webcentral.sonatype.com
org.springframework.security:spring-security-oauth2-jose—exécutionAuthentification et sécuritécentral.sonatype.com
io.jsonwebtoken:jjwt:0.9.1—exécution—central.sonatype.com
com.github.docker-java:docker-java:3.2.13—exécution—central.sonatype.com
com.github.docker-java:docker-java-transport-httpclient5:3.2.13—exécution—central.sonatype.com
org.springdoc:springdoc-openapi-ui:1.6.6—exécution—central.sonatype.com
org.springdoc:springdoc-openapi-webflux-ui:1.6.6—exécution—central.sonatype.com
org.apache.sshd:sshd-core:2.8.0—exécution—central.sonatype.com
com.googlecode.json-simple:json-simple:1.1.1—exécution—central.sonatype.com
org.springframework.boot:spring-boot-starter-test—développementTestscentral.sonatype.com
org.springframework.security:spring-security-test—développementTestscentral.sonatype.com
io.mockk:mockk:1.12.2—développement—central.sonatype.com
com.ninja-squad:springmockk:3.1.0—développement—central.sonatype.com
com.squareup.okhttp3:mockwebserver—développementTestscentral.sonatype.com

13. Glossaire

Dépôt

Les fichiers source, la configuration et l’historique versionné d’un projet.

README

Le document d’entrée du dépôt, qui présente généralement son rôle et son installation.

Dépendance

Une bibliothèque, un outil ou un service nécessaire à la compilation ou à l’exécution d’un composant.

API

Une interface par laquelle des composants logiciels échangent des requêtes et des résultats. Une API n’utilise pas nécessairement HTTP.

HTTP

Un protocole de requête et réponse utilisé par les navigateurs et services web. Une requête comprend une méthode, un chemin, des en-têtes et parfois un corps.

Session

Un état conservé entre plusieurs requêtes, souvent pour suivre un utilisateur connecté. L’authentification et les permissions restent des vérifications distinctes.

Conteneur

Un environnement de processus isolé créé à partir d’une image. Les données persistantes nécessitent un stockage hors de son système de fichiers temporaire.

Docker Compose

Un format de configuration et un outil pour lancer des conteneurs, réseaux et volumes associés. L’ordre de démarrage ne garantit pas qu’un service est prêt.

Volume et montage de dossier

Un volume est un stockage géré par la plateforme de conteneurs ; un montage de dossier expose un chemin de l’hôte dans un conteneur.

Port publié

Un port de l’hôte associé au port d’un service dans un conteneur. Sa publication peut rendre le service accessible hors du réseau des conteneurs.

Interface en ligne de commande

Une interface textuelle où les commandes et arguments choisissent les opérations. Les codes de retour permettent aux scripts de détecter un succès ou un échec.

Compilation

Les étapes qui transforment les sources et dépendances en programme exécutable ou en livrable distribuable.

Mermaid

Un langage de diagrammes textuel. Les nœuds et liens décrivent un modèle ; le diagramme n’exécute pas le projet.

Maillage

Une surface représentée par des sommets et des éléments reliés, souvent des triangles. Sa géométrie est distincte de son matériau ou de sa texture.

Détection continue des collisions

Une recherche de contact pendant le mouvement entre deux états, au lieu de tester seulement ses extrémités.

Backend

Une implémentation derrière une interface commune. Selon le contexte, il peut s’agir d’un service côté serveur ou d’une implémentation graphique, d’entrée ou de stockage.

Base de données

Un système de stockage et d’interrogation de données structurées. Son schéma, ses règles d’accès et sa persistance déterminent comment l’application utilise ces données.

Micrologiciel

Un logiciel exécuté sur un appareil ou microcontrôleur pour contrôler son matériel et ses communications.

14. Références

  1. antoinebou12. (2026, 5 novembre). SpringBootFilesUploader. [Software repository] github.com.
  2. antoinebou12. (2026, 5 novembre). SpringBootFilesUploader: README. [Repository documentation] github.com.
  3. antoinebou12. (2026, 5 novembre). src/main/kotlin/com/api/project/controller/FilesController.kt. [Source file] github.com.
  4. antoinebou12. (2026, 5 novembre). src/main/kotlin/com/api/project/service/FilesService.kt. [Source file] github.com.
  5. antoinebou12. (2026, 5 novembre). build.gradle.kts. [Source file] github.com.
  6. Boucher, A. (2026, 23 octobre). SpringBootFilesUploader : Séparer les octets et les métadonnées. [Project article] antoineboucher.info.

Les sources sans date de publication indiquent la date de leur dernière vérification, le 5 novembre 2026. Les liens des fichiers conservent la révision inspectée lorsqu’elle est disponible.