diff --git a/.eslintrc.js b/.eslintrc.js index 2453cce..d60d0a0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,7 +22,7 @@ module.exports = { 'no-only-tests/no-only-tests': 'error', 'no-param-reassign': ['error', { props: true, - ignorePropertyModificationsFor: ['requete'], + ignorePropertyModificationsFor: ['requete', 'reponse'], }], }, }; diff --git a/src/api/connexionFCPlus.js b/src/api/connexionFCPlus.js index 1b08899..6dda44f 100644 --- a/src/api/connexionFCPlus.js +++ b/src/api/connexionFCPlus.js @@ -1,4 +1,4 @@ -const { redirigeDepuisNavigateur, stockeDansCookieSession } = require('../routes/utils'); +const { stockeDansCookieSession } = require('../routes/utils'); const connexionFCPlus = (config, code, requete, reponse) => { const { adaptateurChiffrement, fabriqueSessionFCPlus } = config; @@ -8,7 +8,7 @@ const connexionFCPlus = (config, code, requete, reponse) => { return fabriqueSessionFCPlus.nouvelleSession(code) .then((session) => session.enJSON()) .then((infos) => stockeDansCookieSession(infos, adaptateurChiffrement, requete)) - .then(() => redirigeDepuisNavigateur('/', reponse)) + .then(() => reponse.render('redirectionNavigateur', { destination: '/' })) .catch((e) => reponse.status(502).json({ erreur: `Échec authentification (${e.message})` })); }; diff --git a/src/api/creationSessionFCPlus.js b/src/api/creationSessionFCPlus.js index 75fb4c0..7b0804c 100644 --- a/src/api/creationSessionFCPlus.js +++ b/src/api/creationSessionFCPlus.js @@ -1,4 +1,4 @@ -const { redirigeDepuisNavigateur, stockeDansCookieSession } = require('../routes/utils'); +const { stockeDansCookieSession } = require('../routes/utils'); const creationSessionFCPlus = (config, requete, reponse) => { const { adaptateurChiffrement, adaptateurEnvironnement, adaptateurFranceConnectPlus } = config; @@ -17,7 +17,7 @@ const creationSessionFCPlus = (config, requete, reponse) => { return stockeDansCookieSession({ etat }, adaptateurChiffrement, requete) .then(() => construisURL()) - .then((url) => redirigeDepuisNavigateur(url, reponse)); + .then((url) => reponse.render('redirectionNavigateur', { destination: url })); }; module.exports = creationSessionFCPlus; diff --git a/src/routes/middleware.js b/src/routes/middleware.js index d53156d..efbd3b5 100644 --- a/src/routes/middleware.js +++ b/src/routes/middleware.js @@ -1,5 +1,3 @@ -const { redirigeDepuisNavigateur } = require('./utils'); - class Middleware { constructor(config) { this.adaptateurChiffrement = config.adaptateurChiffrement; @@ -24,7 +22,7 @@ class Middleware { return this.adaptateurChiffrement.verifieJeton(requete.session.jeton, this.secret) .then(valide) .then(suite) - .catch(() => redirigeDepuisNavigateur('/', reponse)); + .catch(() => reponse.render('redirectionNavigateur', { destination: '/' })); } } diff --git a/src/routes/routesAuth.js b/src/routes/routesAuth.js index 0bb87c2..5e19ac8 100644 --- a/src/routes/routesAuth.js +++ b/src/routes/routesAuth.js @@ -1,6 +1,5 @@ const express = require('express'); -const { redirigeDepuisNavigateur } = require('./utils'); const connexionFCPlus = require('../api/connexionFCPlus'); const deconnexionFCPlus = require('../api/deconnexionFCPlus'); const creationSessionFCPlus = require('../api/creationSessionFCPlus'); @@ -44,7 +43,8 @@ const routesAuth = (config) => { reponse.status(400).json({ erreur: "Paramètre 'code' absent de la requête" }); } else { const paramsRequete = new URLSearchParams(requete.query).toString(); - redirigeDepuisNavigateur(`/auth/fcplus/connexion_apres_redirection?${paramsRequete}`, reponse); + const destination = `/auth/fcplus/connexion_apres_redirection?${paramsRequete}`; + reponse.render('redirectionNavigateur', { destination }); } }); diff --git a/src/routes/utils.js b/src/routes/utils.js index 7614b2a..c93c2c7 100644 --- a/src/routes/utils.js +++ b/src/routes/utils.js @@ -1,13 +1,5 @@ -const redirigeDepuisNavigateur = (destination, reponse) => reponse.send(` - - - - - -`); - const stockeDansCookieSession = (infos, adaptateurChiffrement, requete) => adaptateurChiffrement .genereJeton(infos) .then((jwt) => { requete.session.jeton = jwt; }); -module.exports = { redirigeDepuisNavigateur, stockeDansCookieSession }; +module.exports = { stockeDansCookieSession }; diff --git a/src/vues/redirectionNavigateur.mustache b/src/vues/redirectionNavigateur.mustache new file mode 100644 index 0000000..0226ea2 --- /dev/null +++ b/src/vues/redirectionNavigateur.mustache @@ -0,0 +1,2 @@ + + diff --git a/test/api/connexionFCPlus.spec.js b/test/api/connexionFCPlus.spec.js index 75db5eb..3c1a2fb 100644 --- a/test/api/connexionFCPlus.spec.js +++ b/test/api/connexionFCPlus.spec.js @@ -14,7 +14,7 @@ describe('Le requêteur de connexion FC+', () => { }); requete.session = {}; reponse.json = () => Promise.resolve(); - reponse.redirect = () => Promise.resolve(); + reponse.render = () => Promise.resolve(); reponse.status = () => reponse; }); diff --git a/test/api/creationSessionFCPlus.spec.js b/test/api/creationSessionFCPlus.spec.js index 1563289..4ed82a5 100644 --- a/test/api/creationSessionFCPlus.spec.js +++ b/test/api/creationSessionFCPlus.spec.js @@ -1,5 +1,16 @@ const creationSessionFCPlus = require('../../src/api/creationSessionFCPlus'); +const prepareVerificationPresenceElement = (element, reponse) => { + reponse.render = (_nomPageRedirection, { destination }) => { + try { + expect(destination).toContain(element); + return Promise.resolve(); + } catch (e) { + return Promise.reject(e); + } + }; +}; + describe('Le requêteur de création de session FC+', () => { const adaptateurChiffrement = {}; const adaptateurEnvironnement = {}; @@ -18,99 +29,61 @@ describe('Le requêteur de création de session FC+', () => { adaptateurFranceConnectPlus.urlCreationSession = () => Promise.resolve(''); requete.query = {}; requete.session = {}; - reponse.send = () => Promise.resolve(); + reponse.render = () => Promise.resolve(); }); it('redirige vers serveur France Connect Plus', () => { expect.assertions(1); adaptateurFranceConnectPlus.urlCreationSession = () => Promise.resolve('http://example.com'); - reponse.send = (url) => { - try { - expect(url).toContain('http://example.com?'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + prepareVerificationPresenceElement('http://example.com?', reponse); return creationSessionFCPlus(config, requete, reponse); }); - it('ajoute des paramètres à la requête', () => { - expect.assertions(6); - - reponse.send = (url) => { - try { - expect(url).toContain('scope=profile%20openid%20birthcountry%20birthplace'); - expect(url).toContain('acr_values=eidas2'); - expect(url).toContain('claims={%22id_token%22:{%22amr%22:{%22essential%22:true}}}'); - expect(url).toContain('prompt=login%20consent'); - expect(url).toContain('response_type=code'); - expect(url).toContain('idp_hint='); - - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + const verifiePresenceParametreEnDur = (param) => it(`ajoute le paramètre ${param} à la requête`, () => { + expect.assertions(1); + prepareVerificationPresenceElement(param, reponse); return creationSessionFCPlus(config, requete, reponse); }); + [ + 'scope=profile%20openid%20birthcountry%20birthplace', + 'acr_values=eidas2', + 'claims={%22id_token%22:{%22amr%22:{%22essential%22:true}}}', + 'prompt=login%20consent', + 'response_type=code', + 'idp_hint=', + ].forEach(verifiePresenceParametreEnDur); + it("ajoute l'identifiant client FC+ en paramètre", () => { expect.assertions(1); - adaptateurEnvironnement.identifiantClient = () => '12345'; - reponse.send = (url) => { - try { - expect(url).toContain('client_id=12345'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + prepareVerificationPresenceElement('client_id=12345', reponse); return creationSessionFCPlus(config, requete, reponse); }); it("ajoute l'URL de redirection post-login en paramètre", () => { expect.assertions(1); - adaptateurEnvironnement.urlRedirectionConnexion = () => 'http://example.com'; - reponse.send = (url) => { - try { - expect(url).toContain('redirect_uri=http://example.com'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + prepareVerificationPresenceElement('redirect_uri=http://example.com', reponse); return creationSessionFCPlus(config, requete, reponse); }); - it('ajoute un état et un nonce en paramètres de la requête', () => { - expect.assertions(2); - let nbClesGenerees = 0; + it('ajoute un état en paramètre de la requête', () => { + expect.assertions(1); + adaptateurChiffrement.cleHachage = () => '12345'; - adaptateurChiffrement.cleHachage = () => { - nbClesGenerees += 1; - return `12345-${nbClesGenerees}`; - }; + prepareVerificationPresenceElement('state=12345', reponse); + return creationSessionFCPlus(config, requete, reponse); + }); - reponse.send = (url) => { - try { - expect(url).toContain('state=12345-1'); - expect(url).toContain('nonce=12345-2'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; + it('ajoute un nonce en paramètre de la requête', () => { + expect.assertions(1); + adaptateurChiffrement.cleHachage = () => '12345'; + prepareVerificationPresenceElement('nonce=12345', reponse); return creationSessionFCPlus(config, requete, reponse); }); @@ -144,15 +117,7 @@ describe('Le requêteur de création de session FC+', () => { expect.assertions(1); adaptateurEnvironnement.fournisseurIdentiteSuggere = () => 'eidas-bridge'; - reponse.send = (url) => { - try { - expect(url).toContain('idp_hint=eidas-bridge'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + prepareVerificationPresenceElement('idp_hint=eidas-bridge', reponse); return creationSessionFCPlus(config, requete, reponse); }); }); @@ -163,15 +128,7 @@ describe('Le requêteur de création de session FC+', () => { adaptateurEnvironnement.avecMock = () => true; requete.query.contexteMock = 'unContexte'; - reponse.send = (url) => { - try { - expect(url).toContain('contexte_mock=unContexte'); - return Promise.resolve(); - } catch (e) { - return Promise.reject(e); - } - }; - + prepareVerificationPresenceElement('contexte_mock=unContexte', reponse); return creationSessionFCPlus(config, requete, reponse); }); }); diff --git a/test/routes/middleware.spec.js b/test/routes/middleware.spec.js index 7f135e9..393cefc 100644 --- a/test/routes/middleware.spec.js +++ b/test/routes/middleware.spec.js @@ -13,7 +13,7 @@ describe('Le middleware OOTS-France', () => { adaptateurChiffrement.verifieJeton = () => Promise.resolve(); requete = { query: {}, session: { jeton: '' } }; - reponse.send = () => Promise.resolve(); + reponse.render = () => Promise.resolve(); }); it('vérifie le jeton stocké en session', (suite) => { @@ -82,9 +82,9 @@ describe('Le middleware OOTS-France', () => { }); it('redirige vers page accueil depuis navigateur si tampon communiqué différent', () => { - reponse.send = (html) => { + reponse.render = (_nomPageRedirection, { destination }) => { try { - expect(html).toContain(''); + expect(destination).toBe('/'); return Promise.resolve(); } catch (e) { return Promise.reject(e);