From f7d766e8ebe493ae05db2911b8ebbfb658b75383 Mon Sep 17 00:00:00 2001 From: e-halinen <54105602+e-halinen@users.noreply.github.com> Date: Fri, 30 May 2025 15:48:24 +0300 Subject: [PATCH] AB#60123: Switch to assigned group-based access control --- .env.dev | 6 ++-- .env.prod | 4 +-- constants.js | 4 +-- scripts/auth/authEndpoints.js | 34 +++++++------------ scripts/server.js | 61 +++++++++++++++++++++++++++++++---- 5 files changed, 72 insertions(+), 37 deletions(-) diff --git a/.env.dev b/.env.dev index 6baa078..f0192b3 100644 --- a/.env.dev +++ b/.env.dev @@ -18,7 +18,5 @@ API_CLIENT_ID=2411181397763460 API_CLIENT_SECRET= REDIRECT_URI=https://dev.kartat.hsl.fi/kartta LOGIN_PROVIDER_URI=https://hslid-uat.cinfra.fi -DOMAINS_ALLOWED_TO_GENERATE= -DOMAINS_ALLOWED_TO_LOGIN= - -ROUTEMAP_TEST_GROUP=Karttageneraattori-test \ No newline at end of file +GROUP_GENERATE= +GROUP_READONLY= diff --git a/.env.prod b/.env.prod index c18643f..883fb15 100644 --- a/.env.prod +++ b/.env.prod @@ -18,5 +18,5 @@ API_CLIENT_ID=2411181397763460 API_CLIENT_SECRET= REDIRECT_URI=https://kartat.hsl.fi/kartta LOGIN_PROVIDER_URI=https://hslid-uat.cinfra.fi -DOMAINS_ALLOWED_TO_GENERATE= -DOMAINS_ALLOWED_TO_LOGIN= \ No newline at end of file +GROUP_GENERATE= +GROUP_READONLY= diff --git a/constants.js b/constants.js index 97a68fc..b1a6126 100644 --- a/constants.js +++ b/constants.js @@ -43,8 +43,8 @@ module.exports = { AZURE_STORAGE_KEY: secretsEnv.AZURE_STORAGE_KEY || '', CLIENT_SECRET: secretsEnv.CLIENT_SECRET || '', API_CLIENT_SECRET: secretsEnv.API_CLIENT_SECRET || '', - DOMAINS_ALLOWED_TO_LOGIN: secretsEnv.DOMAINS_ALLOWED_TO_LOGIN || '', + GROUP_GENERATE: secretsEnv.GROUP_GENERATE || '', + GROUP_READONLY: secretsEnv.GROUP_READONLY || '', HSL_TESTING_HSLID_USERNAME: secretsEnv.HSL_TESTING_HSLID_USERNAME || '', HSL_TESTING_HSLID_PASSWORD: secretsEnv.HSL_TESTING_HSLID_PASSWORD || '', - ROUTEMAP_TEST_GROUP: secretsEnv.ROUTEMAP_TEST_GROUP || '', }; diff --git a/scripts/auth/authEndpoints.js b/scripts/auth/authEndpoints.js index 9bfaf89..5b9cf4a 100644 --- a/scripts/auth/authEndpoints.js +++ b/scripts/auth/authEndpoints.js @@ -2,30 +2,19 @@ const { get, last, clone } = require('lodash'); const AuthService = require('./authService'); const validator = require('validator'); -const { DOMAINS_ALLOWED_TO_LOGIN, ROUTEMAP_TEST_GROUP } = require('../../constants'); +const { GROUP_GENERATE, GROUP_READONLY } = require('../../constants'); -const allowedDomains = DOMAINS_ALLOWED_TO_LOGIN.split(','); +const hasAllowedGroup = async (userInfo) => { + const groups = get(userInfo, 'groups', {}); -const hasAllowedDomain = async (userInfo) => { - const groups = get(userInfo, 'groups'); - - const emailValidationOptions = { - host_whitelist: allowedDomains, - }; - - if (groups.includes(ROUTEMAP_TEST_GROUP)) { - return true; - } - - if ( - !validator.isEmail(userInfo.email, emailValidationOptions) && - !groups.includes(ROUTEMAP_TEST_GROUP) - ) { - console.log(`User does not have allowed domain. Logging out.`); + if (!groups || !Array.isArray(groups)) { + console.log('User does not have valid groups assigned'); return false; } - - return true; + if (groups.includes(GROUP_GENERATE) || groups.includes(GROUP_READONLY)) { + return true; + } + return false; }; const authorize = async (req, res, session) => { @@ -63,7 +52,7 @@ const authorize = async (req, res, session) => { if (session && tokenResponse.access_token) { modifiedSession.accessToken = tokenResponse.access_token; const userInfo = await AuthService.requestUserInfo(modifiedSession.accessToken); - const isAllowed = await hasAllowedDomain(userInfo); + const isAllowed = await hasAllowedGroup(userInfo); if (!isAllowed) { return { status: 401, @@ -100,7 +89,7 @@ const authorize = async (req, res, session) => { const checkExistingSession = async (req, res, session) => { if (session && session.accessToken) { - const isAllowed = await hasAllowedDomain(session); + const isAllowed = await hasAllowedGroup(session); if (!isAllowed) { await AuthService.logoutFromIdentityProvider(session.accessToken); return { @@ -111,6 +100,7 @@ const checkExistingSession = async (req, res, session) => { const response = { isOk: true, email: session.email, + groups: session.groups, }; return { status: 200, diff --git a/scripts/server.js b/scripts/server.js index 06fdc0c..564150d 100644 --- a/scripts/server.js +++ b/scripts/server.js @@ -29,7 +29,7 @@ const { } = require('./joreStore'); const { downloadPostersFromCloud } = require('./cloudService'); -const { REDIS_CONNECTION_STRING } = require('../constants'); +const { REDIS_CONNECTION_STRING, GROUP_GENERATE } = require('../constants'); const PORT = 4000; @@ -106,12 +106,40 @@ async function main() { }); router.post('/builds', async (ctx) => { + const authResponse = await authEndpoints.checkExistingSession( + ctx.request, + ctx.response, + ctx.session, + ); + + if (!authResponse.body.isOk) { + ctx.throw(401, 'Not allowed.'); + } + + if (!authResponse.body.groups.includes(GROUP_GENERATE)) { + ctx.throw(403, 'User does not have permission to modify builds.'); + } + const { title } = ctx.request.body; const build = await addBuild({ title }); ctx.body = build; }); router.put('/builds/:id', async (ctx) => { + const authResponse = await authEndpoints.checkExistingSession( + ctx.request, + ctx.response, + ctx.session, + ); + + if (!authResponse.body.isOk) { + ctx.throw(401, 'Not allowed.'); + } + + if (!authResponse.body.groups.includes(GROUP_GENERATE)) { + ctx.throw(403, 'User does not have permission to modify builds.'); + } + const { id } = ctx.params; const { status } = ctx.request.body; const build = await updateBuild({ @@ -122,6 +150,20 @@ async function main() { }); router.delete('/builds/:id', async (ctx) => { + const authResponse = await authEndpoints.checkExistingSession( + ctx.request, + ctx.response, + ctx.session, + ); + + if (!authResponse.body.isOk) { + ctx.throw(401, 'Not allowed.'); + } + + if (!authResponse.body.groups.includes(GROUP_GENERATE)) { + ctx.throw(403, 'User does not have permission to modify builds.'); + } + const { id } = ctx.params; const build = await removeBuild({ id }); ctx.body = build; @@ -143,13 +185,18 @@ async function main() { if (!authResponse.body.isOk) { ctx.throw(401, 'Not allowed.'); } - const posters = []; - for (let i = 0; i < props.length; i++) { - // eslint-disable-next-line no-await-in-loop - const poster = await generatePoster(buildId, props[i]); - posters.push(poster); + + if (!authResponse.body.groups.includes(GROUP_GENERATE)) { + ctx.throw(403, 'User does not have permission to generate posters.'); + } else { + const posters = []; + for (let i = 0; i < props.length; i++) { + // eslint-disable-next-line no-await-in-loop + const poster = await generatePoster(buildId, props[i]); + posters.push(poster); + } + ctx.body = posters; } - ctx.body = posters; }); router.post('/cancelPoster', async (ctx) => {