From 4ef66781499d86c410bafcb16a2b1bf134b18d92 Mon Sep 17 00:00:00 2001 From: Tristan Huet Date: Thu, 11 May 2023 20:56:37 +0200 Subject: [PATCH] fix: add token validation in GetEmbedInfo azure function --- api/GetEmbedInfo/index.js | 2 +- api/GetEmbedInfo/utils.js | 43 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/api/GetEmbedInfo/index.js b/api/GetEmbedInfo/index.js index 28e4776ff..366871f2a 100644 --- a/api/GetEmbedInfo/index.js +++ b/api/GetEmbedInfo/index.js @@ -23,7 +23,7 @@ module.exports = async function (context, req) { }; } else { // Get the details like Embed URL, Access token and Expiry - const error = utils.validateQuery(req); + const error = await utils.validateQuery(req); if (error) { context.res = { status: 200, diff --git a/api/GetEmbedInfo/utils.js b/api/GetEmbedInfo/utils.js index 13242dc04..063eb1ed6 100644 --- a/api/GetEmbedInfo/utils.js +++ b/api/GetEmbedInfo/utils.js @@ -2,6 +2,8 @@ // Licensed under the MIT license. const guid = require('guid'); +const jwt = require('jsonwebtoken'); +const jwksClient = require('jwks-rsa'); function getAuthHeader(accessToken) { // Function to append Bearer against the Access Token @@ -51,7 +53,46 @@ function validateConfig() { } } -const validateQuery = (req) => { +const _validateAndDecodeQueryToken = async (req) => { + const client = jwksClient({ jwksUri: 'https://login.microsoftonline.com/common/discovery/keys' }); + const options = { + // audience check is optional but strongly advised, it won't be checked if CSM_API_TOKEN_AUDIENCE is not defined + audience: process.env.CSM_API_TOKEN_AUDIENCE, + }; + + const _getSigningKey = (header, callback) => { + client.getSigningKey(header.kid, (error, key) => { + if (error) { + console.error(error); + throw error; + } + const signingKey = key.publicKey || key.rsaPublicKey; + callback(null, signingKey); + }); + }; + + const accessToken = req?.headers?.authorization?.replace('Bearer ', ''); + if (!accessToken) { + throw new Error('token is missing in query.'); + } + + return new Promise((resolve, reject) => + jwt.verify(accessToken, _getSigningKey, options, (err, decoded) => { + return err ? reject(err) : resolve(decoded); + }) + ); +}; + +const validateQuery = async (req) => { + try { + const token = await _validateAndDecodeQueryToken(req); + if (!token) return "Unauthorized: can't decode token"; + if (!token.roles || token.roles.length === 0) return 'Unauthorized: missing roles for Cosmo Tech API'; + } catch (error) { + console.error('Token validation error: ' + error); + return 'Unauthorized: ' + error; + } + const reportsIds = req?.body?.reports; if (!Array.isArray(reportsIds)) { return 'Query is invalid. Parameter "reports" must be an array.';