From eec90f84db13a10fe27ddb53efd064735aa12ff9 Mon Sep 17 00:00:00 2001 From: Benoit Serrano Date: Wed, 9 Oct 2024 16:00:39 +0200 Subject: [PATCH] add whitelisting emails --- config.js | 2 ++ lib/domains.js | 12 ++++++++++++ lib/format.js | 14 ++++++++++++++ lib/format.test.js | 40 ++++++++++++++++++++++++++++++++++++++++ lib/oidcAuth.js | 14 ++++++++++++++ 5 files changed, 82 insertions(+) create mode 100644 lib/domains.js create mode 100644 lib/format.test.js diff --git a/config.js b/config.js index 76c9e8c6..8afaba24 100644 --- a/config.js +++ b/config.js @@ -109,6 +109,8 @@ config.STATS_EXTERNAL_DASHBOARD_URL = process.env.STATS_EXTERNAL_DASHBOARD_URL config.OIDC_PROVIDER_URL = process.env.OIDC_PROVIDER_URL +config.GRIST_API_KEY = process.env.GRIST_API_KEY +config.GRIST_API_DOMAINS_URL = process.env.GRIST_API_DOMAINS_URL config.OIDC_CLIENT_ID = process.env.OIDC_CLIENT_ID config.OIDC_CLIENT_SECRET = process.env.OIDC_CLIENT_SECRET config.OIDC_ACR_VALUES = process.env.OIDC_ACR_VALUES diff --git a/lib/domains.js b/lib/domains.js new file mode 100644 index 00000000..f336eafd --- /dev/null +++ b/lib/domains.js @@ -0,0 +1,12 @@ +const config = require("../config") + +module.exports.getWhitelistedDomains = async () => { + const URL = config.GRIST_API_DOMAINS_URL + const API_KEY = config.GRIST_API_KEY + const result = await fetch(URL, {headers: {Authorization: `Bearer ${API_KEY}`}}) + const data = await result.json() + if(data.status !== "success") { + throw new Error("Error while fetching GRIST API") + } + return data.items +} diff --git a/lib/format.js b/lib/format.js index 82166220..dc107725 100644 --- a/lib/format.js +++ b/lib/format.js @@ -80,3 +80,17 @@ module.exports.formatLocalTime = function(date) { return date.getHours() + ":" + minutes + ":" + seconds } +module.exports.extractEmailDomain = function(email) { + // Expression régulière pour valider une adresse email + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; + + // Vérification si l'adresse email est valide + if (!emailRegex.test(email)) { + throw new Error("Adresse email invalide"); + } + + // Extraction du domaine avec un split + const domain = email.split("@")[1]; + + return domain; +} diff --git a/lib/format.test.js b/lib/format.test.js new file mode 100644 index 00000000..aa940d3a --- /dev/null +++ b/lib/format.test.js @@ -0,0 +1,40 @@ +const { expect } = require("chai") +const sinon = require("sinon") + +const extractEmailDomain = require("./format") + +describe("format", function() { + + describe("extractEmailDomain", () => { + test("devrait retourner le domaine d\"une adresse email valide", () => { + const email = "john.doe@example.com"; + const domain = extractEmailDomain(email); + expect(domain).toBe("example.com"); + }); + + test("devrait retourner le domaine d\"une adresse email académique", () => { + const email = "student@university.edu"; + const domain = extractEmailDomain(email); + expect(domain).toBe("university.edu"); + }); + + test("devrait lever une erreur pour une adresse email sans @", () => { + expect(() => { + extractEmailDomain("invalidEmail"); + }).toThrow("Adresse email invalide"); + }); + + test("devrait lever une erreur pour un domaine manquant", () => { + expect(() => { + extractEmailDomain("john.doe@"); + }).toThrow("Domaine email invalide"); + }); + + test("devrait lever une erreur pour une chaîne vide", () => { + expect(() => { + extractEmailDomain("); + }).toThrow("Adresse email invalide"); + }); +}); + +}) diff --git a/lib/oidcAuth.js b/lib/oidcAuth.js index 60353598..35716f24 100644 --- a/lib/oidcAuth.js +++ b/lib/oidcAuth.js @@ -12,6 +12,8 @@ const { generators, Issuer } = require("openid-client") const config = require("../config.js") const urls = require("../urls") const db = require("../lib/db") +const format = require("../lib/format") +const { getWhitelistedDomains } = require("./domains.js") const urlCallback = urls.createConf @@ -119,6 +121,18 @@ module.exports.finishAuth = async (req) => { return { error: "L'identification a échoué. Entrez votre adresse mail ci-dessous pour recommencer." } } const email = userinfo.email + + try { + const domain = format.extractEmailDomain(email) + const whitelistedDomains = await getWhitelistedDomains() + if(!whitelistedDomains.includes(domain)){ + throw new Error(`The domain ${domain} is not whitelisted.`) + } + } catch(e){ + console.error(`error when validating email ${email}`,e) + return { error: `L'adresse e-mail ${email} n'est pas autorisée à utiliser ce service.` } + } + const user = {id_token: tokenSet.id_token, state: request.state} req.session.user = user