From d1f6f7caf6904602db64da472ff79b563c7f5910 Mon Sep 17 00:00:00 2001 From: Fabien Lamarque Date: Mon, 16 Dec 2024 14:36:49 +0100 Subject: [PATCH] =?UTF-8?q?Expose=20la=20cl=C3=A9=20publique=20de=20l'appl?= =?UTF-8?q?ication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.oots.template | 1 + server.js | 2 + src/adaptateurs/adaptateurChiffrement.js | 7 ++++ src/adaptateurs/adaptateurEnvironnement.js | 3 ++ src/ootsFrance.js | 4 ++ src/routes/routesAuth.js | 33 +++++++++++++++++ test/routes/routesAuth.spec.js | 43 ++++++++++++++++++++++ test/routes/serveurTest.js | 7 ++++ 8 files changed, 100 insertions(+) create mode 100644 src/adaptateurs/adaptateurChiffrement.js create mode 100644 src/routes/routesAuth.js create mode 100644 test/routes/routesAuth.spec.js diff --git a/.env.oots.template b/.env.oots.template index c3cb533..7ddf988 100644 --- a/.env.oots.template +++ b/.env.oots.template @@ -1,4 +1,5 @@ AVEC_REQUETE_PIECE_JUSTIFICATIVE= # active l'API /requete/pieceJustificative avec valeur true +CLE_PRIVEE_JWK_EN_BASE64= # Cle privée utilisée pour déchiffrer les infos (données au format JWK, chiffrées en base64) DONNEES_DEPOT_SERVICES_COMMUNS_LOCAL= # données du bouchon des services communs DONNEES_REQUETEURS= # données de l'annuaire des fournisseurs de service requêteurs URL_OOTS_FRANCE= # URL Serveur OOTS-France, ex. https://oots.gouv.fr diff --git a/server.js b/server.js index b216be7..0010258 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ const EcouteurDomibus = require('./src/ecouteurDomibus'); const OOTS_FRANCE = require('./src/ootsFrance'); +const adaptateurChiffrement = require('./src/adaptateurs/adaptateurChiffrement'); const AdaptateurDomibus = require('./src/adaptateurs/adaptateurDomibus'); const adaptateurEnvironnement = require('./src/adaptateurs/adaptateurEnvironnement'); const adaptateurUUID = require('./src/adaptateurs/adaptateurUUID'); @@ -16,6 +17,7 @@ const depotServicesCommuns = new DepotServicesCommuns(); const ecouteurDomibus = new EcouteurDomibus({ adaptateurDomibus, intervalleEcoute: 1000 }); const serveur = OOTS_FRANCE.creeServeur({ + adaptateurChiffrement, adaptateurDomibus, adaptateurEnvironnement, adaptateurUUID, diff --git a/src/adaptateurs/adaptateurChiffrement.js b/src/adaptateurs/adaptateurChiffrement.js new file mode 100644 index 0000000..c97d393 --- /dev/null +++ b/src/adaptateurs/adaptateurChiffrement.js @@ -0,0 +1,7 @@ +const crypto = require('crypto'); + +const cleHachage = (chaine) => crypto.createHash('md5').update(chaine).digest('hex'); + +module.exports = { + cleHachage, +}; diff --git a/src/adaptateurs/adaptateurEnvironnement.js b/src/adaptateurs/adaptateurEnvironnement.js index 8780542..3d90d4a 100644 --- a/src/adaptateurs/adaptateurEnvironnement.js +++ b/src/adaptateurs/adaptateurEnvironnement.js @@ -1,5 +1,7 @@ const avecRequetePieceJustificative = () => process.env.AVEC_REQUETE_PIECE_JUSTIFICATIVE === 'true'; +const clePriveeJWK = () => JSON.parse(atob(process.env.CLE_PRIVEE_JWK_EN_BASE64)); + const donneesDepotServicesCommunsLocal = () => ( JSON.parse(process.env.DONNEES_DEPOT_SERVICES_COMMUNS_LOCAL) ); @@ -8,6 +10,7 @@ const donneesRequeteurs = () => JSON.parse(process.env.DONNEES_REQUETEURS); module.exports = { avecRequetePieceJustificative, + clePriveeJWK, donneesDepotServicesCommunsLocal, donneesRequeteurs, }; diff --git a/src/ootsFrance.js b/src/ootsFrance.js index 1ca385b..c4e3653 100644 --- a/src/ootsFrance.js +++ b/src/ootsFrance.js @@ -1,12 +1,14 @@ const express = require('express'); const routesAdmin = require('./routes/routesAdmin'); +const routesAuth = require('./routes/routesAuth'); const routesBase = require('./routes/routesBase'); const routesEbms = require('./routes/routesEbms'); const routesRequete = require('./routes/routesRequete'); const creeServeur = (config) => { const { + adaptateurChiffrement, adaptateurDomibus, adaptateurEnvironnement, adaptateurUUID, @@ -24,6 +26,8 @@ const creeServeur = (config) => { app.use('/admin', routesAdmin({ ecouteurDomibus })); + app.use('/auth', routesAuth({ adaptateurChiffrement, adaptateurEnvironnement })); + app.use('/ebms', routesEbms({ adaptateurUUID, horodateur })); app.use('/requete', routesRequete({ diff --git a/src/routes/routesAuth.js b/src/routes/routesAuth.js new file mode 100644 index 0000000..e3d642a --- /dev/null +++ b/src/routes/routesAuth.js @@ -0,0 +1,33 @@ +const express = require('express'); + +const routesAuth = (config) => { + const { + adaptateurChiffrement, + adaptateurEnvironnement, + } = config; + + const routes = express.Router(); + + routes.get('/cles_publiques', (_requete, reponse) => { + const { kty, n, e } = adaptateurEnvironnement.clePriveeJWK(); + const idClePublique = adaptateurChiffrement.cleHachage(n); + + const clePubliqueDansJWKSet = { + keys: [{ + kid: idClePublique, + use: 'enc', + kty, + e, + n, + }], + }; + + reponse.set('Content-Type', 'application/json'); + reponse.status(200) + .send(clePubliqueDansJWKSet); + }); + + return routes; +}; + +module.exports = routesAuth; diff --git a/test/routes/routesAuth.spec.js b/test/routes/routesAuth.spec.js new file mode 100644 index 0000000..1df0b18 --- /dev/null +++ b/test/routes/routesAuth.spec.js @@ -0,0 +1,43 @@ +const axios = require('axios'); + +const { leveErreur } = require('./utils'); +const serveurTest = require('./serveurTest'); + +describe('Le serveur des routes `/auth`', () => { + const serveur = serveurTest(); + let port; + + beforeEach((suite) => serveur.initialise(() => { + port = serveur.port(); + suite(); + })); + + afterEach((suite) => serveur.arrete(suite)); + + describe('sur GET /auth/cles_publiques', () => { + it('retourne les clés de chiffrement au format JSON Web Key Set', () => { + serveur.adaptateurEnvironnement().clePriveeJWK = () => ({ + e: 'AQAB', + n: '503as-2qay5...', + kty: 'RSA', + }); + serveur.adaptateurChiffrement().cleHachage = (chaine) => `hash de ${chaine}`; + + return axios.get(`http://localhost:${port}/auth/cles_publiques`) + .then((reponse) => { + expect(reponse.status).toEqual(200); + expect(reponse.data).toEqual({ + keys: [ + { + kid: 'hash de 503as-2qay5...', + kty: 'RSA', + use: 'enc', + e: 'AQAB', + n: '503as-2qay5...', + }], + }); + }) + .catch(leveErreur); + }); + }); +}); diff --git a/test/routes/serveurTest.js b/test/routes/serveurTest.js index f6a077a..cdb835e 100644 --- a/test/routes/serveurTest.js +++ b/test/routes/serveurTest.js @@ -5,6 +5,7 @@ const Requeteur = require('../../src/ebms/requeteur'); const TypeJustificatif = require('../../src/ebms/typeJustificatif'); const serveurTest = () => { + let adaptateurChiffrement; let adaptateurDomibus; let adaptateurEnvironnement; let adaptateurUUID; @@ -22,6 +23,10 @@ const serveurTest = () => { }; const initialise = (suite) => { + adaptateurChiffrement = { + cleHachage: () => '', + }; + adaptateurDomibus = { envoieMessageRequete: () => Promise.resolve(), urlRedirectionDepuisReponse: () => Promise.reject(new ErreurAbsenceReponseDestinataire('aucune URL reçue')), @@ -69,6 +74,7 @@ const serveurTest = () => { serveur = OOTS_FRANCE.creeServeur({ adaptateurDomibus, + adaptateurChiffrement, adaptateurEnvironnement, adaptateurUUID, depotPointsAcces, @@ -85,6 +91,7 @@ const serveurTest = () => { const port = () => serveur.port(); return { + adaptateurChiffrement: () => adaptateurChiffrement, adaptateurDomibus: () => adaptateurDomibus, adaptateurEnvironnement: () => adaptateurEnvironnement, adaptateurUUID: () => adaptateurUUID,